diff --git a/src/wasm/WabtOutput.test.ts b/src/wasm/WabtOutput.test.ts index f1aabe95a9..9fc83b987e 100644 --- a/src/wasm/WabtOutput.test.ts +++ b/src/wasm/WabtOutput.test.ts @@ -381,3 +381,16 @@ it("matches a CLI-selected ./ module exactly against its glue reference", () => }, ]); }); + +it("tests long multi-line glue literals for a .wasm suffix in linear time", () => { + const value = `${".wasm#".repeat(32_000)}\nend`; + const started = performance.now(); + expect( + associateWasmGlue(`const s = ${JSON.stringify(value)};`, "/glue.js", []), + ).toEqual({ parse_status: "complete", references: [] }); + expect(performance.now() - started).toBeLessThan(1_000); + expect( + associateWasmGlue("const s = `first\nmodule.wasm?v=1`;", "/glue.js", []) + .references, + ).toMatchObject([{ value: "first\nmodule.wasm?v=1", line: 1 }]); +}); diff --git a/src/wasm/WasmGlueAdapter.ts b/src/wasm/WasmGlueAdapter.ts index 4a130508ed..e860efff84 100644 --- a/src/wasm/WasmGlueAdapter.ts +++ b/src/wasm/WasmGlueAdapter.ts @@ -3,6 +3,24 @@ import * as t from "@babel/types"; import { parseJavaScriptSource } from "../domain/javascript/javascriptSourceParser.js"; import { traverseJavaScriptAst } from "../domain/javascript/javascriptSemanticTraversal.js"; import { absoluteCallerPath } from "../filesystem/callerPath.js"; + +/** + * `.` cannot cross a line terminator and `$` only matches at the end of the + * literal, so a `.wasm` suffix can only occur on its last line. Testing that + * line alone keeps long multi-line literals linear. + */ +const endsWithWasmReference = (value: string): boolean => + /\.wasm(?:[?#].*)?$/iu.test( + value.slice( + Math.max( + value.lastIndexOf("\n"), + value.lastIndexOf("\r"), + value.lastIndexOf("
"), + value.lastIndexOf("
"), + ) + 1, + ), + ); + /** Associate visible literals with selected candidates without asserting data flow or URL identity. */ export const associateWasmGlue = ( source: string, @@ -43,7 +61,7 @@ export const associateWasmGlue = ( if ( value === undefined || value === null || - !/\.wasm(?:[?#].*)?$/iu.test(value) || + !endsWithWasmReference(value) || node.loc == null ) return;