Files
rea/scripts/package-runner-bootstrap.mjs
T

73 lines
2.2 KiB
JavaScript

import { spawn } from "node:child_process";
import { resolve } from "node:path";
const BOOTSTRAP_MARKER = "REA_PACKAGE_RUNNER_BOOTSTRAPPED";
/**
* Plan a current-release setup bootstrap when bare npx selected a project-local
* package. Explicit `npm exec --package=<name>@<version>` rollbacks bypass it.
*/
export function packageRunnerSetupPlan(input) {
if (input.args[0] !== "setup") return undefined;
if (input.environment[BOOTSTRAP_MARKER] === "1") return undefined;
if (input.environment.npm_lifecycle_event !== "npx") return undefined;
const localPrefix = input.environment.npm_config_local_prefix;
if (localPrefix === undefined || localPrefix.length === 0) return undefined;
if (
!isPackageBelowLocalPrefix(
input.packageRoot,
localPrefix,
input.packageName,
)
)
return undefined;
const requestedPackage = input.environment.npm_config_package;
if (
requestedPackage !== undefined &&
isExactPackageVersion(requestedPackage, input.packageName)
)
return undefined;
return {
command: "npm",
args: [
"exec",
"--yes",
`--package=${input.packageName}@latest`,
"--",
"rea",
...input.args,
],
};
}
/** Execute a planned package-runner bootstrap and return its exit status. */
export async function runPackageRunnerSetupBootstrap(input) {
const plan = packageRunnerSetupPlan(input);
if (plan === undefined) return undefined;
return await new Promise((resolveExitCode) => {
const child = spawn(plan.command, plan.args, {
stdio: "inherit",
env: { ...input.environment, [BOOTSTRAP_MARKER]: "1" },
});
child.once("error", () => resolveExitCode(1));
child.once("exit", (code) => resolveExitCode(code ?? 1));
});
}
function isPackageBelowLocalPrefix(packageRoot, localPrefix, packageName) {
const expectedRoot = resolve(localPrefix, "node_modules", packageName);
return resolve(packageRoot) === expectedRoot;
}
function isExactPackageVersion(packageSpecifier, packageName) {
const version = packageSpecifier.slice(`${packageName}@`.length);
return (
packageSpecifier.startsWith(`${packageName}@`) &&
/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u.test(version)
);
}