135 lines
4.5 KiB
JavaScript
135 lines
4.5 KiB
JavaScript
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
import { join, relative } from "node:path";
|
|
import process from "node:process";
|
|
|
|
const root = process.cwd();
|
|
const VERSION = "0.3.0";
|
|
const errors = [];
|
|
const notes = [];
|
|
const readJson = (file) => JSON.parse(readFileSync(file, "utf8"));
|
|
|
|
function walk(dir, name = "package.json") {
|
|
const out = [];
|
|
if (!existsSync(dir)) return out;
|
|
for (const entry of readdirSync(dir)) {
|
|
if (entry === "node_modules" || entry === ".git" || entry === "dist") continue;
|
|
const path = join(dir, entry);
|
|
const stat = statSync(path);
|
|
if (stat.isDirectory()) out.push(...walk(path, name));
|
|
else if (entry === name) out.push(path);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
const packageFiles = [join(root, "package.json"), ...walk(join(root, "packages"))];
|
|
const packages = new Map();
|
|
for (const file of packageFiles) {
|
|
const pkg = readJson(file);
|
|
if (pkg.name) packages.set(pkg.name, { file, pkg });
|
|
if (file.includes(`${join(root, "packages")}/`) && pkg.version !== VERSION) {
|
|
errors.push(`${relative(root, file)} has version ${pkg.version ?? "<missing>"}`);
|
|
}
|
|
}
|
|
if (readJson(join(root, "package.json")).version !== VERSION) {
|
|
errors.push(`root package version is not ${VERSION}`);
|
|
}
|
|
|
|
for (const { file, pkg } of packages.values()) {
|
|
for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
|
|
for (const [name, range] of Object.entries(pkg[field] ?? {})) {
|
|
if (String(range).startsWith("workspace:") && !packages.has(name)) {
|
|
errors.push(`${relative(root, file)} references missing workspace ${name}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const required of [
|
|
"packages/syntax/src/index.ts",
|
|
"packages/plugin/src/index.ts",
|
|
"scripts/build-editor-compiler.mjs",
|
|
"docs/WRN-LANGUAGE-SPEC-1.0.md",
|
|
"docs/ARCHITECTURE-0.3.md",
|
|
"docs/UPGRADE-0.3.md",
|
|
"docs/40-POINT-IMPLEMENTATION-0.3.md",
|
|
"docs/TEST-CHECKLIST-0.3.md",
|
|
"docs/AUDIT-0.3.md",
|
|
]) {
|
|
if (!existsSync(join(root, required))) errors.push(`missing ${required}`);
|
|
}
|
|
|
|
const updateSource = readFileSync(join(root, "packages/cli/src/update.ts"), "utf8");
|
|
const migrationPairs = [
|
|
...updateSource.matchAll(/version:\s*"([^"]+)"[\s\S]*?id:\s*"([^"]+)"/g),
|
|
].map((match) => ({ version: match[1], id: match[2] }));
|
|
const ids = new Set();
|
|
for (const migration of migrationPairs) {
|
|
if (ids.has(migration.id)) errors.push(`duplicate migration id ${migration.id}`);
|
|
ids.add(migration.id);
|
|
}
|
|
if (!migrationPairs.some((migration) => migration.version === VERSION)) {
|
|
errors.push(`missing ${VERSION} updater migration`);
|
|
}
|
|
|
|
for (const jsonFile of [
|
|
"editors/vscode/package.json",
|
|
"editors/vscode/package-lock.json",
|
|
"editors/vscode/snippets/wrn.json",
|
|
"editors/vscode/syntaxes/wrn.tmLanguage.json",
|
|
]) {
|
|
try {
|
|
readJson(join(root, jsonFile));
|
|
} catch (error) {
|
|
errors.push(`${jsonFile} is invalid JSON: ${error instanceof Error ? error.message : error}`);
|
|
}
|
|
}
|
|
|
|
try {
|
|
const lockText = readFileSync(join(root, "bun.lock"), "utf8").replace(/,\s*([}\]])/g, "$1");
|
|
const lock = JSON.parse(lockText);
|
|
for (const workspace of ["packages/syntax", "packages/plugin"]) {
|
|
if (!lock.workspaces?.[workspace]) errors.push(`bun.lock missing ${workspace}`);
|
|
}
|
|
for (const name of ["@wrnexus/syntax", "@wrnexus/plugin"]) {
|
|
if (!lock.packages?.[name]) errors.push(`bun.lock missing workspace link ${name}`);
|
|
}
|
|
} catch (error) {
|
|
errors.push(`bun.lock structure is invalid: ${error instanceof Error ? error.message : error}`);
|
|
}
|
|
|
|
const compilerParser = readFileSync(join(root, "packages/compiler/src/parser.ts"), "utf8");
|
|
if (!compilerParser.includes("@wrnexus/syntax")) {
|
|
errors.push("compiler parser is not a compatibility re-export of @wrnexus/syntax");
|
|
}
|
|
|
|
const tsconfig = readJson(join(root, "tsconfig.json"));
|
|
for (const name of packages.keys()) {
|
|
if (name.startsWith("@wrnexus/") && !tsconfig.compilerOptions?.paths?.[name]) {
|
|
errors.push(`tsconfig paths missing ${name}`);
|
|
}
|
|
}
|
|
|
|
notes.push(`${packages.size} named packages checked`);
|
|
notes.push(`${migrationPairs.length} migration entries checked`);
|
|
notes.push("editor JSON and Bun workspace lock structure checked");
|
|
|
|
if (errors.length) {
|
|
process.stderr.write(
|
|
[
|
|
`WRNexusJS ${VERSION} verification failed:`,
|
|
...errors.map((error) => ` - ${error}`),
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
|
|
process.exitCode = 1;
|
|
} else {
|
|
process.stdout.write(
|
|
[
|
|
`WRNexusJS ${VERSION} structural verification passed.`,
|
|
...notes.map((note) => ` ✓ ${note}`),
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
}
|