mirror of
https://github.com/Narcooo/inkos
synced 2026-04-21 14:37:16 +00:00
105 lines
2.9 KiB
JavaScript
105 lines
2.9 KiB
JavaScript
/**
|
|
* Standalone verification for publishable package manifests.
|
|
*
|
|
* Usage:
|
|
* node scripts/verify-no-workspace-protocol.mjs packages/cli packages/core
|
|
* node ../../scripts/verify-no-workspace-protocol.mjs .
|
|
*
|
|
* Checks two invariants before publish:
|
|
* 1. publishable dependency fields must not contain workspace: specifiers
|
|
* 2. internal workspace dependencies must match the current workspace package version exactly
|
|
*/
|
|
|
|
import { access, readdir, readFile } from "node:fs/promises";
|
|
import { join, resolve } from "node:path";
|
|
|
|
const dirs = process.argv.slice(2);
|
|
if (dirs.length === 0) {
|
|
process.stderr.write("Usage: node verify-no-workspace-protocol.mjs <pkg-dir> [<pkg-dir>...]\n");
|
|
process.exit(1);
|
|
}
|
|
|
|
async function exists(path) {
|
|
try {
|
|
await access(path);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function findWorkspaceRoot(startDir) {
|
|
let dir = resolve(startDir);
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
if (await exists(join(dir, "packages"))) {
|
|
return dir;
|
|
}
|
|
|
|
const parent = resolve(dir, "..");
|
|
if (parent === dir) break;
|
|
dir = parent;
|
|
}
|
|
|
|
throw new Error(`Could not find workspace root from ${startDir}`);
|
|
}
|
|
|
|
async function loadWorkspaceVersions(workspaceRoot) {
|
|
const packagesDir = join(workspaceRoot, "packages");
|
|
const entries = await readdir(packagesDir);
|
|
const versions = new Map();
|
|
|
|
for (const entry of entries) {
|
|
try {
|
|
const raw = await readFile(join(packagesDir, entry, "package.json"), "utf-8");
|
|
const pkg = JSON.parse(raw);
|
|
versions.set(pkg.name, pkg.version);
|
|
} catch {
|
|
// ignore directories that are not publishable packages
|
|
}
|
|
}
|
|
|
|
return versions;
|
|
}
|
|
|
|
let failed = false;
|
|
const workspaceRoot = await findWorkspaceRoot(process.cwd());
|
|
const workspaceVersions = await loadWorkspaceVersions(workspaceRoot);
|
|
|
|
for (const dirArg of dirs) {
|
|
const dir = resolve(process.cwd(), dirArg);
|
|
const packageJsonPath = join(dir, "package.json");
|
|
const raw = await readFile(packageJsonPath, "utf-8");
|
|
const pkg = JSON.parse(raw);
|
|
let dirFailed = false;
|
|
|
|
for (const field of ["dependencies", "optionalDependencies", "peerDependencies"]) {
|
|
const deps = pkg[field];
|
|
if (!deps) continue;
|
|
for (const [name, specifier] of Object.entries(deps)) {
|
|
if (typeof specifier === "string" && specifier.startsWith("workspace:")) {
|
|
process.stderr.write(`FAIL: ${dir} — ${field}.${name}: ${specifier}\n`);
|
|
dirFailed = true;
|
|
failed = true;
|
|
continue;
|
|
}
|
|
|
|
const workspaceVersion = workspaceVersions.get(name);
|
|
if (workspaceVersion && specifier !== workspaceVersion) {
|
|
process.stderr.write(
|
|
`FAIL: ${dir} — ${field}.${name}: expected ${workspaceVersion}, got ${specifier}\n`,
|
|
);
|
|
dirFailed = true;
|
|
failed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!dirFailed) {
|
|
process.stderr.write(`OK: ${dir}\n`);
|
|
}
|
|
}
|
|
|
|
if (failed) {
|
|
process.exit(1);
|
|
}
|