Files
Rental-operations-platform/scripts/validate-runtime-dependencies.mjs
2026-06-25 19:06:59 -04:00

56 lines
2.1 KiB
JavaScript

import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { fail, pass, repositoryRoot } from './lib.mjs';
const expected = {
node: '24.17.0',
pnpm: '11.9.0',
};
const packageJson = JSON.parse(await readFile(path.join(repositoryRoot, 'package.json'), 'utf8'));
const lockfile = await readFile(path.join(repositoryRoot, 'pnpm-lock.yaml'), 'utf8');
const nodeVersion = (await readFile(path.join(repositoryRoot, '.node-version'), 'utf8')).trim();
const nvmVersion = (await readFile(path.join(repositoryRoot, '.nvmrc'), 'utf8')).trim();
const errors = [];
if (packageJson.packageManager !== `pnpm@${expected.pnpm}`) {
errors.push(`packageManager must be pnpm@${expected.pnpm}.`);
}
if (packageJson.engines?.node !== expected.node) {
errors.push(`package.json engines.node must be ${expected.node}.`);
}
if (packageJson.engines?.pnpm !== expected.pnpm) {
errors.push(`package.json engines.pnpm must be ${expected.pnpm}.`);
}
if (nodeVersion !== expected.node || nvmVersion !== expected.node) {
errors.push('.node-version and .nvmrc must match the approved Node.js runtime.');
}
const directDependencies = {
...(packageJson.dependencies ?? {}),
...(packageJson.devDependencies ?? {}),
};
const exactVersion = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
for (const [name, version] of Object.entries(directDependencies)) {
if (typeof version !== 'string' || !exactVersion.test(version)) {
errors.push(`${name} must use an exact direct version, received ${String(version)}.`);
continue;
}
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const escapedVersion = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const lockSpecifier = new RegExp(
`(?:^|\\n)\\s{6}['\"]?${escapedName}['\"]?:\\n\\s{8}specifier: ${escapedVersion}(?:\\n|$)`,
);
if (!lockSpecifier.test(lockfile)) {
errors.push(
`${name}@${version} is not represented by an exact importer specifier in pnpm-lock.yaml.`,
);
}
}
if (errors.length) fail(errors);
else {
pass(
`Pinned Node ${expected.node}, pnpm ${expected.pnpm}, and ${Object.keys(directDependencies).length} exact direct dependency versions match the lockfile.`,
);
}