astro-ghostcms/.pnpm-store/v3/files/d0/3c6c0a42e5cb4cbe8ecca42a581...

127 lines
3.2 KiB
Plaintext

// This is a modified version of the graph-getting in bolt
import Range from "semver/classes/range";
import chalk from "chalk";
import { Packages, Package } from "@manypkg/get-packages";
import { PackageJSON } from "@changesets/types";
const DEPENDENCY_TYPES = [
"dependencies",
"devDependencies",
"peerDependencies",
"optionalDependencies",
] as const;
const getAllDependencies = (config: PackageJSON) => {
const allDependencies = new Map<string, string>();
for (const type of DEPENDENCY_TYPES) {
const deps = config[type];
if (!deps) continue;
for (const name of Object.keys(deps)) {
const depRange = deps[name];
if (
(depRange.startsWith("link:") || depRange.startsWith("file:")) &&
type === "devDependencies"
) {
continue;
}
allDependencies.set(name, depRange);
}
}
return allDependencies;
};
const isProtocolRange = (range: string) => range.indexOf(":") !== -1;
const getValidRange = (potentialRange: string) => {
if (isProtocolRange(potentialRange)) {
return null;
}
try {
return new Range(potentialRange);
} catch {
return null;
}
};
export default function getDependencyGraph(
packages: Packages,
opts?: {
bumpVersionsWithWorkspaceProtocolOnly?: boolean;
}
): {
graph: Map<string, { pkg: Package; dependencies: Array<string> }>;
valid: boolean;
} {
const graph = new Map<
string,
{ pkg: Package; dependencies: Array<string> }
>();
let valid = true;
const packagesByName: { [key: string]: Package } = {
[packages.root.packageJson.name]: packages.root,
};
const queue = [packages.root];
for (const pkg of packages.packages) {
queue.push(pkg);
packagesByName[pkg.packageJson.name] = pkg;
}
for (const pkg of queue) {
const { name } = pkg.packageJson;
const dependencies = [];
const allDependencies = getAllDependencies(pkg.packageJson);
for (let [depName, depRange] of allDependencies) {
const match = packagesByName[depName];
if (!match) continue;
const expected = match.packageJson.version;
const usesWorkspaceRange = depRange.startsWith("workspace:");
if (usesWorkspaceRange) {
depRange = depRange.replace(/^workspace:/, "");
if (depRange === "*" || depRange === "^" || depRange === "~") {
dependencies.push(depName);
continue;
}
} else if (opts?.bumpVersionsWithWorkspaceProtocolOnly === true) {
continue;
}
const range = getValidRange(depRange);
if ((range && !range.test(expected)) || isProtocolRange(depRange)) {
valid = false;
console.error(
`Package ${chalk.cyan(
`"${name}"`
)} must depend on the current version of ${chalk.cyan(
`"${depName}"`
)}: ${chalk.green(`"${expected}"`)} vs ${chalk.red(`"${depRange}"`)}`
);
continue;
}
// `depRange` could have been a tag and if a tag has been used there might have been a reason for that
// we should not count this as a local monorepro dependant
if (!range) {
continue;
}
dependencies.push(depName);
}
graph.set(name, { pkg, dependencies });
}
return { graph, valid };
}