import { lstat, readFile, writeFile } from "node:fs/promises"; import { dirname, join, relative } from "node:path"; import { fileURLToPath } from "node:url"; import { format } from "prettier"; const root = join(dirname(fileURLToPath(import.meta.url)), ".."); const sourcePath = join(root, "src", "toolbox", "manifest.source.json"); const outputPath = join(root, "public", "toolbox-app.json"); const source = JSON.parse(await readFile(sourcePath, "utf8")); const packageJson = JSON.parse( await readFile(join(root, "package.json"), "utf8"), ); const versionSource = await readFile(join(root, "src", "version.ts"), "utf8"); const applicationVersion = /^export const APPLICATION_VERSION = "([^"]+)";$/mu.exec(versionSource)?.[1]; if ( source.version !== packageJson.version || applicationVersion !== packageJson.version ) throw new Error( `Version drift: manifest ${source.version}, application ${String(applicationVersion)}, package ${packageJson.version}`, ); if ( source.id !== "de.add-ideas.sudoku-tools" || source.source?.repository !== "https://git.add-ideas.de/lotobo/sudoku-tools" || source.source?.license !== "GPL-3.0-or-later" ) throw new Error("Manifest source identity is incomplete or inconsistent"); for (const asset of source.assets ?? []) { if ( typeof asset !== "string" || !asset.startsWith("./") || asset.includes("\\") || asset.split("/").includes("..") ) throw new Error(`Unsafe manifest asset path: ${JSON.stringify(asset)}`); const details = await lstat(join(root, "public", asset.slice(2))).catch( () => null, ); if (!details?.isFile() || details.isSymbolicLink()) throw new Error(`Manifest asset is missing or unsafe: ${asset}`); } const serialized = await format(JSON.stringify(source), { filepath: outputPath, }); if (process.argv.includes("--check")) { if ((await readFile(outputPath, "utf8").catch(() => "")) !== serialized) throw new Error( `${relative(root, outputPath)} is stale; run npm run manifest:generate`, ); console.log("Toolbox manifest is synchronized"); } else { await writeFile(outputPath, serialized); console.log(`Generated ${relative(root, outputPath)}`); }