Skip to content

feat(extractor): alias @emotion/css css, cx, keyframes and injectGlobal - #716

Merged
owjs3901 merged 13 commits into
mainfrom
fix/emotion-css
Oct 14, 2026
Merged

owjs3901 merged 13 commits into
mainfrom
fix/emotion-css

Conversation

@owjs3901

@owjs3901 owjs3901 commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Refs #690 (D 이슈 첫 번째 PR). main에서 분기했습니다.

요약

@emotion/css를 기본 alias에 추가하고, cx는 Emotion처럼 클래스 이름을 받아 합치도록, merge는 빌드 때 클래스 문자열을 합성하도록 컴파일합니다.

import { css, cx, merge } from '@emotion/css'

const red = css({ color: 'red' })
export const a = cx('external')
export const b = cx(red, 'external', { picked: true })
export const d = (cls) => merge(`${red} external ${cls}`)
export const a = "external"
export const b = "a external picked"
export const d = (cls) => `a external ${cls}`
// .a{color:red}

동작

  • @emotion/css를 기본 alias에 추가했습니다.
    • css, keyframes: Devup UI와 같이 컴파일합니다. 숫자는 Emotion처럼 px로 읽습니다(padding: 8 → 8px).
    • injectGlobal: globalCss로 바뀝니다.
    • cx, merge: @devup-ui/react/compat로 옮겨 빌드 때 컴파일합니다(런타임에 호출하면 Cannot run on the runtime을 던집니다).
  • cx(...)는 css()가 아니라 클래스 이름을 받습니다.
    • 문자열은 항상 클래스입니다. 공백으로 나눠 한 개씩 합성합니다(cx('external') → "external").
    • 런타임 값(cls, props.className 등)은 그대로 남는 클래스입니다. falsy 값은 건너뜁니다.
    • 객체는 항상 { name: condition } 클래스 맵입니다. 조건이 참인 동안 name이 붙고, 계산된 키([cls]: on)는 키의 값이 클래스가 됩니다. true/false/null/숫자 같은 리터럴 조건은 빌드 때 접습니다. 객체 안의 숫자는 px로 바뀌지 않습니다.
    • 배열은 중첩됩니다. a && 'x', a || 'x', a ?? 'x', 삼항식도 읽습니다.
    • 인라인 css(...) 호출과 빌드가 아는 css() 클래스는 css(a, b)가 쓰는 합성 경로를 그대로 지나갑니다. 이 브랜치에서는 클래스를 이어 붙이고, #706이 병합되면 스타일 기준 합성(뒤가 이김)이 자동으로 따라옵니다.
  • merge(className): 인자를 빌드 때 읽을 수 있는 만큼 나눕니다(문자열 토큰, 공백으로 떨어진 템플릿 리터럴 조각). 알려진 css() 클래스는 cx처럼 합성하고, 나머지 클래스는 그대로 둡니다. 나눌 수 없는 런타임 문자열은 그대로 둡니다(cascade가 정합니다).
  • 타입 선언(compat/emotion): cx(...args: ClassNamesArg[]) => string, merge(className: string) => string, ClassNamesArg 타입을 @emotion/css에 선언했습니다. 소비자 프로젝트에서 @ts-expect-error로 merge('a', 'b'), merge({}), cx(() => 'a')가 거부되는 것까지 검사했습니다.

새로 생기는 오류

모두 파일:줄:열과 함께 빌드 오류로 보고됩니다.

  • cx()/merge()의 인자 spread: cx(...list), 배열 안 spread cx([...list])
  • cx() 클래스 맵의 spread, getter, setter, 메서드: cx({ ...rest }), cx({ get x() { ... } })
  • cx 또는 merge를 태그드 템플릿으로 호출: cx`a b`
  • merge()에 인자가 하나가 아닌 경우: merge('a', 'b'), merge()

남는 한계

  • 런타임 문자열은 나눌 수 없습니다. merge(props.className)는 그대로 남고, 그 안에 든 css() 클래스끼리의 우선순위는 CSS cascade가 정합니다.
  • 다른 파일에서 정의한 css() 결과는 변수로만 합쳐지는 런타임 클래스입니다(모듈 해석을 통한 합성은 A 이슈 범위).
  • 런타임 전용 API(cache, flush, hydrate, sheet, getRegisteredStyles, create-instance)는 @emotion/css에 남습니다. K #693에서 문서화합니다.

검증

  • cargo fmt, cargo +1.99 clippy --workspace --all-targets -- -D warnings, cargo test --workspace 통과. 새 테스트: test_emotion_cx_takes_class_names, test_emotion_merge_splits_what_it_can, test_emotion_cx_and_merge_report_what_they_cannot_compile, test_emotion_class_calls_follow_the_package_namespace_and_aliases, test_emotion_css_maps_onto_devup_equivalents.
  • 넓은 rustfmt 설정(CI와 같은 설정)으로 cargo tarpaulin을 돌려 새 코드(class_arguments.rs, util_type.rs, style_values.rs) 줄 커버리지 100%를 확인했습니다.
  • WASM 재빌드, 루트 bun run build, bun test 5476 통과, 커버리지 100%
  • bun lint: 기존 경고 2개 외 없음
  • 프로브 emotion-css-cx.tsx: a = "external", b = "a external picked", .a{color:red}만 생성되고 .b{picked:true} 규칙은 없습니다.
  • 소비자 프로젝트 타입 검사(@devup-ui/react/compat/emotion) 통과
  • Rust 1.99 clippy assert_is_empty 수정은 fix(extractor): let a later css() part replace an earlier one's declarations #706 등과 같은 내용입니다.

W28: 네임스페이스 Import 보강

요약

import * as E from '@emotion/css'의 E.css, E.cx, E.merge, E.keyframes, E.injectGlobal을 기존 named import와 같은 추출 경로로 컴파일합니다. 네임스페이스만 쓰는 파일이 런타임 Emotion 호출과 빈 CSS를 그대로 내보내던 문제를 수정했습니다.

동작

  • 점 표기, 문자열 대괄호 표기, 상수 문자열 키, const { css, cx: classNames } = E 구조분해, const N = E / const c = N.css 별칭을 심볼 기준으로 추적합니다. 같은 이름의 지역 변수·매개변수는 변경하지 않습니다.
  • css·keyframes·injectGlobal의 숫자는 px이며 단위 없는 속성은 숫자를 유지합니다. 상수 인라인·Boa 정적 계산 뒤에도 같은 단위를 유지합니다.
  • cx 클래스 맵의 숫자는 참/거짓 조건으로만 쓰고 CSS 선언으로 읽지 않습니다. merge와 클래스 합성은 이 PR의 named import와 같은 규칙을 사용합니다.
  • 런타임 전용 cache, flush, hydrate, sheet, getRegisteredStyles를 읽는 경우 해당 참조와 @emotion/css import를 유지합니다. 이 멤버들의 중첩 구조분해·기본값·optional 조회도 유지합니다. 스타일 API만 사용하면 Emotion import는 사라집니다.
  • alias를 끄면 해당 Emotion 코드는 기존처럼 처리하지 않습니다. 원본 소스 맵과 오류의 파일·줄·열을 유지합니다.

새로 생기는 오류

모두 파일:줄:열: ... cannot use ... at build time: ... 형식입니다.

  • 루트 @emotion/css에는 default export가 없으므로 value default import를 거부합니다. default export가 있는 @emotion/css/create-instance와 혼동하지 않습니다.
  • 정적으로 알 수 없는 네임스페이스 키, 존재하지 않는 export, 네임스페이스 객체 또는 스타일 함수의 외부 전달·변경·재수출
  • optional 스타일 조회·호출, let·var 스타일 별칭, 네임스페이스 rest 구조분해, 스타일 API의 기본값·중첩 구조분해, 스타일 API 바인딩 자체의 export
  • 별칭이 초기화되기 전에 실행될 수 있는 조회: 기존 코드의 TDZ 오류를 클래스 문자열로 바꾸어 숨기지 않도록, 초기화 순서를 증명할 수 없으면 빌드 오류로 보고합니다.
  • require·TS import-equals·동적 import 등 정적 ESM import가 아닌 경로에서 스타일 API를 읽는 경우: 정적 import * as ns from '@emotion/css' 사용을 안내합니다. await 없이 namespace를 Promise·callback으로 넘기는 동적 import도 빌드가 추적할 수 없어 오류입니다. 인식되는 런타임 로더의 런타임 전용 API 조회는 보존합니다.
  • 기존 css·cx·merge·keyframes·injectGlobal이 읽을 수 없는 입력은 named import와 같은 빌드 오류를 보고합니다.

남는 한계

  • 런타임 클래스 문자열의 합성 한계는 위 PR 설명과 같습니다. 네임스페이스 지원은 런타임 스타일 함수를 추가하지 않습니다.
  • @emotion/react·@vanilla-extract/css 네임스페이스와 @emotion/css/create-instance는 이 작업 범위가 아닙니다.
  • 기존 compat/emotion.d.ts는 런타임 전용 API의 타입을 선언하지 않습니다. 런타임 전용 멤버 보존과 별개인 기존 타입 선언 누락으로 코디네이터에 보고합니다.
  • 별칭 선언보다 먼저 만들어진 함수 표현식·arrow는 호출이 나중이어도 초기화 순서를 보수적으로 판정해 거부할 수 있습니다. 별칭을 먼저 선언하면 됩니다. Hoisted 함수 선언은 알려진 호출 위치가 모두 초기화 뒤인 경우 컴파일합니다.

검증

  • cargo fmt --all, cargo +1.99 clippy --workspace --all-targets -- -D warnings, cargo test --workspace 통과: extractor 테스트 1581개 통과
  • WASM·루트 패키지 재빌드 통과, bun test 5476개 통과, 커버리지 100%, bun lint는 기존 경고 2개 외 없음
  • 최종 WASM 공개 API 프로브 20개 및 namespace-only 소스 맵 프로브 통과. 정적 멤버·구조분해·문자열 키·별칭·shadowing·런타임 멤버 보존·빌드 오류·alias 비활성화 및 wrapper·템플릿 리터럴이 있는 오류 표현의 원문 복원을 확인했습니다.
  • Linux CI run 37163339327 전체 통과: Rust 100.00% coverage, 10529/10529 lines covered, Bun 5484개/0 fail/100%, publish·benchmark·landing-next-e2e·vinext-rsc-css-e2e 및 codecov/patch SUCCESS. 최초 CI의 미실행 6줄을 실제 테스트와 구조 정리로 보강했으며 제외나 suppression은 추가하지 않았습니다.
  • 최종 head: 9b2a04a346d0d9f13748a9bf358512206db5e5bc. 새 커밋은 37f692ab(구현·회귀 테스트), 112af7b0(Patch note), 9b2a04a3(커버리지 보강)이며 기존 PR branch에 fast-forward로 푸시했습니다.
  • 최종 원문 복원·커버리지 수정의 Oracle 재검토 APPROVE. 재검토에서도 24개 공개 WASM assertions가 독립적으로 통과했습니다.
  • LSP daemon은 timeout이라 LSP clean 결과는 주장하지 않습니다. Rust 컴파일러·workspace clippy·테스트가 정적 검증 근거입니다.

아래는 빈 theme를 등록한 실제 WASM 프로브의 출력입니다. 클래스 합성은 named import와 같으며, 런타임 전용 멤버를 읽을 때만 Emotion import가 남습니다.

namespace.tsx

=== CODE ===
import "@devup-ui/react/devup-ui.css";
const red = "a b c";
const { css: localCss, cx: classNames, merge: joinClasses } = {
	"css": void 0,
	"cx": void 0,
	"merge": void 0
};
const blue = "d e";
export const direct = "a b c d e external picked";
export const destructured = "a b c on";
export const merged = "a b c external";
export const animation = "f";
;

=== CSS (this file) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */@layer b;@layer b{body{margin:8px}}@keyframes f{from{opacity:0;width:10px}}.d{color:blue}.a{color:red}.c{line-height:1.5}.e{margin:2px}.b{padding:8px}
=== CSS (whole sheet) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */@layer b;@layer b{body{margin:8px}}@keyframes f{from{opacity:0;width:10px}}.d{color:blue}.a{color:red}.c{line-height:1.5}.e{margin:2px}.b{padding:8px}

brackets.tsx

=== CODE ===
import "@devup-ui/react/devup-ui.css";
const red = "a b";
const { ["css"]: localCss, cx, merge, keyframes, injectGlobal } = {
	"css": void 0,
	"cx": void 0,
	"merge": void 0,
	"keyframes": void 0,
	"injectGlobal": void 0
};
const blue = "c";
export const direct = "a b c selected";
export const merged = "a b external";
export const animation = "d";
;

=== CSS (this file) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */body{margin:0}@keyframes d{from{width:10px}}.c{color:blue}.b{opacity:.5}.a{padding:8px}
=== CSS (whole sheet) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */body{margin:0}@keyframes d{from{width:10px}}.c{color:blue}.b{opacity:.5}.a{padding:8px}

runtime.tsx

=== CODE ===
import "@devup-ui/react/devup-ui.css";
import * as E from "@emotion/css";
export const style = "a";
export const cache = E.cache;
export const sheet = E.sheet;
E.flush();
E.hydrate(["server"]);
E.getRegisteredStyles([], "external");

=== CSS (this file) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */.a{padding:8px}
=== CSS (whole sheet) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */.a{padding:8px}

shadow.tsx

=== CODE ===
import "@devup-ui/react/devup-ui.css";
export const style = "a";
export function nested(E: {
	css: (rules: {
		padding: number;
	}) => string;
}) {
	return E.css({ padding: 8 });
}
export function scoped() {
	const { css: make } = { "css": void 0 };
	return "b";
}

=== CSS (this file) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */.b{margin:2px}.a{padding:8px}
=== CSS (whole sheet) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */.b{margin:2px}.a{padding:8px}

runtime-patterns.tsx

=== CODE ===
import * as E from "@emotion/css";
const { cache: { key }, flush = () => {} } = {
	"cache": E["cache"],
	"flush": E["flush"]
};
export const optionalCache = E?.cache;
export const runtime = {
	key,
	flush
};

=== CSS (this file) ===

=== CSS (whole sheet) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */

undefined.tsx

=== CODE ===
import "@devup-ui/react/devup-ui.css";
const c = void 0;
const undefined = 1;
export const style = "a";
export const value = undefined;

=== CSS (this file) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */.a{padding:8px}
=== CSS (whole sheet) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */.a{padding:8px}

alias-wrappers.tsx

=== CODE ===
import "@devup-ui/react/devup-ui.css";
const c = void 0;
const other = void 0;
export const style = "a";
export const style2 = "b";

=== CSS (this file) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */.b{margin:2px}.a{padding:8px}
=== CSS (whole sheet) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */.b{margin:2px}.a{padding:8px}

string-named.tsx

=== CODE ===
import "@devup-ui/react/devup-ui.css";
export const style = "a";

=== CSS (this file) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */.a{padding:8px}
=== CSS (whole sheet) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */.a{padding:8px}

error.tsx

=== ERROR ===
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w28-emotion-css-namespace/error.tsx:3:35: `@emotion/css()` cannot use `E[key]` at build time: namespace member keys must be constant strings

default.tsx

=== ERROR ===
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w28-emotion-css-namespace/default.tsx:1:8: `@emotion/css()` cannot use `E` at build time: the root module has no default export; use named or namespace imports

import-equals.tsx

=== ERROR ===
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w28-emotion-css-namespace/import-equals.tsx:2:22: `@emotion/css()` cannot use `E.css` at build time: styling APIs read through require(), import-equals or dynamic import cannot be compiled; use `import * as ns from '@emotion/css'`

tdz.tsx

=== ERROR ===
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w28-emotion-css-namespace/tdz.tsx:3:16: `@emotion/css()` cannot use `c` at build time: an alias must be initialized before any read that can run first; declare it above the earliest code that can reach this read

comment.tsx

=== ERROR ===
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w28-emotion-css-namespace/comment.tsx:3:22: `cx()` cannot use `E.cx`a b`` at build time: call it with class names, as in `cx('a', 'b')`

dynamic-styling.tsx

=== ERROR ===
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w28-emotion-css-namespace/dynamic-styling.tsx:2:22: `@emotion/css()` cannot use `E.css` at build time: styling APIs read through require(), import-equals or dynamic import cannot be compiled; use `import * as ns from '@emotion/css'`

dynamic-runtime.tsx

=== CODE ===
const E = await import('@emotion/css')
E.flush()
export const cache = E?.cache

=== CSS (this file) ===

=== CSS (whole sheet) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */

module-loader.cjs

=== ERROR ===
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w28-emotion-css-namespace/module-loader.cjs:2:15: `@emotion/css()` cannot use `E.css` at build time: styling APIs read through require(), import-equals or dynamic import cannot be compiled; use `import * as ns from '@emotion/css'`

alias-off.tsx

=== CODE ===
import * as E from '@emotion/css'
export const style = E.css({ padding: 8 })

=== CSS (this file) ===

=== CSS (whole sheet) ===
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */

wrapped-error.tsx

=== ERROR ===
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w28-emotion-css-namespace/wrapped-error.tsx:2:23: `cx()` cannot use `(E.cx)`a b`` at build time: call it with class names, as in `cx('a', 'b')`

cast-error.tsx

=== ERROR ===
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w28-emotion-css-namespace/cast-error.tsx:2:23: `cx()` cannot use `(E.cx as typeof E.cx)`a b`` at build time: call it with class names, as in `cx('a', 'b')`

literal-error.tsx

=== ERROR ===
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w28-emotion-css-namespace/literal-error.tsx:2:23: `cx()` cannot use `E.cx`a __emotion_user`` at build time: call it with class names, as in `cx('a', 'b')`

2026-10-08 업데이트: main 11790bef를 merge commit으로 병합했습니다; 충돌 파일: 없음; 충돌 없이 자동 병합했고, 이미 포함된 squash 원본은 조상 확인 후 ours 전략으로 중복 적용하지 않았습니다.

  • 2026-10-14 업데이트: main bf3c92b6(fix(extractor): preserve conditional-spread precedence in styled objects #776, test: restore global state and scoped spies #778)부터 최신 a2b74d0f까지 실제 두 부모 merge commit으로 병합했습니다. 충돌 파일 libs/extractor/src/{import_alias_visit.rs,lib.rs,style_values.rs,visit.rs}, packages/next-plugin/src/__tests__/plugin.test.ts, packages/react/src/compat/{index.ts,__tests__/index.test.ts}에서 main의 타입 전용 import·VE companion 검사·keyframes getName·선택자 오류 요건·createTheme·process.env 객체 복원 및 scoped spy와 이 PR의 Emotion namespace·cx/merge·@emotion/css alias를 모두 보존했습니다. 공통 복구 7960b48f(fix: repair main tests, docs lint and Tailwind test isolation #780)의 전체 7개 파일도 원본과 바이트 동일하게 포함했으며, Rust 전체·Bun 5,877개(함수/줄 100%)·새 WASM/루트 빌드·실제 WASM 통합 프로브 16개·전체 훅이 통과했습니다. 기존 snapshot 변경 없음, 새 오류·추가 한계 없음.

  • 2026-10-14 추가 검증: 최초 업데이트 CI 38547094726의 기존 Tailwind 색상 기대값 20건은 공통 복구 b71ca4ea(fix: repair main tests, docs lint and Tailwind test isolation #780)를 별도 -x cherry-pick한 da26b8e2에서 수정했습니다. 새 WASM/루트 빌드를 다시 완료했으며 나머지 병합 내용과 snapshot은 그대로 유지했습니다.

owjs3901 and others added 2 commits October 2, 2026 12:49
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Changepacks

@devup-ui/wasm@1.0.83 → 1.0.84 - bindings/devup-ui-wasm/package.json

Patch

  • Rewriting styled-components, Emotion and vanilla-extract imports keeps type-only imports type-only: import { type DefaultTheme, ThemeProvider } now leaves import type { DefaultTheme } on the package instead of a value import that made it a runtime dependency, and an import type declaration is left as written. spin.getName() on a keyframes() binding becomes the generated keyframes name instead of a call on a string that threw at runtime
  • The styled-components and Emotion compat ThemeProvider now gives its theme through React context: useTheme, withTheme and the new ThemeConsumer return the real theme object (an object merged over the outer theme, or what a theme function makes of it) instead of an empty Proxy of var() references, withTheme forwards refs, lets a caller's theme win and sets a displayName. Styles keep reading the CSS variables the provider declares. styled-components v6.4 createTheme is available from the compat entry, and ThemeConsumer and createTheme imports are redirected there instead of staying a runtime dependency on styled-components
  • Respect source-order property replacement across conditional spreads in styled rule objects, and document that styled callbacks cannot return runtime class names. No new build errors; existing located Cannot compose errors remain unchanged.
  • Typography documents the emitted default breakpoints, and source-backed integration tests keep the public breakpoint lists and range bounds synchronized with the production defaults. No runtime changes or new build errors.
  • @emotion/css is aliased by default: css and keyframes compile like Devup UI's own (numbers in px, as Emotion reads them), injectGlobal declares global CSS. cx takes class names, as in Emotion: strings and runtime values are classes kept as written (falsy values are skipped), an object is a { name: condition } class map, arrays nest, and inline css() calls and css() classes compose with the rules css(a, b) uses. merge(className) splits what the build can read (string tokens, template literal parts) and composes the css() classes in it, keeping a runtime string it cannot split as it is. Namespace members, constant-string bracket access, const destructuring and const alias chains compile through these same named APIs with scope-aware binding resolution; numeric values retain Emotion units after constant inlining and build-time evaluation. The Emotion import disappears when no runtime-only member is used. Ambient declarations type the styling imports (cx(...args: ClassNamesArg[]), merge(className: string)). New located build errors: cx() cannot use a spread, a getter, a setter or a method in a class map, or a template literal call; merge() takes exactly one class string, not a spread or a template literal call; the root module has no default export, namespace member keys must be constant strings naming supported exports, and styling functions cannot be passed, mutated or re-exported. Optional styling reads/calls, namespace rest destructuring, styling defaults or nested patterns, non-const aliases, exported styling bindings and reads whose initialization order cannot be established are build errors instead of runtime dependencies. Styling loaded through require, import-equals or dynamic import must use static ES module imports; an unawaited dynamic namespace that the build cannot follow is also a located error. Its runtime-only APIs (cache, flush, hydrate, sheet, getRegisteredStyles) stay on @emotion/css, including their nested/default destructuring, optional reads and recognized runtime-loader access
  • style-order-range only checks styleOrder where the build reads it: a prop of a Devup UI component and a top-level key of a style object passed to css/globalCss/keyframes. A styleOrder key in nested data, in a prop value such as an element passed as a prop, or in a call of a function sharing a name with an Object.prototype member is no longer reported. The array, typography and media rules already skip non-style data, and css-utils-literal-only accepts a css()/keyframes() result held in a const inside a function. No new build errors.
  • The extractor guide shows reproducible native-element output, generated CSS-variable bindings, and actual atomic CSS rather than obsolete class names. Documentation only: no new build errors.
  • Selectors: a nested rule without & in a styled or css template is scoped to the component instead of becoming a global rule (.child {} and > p {} select descendants, :hover {} and ::before {} the component), and a rule nested in a selector list applies under each of its selectors; content keeps the quotes of its strings (content: 'x', content: ""); params go on the pseudo-class that takes them, so _groupNthChild gives :is(...):nth-child(2n) .a also when nested; a bare selectors key is a pseudo-class name, an attribute of the element or a descendant selector ('div p', '> p'), under a parent too, and keeps the case of class names; ::part(), ::slotted(), ::highlight(), ::picker() and the view-transition pseudo-elements get two colons. New build errors: a _name prop or selector key that names nothing (_notASelector, selectors={{ div: ... }}), and a string under a selector that is not CSS text (_hover="external-class")
  • stylex.attrs() gives the dynamic CSS variables it sets as style attribute text ("--a:" + value), as StyleX does for spreading onto non-React targets, instead of a style object; stylex.props() keeps the object React takes. The attrs() return type declares style as a string
  • Tailwind classes in a className: each class compiles on its own and every class Tailwind does not define (custom, plugin and analytics classes) stays as written, where any recognized class used to rebuild the whole className without them and could rewrite part of another class; a class touching a template interpolation (icon-${name}) is left as written, and template classNames no longer get spaces inserted around interpolations. A class whose variant is not understood stays as written instead of applying unconditionally; variants follow Tailwind v4: stacked variants compose (hover:focus: matches the element itself), hover is guarded by @media (hover: hover), group-/peer- use the group/peer marker classes (and group-hover/name), and data-, aria-, has-, nth-, , **, supports-[…] and [&…]/[@media …] variants compile. Utilities emit all their declarations (size-, rounded-t-, truncate, sr-only, not-sr-only, text-sm with its line height, text-sm/6, leading-), translate/rotate/scale/skew compose through Tailwind's individual properties and registered variables (@Property) with negative values kept negative, and arbitrary values follow Tailwind's grammar: spaces for underscores except in url() and var() names, _ for an underscore, spaces around math operators, type hints, [property:value] and (--variable) shorthands. Words that only share a utility's prefix (select-wrapper, order-summary, cursor-foo) are no longer compiled
  • Order standalone nonresponsive hover-capability guards within their selector group so active, focus and disabled styles can override hover. Keep responsive Tailwind hover and Devup selector prop ordering unchanged. No new build errors.
  • Tailwind classes in a className follow Tailwind CSS v4: colors are the v4 default palette (oklch) and the colors and shadows of devup.json theme are usable as Tailwind theme values (bg-primary, text-text, shadow-card, as var(--token)); the opacity modifier (bg-red-500/50, /[71.37%], /(--alpha)) mixes with color-mix as v4 does; a trailing or leading ! makes every declaration important; blur, brightness, contrast, grayscale, hue-rotate, invert, saturate, sepia and their backdrop-* forms compose through Tailwind's custom properties instead of overwriting filter and backdrop-filter; gradients use bg-linear-, bg-conic- and bg-radial-* with from-, via- and to-* composing through the gradient variables (bg-gradient-to-* is not defined by v4 and stays as written); animate-* brings the @Keyframes it names and transition, duration, delay and ease follow v4; space-* and divide-* apply to the children like v4 (:where(& > :not(:last-child))); @Property rules are emitted only for the custom properties a class uses. Anything the build cannot reproduce exactly (drop-shadow-*) stays as written in the className. No new build errors
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors
  • A styled-components or Emotion style function reading the theme by literal keys, such as p => p.theme.space[2] or ({ theme }) => theme.colors['brand'], now reads the CSS variable ThemeProvider declares (var(--space-2)). A theme read the build cannot turn into a CSS variable, such as p => p.theme, p => p.theme.brand() or theme.space[i], is a build error naming the file, line, column and code, where it used to read a theme object that does not exist at runtime and give undefined or throw
  • While @vanilla-extract/css is aliased, importing @vanilla-extract/recipes or @vanilla-extract/sprinkles is a build error naming the file, line and column: those packages generate CSS Devup UI does not compile, so their rules used to be silently missing from the stylesheet. The error says to write the styles with css(), or to disable the alias and build with the vanilla-extract plugin. Type-only imports are allowed
  • Skip source-map generation in the codeExtractWithoutSourceMap WASM export while preserving extracted code, CSS and dependencies. Add real WASM and Next loader regressions for map-enabled and map-disabled extraction. No new build errors.

@devup-ui/bun-plugin@1.0.22 → 1.0.23 - packages/bun-plugin/package.json

Patch

  • Bun plugin works with Bun.build: DevupUI() (from @devup-ui/bun-plugin/register) serves the generated stylesheet to the bundler's CSS loader once every other module is loaded, so the build emits a CSS output with the styles of the whole bundle instead of an empty module; class names are short there and readable under the runtime (debug option). Files importing the packages Devup UI takes the place of (@emotion/react, @emotion/styled, styled-components, @vanilla-extract/css), @stylexjs/stylex, or a subpath or re-export of these or @devup-ui/react, are compiled instead of skipped
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@devup-ui/components@0.1.60 → 0.1.61 - packages/components/package.json

Patch

  • Auto-update: depends on '@devup-ui/react' via a local workspace dependency

@devup-ui/eslint-plugin@1.0.22 → 1.0.23 - packages/eslint-plugin/package.json

Patch

  • The @devup-ui/react README and the css-utils-literal-only rule docs link their mention of build errors to the new Build Errors reference (https://devup-ui.com/docs/build-errors), which lists the build errors grouped by API; the docs sidebar lists the page after Supported Syntax & Limitations, whose Build errors section links to it. Documentation only: no new build errors
  • ESLint rules now check exactly what the build reads. The array, typography, media and styleOrder rules and css-utils-literal-only follow the import aliases the build compiles by default (@emotion/react, @emotion/styled, styled-components, @vanilla-extract/css) and the rules of styled (styled.div({...}), styled("div", {...}), styled(Base)({...}, {...}); not .attrs()), createGlobalStyle({...}) and the styles of Emotion Global, and check and fix a module-level const object that only styles read. Vanilla-extract stylesheets (.css.ts/.css.js) are no longer read as Devup UI. New rule no-runtime-read reports css/keyframes/styled/Box read as a value ("X is read at runtime, where it does not exist"), and css-utils-literal-only reports globals that do not exist where a .css.ts is evaluated (window, document, process, ...). No new build errors.
  • style-order-range only checks styleOrder where the build reads it: a prop of a Devup UI component and a top-level key of a style object passed to css/globalCss/keyframes. A styleOrder key in nested data, in a prop value such as an element passed as a prop, or in a call of a function sharing a name with an Object.prototype member is no longer reported. The array, typography and media rules already skip non-style data, and css-utils-literal-only accepts a css()/keyframes() result held in a const inside a function. No new build errors.

@devup-ui/next-plugin@1.0.90 → 1.0.91 - packages/next-plugin/package.json

Patch

  • Isolate the coordinator port file per owning process when another live next dev/build holds it, record the owner pid, and report port, pid and recovery when the coordinator is missing or unreachable
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors
  • Skip source-map generation in the codeExtractWithoutSourceMap WASM export while preserving extracted code, CSS and dependencies. Add real WASM and Next loader regressions for map-enabled and map-disabled extraction. No new build errors.

@devup-ui/plugin-utils@1.0.17 → 1.0.18 - packages/plugin-utils/package.json

Patch

  • Webpack and Rsbuild builds hold every style in their stylesheets: a stylesheet module is built on its first import, so styles extracted later (the global styles of files webpack or Rsbuild reached late, often outside src) were missing from the output. The files the entries reach under src are now extracted before the build, the shared base on disk is kept current, and when a stylesheet still changed during the build it is compiled once more, writing only the complete result. Rsbuild serves each stylesheet from the current sheet instead of a module-wide string kept only when it grew, which left edits that shortened the CSS and later builds in the same process stale. plugin-utils adds computeReachableFiles
  • @emotion/css is aliased by default: css and keyframes compile like Devup UI's own (numbers in px, as Emotion reads them), injectGlobal declares global CSS. cx takes class names, as in Emotion: strings and runtime values are classes kept as written (falsy values are skipped), an object is a { name: condition } class map, arrays nest, and inline css() calls and css() classes compose with the rules css(a, b) uses. merge(className) splits what the build can read (string tokens, template literal parts) and composes the css() classes in it, keeping a runtime string it cannot split as it is. Namespace members, constant-string bracket access, const destructuring and const alias chains compile through these same named APIs with scope-aware binding resolution; numeric values retain Emotion units after constant inlining and build-time evaluation. The Emotion import disappears when no runtime-only member is used. Ambient declarations type the styling imports (cx(...args: ClassNamesArg[]), merge(className: string)). New located build errors: cx() cannot use a spread, a getter, a setter or a method in a class map, or a template literal call; merge() takes exactly one class string, not a spread or a template literal call; the root module has no default export, namespace member keys must be constant strings naming supported exports, and styling functions cannot be passed, mutated or re-exported. Optional styling reads/calls, namespace rest destructuring, styling defaults or nested patterns, non-const aliases, exported styling bindings and reads whose initialization order cannot be established are build errors instead of runtime dependencies. Styling loaded through require, import-equals or dynamic import must use static ES module imports; an unawaited dynamic namespace that the build cannot follow is also a located error. Its runtime-only APIs (cache, flush, hydrate, sheet, getRegisteredStyles) stay on @emotion/css, including their nested/default destructuring, optional reads and recognized runtime-loader access
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@devup-ui/react@1.0.44 → 1.0.45 - packages/react/package.json

Patch

  • The @devup-ui/react README and the css-utils-literal-only rule docs link their mention of build errors to the new Build Errors reference (https://devup-ui.com/docs/build-errors), which lists the build errors grouped by API; the docs sidebar lists the page after Supported Syntax & Limitations, whose Build errors section links to it. Documentation only: no new build errors
  • The styled-components and Emotion compat ThemeProvider now gives its theme through React context: useTheme, withTheme and the new ThemeConsumer return the real theme object (an object merged over the outer theme, or what a theme function makes of it) instead of an empty Proxy of var() references, withTheme forwards refs, lets a caller's theme win and sets a displayName. Styles keep reading the CSS variables the provider declares. styled-components v6.4 createTheme is available from the compat entry, and ThemeConsumer and createTheme imports are redirected there instead of staying a runtime dependency on styled-components
  • @emotion/css is aliased by default: css and keyframes compile like Devup UI's own (numbers in px, as Emotion reads them), injectGlobal declares global CSS. cx takes class names, as in Emotion: strings and runtime values are classes kept as written (falsy values are skipped), an object is a { name: condition } class map, arrays nest, and inline css() calls and css() classes compose with the rules css(a, b) uses. merge(className) splits what the build can read (string tokens, template literal parts) and composes the css() classes in it, keeping a runtime string it cannot split as it is. Namespace members, constant-string bracket access, const destructuring and const alias chains compile through these same named APIs with scope-aware binding resolution; numeric values retain Emotion units after constant inlining and build-time evaluation. The Emotion import disappears when no runtime-only member is used. Ambient declarations type the styling imports (cx(...args: ClassNamesArg[]), merge(className: string)). New located build errors: cx() cannot use a spread, a getter, a setter or a method in a class map, or a template literal call; merge() takes exactly one class string, not a spread or a template literal call; the root module has no default export, namespace member keys must be constant strings naming supported exports, and styling functions cannot be passed, mutated or re-exported. Optional styling reads/calls, namespace rest destructuring, styling defaults or nested patterns, non-const aliases, exported styling bindings and reads whose initialization order cannot be established are build errors instead of runtime dependencies. Styling loaded through require, import-equals or dynamic import must use static ES module imports; an unawaited dynamic namespace that the build cannot follow is also a located error. Its runtime-only APIs (cache, flush, hydrate, sheet, getRegisteredStyles) stay on @emotion/css, including their nested/default destructuring, optional reads and recognized runtime-loader access
  • The README no longer claims every CSS-in-JS pattern compiles: it describes what the build compiles and that anything it cannot know is a CSS variable or a located build error, and links the new Supported Syntax & Limitations page, which lists what compiles, the style override rules (where a later part wins and where the CSS cascade decides), Baseline 2024 browser support, that a component taking the css prop must pass className and style on, the runtime-only APIs and how each is handled, and the known limitations
  • stylex.attrs() gives the dynamic CSS variables it sets as style attribute text ("--a:" + value), as StyleX does for spreading onto non-React targets, instead of a style object; stylex.props() keeps the object React takes. The attrs() return type declares style as a string

@devup-ui/reset-css@1.0.31 → 1.0.32 - packages/reset-css/package.json

Patch

  • Auto-update: depends on '@devup-ui/react' via a local workspace dependency

@devup-ui/rsbuild-plugin@1.0.67 → 1.0.68 - packages/rsbuild-plugin/package.json

Patch

  • Webpack and Rsbuild builds hold every style in their stylesheets: a stylesheet module is built on its first import, so styles extracted later (the global styles of files webpack or Rsbuild reached late, often outside src) were missing from the output. The files the entries reach under src are now extracted before the build, the shared base on disk is kept current, and when a stylesheet still changed during the build it is compiled once more, writing only the complete result. Rsbuild serves each stylesheet from the current sheet instead of a module-wide string kept only when it grew, which left edits that shortened the CSS and later builds in the same process stale. plugin-utils adds computeReachableFiles
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@devup-ui/vite-plugin@1.0.73 → 1.0.74 - packages/vite-plugin/package.json

Patch

  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@devup-ui/webpack-plugin@1.0.71 → 1.0.72 - packages/webpack-plugin/package.json

Patch

  • Webpack and Rsbuild builds hold every style in their stylesheets: a stylesheet module is built on its first import, so styles extracted later (the global styles of files webpack or Rsbuild reached late, often outside src) were missing from the output. The files the entries reach under src are now extracted before the build, the shared base on disk is kept current, and when a stylesheet still changed during the build it is compiled once more, writing only the complete result. Rsbuild serves each stylesheet from the current sheet instead of a module-wide string kept only when it grew, which left edits that shortened the CSS and later builds in the same process stale. plugin-utils adds computeReachableFiles
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
libs/extractor/src/class_arguments.rs 100.00% <100.00%> (ø)
libs/extractor/src/emotion_namespace.rs 100.00% <100.00%> (ø)
libs/extractor/src/emotion_namespace/acquire.rs 100.00% <100.00%> (ø)
libs/extractor/src/emotion_namespace/bindings.rs 100.00% <100.00%> (ø)
...bs/extractor/src/emotion_namespace/declarations.rs 100.00% <100.00%> (ø)
libs/extractor/src/emotion_namespace/driver.rs 100.00% <100.00%> (ø)
libs/extractor/src/emotion_namespace/order.rs 100.00% <100.00%> (ø)
libs/extractor/src/emotion_namespace/output.rs 100.00% <100.00%> (ø)
libs/extractor/src/emotion_namespace/reads.rs 100.00% <100.00%> (ø)
libs/extractor/src/emotion_namespace/restore.rs 100.00% <100.00%> (ø)
... and 18 more

... and 10 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

owjs3901 and others added 4 commits October 3, 2026 16:18
…composition

Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
owjs3901 and others added 7 commits October 8, 2026 22:53
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Refs #690; includes exact main repair 7960b48

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #770, #734

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
(cherry picked from commit b71ca4e)
@owjs3901
owjs3901 merged commit 9363d5e into main Oct 14, 2026
5 checks passed
@owjs3901
owjs3901 deleted the fix/emotion-css branch October 14, 2026 11:55
owjs3901 added a commit that referenced this pull request Oct 14, 2026
Refs #688 #707 #777 #716 #743

Preserve inherited captures and actual TS targets; cover dynamic bases and assertion guards

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant