mirror of
https://github.com/Narcooo/inkos
synced 2026-04-21 14:37:16 +00:00
140 lines
4.1 KiB
JavaScript
140 lines
4.1 KiB
JavaScript
/**
|
|
* Verify that source manifests are publishable once prepack normalization runs.
|
|
*
|
|
* Usage:
|
|
* node scripts/verify-no-workspace-protocol.mjs packages/cli packages/core
|
|
* node ../../scripts/verify-no-workspace-protocol.mjs .
|
|
*
|
|
* This script is safe to run on source manifests before prepack.
|
|
*
|
|
* Checks two invariants before publish:
|
|
* 1. workspace:* / workspace:^ / workspace:~ references can be normalized to real versions
|
|
* 2. non-workspace internal dependencies already point at the current workspace version
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
function normalizeWorkspaceSpecifier(specifier, version) {
|
|
const value = specifier.slice("workspace:".length);
|
|
if (value === "*" || value === "") return version;
|
|
if (value === "^") return `^${version}`;
|
|
if (value === "~") return `~${version}`;
|
|
return value;
|
|
}
|
|
|
|
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)) {
|
|
const workspaceVersion = workspaceVersions.get(name);
|
|
if (typeof specifier !== "string") {
|
|
continue;
|
|
}
|
|
|
|
if (specifier.startsWith("workspace:")) {
|
|
if (!workspaceVersion) {
|
|
process.stderr.write(`FAIL: ${dir} — ${field}.${name}: ${specifier} (workspace package not found)\n`);
|
|
dirFailed = true;
|
|
failed = true;
|
|
continue;
|
|
}
|
|
|
|
const normalized = normalizeWorkspaceSpecifier(specifier, workspaceVersion);
|
|
if (
|
|
normalized !== workspaceVersion
|
|
&& normalized !== `^${workspaceVersion}`
|
|
&& normalized !== `~${workspaceVersion}`
|
|
) {
|
|
process.stderr.write(
|
|
`FAIL: ${dir} — ${field}.${name}: ${specifier} normalizes to ${normalized}, expected ${workspaceVersion}, ^${workspaceVersion}, or ~${workspaceVersion}\n`,
|
|
);
|
|
dirFailed = true;
|
|
failed = true;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (
|
|
workspaceVersion
|
|
&& specifier !== workspaceVersion
|
|
&& specifier !== `^${workspaceVersion}`
|
|
&& specifier !== `~${workspaceVersion}`
|
|
) {
|
|
process.stderr.write(
|
|
`FAIL: ${dir} — ${field}.${name}: expected ${workspaceVersion}, ^${workspaceVersion}, or ~${workspaceVersion}, got ${specifier}\n`,
|
|
);
|
|
dirFailed = true;
|
|
failed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!dirFailed) {
|
|
process.stderr.write(`OK: ${dir}\n`);
|
|
}
|
|
}
|
|
|
|
if (failed) {
|
|
process.exit(1);
|
|
}
|