diff --git a/compiler/crates/TODO.md b/compiler/crates/TODO.md index 0d3b0c96efc1..f801cc1a448e 100644 --- a/compiler/crates/TODO.md +++ b/compiler/crates/TODO.md @@ -111,6 +111,46 @@ Each line names the failure mode and a sketch of where to look. `TSTypeParameterInstantiation` in `convert_ast.rs` AND deserialization in `convert_ast_reverse.rs::convert_ts_type_from_json`. +## Cross-frontend: TypeScript module interop statements + +Three `todo-ts-*` fixtures pin how TS module-interop statements +(`import x = require(...)`, `export = x`, `export as namespace X`) must +behave: the statement is preserved in output and the file's functions +still compile. The TS reference does both. The three frontends share +the broken symptom today via three different root causes: + +- **Babel/NAPI** throws `Failed to parse AST JSON: unknown variant + TSImportEqualsDeclaration` (etc.) because the typed AST's + `#[serde(tag = "type")]` enums have no catch-all, failing the whole + file. The same root cause reds both `react_compiler_ast` fixture + tests (`round_trip` and `scope_resolution_rename`) under + `test-babel-ast.sh`. +- **SWC**'s converter explicitly rewrites all three statements to + `EmptyStatement` (`react_compiler_swc/src/convert_ast.rs`, + `TsImportEquals` / `TsExportAssignment` / `TsNamespaceExport` arms), + erasing them from output with no error and no event. +- **OXC** `todo!()`-panics in `react_compiler_oxc/src/convert_ast.rs` + (arms of the same three names; the sibling `TSGlobalDeclaration` arm + is also unmodeled but unreachable from Babel-parsed fixtures, which + represent `declare global` as `TSModuleDeclaration`). Deferred. + +Known-red until the fixes land: the three fixtures fail Babel and SWC +e2e and `test-babel-ast.sh`, and the e2e totals elsewhere in this doc +are stale by +3 fixtures. + +Planned fixes: (1) Babel path: unknown-statement tolerance in +`react_compiler_ast` (untagged catch-all carrying the raw node, +preserved through codegen and re-serialization); (2) SWC: replace the +`EmptyStatement` arms with real preservation; mapping unknown nodes to +`EmptyStatement` is the bug, not a fallback. Rename each fixture to +drop the `todo-` prefix as it goes green end to end, and update the +`SproutTodoFilter` entry for the namespace fixture in the same change +(the filter matches by basename). + +- `todo-ts-import-equals-declaration.ts` +- `todo-ts-export-assignment.ts` +- `todo-ts-namespace-export-declaration.ts` + ## Babel **TODO: scope this out.** Babel is at 1788 / 1795 (7 failures). These have diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-export-assignment.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-export-assignment.expect.md new file mode 100644 index 000000000000..28796358a5ce --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-export-assignment.expect.md @@ -0,0 +1,36 @@ + +## Input + +```javascript +function useValue(value: number) { + return [value + 1]; +} + +export = useValue; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function useValue(value) { + const $ = _c(2); + const t0 = value + 1; + let t1; + if ($[0] !== t0) { + t1 = [t0]; + $[0] = t0; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +export = useValue; + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-export-assignment.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-export-assignment.ts new file mode 100644 index 000000000000..0d20ad075d5f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-export-assignment.ts @@ -0,0 +1,5 @@ +function useValue(value: number) { + return [value + 1]; +} + +export = useValue; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-import-equals-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-import-equals-declaration.expect.md new file mode 100644 index 000000000000..3dc9330eb300 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-import-equals-declaration.expect.md @@ -0,0 +1,35 @@ + +## Input + +```javascript +import lib = require('shared-runtime'); + +function useValue(value: number) { + return lib.identity(value); +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import lib = require("shared-runtime"); + +function useValue(value) { + const $ = _c(2); + let t0; + if ($[0] !== value) { + t0 = lib.identity(value); + $[0] = value; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-import-equals-declaration.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-import-equals-declaration.ts new file mode 100644 index 000000000000..effbc5b1c971 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-import-equals-declaration.ts @@ -0,0 +1,5 @@ +import lib = require('shared-runtime'); + +function useValue(value: number) { + return lib.identity(value); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-namespace-export-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-namespace-export-declaration.expect.md new file mode 100644 index 000000000000..a01bd1398f16 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-namespace-export-declaration.expect.md @@ -0,0 +1,33 @@ + +## Input + +```javascript +export as namespace Foo; + +function useValue(value: number) { + return {value}; +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +export as namespace Foo; + +function useValue(value) { + const $ = _c(2); + let t0; + if ($[0] !== value) { + t0 = { value }; + $[0] = value; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-namespace-export-declaration.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-namespace-export-declaration.ts new file mode 100644 index 000000000000..af6d6abce0c9 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-ts-namespace-export-declaration.ts @@ -0,0 +1,5 @@ +export as namespace Foo; + +function useValue(value: number) { + return {value}; +} diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index 9cc6d7048c33..c0beeac90d6d 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -17,6 +17,15 @@ const skipFilter = new Set([ 'todo-round3_outlined_naming', 'todo-round3_promote_used_temps', + /** + * `export as namespace` is a .d.ts-shaped construct; sprout's second-stage + * evaluator transform cannot evaluate it. The sibling todo-ts-* interop + * fixtures evaluate fine (they transform to CJS) and are deliberately not + * skipped. Remove or update this entry when the fixture is renamed after + * the Rust fix lands (the filter matches by basename). + */ + 'todo-ts-namespace-export-declaration', + /** * Observable different in logging between Forget and non-Forget */