import { cp, mkdir, readdir, rm, readFile } from "node:fs/promises"; import { basename, dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; const appRoot = dirname(dirname(fileURLToPath(import.meta.url))); const repoRoot = dirname(dirname(appRoot)); const distDir = join(appRoot, "dist"); const recursiveStaticCopyOptions = { recursive: true, filter: includeStaticReleaseAsset }; await rm(distDir, { recursive: true, force: true }); await mkdir(distDir, { recursive: true }); await cp(join(appRoot, "index.html"), join(distDir, "index.html")); await cp(join(appRoot, "src"), join(distDir, "src"), { recursive: true }); await copyLinuxCncManifest(); await copyLinuxCncConfigAssets(); await copyLinuxCncReferenceAssets(); await copyBundledTestLinuxCncSourceAssets(); await copyKinematicsRuntimeAssets(); await copyInterpreterRuntimeAssets(); await copyTpRuntimeAssets(); await copyTaskHalRuntimeAssets(); await copyPythonRemapRuntimeAssets(); const packageJson = JSON.parse(await readFile(join(appRoot, "package.json"), "utf8")); const forbiddenDependencies = ["react", "vue", "@angular/core", "svelte"]; const dependencyNames = [ ...Object.keys(packageJson.dependencies || {}), ...Object.keys(packageJson.devDependencies || {}), ]; const forbidden = dependencyNames.filter((name) => forbiddenDependencies.includes(name)); if (forbidden.length > 0) { throw new Error(`forbidden frontend framework dependency detected: ${forbidden.join(", ")}`); } async function copyInterpreterRuntimeAssets() { const coreSrcDir = join(repoRoot, "wasm-port/build/wasm/core"); const coreDistDir = join(distDir, "wasm-port/build/wasm/core"); await mkdir(coreDistDir, { recursive: true }); for (const entry of ["linuxcnc_interp.js", "linuxcnc_interp.wasm"]) { await cp(join(coreSrcDir, entry), join(coreDistDir, entry)); } } async function copyTpRuntimeAssets() { const tpSrcDir = join(repoRoot, "wasm-port/build/wasm/tp"); const tpDistDir = join(distDir, "wasm-port/build/wasm/tp"); await mkdir(tpDistDir, { recursive: true }); for (const entry of ["linuxcnc_tp.js", "linuxcnc_tp.wasm"]) { await cp(join(tpSrcDir, entry), join(tpDistDir, entry)); } } async function copyTaskHalRuntimeAssets() { const taskHalSrcDir = join(repoRoot, "wasm-port/build/wasm/task-hal"); const taskHalDistDir = join(distDir, "wasm-port/build/wasm/task-hal"); await mkdir(taskHalDistDir, { recursive: true }); for (const entry of ["linuxcnc_task_hal.js", "linuxcnc_task_hal.wasm"]) { await cp(join(taskHalSrcDir, entry), join(taskHalDistDir, entry)); } } console.log("gmoccapy_static_build=ok"); async function copyLinuxCncConfigAssets() { const configSrcDir = join(repoRoot, "wasm-port/vendor/linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting"); const configDistDir = join(distDir, "configs/sim/axis/vismach/5axis/table-rotary-tilting"); const vendorConfigDistDir = join(distDir, "wasm-port/vendor/linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting"); const gmoccapyConfigSrcDir = join(repoRoot, "wasm-port/vendor/linuxcnc/configs/sim/gmoccapy"); const gmoccapyConfigDistDir = join(distDir, "configs/sim/gmoccapy"); const gmoccapyVendorConfigDistDir = join(distDir, "wasm-port/vendor/linuxcnc/configs/sim/gmoccapy"); const wrappedRotarySrcDir = join(repoRoot, "wasm-port/vendor/linuxcnc/configs/sim/axis/wrapped_rotary"); const wrappedRotaryDistDir = join(distDir, "configs/sim/axis/wrapped_rotary"); const wrappedRotaryVendorDistDir = join( distDir, "wasm-port/vendor/linuxcnc/configs/sim/axis/wrapped_rotary", ); await mkdir(configDistDir, { recursive: true }); await mkdir(vendorConfigDistDir, { recursive: true }); await mkdir(gmoccapyConfigDistDir, { recursive: true }); await mkdir(gmoccapyVendorConfigDistDir, { recursive: true }); await mkdir(wrappedRotaryDistDir, { recursive: true }); await mkdir(wrappedRotaryVendorDistDir, { recursive: true }); await cp(configSrcDir, configDistDir, recursiveStaticCopyOptions); await cp(configSrcDir, vendorConfigDistDir, recursiveStaticCopyOptions); await cp(gmoccapyConfigSrcDir, gmoccapyConfigDistDir, recursiveStaticCopyOptions); await cp(gmoccapyConfigSrcDir, gmoccapyVendorConfigDistDir, recursiveStaticCopyOptions); await cp(wrappedRotarySrcDir, wrappedRotaryDistDir, recursiveStaticCopyOptions); await cp(wrappedRotarySrcDir, wrappedRotaryVendorDistDir, recursiveStaticCopyOptions); } async function copyLinuxCncReferenceAssets() { const linuxCncSrcDir = join(repoRoot, "linuxcnc"); const linuxCncDistDir = join(distDir, "linuxcnc"); await mkdir(linuxCncDistDir, { recursive: true }); for (const entry of [ "configs/sim/axis/laser", "configs/sim/axis/remap", "configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating", "configs/sim/axis/vismach/VMC_toolchange", "configs/sim/gmoccapy", "nc_files", ]) { await cp(join(linuxCncSrcDir, entry), join(linuxCncDistDir, entry), recursiveStaticCopyOptions); } } async function copyPythonRemapRuntimeAssets() { const runtimeDistDir = join(distDir, "wasm-port/runtime"); const sdkSrcDir = join(repoRoot, "wasm-port/runtime/sdk/src"); const sdkDistDir = join(runtimeDistDir, "sdk/src"); const workersSrcDir = join(repoRoot, "wasm-port/runtime/workers"); const workersDistDir = join(runtimeDistDir, "workers"); const pyodideSrcDir = join(appRoot, "node_modules/pyodide"); const pyodideDistDir = join(runtimeDistDir, "third_party/pyodide"); await mkdir(sdkDistDir, { recursive: true }); await mkdir(workersDistDir, { recursive: true }); await mkdir(pyodideDistDir, { recursive: true }); for (const entry of [ "python-remap-browser-worker-adapter.js", "python-remap-pyodide-provider.js", "python-remap-runtime-port.js", ]) { await cp(join(sdkSrcDir, entry), join(sdkDistDir, entry)); } for (const entry of [ "python-remap-worker.js", "python-remap-pyodide-provider.js", ]) { await cp(join(workersSrcDir, entry), join(workersDistDir, entry)); } for (const entry of [ "pyodide-lock.json", "pyodide.asm.mjs", "pyodide.asm.wasm", "pyodide.mjs", "python_stdlib.zip", ]) { await cp(join(pyodideSrcDir, entry), join(pyodideDistDir, entry)); } } async function copyBundledTestLinuxCncSourceAssets() { const testSourceDir = join(repoRoot, "web-rtcp-5axis-sim-plan/working_run/test_linuxcnc_source"); const testSourceDistDir = join(distDir, "working_run/test_linuxcnc_source"); await mkdir(testSourceDistDir, { recursive: true }); await cp(testSourceDir, testSourceDistDir, recursiveStaticCopyOptions); } function includeStaticReleaseAsset(source) { const name = basename(source); return name !== "__pycache__" && !/\.py[co]$/i.test(name); } async function copyLinuxCncManifest() { const manifestDistDir = join(distDir, "wasm-port/tools"); await mkdir(manifestDistDir, { recursive: true }); await cp( join(repoRoot, "wasm-port/tools/source-manifest.txt"), join(manifestDistDir, "source-manifest.txt"), ); } async function copyKinematicsRuntimeAssets() { const sdkSrcDir = join(repoRoot, "wasm-port/runtime/sdk/src"); const sdkDistDir = join(distDir, "wasm-port/runtime/sdk/src"); await mkdir(sdkDistDir, { recursive: true }); await cp( join(sdkSrcDir, "linuxcnc-kinematics.js"), join(sdkDistDir, "linuxcnc-kinematics.js"), ); for (const entry of [ "linuxcnc-interp.js", "linuxcnc-hal.js", "linuxcnc-tp.js", "linuxcnc-task-hal.js", "sim-config-staging.js", ]) { await cp(join(sdkSrcDir, entry), join(sdkDistDir, entry)); } const kinematicsSrcDir = join(repoRoot, "wasm-port/build/wasm/kinematics"); const kinematicsDistDir = join(distDir, "wasm-port/build/wasm/kinematics"); await mkdir(kinematicsDistDir, { recursive: true }); for (const entry of await readdir(kinematicsSrcDir)) { if (!/^linuxcnc_.*_kinematics\.(js|wasm)$/.test(entry)) continue; await cp(join(kinematicsSrcDir, entry), join(kinematicsDistDir, entry)); } }