everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
150 lines (148 loc) • 5.77 kB
JavaScript
const require_http_client = require('../http-client.cjs');
const require_fastkv = require('../fastkv.cjs');
const require_config = require('../config.cjs');
const require_snapshot = require('./snapshot.cjs');
const require_framework_version = require('./framework-version.cjs');
let node_fs = require("node:fs");
let node_path = require("node:path");
//#region src/cli/status.ts
const FRAMEWORK_PACKAGES = ["everything-dev", "every-plugin"];
const CATALOG_TOOL_PACKAGES = [
"@rspack/core",
"@rspack/cli",
"@rsbuild/core",
"@rsbuild/plugin-react",
"@module-federation/enhanced",
"@module-federation/node",
"@module-federation/rsbuild-plugin",
"@module-federation/runtime-core",
"@module-federation/sdk",
"@module-federation/dts-plugin"
];
const PRERELEASE_PATTERN = /-[0-9A-Za-z.-]+$/;
/**
* The dist-tag to compare an installed version against: prerelease installs
* track the `rc` dist-tag (the changesets pre-mode train), stable installs
* track `latest`. Falls back to `latest` when no `rc` tag is published.
*/
function resolveUpdateDistTag(installed) {
return installed && PRERELEASE_PATTERN.test(installed) ? "rc" : "latest";
}
/** The version a given dist-tag currently points at, or null when absent. */
function pickDistTagVersion(distTags, tag) {
return distTags?.[tag] ?? null;
}
const SEMVER_PATTERN = /^(?<core>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(?:-(?<prerelease>[0-9A-Za-z.-]+))?(?:\+[\w.-]+)?$/;
function parseVersion(version) {
if (!version) return null;
const match = SEMVER_PATTERN.exec(version.trim().replace(/^[\^~>=v]+/, ""));
if (!match?.groups) return null;
const prerelease = match.groups.prerelease ? match.groups.prerelease.split(".").map((id) => /^\d+$/.test(id) ? Number(id) : id) : [];
return {
core: [
Number(match.groups.core),
Number(match.groups.minor),
Number(match.groups.patch)
],
prerelease
};
}
function comparePrerelease(a, b) {
if (a.length === 0 && b.length === 0) return 0;
if (a.length === 0) return 1;
if (b.length === 0) return -1;
const length = Math.max(a.length, b.length);
for (let i = 0; i < length; i += 1) {
const left = a[i];
const right = b[i];
if (left === void 0) return -1;
if (right === void 0) return 1;
if (typeof left === "number" && typeof right === "number") {
if (left !== right) return left < right ? -1 : 1;
} else if (typeof left === "number") return -1;
else if (typeof right === "number") return 1;
else if (left !== right) return left < right ? -1 : 1;
}
return 0;
}
/**
* Semver-ordered comparison of two version strings: -1 when `a` is older than
* `b`, 1 when newer, 0 when equal. Unparseable versions compare as equal —
* the update check must never fire on versions it cannot order (that is how
* an install ahead of npm got flagged "outdated" with a downgrade arrow).
*/
function compareSemver(a, b) {
const left = parseVersion(a);
const right = parseVersion(b);
if (!left || !right) return 0;
for (let i = 0; i < left.core.length; i += 1) if (left.core[i] !== right.core[i]) return left.core[i] < right.core[i] ? -1 : 1;
return comparePrerelease(left.prerelease, right.prerelease);
}
async function fetchLatestNpmVersion(packageName, tag) {
if (tag === "latest") return require_http_client.fetchJsonOrNull(`https://registry.npmjs.org/${packageName}/latest`, {
headers: { Accept: "application/json" },
retries: 0
}).then((data) => data?.version ?? null);
return pickDistTagVersion((await require_http_client.fetchJsonOrNull(`https://registry.npmjs.org/${packageName}`, {
headers: { Accept: "application/vnd.npm.install-v1+json" },
retries: 0
}))?.["dist-tags"], tag);
}
function readInstalledVersion(projectDir, packageName) {
return require_framework_version.readInstalledFrameworkVersion(projectDir, packageName);
}
function checkEnvFile(projectDir) {
if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, ".env"))) return "found";
if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, ".env.example"))) return "example-only";
return "missing";
}
async function checkParentReachable(extendsRef) {
if (!extendsRef?.startsWith("bos://")) return void 0;
try {
return await require_fastkv.fetchBosConfigFromFastKv(extendsRef) !== null;
} catch {
return false;
}
}
async function getStatus(projectDir) {
const authored = await require_config.readAuthoredConfigInput(projectDir);
if (!authored) return {
status: "error",
error: `${require_config.MISSING_CONFIG_MESSAGE} in current directory`,
packages: [],
envFile: "missing"
};
const config = authored;
const packageNames = [...FRAMEWORK_PACKAGES];
for (const name of CATALOG_TOOL_PACKAGES) if (readInstalledVersion(projectDir, name)) packageNames.push(name);
const packages = await Promise.all(packageNames.map(async (name) => {
const resolved = require_framework_version.resolveFrameworkPackage(projectDir, name);
const latest = await fetchLatestNpmVersion(name, FRAMEWORK_PACKAGES.includes(name) ? resolveUpdateDistTag(resolved.installedVersion) : "latest");
return {
name,
installed: resolved.installedVersion,
latest: latest ?? void 0,
isLinked: resolved.isLinked,
specifier: resolved.specifier
};
}));
const snapshot = await require_snapshot.readSnapshot(projectDir);
const extendsRef = config.extends;
const parentReachable = await checkParentReachable(extendsRef);
return {
status: "ok",
extends: extendsRef,
account: config.account,
domain: config.domain,
packages,
lastSync: snapshot?.timestamp,
envFile: checkEnvFile(projectDir),
parentReachable
};
}
//#endregion
exports.compareSemver = compareSemver;
exports.getStatus = getStatus;
exports.pickDistTagVersion = pickDistTagVersion;
exports.resolveUpdateDistTag = resolveUpdateDistTag;
//# sourceMappingURL=status.cjs.map