diff --git a/docs/wasm-artifacts.md b/docs/wasm-artifacts.md index 75fc5a4a3d..3dff7ffb2b 100644 --- a/docs/wasm-artifacts.md +++ b/docs/wasm-artifacts.md @@ -194,3 +194,9 @@ After building, run `REA_WABT_BIN_DIRECTORY=/absolute/wabt/bin node scripts/verify-wasm-interface-comparison.mjs` for original-module comparison through the compiled CLI and stdio MCP. It uses owned fixtures and WABT 1.0.42; no WASM module is instantiated or executed. + +Glue parsing accepts Node-supported WASM source-phase imports, including +`import source module from "./module.wasm"` and +`await import.source("./module.wasm")`. Their string literals retain the same +coordinates and local candidate associations as ordinary import literals; these +are static source observations, without module instantiation or execution. diff --git a/scripts/verify-wasm-artifact.mjs b/scripts/verify-wasm-artifact.mjs index 38ee229bd4..9a2ef5b724 100644 --- a/scripts/verify-wasm-artifact.mjs +++ b/scripts/verify-wasm-artifact.mjs @@ -231,6 +231,8 @@ try { 'fetch("./module.wasm"); new URL("https://example.invalid/module.wasm?version=1", import.meta.url);'; const glueSources = [ glueSource, + 'import source module from "./module.wasm"; new URL("https://example.invalid/module.wasm?version=1", import.meta.url);', + 'const module = await import.source("./module.wasm"); new URL("https://example.invalid/module.wasm?version=1", import.meta.url);', `\uFEFF${glueSource}`, `\uFEFF\n${glueSource}`, `#!/usr/bin/env node\n${glueSource}`, diff --git a/src/domain/javascript/javascriptSourceParser.ts b/src/domain/javascript/javascriptSourceParser.ts index 5038ccbcd5..e71f671a82 100644 --- a/src/domain/javascript/javascriptSourceParser.ts +++ b/src/domain/javascript/javascriptSourceParser.ts @@ -87,6 +87,7 @@ const parseWithRuntimeContext = ( * `.ts/.cts/.mts` (angle-bracket assertions, not JSX) and for all * declaration files. `.mts` (including `.d.mts`) sets * `disallowAmbiguousJSXLike`, matching tsc's `.mts` mode. + * - `sourcePhaseImports` retains Node-supported WASM source imports as AST data. * - `decorators-legacy` always present: without it decorated sources fail * hard instead of reporting recovered syntax, losing every derived fact. * - Unknown paths retain the existing JSX- and TypeScript-capable contract @@ -94,7 +95,8 @@ const parseWithRuntimeContext = ( */ export const parserPluginsForPath = (sourcePath?: string): ParserPlugin[] => { const path = sourcePath ?? ""; - if (/\.(?:js|jsx|mjs|cjs)$/iu.test(path)) return ["decorators-legacy", "jsx"]; + const syntax: ParserPlugin[] = ["decorators-legacy", "sourcePhaseImports"]; + if (/\.(?:js|jsx|mjs|cjs)$/iu.test(path)) return [...syntax, "jsx"]; const dts = /\.d\.(?:ts|mts|cts)$/iu.test(path); const isTsLike = /\.(?:ts|cts|mts)$/iu.test(path); const isTsx = /\.tsx$/iu.test(path); @@ -107,9 +109,7 @@ export const parserPluginsForPath = (sourcePath?: string): ParserPlugin[] => { }, ]; const jsxCapable = !dts && (isTsx || !isTsLike); - return jsxCapable - ? ["decorators-legacy", "jsx", typescript] - : ["decorators-legacy", typescript]; + return jsxCapable ? [...syntax, "jsx", typescript] : [...syntax, typescript]; }; /** `.mjs` and `.mts` explicitly select module mode. */ diff --git a/src/wasm/WabtOutput.test.ts b/src/wasm/WabtOutput.test.ts index 0b981c6d3e..9648ae6db0 100644 --- a/src/wasm/WabtOutput.test.ts +++ b/src/wasm/WabtOutput.test.ts @@ -435,3 +435,26 @@ it.each(["\n", "\r", "\u2028", "\u2029"])( } }, ); +it.each([ + 'import source module from "./module.wasm";', + 'const module = await import.source("./module.wasm");', + 'import * as module from "./module.wasm";', + 'const module = await import("./module.wasm");', +])("retains source-phase and ordinary WASM import literals: %s", (source) => { + const offset = source.indexOf('"./module.wasm"'); + expect( + associateWasmGlue(source, "/app/glue.mjs", ["/app/module.wasm"]), + ).toEqual({ + parse_status: "complete", + references: [ + { + value: "./module.wasm", + line: 1, + column: offset, + candidate_paths: ["/app/module.wasm"], + association: "local-path-candidate", + evidence_kind: "static-literal", + }, + ], + }); +});