Skip to content

fix(extractor): prevent folding escaped object reads - #765

Draft
owjs3901 wants to merge 54 commits into
mainfrom
fix/escape-aware-folding
Draft

owjs3901 wants to merge 54 commits into
mainfrom
fix/escape-aware-folding

Conversation

@owjs3901

@owjs3901 owjs3901 commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Refs #694 (G: 결정론), #695 (F: 상수 및 spread). #756과 #757을 모두 포함하는 브랜치이며, 두 PR이 모두 먼저 병합되어야 합니다.

요약

이 PR은 W39 작업 중인 초안입니다. 핵심 수정 59f2dce5와 scalar 정밀도 수정 bba266d69622d0e01a5c47ffe6114f8b4c2b341a를 커밋 및 push했습니다. 추가로 발견한 4개 escape 예외와 Linux Rust 100% 커버리지 개선을 진행 중이므로 아직 merge-ready가 아닙니다. 객체가 알 수 없는 코드로 전달되거나 변경된 뒤의 프로퍼티 읽기를 초기값으로 잘못 폴딩하는 문제를 수정합니다. 런타임 스타일링은 추가하지 않습니다.

병합 기준 커밋은 7391e11aebb604c8a73804ddf82b6301044e5f9f입니다. 테스트 모듈 충돌은 양쪽을 모두 유지했고, inline_imported_constants 스냅샷은 테스트로 재생성하여 #757의 CJS_DYNAMIC과 #756의 spread lowering을 함께 확인했습니다. #756 테스트의 이전 평가 호출은 #757의 evaluate_located 반환형으로 연결했습니다.

shadowed require 테스트는 모듈 해석을 하지 않는 경우와 실제 global require 오류로 분리했습니다. 실제 오류는 helper.ts:1:25, 소스 위치가 없는 요청의 ingress fallback은 entry.tsx:2:23으로 검증합니다. 잘못된 빈 JSX styleOrder={}는 위치 있는 파싱 오류로 검증하고, 정상 fixture는 void 0을 사용합니다. bun install이 갱신한 11개 workspace 버전 메타데이터도 같은 병합 트리에 포함했습니다. #756과 #757 중 나중에 main에 병합하는 PR에도 이 통합 변경이 필요합니다.

동작

수정 전 실제 WASM 프로브:

const make = () => ({ p: 1 });
const made = make();
watch(made);
const f = () => made.p;
export const a = css({ p: f() });
const make = () => ({ p: 1 });
const made = make();
watch(made);
const f = () => made.p;
export const a = "a-b";
// .a-b{padding:4px}

watch가 made.p를 변경할 수 있는데도 초기값을 CSS로 고정하는 것이 문제입니다. 수정 후 같은 실제 WASM 프로브는 다음 오류를 냅니다.

/src/escape.tsx:6:18: `css()` cannot use `f()` at build time: its values must be literals, theme tokens or constants, or be computed from them
/src/escape.tsx:4:7: `made` is handed here to code that may change it near `watch(made)`, so the build cannot read it as a constant; use a direct value, freeze before the first escape, or move the mutation outside the build-time computation

일반 요소의 <Box p={f()} />는 원래 f()를 CSS 변수로 전달합니다. getter/coercion/callback이 없는 plain-data 인자에 한해 JSON.stringify, String, Number, Object.keys, Object.freeze와 명시된 17개 console builtin을 read-only로 취급합니다. Shadowed/변경된 builtin, 사용자 메서드 이름만 같은 경우는 제외합니다. Object.freeze는 얕으므로 자신의 scalar slot만 보호하고 nested 객체는 보호하지 않습니다.

새로 생기는 오류

객체 escape 또는 쓰기 이후 정확성을 증명할 수 없는 값을 css, styled 템플릿, globalCss, keyframes, compat/StyleX 등 요소에 런타임 값을 전달할 수 없는 API가 읽으면 위치 있는 빌드 오류가 발생합니다. Unknown call/메서드, alias/중첩 컨테이너 전달, captured write, assignment/update/delete, Object.assign/defineProperty 계열, setter가 대상입니다. 소비 위치와 원래 binding/escape·쓰기 위치 및 코드, direct scalar/copy 전달·escape 전 freeze·변경 이동 방법을 보고합니다. 요소의 일반 스타일 값은 기존 CSS 변수 경로를 사용합니다.

남는 한계

  • 분석 범위는 한 JavaScript 모듈입니다. 다른 모듈이 exported/imported 객체를 변경하지 않는다는 기존 가정은 유지합니다.
  • 클래스 이름, resolver, JSX-02 변경은 이번 수정의 범위가 아닙니다.
  • sibling scalar helper, scalar shallow-copy helper, frozen-parent scalar helper 정밀도는 bba266d6에서 수정했고 exact-positive 22개를 모두 통과합니다.
  • 미완료: 요소 prop 안의 nested runtime unknown call, runtime setTheme를 compile-only로 취급하는 예외, shallow-freeze 반환 alias의 nested child 전달, direct eval의 lexical mutation 경로를 추가로 재현했습니다. 이 4개와 Rust 100% 검증 전에는 완료/merge-ready로 간주하지 않습니다.

검증

  • 병합 기준 트리: WASM 빌드 및 루트 패키지 빌드 통과.
  • cargo fmt --all, Rust 1.99 clippy 및 workspace 테스트 통과: extractor 2708, CSS 530, sheet 148, WASM 42.
  • exact-tree 병합 커밋 hook 통과; Bun 5504 통과 / 0 실패 / 커버리지 100%.
  • Windows 기본 포맷 tarpaulin 기준: 97.87%, 20332/20775줄. Linux CI의 넓은 rustfmt 설정에서 100%를 별도 검증합니다.
  • apps/landing/dist/client 기준 비압축 CSS 61,850바이트, JS 693,559바이트, 172개 파일. 수정 후 같은 조건으로 비교합니다.
  • 18개 실제 WASM 프로브의 수정 전 결과를 기록했습니다. 기존 테스트, 스냅샷, 프로브의 변경 목록은 구현 완료 후 갱신합니다.
  • 기준 트리 Linux CI 37367102468: vinext-rsc-css-e2e 통과. publish, benchmark, landing-next-e2e는 runner를 할당받지 못하여 0개 단계 실행 후 취소되었습니다. GitHub Actions의 hosted-runner 할당 장애이며 코드 실패로 처리하지 않습니다. workflow 변경이나 반복 재실행 없이, 장애 복구 후 coordinator가 취소된 job을 재실행합니다.

핵심 수정 검증

  • 커밋된 최신 전체 Rust: extractor 2886 / CSS 530 / sheet 148 / WASM 42 통과. Rust 1.99 clippy 통과.
  • WASM 및 루트 패키지 재빌드, Bun 5504 통과 / 0 실패 / 100% 커버리지. exact-tree 커밋 hook 통과.
  • Windows 기본 포맷 최신 커밋 Rust 커버리지 97.63%, 20971/21481줄. Linux의 넓은 포맷에서 100%는 아직 증명되지 않았습니다.
  • landing, next, rsbuild, vite-lib, vite 앱 모두 빌드 통과. 모든 18개 benchmark fixture 빌드 통과. 앱·fixture 소스는 수정하지 않았고 새 빌드 오류도 없었습니다.
  • landing CSS 61,850 → 61,850바이트, JS 693,559 → 693,559바이트, 각각 172개 client CSS/JS 파일 기준.
  • 독립 실제 WASM 98개: build-only 오류 41/41, 요소 CSS 변수 35/35, exact-positive 22/22. 해당 matrix는 모두 통과하며, 이후 발견한 4개 추가 재현은 별도 수정 중입니다.
  • 핵심 수정 CI 37388610454, head 59f2dce5: landing-next-e2e, vinext-rsc-css-e2e, benchmark 통과. publish는 실제 Rust 커버리지 99.85% (14948/14970, 22줄 부족)로 실패했습니다. 스타일 기능 실패나 외부 장애로 숨기지 않습니다.
  • scalar 수정 CI 37391632758, head bba266d6: landing-next-e2e, vinext-rsc-css-e2e, benchmark 통과. publish의 실제 Rust 커버리지 실패를 추가 회귀 및 typed 구조 개선으로 처리 중입니다.
  • LSP daemon 요청은 timeout되며 LSP-clean은 주장하지 않습니다. compiler/clippy/test 및 실제 WASM 검증을 수행했습니다.

기존 테스트·스냅샷 출력 변경

  • mutations::tests::changes: 실제 Array identity가 증명되지 않은 .map은 callback-element escape 대신 receiver call hazard로 분류합니다.
  • mutations::tests::escapes: unknown .forEach/.map receiver hazard, 반환값·arrow capture의 holder 그래프를 기록합니다.
  • mutations::tests::reads: plain-data가 아닌 builtin 인자와 사용자 receiver 메서드는 보수적으로 hazard를 기록합니다. plain console 사례의 정상 폴딩은 별도 17개 회귀 사례로 유지합니다.
  • tests::test_changed_constants: 증거 사례가 class/padding:4px 대신 located error로 바뀌고, 기존 changed-value 오류에 origin 코드와 fix가 추가됩니다.
  • tests::test_emotion_css_prop_reports_what_it_cannot_compile: 기존 mutation 오류에 origin 코드와 fix가 추가됩니다.
  • tests::test_values_known_only_at_runtime: 기존 imported/changed-value 오류에 fix가 추가됩니다. 성공한 요소 출력은 그대로입니다.

변경된 스냅샷은 위 테스트와 대응하는 6개뿐이며, 모두 .snap.new를 검토한 후 assertion_line을 제거하여 수락했습니다. 신규 Rust 회귀 147개는 기존 API의 mutation, alias, freeze, builtin identity 및 scalar-copy 경계를 검증합니다.

Scalar 후속 수정

scalar 결과만 원래 source span에서 인라인하며 객체 전체나 closure에 새 실행 허용을 부여하지 않습니다. 모든 hazard, 원래 lexical binding 및 TDZ/source-readiness를 검사하여 mutable child와 shadowed/deferred/alias 경로는 계속 거절합니다. 정밀도 회귀 28개를 추가했습니다.

추가 재현한 factory 재할당도 차단했습니다. let make=()=>({p:1}); make=()=>({p:5}); const made=make(); css({p:made.p})는 수정 전 잘못된 padding:4px였고, 수정 후 /src/factory-write.tsx:1:108의 located error입니다. syntax factory fast path와 Boa sparse-definition 경로 모두 semantic write를 거절하며 3개 회귀를 추가했습니다.

기존 실제 프로브 출력 변경

18개 중 변경된 11개를 아래에 전부 나열합니다. 나머지 7개는 compiled code/CSS/error가 동일합니다.

프로브 수정 전 수정 후
evidence .a-b{padding:4px} /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
literalEscape /src/escape.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
method .a-b{padding:4px} /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
alias .a-b{padding:4px} /src/escape.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
nested .a-b{padding:4px} /src/escape.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
capturedWrite /src/escape.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
assignment /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
deletion /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
assign /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
defineProperty /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
lateFreeze .a-b{padding:4px} /src/escape.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them

독립 프로브 출력 변경

98개 중 code/CSS/error가 변경된 56개를 모두 나열합니다. 동일한 입력 소스를 비교했고, 기존 오류에 origin/fix가 추가된 변경도 포함합니다.

프로브 수정 전 수정 후
primitive-exposure .a-b{width:13px} .a-a{width:13px}
nested-sibling-scalar /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them .a-a{width:13px}
shallow-copy-scalar /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them .a-a{width:13px}
shadow-distinct-allocation .a-b{width:13px} .a-a{width:13px}
freeze-initializer .a-b{width:13px} .a-a{width:13px}
freeze-alias-before /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them .a-b{width:13px}
freeze-parent-scalar .a-b{width:13px} .a-a{width:13px}
freeze-array-scalar /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them .a-b{width:13px}
readonly-String .a-b{width:13px} .a-a{width:13px}
readonly-Number .a-b{width:13px} .a-a{width:13px}
readonly-JSON-stringify .a-b{width:13px} .a-a{width:13px}
readonly-Object-keys .a-b{width:13px} .a-a{width:13px}
readonly-api-globalCss @layer b;@layer b{body{width:13px}} .a-b{width:13px} @layer b;@layer b{body{width:13px}} .a-a{width:13px}
readonly-api-keyframes @Keyframes a-a{from{width:13px}}.a-c{width:13px} @Keyframes a-a{from{width:13px}}.a-b{width:13px}
readonly-api-createGlobalStyle @layer b;@layer b{body{width:13px}} .a-b{width:13px} @layer b;@layer b{body{width:13px}} .a-a{width:13px}
alias-chain-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
destructure-holder-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
let-alias-css .a-b{width:13px} /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
let-reassigned-alias-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
nested-holder-alias-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
partial-member-css .a-b{width:13px} /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shallow-copy-child-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
scope-helper-alias-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
scope-direct-read-css .a-b{width:13px} /src/independent.tsx:6:18: css() cannot use made.width at build time: its values must be literals, theme tokens or constants, or be computed from them
scope-nested-element-css .a-b{width:13px} /src/independent.tsx:6:18: css() cannot use (()=>{const local=made;return local.width})() at build time: its values must be literals, theme tokens or constants, or be computed from them
custom-join-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
custom-valueOf-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
getter-named-join-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
setter-named-valueOf-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
arrow-method-capture-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
invoked-captured-writer-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
escaped-captured-writer-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
escaped-writer-container-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
late-deferred-writer-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
freeze-after-escape-alias-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
freeze-shallow-child-css .a-b{width:13px} /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
freeze-shallow-array-child-css .a-b{width:13px} /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
freeze-conditional-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
freeze-after-write-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
seal-not-freeze-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shadow-String-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shadow-Number-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shadow-JSON-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shadow-Object-keys-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shadow-Object-freeze-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
String-coercion-hook-css /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
Number-coercion-hook-css /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
JSON-toJSON-hook-css /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
JSON-replacer-capture-css /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
frozen-accessor-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-api-globalCss @layer b;@layer b{body{width:13px}} /src/independent.tsx:6:1: globalCss() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-api-keyframes @Keyframes a-b{from{width:13px}} /src/independent.tsx:6:18: keyframes() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-api-emotion-css .a-b{width:13px} /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-api-createGlobalStyle @layer b;@layer b{body{width:13px}} /src/independent.tsx:6:18: globalCss() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-api-stylex-create .a-a{width:13px} /src/independent.tsx:6:49: stylex.create() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-css-object-structure .a-a{width:13px} /src/independent.tsx:5:22: css() cannot use made at build time: its styles must be an object literal or a constant object, or be computed from constants

owjs3901 and others added 30 commits October 1, 2026 21:16
…rations

css(a, b) composing classes whose styles the build knows, bound to css() in the file or exported by another module, merges their atoms per property, selector, breakpoint and layer, conditions included, instead of joining classes whose winner the stylesheet order picked. vanilla-extract style([...]) passes each composed style as its own argument, keeping a style composed again later.

Refs #688

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

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

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

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

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

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

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…asurable

Refs #688

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…JSX spreads win

Refs #688

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…led order and JSX element className

Refs #688

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

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

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…uate shouldForwardProp at build time

Refs #689

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ring

Refs #689

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

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

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>
… and conditional styles

Refs #690

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…h Emotion

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>
…ed parameters

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>
…ead through namespaces

Refs #695

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…akes from the visitor

Refs #695

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…eclared after their use

Refs #695, #686

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

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

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

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

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…nding

Refs #695

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
owjs3901 and others added 22 commits October 5, 2026 00:48
Refs #695

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…graphs

Refs #685, #694

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

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

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

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

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

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

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

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

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Resolve both module-declaration and regenerated snapshot conflicts; adapt the #756 source-evaluation test to #757 evaluate_located. Synchronize bun.lock workspace versions.

Split shadowed require from global resolver diagnostics, preserve entry-ingress fallback, and adapt empty JSX styleOrder to located parse rejection. Both #756 and #757 must merge first.

Refs #694, #695

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 5, 2026

Copy link
Copy Markdown
Contributor

Changepacks

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

Patch

  • A project module re-exporting Devup UI (export { Box, css } from '@devup-ui/react', export * from '@devup-ui/react', export { styled as s }, export * as Devup, a default export of an import, chains of barrels and the compat entry) now works: a file importing Box or css from it compiles exactly as if it imported from the package, following the barrel through the resolver (relative paths, tsconfig paths, package exports), and hasDevupUI sees such a file. Members read from a namespace or default import of the package (Devup['css'], const { css } = Devup, Devup.css as a value) compile where the build can follow them, Devup.x for a name the package compiles being read like the named import. New build errors, located at the use: what a barrel re-exports but the build cannot read (an unresolvable export * or module, a namespace of modules re-exporting the package) is an error where its name is used instead of a runtime crash, and a namespace member read by a key the build cannot know (Devup[key]), written, or destructured in a form it cannot follow (a rest, a computed key, a default value, a nested pattern, an exported declaration, or members mixed with ones that stay at runtime) is an error that names the members to read. A namespace passed on whole (Object.keys(Devup), spyOn(Devup, 'css'), export default Devup) is left as it is
  • css(a, b) composing classes whose styles the build knows (a const bound to css() in the file, or a css() result another module exports with a rule object every value of which is known) merges their styles: a later part's declaration replaces an earlier one's for the same property, selector, breakpoint and layer, also under conditions (css(base, cond && danger)) and for ||/?? parts, where the classes used to be joined and the stylesheet order picked the winner. vanilla-extract style([a, b]) passes each composed style as its own argument, so the later one wins, and a style composed again later (style([a, b, a])) is kept. Classes the build does not know (strings, props, CSS Modules) are kept as they are
  • styled(Base) extending a styled component the file binds to a const renders Base's tag directly with Base's styles composed under its own, so the extension's declarations replace Base's for the same property, selector, breakpoint and layer instead of losing to them by stylesheet order; Base's attrs apply before the extension's. attrs merge as styled-components merges them: className is joined with the caller's, style is merged and other props replace earlier ones. On an element, a className or style spread after the explicit prop now wins, as React merges props in the order they are written
  • Emotion's now compiles at build time with no runtime: the element becomes what its child function ({ css, cx, theme }) => ... renders, each css and cx call becomes the classes it composes (later styles replace earlier ones; css reads strings as CSS text and its tagged templates split around mixins; cx keeps unknown classes, reads { name: condition } objects as conditional classes and composes nested css and cx calls), and theme.a.b in their values becomes var(--a-b). Numbers in css rules are px lengths, as Emotion reads them, and top-level constants are inlined. New build errors, each at file:line:col: a without exactly one child function taking { css, cx, theme } that gives what it renders at once (attributes, other children, rest or default parameters, async or generator functions, several statements); reading the theme other than as theme.a.b in a css value; using css or cx other than by calling them; a cx object with a spread, getter or method; parts css and cx cannot compose (runtime calls, spreads, a condition choosing between styles and classes). @devup-ui/react/compat exports ClassNames with the ClassNamesContent and ClassNamesArg types, and the @emotion/react declarations include them
  • Emotion and styled-components component selectors now compile at build time: a styled component the file defines that another style selects (${Child} { ... } in CSS text, [Child] or [&:hover ${Child}] as a rule key) gets a short marker class, which only such components get, and the selector reads it as .marker; a component extending it, or an element inlining it for its css prop, keeps the marker. Selectors written without & now nest under the component as stylis nests them (ul { ... } is & ul, a selector list nests each selector, :hover applies to the component itself) instead of becoming global rules, and rule-object keys starting with ., #, [, *, >, + or ~ are read as nested selectors instead of properties
  • Emotion's css prop compiles at build time while @emotion/react is aliased: on tags and Devup UI components always, and on every element once the file imports @emotion/react or @emotion/styled or names @emotion/react in a @jsxImportSource pragma; jsx, jsxs and jsxDEV from @emotion/react/jsx-runtime (or jsx-dev-runtime) and jsx from @emotion/react compile it too, so libraries built with Emotion's JSX runtime do as well. The prop becomes the element's className, with CSS variables in its style for values only the runtime gives: arrays and conditions compose with a later part replacing what an earlier one sets, css() classes the file knows compose by their styles, strings and templates are CSS text, css`` mixins split the text around them, a function of the theme reads theme.a.b as var(--a-b), unitless numbers are px as in Emotion (constants included), and a className holding known css() classes overrides the prop as Emotion's registered classes do. A styled component the file defines renders its tag in the element's place when the prop overrides its styles and it renders a tag with no attrs or props read and the element has no spread, as or forwardedAs. Emotion's JSX runtime imports become react/jsx-runtime, the pragma names react, and jsx comes from @devup-ui/react/compat (React's createElement); @devup-ui/react/compat/css-prop types the prop on React.Attributes. New build errors, each with file:line:column and the code: a css prop part the build cannot read (a call, an element), a style object declared inside a function or with let, a binding only running the module gives or code changes, a theme function that does more than return rules or reads the theme other than as theme.a.b in a value, an interpolation CSS text cannot place or a mixin inside a nested rule, and a css prop overriding a styled component's styles where its tag cannot be rendered in place. Composing css() with a part that reads a known binding (such as a keyframes name) now reads its value
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • hasDevupUI takes the import aliases and is true for a file extraction changes: one importing a redirected package (@emotion/styled, ...), naming @emotion/react in a @jsxImportSource pragma, or in a project whose tsconfig jsxImportSource is @emotion/react, so the Bun plugin no longer skips files whose only Devup UI is Emotion's css prop or an aliased import. Aliases of Devup UI now compile like the original: export const B = Box, const c = css; export { c as cc }, export const D = Devup and export const C = Devup.css in a barrel (the barrel module exports them as re-exports of the package, and what imports them follows them), export { Box } after an import, export default Box, const D = Devup namespace aliases, and const inner = css declared inside a function. A css() or keyframes() const that a function reads before its declaration compiles. New build error: a css()/keyframes() const read before its declaration runs (outside a function) is located and says to move the declaration above its first read
  • Preserve JavaScript semantics for exact imported enum and Math values including negative zero, lexical constants, binding-aware CommonJS require, React createElement calls, type-only imports, and source-ordered props evaluation with native spread snapshots and CSS-variable fallbacks without a styling runtime. Migrate UI-kit style defaults by pure reordering and test reset CSS through compiled output. Report located build errors for runtime styleOrder values, unknowable whole-object style overrides, opaque selector literals, genuinely unmovable lazy logical suspension, Devup UI namespaces passed whole to runtime code, and immediate style reads in the temporal dead zone of lexical bindings; deferred initialized reads keep folding and pre-assignment var reads remain dynamic.
  • Report extraction, module-resolution and stylesheet execution failures at their original source locations with the cause and repair. Reject recoverable syntax errors, nondeterministic build-time reads, synthetic descriptor/function-source and legacy accessor reflection, and unsafe stylesheet execution fallbacks instead of silently changing CSS. Preserve module resolver and serialization exceptions, evaluate transitive helper side effects, and prevent placeholder-name collisions from losing styles. Match import package names only at exact or slash-delimited boundaries so sibling data packages remain external. Retain helper CSS loads in evaluation order with deduplicated portable relative specifiers and query suffixes, without CSS content dependencies. Report missing CSS or incompatible path roots as located errors, and reject host-recorded unknown CSS export observations even when caught; unused bindings, object passing and typeof follow default TypeScript/JavaScript import semantics.
  • Resolve compiled styling APIs and components by their lexical binding so shadowed local names, including minified library identifiers, remain ordinary JavaScript and JSX. No new build errors; existing diagnostics now apply only to the compiled binding they describe.
  • Styled components the build generates are wrapped in React's forwardRef, so a ref passed to them reaches the element they render on React 18 as well as React 19; the file imports forwardRef from react when it defines one
  • Styled components no longer pass every prop to the tag they render: $ props, theme and the props their style functions or attrs read are kept away from a tag unless it takes them as attributes, and shouldForwardProp (Emotion options or styled-components withConfig) is evaluated at build time. A shouldForwardProp the build cannot evaluate is a build error naming the file, line and code, with the forms it accepts. An element using a styled component the file defines drops props the component neither reads nor passes on; spread props are passed as written
  • Styled components render what their as prop names, defaulting to the tag or component they were defined with, and pass forwardedAs on as as, as styled-components and Emotion do; as used to reach the rendered tag as an attribute. Component.withComponent(target) on a styled component the file binds to a const builds a component rendering the same styles and attrs as target (a tag name or a component JSX can name), where it used to call a method the generated function does not have and throw

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

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • hasDevupUI takes the import aliases and is true for a file extraction changes: one importing a redirected package (@emotion/styled, ...), naming @emotion/react in a @jsxImportSource pragma, or in a project whose tsconfig jsxImportSource is @emotion/react, so the Bun plugin no longer skips files whose only Devup UI is Emotion's css prop or an aliased import. Aliases of Devup UI now compile like the original: export const B = Box, const c = css; export { c as cc }, export const D = Devup and export const C = Devup.css in a barrel (the barrel module exports them as re-exports of the package, and what imports them follows them), export { Box } after an import, export default Box, const D = Devup namespace aliases, and const inner = css declared inside a function. A css() or keyframes() const that a function reads before its declaration compiles. New build error: a css()/keyframes() const read before its declaration runs (outside a function) is located and says to move the declaration above its first read

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

Patch

  • Preserve JavaScript semantics for exact imported enum and Math values including negative zero, lexical constants, binding-aware CommonJS require, React createElement calls, type-only imports, and source-ordered props evaluation with native spread snapshots and CSS-variable fallbacks without a styling runtime. Migrate UI-kit style defaults by pure reordering and test reset CSS through compiled output. Report located build errors for runtime styleOrder values, unknowable whole-object style overrides, opaque selector literals, genuinely unmovable lazy logical suspension, Devup UI namespaces passed whole to runtime code, and immediate style reads in the temporal dead zone of lexical bindings; deferred initialized reads keep folding and pre-assignment var reads remain dynamic.

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

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

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

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

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

Patch

  • Emotion's now compiles at build time with no runtime: the element becomes what its child function ({ css, cx, theme }) => ... renders, each css and cx call becomes the classes it composes (later styles replace earlier ones; css reads strings as CSS text and its tagged templates split around mixins; cx keeps unknown classes, reads { name: condition } objects as conditional classes and composes nested css and cx calls), and theme.a.b in their values becomes var(--a-b). Numbers in css rules are px lengths, as Emotion reads them, and top-level constants are inlined. New build errors, each at file:line:col: a without exactly one child function taking { css, cx, theme } that gives what it renders at once (attributes, other children, rest or default parameters, async or generator functions, several statements); reading the theme other than as theme.a.b in a css value; using css or cx other than by calling them; a cx object with a spread, getter or method; parts css and cx cannot compose (runtime calls, spreads, a condition choosing between styles and classes). @devup-ui/react/compat exports ClassNames with the ClassNamesContent and ClassNamesArg types, and the @emotion/react declarations include them
  • Emotion's css prop compiles at build time while @emotion/react is aliased: on tags and Devup UI components always, and on every element once the file imports @emotion/react or @emotion/styled or names @emotion/react in a @jsxImportSource pragma; jsx, jsxs and jsxDEV from @emotion/react/jsx-runtime (or jsx-dev-runtime) and jsx from @emotion/react compile it too, so libraries built with Emotion's JSX runtime do as well. The prop becomes the element's className, with CSS variables in its style for values only the runtime gives: arrays and conditions compose with a later part replacing what an earlier one sets, css() classes the file knows compose by their styles, strings and templates are CSS text, css`` mixins split the text around them, a function of the theme reads theme.a.b as var(--a-b), unitless numbers are px as in Emotion (constants included), and a className holding known css() classes overrides the prop as Emotion's registered classes do. A styled component the file defines renders its tag in the element's place when the prop overrides its styles and it renders a tag with no attrs or props read and the element has no spread, as or forwardedAs. Emotion's JSX runtime imports become react/jsx-runtime, the pragma names react, and jsx comes from @devup-ui/react/compat (React's createElement); @devup-ui/react/compat/css-prop types the prop on React.Attributes. New build errors, each with file:line:column and the code: a css prop part the build cannot read (a call, an element), a style object declared inside a function or with let, a binding only running the module gives or code changes, a theme function that does more than return rules or reads the theme other than as theme.a.b in a value, an interpolation CSS text cannot place or a mixin inside a nested rule, and a css prop overriding a styled component's styles where its tag cannot be rendered in place. Composing css() with a part that reads a known binding (such as a keyframes name) now reads its value
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

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

Patch

  • Preserve JavaScript semantics for exact imported enum and Math values including negative zero, lexical constants, binding-aware CommonJS require, React createElement calls, type-only imports, and source-ordered props evaluation with native spread snapshots and CSS-variable fallbacks without a styling runtime. Migrate UI-kit style defaults by pure reordering and test reset CSS through compiled output. Report located build errors for runtime styleOrder values, unknowable whole-object style overrides, opaque selector literals, genuinely unmovable lazy logical suspension, Devup UI namespaces passed whole to runtime code, and immediate style reads in the temporal dead zone of lexical bindings; deferred initialized reads keep folding and pre-assignment var reads remain dynamic.

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

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

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

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

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

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@codecov

codecov Bot commented Oct 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
bindings/devup-ui-wasm/src/lib.rs 100.00% <ø> (ø)
bindings/devup-ui-wasm/src/resolver_state.rs 100.00% <100.00%> (ø)
libs/css/src/lib.rs 100.00% <100.00%> (ø)
libs/css/src/theme_tokens.rs 100.00% <ø> (ø)
libs/extractor/src/barrel.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/aliases.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/gate.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/namespace_aliases.rs 100.00% <100.00%> (ø)
libs/extractor/src/build_time_values.rs 100.00% <100.00%> (ø)
libs/extractor/src/build_time_values/exact_math.rs 100.00% <100.00%> (ø)
... and 50 more

... and 43 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 2 commits October 6, 2026 08:22
Keep module-local object identity hazards independent of constant evaluation; preserve element CSS variables and attach originating hazard diagnostics to build-only style reads. Add explicit plain-data builtin policies, shallow-freeze proofs, scalar snapshot handling and regression coverage.

Refs #694, #695

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Project only proven scalar values at eager style sites without restoring escaped aggregates or unsafe closures. Preserve independent child slots, primitive shallow copies and frozen own properties, and reject reassigned factory bindings in both static evaluation paths.

Refs #694, #695

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