import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { createRequire } from "node:module"; import { pathToFileURL } from "node:url"; const root = path.resolve(path.dirname(new URL(import.meta.url).pathname), ".."); const build = path.resolve(process.argv[2] ?? path.join(root, "freecad-source/build-web/configure/bin")); const docs = path.join(root, "docs/p6"); globalThis.__dirname = `${build}${path.sep}`; globalThis.require = createRequire(import.meta.url); const loader = await import(pathToFileURL(path.join(build, "FreeCADWebReverseEngineeringRuntimeProbe.js"))); const kernel = await loader.default({ wasmBinary: fs.readFileSync(path.join(build, "FreeCADWebReverseEngineeringRuntimeProbe.wasm")), print: () => {}, printErr: () => {} }); const call = (name, returnType = "number", argTypes = [], args = []) => kernel.ccall(name, returnType, argTypes, args); const run = () => ({ initialize: call("fc_web_reverseengineering_initialize"), initializationCalls: call("fc_web_reverseengineering_initialization_calls"), initializationRuns: call("fc_web_reverseengineering_initialization_runs"), moduleAvailable: call("fc_web_reverseengineering_module_available"), error: call("fc_web_reverseengineering_error", "string") }); const first = run(); const repeated = run(); const sourceEntry = "src/Mod/ReverseEngineering/App/AppReverseEngineering.cpp"; const apiValidation = call("fc_web_reverseengineering_python_api_validate", "number", ["string"], [sourceEntry]); const apiExecution = call("fc_web_reverseengineering_python_api"); const second = run(); const invalidSource = call( "fc_web_reverseengineering_python_api_validate", "number", ["string"], ["src/Mod/ReverseEngineering/App/AppReverseEngineering.hxx"] ); const invalidError = call("fc_web_reverseengineering_error", "string"); const semantic = value => ({ initialize: value.initialize, initializationRuns: value.initializationRuns, moduleAvailable: value.moduleAvailable, error: value.error }); const result = { first, repeated, second, apiValidation, apiExecution, apiNames: call("fc_web_reverseengineering_api_names", "string"), apiCount: call("fc_web_reverseengineering_api_count"), curveValid: call("fc_web_reverseengineering_curve_valid"), invalidSource, invalidError, deterministic: JSON.stringify(semantic(first)) === JSON.stringify(semantic(second)), pass: first.initialize === 1 && repeated.initialize === 1 && second.initialize === 1 && first.initializationRuns === 1 && repeated.initializationRuns === 1 && second.initializationRuns === 1 && repeated.initializationCalls === 2 && first.moduleAvailable === 1 && apiValidation === 1 && apiExecution === 1 && resultApiCountPlaceholder() && invalidSource === 0 && invalidError === "revision_mismatch" }; function resultApiCountPlaceholder() { return call("fc_web_reverseengineering_api_count") === 2 && call("fc_web_reverseengineering_curve_valid") === 1; } const wasmPath = path.join(build, "FreeCADWebReverseEngineeringRuntimeProbe.wasm"); const fixture = { module: "ReverseEngineering", sourceEntry, api: ["approxCurve", "approxSurface"] }; const hash = value => crypto.createHash("sha256").update(value).digest("hex"); const report = { schema: "freecad-web-p6-reverseengineering-runtime/v1", task_id: "FW-P6-REV-B-R1", module: "ReverseEngineering", status: result.pass && result.deterministic ? "pass" : "fail", source_revision: "working-tree", fixture: { ...fixture, input_sha256: hash(JSON.stringify(fixture)) }, result, result_sha256: hash(JSON.stringify(result)), artifacts: { wasm: { path: "freecad-source/build-web/configure/bin/FreeCADWebReverseEngineeringRuntimeProbe.wasm", sha256: hash(fs.readFileSync(wasmPath)) } }, boundaries: ["The Web target enables ReverseEngineering App only; ReverseEngineeringGui and PCL-only APIs remain outside this slice.", "The native probe registers Part and Mesh dependencies before the official ReverseEngineering Python module."] }; fs.mkdirSync(docs, { recursive: true }); fs.writeFileSync(path.join(docs, "reverseengineering-runtime.json"), `${JSON.stringify(report, null, 2)}\n`); fs.writeFileSync(path.join(root, "docs/freecad-p6-reverseengineering-b-runtime.log"), `${JSON.stringify({ status: report.status, initializationRuns: second.initializationRuns, apiCount: result.apiCount, invalidError })}\n`); console.log(JSON.stringify({ status: report.status, initializationRuns: second.initializationRuns, apiCount: result.apiCount, apiExecution: result.apiExecution, invalidError })); if (report.status !== "pass") process.exitCode = 1;