diff --git a/.github/workflows/real-javascript-recovery.yml b/.github/workflows/real-javascript-recovery.yml index 7076a29cd..14101ff55 100644 --- a/.github/workflows/real-javascript-recovery.yml +++ b/.github/workflows/real-javascript-recovery.yml @@ -56,9 +56,9 @@ jobs: shell: bash run: | mkdir -p "$RUNNER_TEMP/rea-wakaru" - curl --fail --location --retry 3 https://github.com/pionxzh/wakaru/releases/download/v1.13.0/wakaru-linux-x64.tar.gz -o "$RUNNER_TEMP/rea-wakaru/release.tar.gz" + curl --fail --location --retry 3 https://github.com/pionxzh/wakaru/releases/download/v1.14.0/wakaru-linux-x64.tar.gz -o "$RUNNER_TEMP/rea-wakaru/release.tar.gz" tar -xzf "$RUNNER_TEMP/rea-wakaru/release.tar.gz" -C "$RUNNER_TEMP/rea-wakaru" wakaru - printf '%s %s\n' e8c7ca052974604197389f6ace7464e4dd24dce64e2730971521bd6606ec9c9e "$RUNNER_TEMP/rea-wakaru/wakaru" | sha256sum --check + printf '%s %s\n' 664fa06782a61eda7ed15885134b52525fd565dd77607e642062ceb6cd927c38 "$RUNNER_TEMP/rea-wakaru/wakaru" | sha256sum --check - name: Install isolated fixture compilers run: npm install --prefix "$RUNNER_TEMP/rea-fixture-compilers" --ignore-scripts --no-audit --no-fund esbuild@0.25.10 webpack@5.101.3 - run: npm run build:cached diff --git a/docs/javascript-recovery.md b/docs/javascript-recovery.md index 1a0af9ff6..f0105e88d 100644 --- a/docs/javascript-recovery.md +++ b/docs/javascript-recovery.md @@ -7,19 +7,46 @@ never executes the selected or recovered application code. ## Caller-supplied engine -The initial adapter is verified on Linux x64 with Wakaru **1.13.0**. Set -`REA_WAKARU_COMMAND` to the absolute path of an executable supplied by the caller. -The adapter uses util-linux `prlimit` (default `/usr/bin/prlimit`; override with -an absolute `REA_JAVASCRIPT_PRLIMIT_COMMAND`). REA does not install either tool. -Engine configuration is checked only when recovery is requested; other REA -capabilities remain available without it. +REA accepts Wakaru **^1.13.0** on Linux x64. The report parser is verified with +Wakaru **1.14.0**. Another release in that range is accepted, the observed +version is reported, and a limitation records that the parser was not verified +against that release. Wakaru changes `--version`, `--json` and `provenance.json` +only by addition within a major version +([compatibility policy](https://github.com/pionxzh/wakaru/blob/v1.14.0/docs/cli.md#machine-readable-output-compatibility)), +so the parser keeps unknown report fields and reported module statuses. + +Set `REA_WAKARU_COMMAND` to the absolute path of an executable supplied by the +caller. The adapter uses util-linux `prlimit` (default `/usr/bin/prlimit`; +override with an absolute `REA_JAVASCRIPT_PRLIMIT_COMMAND`). REA does not install +either tool. Engine configuration is checked only when recovery is requested; +other REA capabilities remain available without it. Unmodified upstream source is retained in `third_party/wakaru`, pinned to -`6070266d24b32951fa2fe1d2dad5b4313bd5c81b` (v1.13.0, Apache-2.0). +`8219bf5016a063d7fb215101a8c45d5959ec733f` (v1.14.0, Apache-2.0). The result reports the executed binary's exact path, SHA-256 and observed version. The audited source revision is distinct from `executed_source_revision: null`: a version string cannot prove which source produced a caller-supplied binary. +### Install Wakaru + +Use the official release binary, the same one CI verifies: + +```sh +curl -fL https://github.com/pionxzh/wakaru/releases/download/v1.14.0/wakaru-linux-x64.tar.gz | tar -xz wakaru +export REA_WAKARU_COMMAND="$PWD/wakaru" +``` + +Or install it from npm. Point at the platform binary, not the Node.js shim in +`node_modules/.bin`: + +```sh +npm install wakaru@1.14.0 +export REA_WAKARU_COMMAND="$(realpath node_modules/@wakaru/cli-linux-x64/wakaru)" +``` + +Both give the same binary (SHA-256 +`664fa06782a61eda7ed15885134b52525fd565dd77607e642062ceb6cd927c38`). + ## Recover and analyze ```sh diff --git a/docs/testing.md b/docs/testing.md index d4c0366ae..9896b9bc3 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -876,12 +876,14 @@ Neither optional toolchain is a base-lane prerequisite. See Build once with `npm run build:cached`, then run `npm run verify:javascript:recovery`. This focused lane requires Linux x64, util-linux `prlimit`, -`REA_WAKARU_COMMAND` pointing to the official Wakaru 1.13.0 Linux x64 binary, +`REA_WAKARU_COMMAND` pointing to the official Wakaru 1.14.0 Linux x64 binary, and `REA_JAVASCRIPT_FIXTURE_TOOLS` pointing to an isolated npm prefix containing esbuild 0.25.10 and webpack 5.101.3. No global installation is required. The lane compiles source-owned fixtures, exercises CLI and stdio MCP, verifies published bytes and provenance, feeds recovered modules into existing analysis, -and compares a finite set of known fixture results. It does not establish +and compares a finite set of known fixture results. The provider also accepts +other ^1.13.0 releases and reports them as unverified; this lane proves the +audited release. It does not establish arbitrary recovered-application equivalence. CI installs these prerequisites only in `.github/workflows/real-javascript-recovery.yml`; the existing `real-browser` lane uses real Chrome for browser capture and website workflows. diff --git a/scripts/verify/javascript/recovery.mjs b/scripts/verify/javascript/recovery.mjs index 169f8a53a..0785d8ac1 100644 --- a/scripts/verify/javascript/recovery.mjs +++ b/scripts/verify/javascript/recovery.mjs @@ -15,10 +15,10 @@ import { buildRecoveryFixtures } from "../../fixtures/javascript-recovery/build. import { mcpTextValue } from "../../lib/mcp-verifier-results.mjs"; const OFFICIAL_BINARY_SHA256 = - "e8c7ca052974604197389f6ace7464e4dd24dce64e2730971521bd6606ec9c9e"; + "664fa06782a61eda7ed15885134b52525fd565dd77607e642062ceb6cd927c38"; if (!process.env.REA_WAKARU_COMMAND) throw new Error( - "Provide REA_WAKARU_COMMAND for the official Wakaru 1.13.0 Linux x64 binary", + "Provide REA_WAKARU_COMMAND for the official Wakaru 1.14.0 Linux x64 binary", ); const entrypoint = process.argv[2] ?? fileURLToPath(new URL("../../rea.mjs", import.meta.url)); @@ -130,7 +130,7 @@ try { } } finalReport = { - engine: "wakaru 1.13.0", + engine: "wakaru 1.14.0", toolchains: fixtures.toolchains, results: counts, verified: true, diff --git a/src/application/CapabilityInventory.ts b/src/application/CapabilityInventory.ts index 539796f57..e06d86839 100644 --- a/src/application/CapabilityInventory.ts +++ b/src/application/CapabilityInventory.ts @@ -303,7 +303,7 @@ const workflowAvailabilityFor = ({ : { reason: "provider_missing", remediation: - "On Linux x64, provide an absolute REA_WAKARU_COMMAND for Wakaru 1.13.0 and util-linux prlimit. No binary target is required.", + "On Linux x64, provide an absolute REA_WAKARU_COMMAND for Wakaru ^1.13.0 (verified with 1.14.0) and util-linux prlimit; see docs/javascript-recovery.md#install-wakaru. No binary target is required.", }; if (name === "inspect_binary_layout") return policy.binaryLayoutEnabled === true diff --git a/src/contracts/javascript/javascriptRecoveryToolContracts.ts b/src/contracts/javascript/javascriptRecoveryToolContracts.ts index e085440e4..334b2d961 100644 --- a/src/contracts/javascript/javascriptRecoveryToolContracts.ts +++ b/src/contracts/javascript/javascriptRecoveryToolContracts.ts @@ -13,7 +13,7 @@ export const JAVASCRIPT_RECOVERY_TOOL_CONTRACTS = [ ...toolContractMetadata("recover_javascript_sources"), kind: "application", description: - "Recover readable modules from one local UTF-8 JavaScript script/bundle into an absent directory, using caller-supplied Wakaru 1.13.0 on Linux x64. Returns original/derived digests, extraction byte ranges, emitted source maps, warnings and analysis_input inline. Structural splitting may fall back to one module; original names and runtime equivalence remain unknown. No application code execution. Requires util-linux prlimit; one worker, 1 GiB address-space ceiling, 120-second deadline, 64 MiB input, 128 MiB output, 10000 entries and 8 MiB per diagnostic/report stream.", + "Recover readable modules from one local UTF-8 JavaScript script/bundle into an absent directory, using caller-supplied Wakaru ^1.13.0 (verified with 1.14.0) on Linux x64. Returns original/derived digests, extraction byte ranges, emitted source maps, warnings and analysis_input inline. Structural splitting may fall back to one module; original names and runtime equivalence remain unknown. No application code execution. Requires util-linux prlimit; one worker, 1 GiB address-space ceiling, 120-second deadline, 64 MiB input, 128 MiB output, 10000 entries and 8 MiB per diagnostic/report stream.", inputSchema: javascriptRecoveryInputSchema, outputSchema: evidenceResultOf(javascriptRecoveryResultSchema), examples: [ diff --git a/src/javascript/recovery/WakaruCommand.ts b/src/javascript/recovery/WakaruCommand.ts index 41e11d55f..464cd1745 100644 --- a/src/javascript/recovery/WakaruCommand.ts +++ b/src/javascript/recovery/WakaruCommand.ts @@ -26,7 +26,7 @@ import { RECOVERY_LIMITS } from "./WakaruRelease.js"; const OPERATION = "recover_javascript_sources"; const WAKARU_REQUIREMENT = - "Provide an absolute REA_WAKARU_COMMAND pointing to Wakaru 1.13.0 on Linux x64; no tool is installed by REA"; + "Provide an absolute REA_WAKARU_COMMAND pointing to a Wakaru ^1.13.0 Linux x64 binary (verified with 1.14.0); no tool is installed by REA. See docs/javascript-recovery.md#install-wakaru."; /** Inject the owned process launcher while retaining production protocol parsing. */ export type WakaruLauncher = ( diff --git a/src/javascript/recovery/WakaruExecution.ts b/src/javascript/recovery/WakaruExecution.ts index 2d99b46ed..023e7eb23 100644 --- a/src/javascript/recovery/WakaruExecution.ts +++ b/src/javascript/recovery/WakaruExecution.ts @@ -24,11 +24,8 @@ import { } from "./WakaruCommand.js"; import { parseWakaruReports } from "./WakaruReport.js"; import { publishWakaruArtifacts } from "./WakaruPublication.js"; -import { - RECOVERY_LIMITS, - WAKARU_RELEASE, - WAKARU_PROVIDER_IDENTITY, -} from "./WakaruRelease.js"; +import { RECOVERY_LIMITS, WAKARU_PROVIDER_IDENTITY } from "./WakaruRelease.js"; +import { admitWakaruVersion } from "./WakaruVersion.js"; const OPERATION = "recover_javascript_sources"; const MODES = { @@ -66,12 +63,13 @@ const executeWakaruRecovery = async (context: RecoveryWorkspace) => { ...commandContext, arguments: ["--version"], }); - if ( - version.exit_code !== 0 || - version.stdout.trim() !== `wakaru ${WAKARU_RELEASE.version}` - ) { + const admitted = + version.exit_code === 0 + ? admitWakaruVersion(version.stdout.trim()) + : undefined; + if (admitted === undefined || admitted.status === "unsupported") { // The message names the mismatch; the reason also keeps the tool's stderr. - const mismatch = `This adapter requires Wakaru ${WAKARU_RELEASE.version}; reported version: ${version.stdout.trim()}; exit: ${String(version.exit_code)}`; + const mismatch = `${admitted?.message ?? `Wakaru --version failed; reported version: ${version.stdout.trim()}`}; exit: ${String(version.exit_code)}`; throw new AnalysisCapabilityUnavailableError( "wakaru", OPERATION, @@ -106,20 +104,22 @@ const executeWakaruRecovery = async (context: RecoveryWorkspace) => { sourceBytes: snapshot, files, }); - return { version, run, parsed }; + return { version, admitted, run, parsed }; }; /** Publish validated recovery and retain exact source and engine bindings. */ export const prepareWakaruExecution = async (context: RecoveryWorkspace) => { const { root, tree, input, source, engine, options } = context; const staging = join(root, "modules"); - const { version, run, parsed } = await executeWakaruRecovery(context); + const { version, admitted, run, parsed } = + await executeWakaruRecovery(context); const result = await publishWakaruArtifacts({ tree, staging, input, source, engine, + admitted, parsed, execution: run, ...(options?.signal === undefined ? {} : { signal: options.signal }), @@ -150,25 +150,29 @@ export const prepareWakaruExecution = async (context: RecoveryWorkspace) => { OPERATION, "Configured engine bytes changed during recovery", ); - return createAnalysisExecution(result, WAKARU_PROVIDER_IDENTITY, { - rawResult: jsonValueSchema.parse({ - version, - execution: run, - report: parsed.report, - provenance: parsed.provenance, - }), - subject: { - path: source.path, - sha256: source.sha256, - format: "javascript", + return createAnalysisExecution( + result, + { ...WAKARU_PROVIDER_IDENTITY, version: admitted.version }, + { + rawResult: jsonValueSchema.parse({ + version, + execution: run, + report: parsed.report, + provenance: parsed.provenance, + }), + subject: { + path: source.path, + sha256: source.sha256, + format: "javascript", + }, + locations: [ + { kind: "artifact-path", path: source.path }, + ...result.modules.map((module) => ({ + kind: "artifact-path" as const, + path: module.artifact.path, + })), + ], + limitations: result.limitations, }, - locations: [ - { kind: "artifact-path", path: source.path }, - ...result.modules.map((module) => ({ - kind: "artifact-path" as const, - path: module.artifact.path, - })), - ], - limitations: result.limitations, - }); + ); }; diff --git a/src/javascript/recovery/WakaruPublication.ts b/src/javascript/recovery/WakaruPublication.ts index 40a0586cd..5b89ebe68 100644 --- a/src/javascript/recovery/WakaruPublication.ts +++ b/src/javascript/recovery/WakaruPublication.ts @@ -22,6 +22,7 @@ import type { resolveWakaruCommand, runWakaruCommand, } from "./WakaruCommand.js"; +import type { WakaruVersionAdmission } from "./WakaruVersion.js"; type PublicationContext = { tree: SafeOutputTree; @@ -34,6 +35,7 @@ type PublicationContext = { bytes: number; }; engine: Awaited>; + admitted: Exclude; parsed: Awaited>; execution: Awaited>; signal?: AbortSignal; @@ -86,7 +88,7 @@ export const publishWakaruArtifacts = async ( source: { ...source, published_copy: publishedCopy }, engine: { id: "wakaru", - version: WAKARU_RELEASE.version, + version: context.admitted.version, executable: { path: context.engine.command, sha256: context.engine.sha256, @@ -107,7 +109,14 @@ export const publishWakaruArtifacts = async ( total: parsed.report.total, failed: parsed.report.failed, modules, - warnings: parsed.report.warnings, + warnings: parsed.report.warnings.map( + ({ filename, kind, is_error, message }) => ({ + filename, + kind, + is_error, + message, + }), + ), report, provenance, analysis_input: @@ -118,7 +127,12 @@ export const publishWakaruArtifacts = async ( format: "directory" as const, }, runtime_equivalence: "unknown" as const, - limitations: [...RECOVERY_LIMITATIONS], + limitations: [ + ...RECOVERY_LIMITATIONS, + ...(context.admitted.status === "compatible" + ? [context.admitted.limitation] + : []), + ], }; const manifest = await write( "manifest.json", diff --git a/src/javascript/recovery/WakaruRelease.ts b/src/javascript/recovery/WakaruRelease.ts index 60d94cb7a..207b35845 100644 --- a/src/javascript/recovery/WakaruRelease.ts +++ b/src/javascript/recovery/WakaruRelease.ts @@ -1,11 +1,19 @@ /** Unchanged upstream source pin; executed bytes are identified separately. */ export const WAKARU_RELEASE = { - version: "1.13.0", - revision: "6070266d24b32951fa2fe1d2dad5b4313bd5c81b", + version: "1.14.0", + revision: "8219bf5016a063d7fb215101a8c45d5959ec733f", repository: "https://github.com/pionxzh/wakaru", } as const; -/** Exact provider identity shared by executions and the generated catalog. */ +/** + * Releases the report parser accepts. Wakaru changes `--version`, `--json` + * and `provenance.json` only by addition within a major version + * (https://github.com/pionxzh/wakaru/blob/v1.14.0/docs/cli.md#machine-readable-output-compatibility); + * 1.13.0 is the first release this adapter verified. + */ +export const WAKARU_ACCEPTED_RANGE = "^1.13.0"; + +/** Catalog identity for the verified Wakaru release. Evidence replaces version with the observed banner. */ export const WAKARU_PROVIDER_IDENTITY = { id: "wakaru", name: "Wakaru", diff --git a/src/javascript/recovery/WakaruReport.ts b/src/javascript/recovery/WakaruReport.ts index ab7f4474b..6ad5faf4b 100644 --- a/src/javascript/recovery/WakaruReport.ts +++ b/src/javascript/recovery/WakaruReport.ts @@ -10,20 +10,20 @@ import { readRecoveryFile, recoveryFailureMessage } from "./RecoveryFiles.js"; import { RECOVERY_LIMITS } from "./WakaruRelease.js"; import type { runWakaruCommand } from "./WakaruCommand.js"; -const warningSchema = z.strictObject({ +const warningSchema = z.looseObject({ filename: z.string(), kind: z.string(), is_error: z.boolean(), message: z.string(), }); -const reportSchema = z.strictObject({ +const reportSchema = z.looseObject({ detected_formats: z.array(z.string()), safety: z.string(), modules: z.array( - z.strictObject({ + z.looseObject({ filename: z.string().min(1), kind: z.literal("javascript"), - status: z.literal("decompiled"), + status: z.string().min(1), }), ), warnings: z.array(warningSchema), @@ -35,12 +35,12 @@ const rangeSchema = z.tuple([ z.number().int().nonnegative(), z.number().int().nonnegative(), ]); -const provenanceSchema = z.strictObject({ +const provenanceSchema = z.looseObject({ format: z.string(), strategy: z.string(), modules: z.record( z.string(), - z.strictObject({ + z.looseObject({ input: z.string(), ranges: z.array(rangeSchema), extraction: z.string(), @@ -59,7 +59,12 @@ type ReportContext = { files: readonly { relativePath: string }[]; }; -/** Parse exact pinned producer JSON before projecting provider-neutral artifacts. */ +/** + * Parse producer JSON before projecting provider-neutral artifacts. Wakaru adds + * fields and category values within a major version, so unknown keys are kept + * and `status` stays the reported string; identity, path, range and file-set + * checks below remain exact. + */ export const parseWakaruReports = async (context: ReportContext) => { const { execution, provenancePath } = context; diff --git a/src/javascript/recovery/WakaruVersion.test.ts b/src/javascript/recovery/WakaruVersion.test.ts new file mode 100644 index 000000000..939c2e088 --- /dev/null +++ b/src/javascript/recovery/WakaruVersion.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from "vitest"; +import { admitWakaruVersion } from "./WakaruVersion.js"; +import { WAKARU_RELEASE } from "./WakaruRelease.js"; + +describe("Wakaru release range", () => { + it("accepts the verified banner without an extra limitation", () => { + expect(admitWakaruVersion(`wakaru ${WAKARU_RELEASE.version}`)).toEqual({ + status: "verified", + version: WAKARU_RELEASE.version, + }); + }); + + it.each([ + ["wakaru 1.13.0", "1.13.0"], + ["wakaru 1.15.2", "1.15.2"], + ])("accepts %s as compatible", (banner, version) => { + const admitted = admitWakaruVersion(banner); + expect(admitted).toMatchObject({ status: "compatible", version }); + if (admitted.status !== "compatible") + throw new Error("expected a compatible release"); + expect(admitted.limitation).toContain(version); + expect(admitted.limitation).toContain(WAKARU_RELEASE.version); + }); + + it.each([ + ["wakaru 1.12.0", "wakaru 1.12.0"], + ["wakaru 2.0.0", "wakaru 2.0.0"], + ["wakaru 1.15.0-rc.1", "wakaru 1.15.0-rc.1"], + ["wakaru v1.14.0", "wakaru v1.14.0"], + ["1.14.0", "1.14.0"], + ["", "missing"], + ])("rejects banner %j", (banner, detail) => { + const admitted = admitWakaruVersion(banner); + if (admitted.status !== "unsupported") + throw new Error("expected a rejected banner"); + expect(admitted.message).toContain(detail); + expect(admitted.message).toContain("^1.13.0"); + }); +}); diff --git a/src/javascript/recovery/WakaruVersion.ts b/src/javascript/recovery/WakaruVersion.ts new file mode 100644 index 000000000..f4c2d92ae --- /dev/null +++ b/src/javascript/recovery/WakaruVersion.ts @@ -0,0 +1,39 @@ +import { satisfies, valid } from "semver"; +import { WAKARU_ACCEPTED_RANGE, WAKARU_RELEASE } from "./WakaruRelease.js"; + +/** Admission of one observed `wakaru --version` banner. */ +export type WakaruVersionAdmission = + | { readonly status: "verified"; readonly version: string } + | { + readonly status: "compatible"; + readonly version: string; + readonly limitation: string; + } + | { readonly status: "unsupported"; readonly message: string }; + +/** Caller-facing accepted releases, naming the verified build. */ +export const wakaruReleaseLine = (): string => + `Wakaru ${WAKARU_ACCEPTED_RANGE} (verified with ${WAKARU_RELEASE.version})`; + +/** Classify a `wakaru ` banner against the accepted release range. */ +export const admitWakaruVersion = (banner: string): WakaruVersionAdmission => { + const token = banner.startsWith("wakaru ") + ? banner.slice("wakaru ".length) + : undefined; + if ( + token === undefined || + valid(token) !== token || + !satisfies(token, WAKARU_ACCEPTED_RANGE) + ) + return { + status: "unsupported", + message: `Unsupported Wakaru version ${banner.length === 0 ? "missing" : banner}; accepted releases are ${wakaruReleaseLine()}`, + }; + if (token === WAKARU_RELEASE.version) + return { status: "verified", version: token }; + return { + status: "compatible", + version: token, + limitation: `This session uses Wakaru ${token}. The report parser is verified against ${WAKARU_RELEASE.version}; other ${WAKARU_ACCEPTED_RANGE} releases are accepted and the observed version is reported.`, + }; +}; diff --git a/tests/boundary/javascript-recovery/wakaruIntegration.test.ts b/tests/boundary/javascript-recovery/wakaruIntegration.test.ts index 8b2975788..a46009f3b 100644 --- a/tests/boundary/javascript-recovery/wakaruIntegration.test.ts +++ b/tests/boundary/javascript-recovery/wakaruIntegration.test.ts @@ -97,6 +97,44 @@ describe.skipIf(process.platform !== "linux" || process.arch !== "x64")( await assertRecoveryCleanup(fixture.launches); }); + it("accepts a later release on the verified major line with additive report fields", async () => { + const fixture = await recoveryFixture("additive"); + const result = await fixture.service.recover({ + path: fixture.path, + output_directory: fixture.output, + }); + if (!result.ok) throw result.error; + const value = javascriptRecoveryResultSchema.parse( + result.value.normalized_result, + ); + expect(value).toMatchObject({ + status: "complete", + engine: { version: "1.99.0" }, + modules: [{ reported_status: "future_status" }], + }); + expect(result.value.provider.version).toBe("1.99.0"); + expect( + value.limitations.some((limitation) => + limitation.includes("This session uses Wakaru 1.99.0"), + ), + ).toBe(true); + expect( + JSON.parse(await readFile(value.report.path, "utf8")), + ).toMatchObject({ + future_report_field: { nested: true }, + warnings: [{ code: "W001" }], + }); + expect(value.warnings).toEqual([ + { + filename: "module.js", + kind: "notice", + is_error: false, + message: "future warning", + }, + ]); + await assertRecoveryCleanup(fixture.launches); + }); + it("retains valid partial output and exact failure diagnostics", async () => { const fixture = await recoveryFixture("partial"); const result = await fixture.service.recover({ diff --git a/tests/fixtures/javascript-recovery/producer.mjs b/tests/fixtures/javascript-recovery/producer.mjs index e435a57cf..c97b7ace0 100644 --- a/tests/fixtures/javascript-recovery/producer.mjs +++ b/tests/fixtures/javascript-recovery/producer.mjs @@ -4,7 +4,13 @@ import { dirname, join } from "node:path"; const args = process.argv.slice(2); const mode = process.env.REA_RECOVERY_FIXTURE_MODE ?? "normal"; if (args.includes("--version")) { - console.log(mode === "wrong-version" ? "wakaru 0.0.0" : "wakaru 1.13.0"); + console.log( + mode === "wrong-version" + ? "wakaru 0.0.0" + : mode === "additive" + ? "wakaru 1.99.0" + : "wakaru 1.14.0", + ); } else { const input = args[0]; const output = args[args.indexOf("-o") + 1]; @@ -25,7 +31,16 @@ if (args.includes("--version")) { if (mode === "source-change") await writeFile(process.env.REA_RECOVERY_ORIGINAL_PATH, "changed original"); const filename = mode === "escaping" ? "../escaped.js" : "module.js"; - const modules = [{ filename, kind: "javascript", status: "decompiled" }]; + const modules = [ + mode === "additive" + ? { + filename, + kind: "javascript", + status: "future_status", + future_module_field: true, + } + : { filename, kind: "javascript", status: "decompiled" }, + ]; if (mode === "duplicate") modules.push(modules[0]); if (mode !== "missing-file" && mode !== "escaping") { if (mode === "symlink") await symlink(input, join(output, filename)); @@ -65,6 +80,10 @@ if (args.includes("--version")) { }, }, }; + if (mode === "additive") { + provenance.future_top_field = "added"; + provenance.modules[filename].future_entry_field = [1]; + } if (mode === "extra-provenance") provenance.modules["extra.js"] = provenance.modules[filename]; if (mode !== "missing-provenance") @@ -86,7 +105,18 @@ if (args.includes("--version")) { message: "fixture transform failed; retained source", }, ] - : [], + : mode === "additive" + ? [ + { + filename, + kind: "notice", + is_error: false, + message: "future warning", + code: "W001", + }, + ] + : [], + ...(mode === "additive" ? { future_report_field: { nested: true } } : {}), total: modules.length, failed: mode === "partial" ? 1 : 0, elapsed_ms: 1, diff --git a/third_party/wakaru b/third_party/wakaru index 6070266d2..8219bf501 160000 --- a/third_party/wakaru +++ b/third_party/wakaru @@ -1 +1 @@ -Subproject commit 6070266d24b32951fa2fe1d2dad5b4313bd5c81b +Subproject commit 8219bf5016a063d7fb215101a8c45d5959ec733f