workspace-tools
Version:
A collection of utilities that are useful in a git-controlled monorepo managed by one of these tools:
115 lines • 4.6 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPackageGraph = void 0;
const createDependencyMap_1 = require("./createDependencyMap");
const micromatch_1 = __importDefault(require("micromatch"));
function createPackageGraph(packages, filters) {
/** Set of packages being accumulated as the graph is filtered */
const packageSet = new Set();
/** Array of package names & its dependencies being accumulated as the graph is filtered */
const edges = [];
const edgeKeys = new Set();
const dependencyMapCache = new Map();
function visitorForFilter(filter, pkg, dependencies, dependents) {
packageSet.add(pkg);
if (!filter || (filter.includeDependencies && dependencies)) {
for (const dep of dependencies) {
const key = edgeKey(pkg, dep);
if (!edgeKeys.has(key)) {
edgeKeys.add(key);
edges.push({ name: pkg, dependency: dep });
}
packageSet.add(dep);
}
}
if (!filter || (filter.includeDependents && dependents)) {
for (const dep of dependents) {
const key = edgeKey(dep, pkg);
if (!edgeKeys.has(key)) {
edgeKeys.add(key);
edges.push({ name: dep, dependency: pkg });
}
packageSet.add(dep);
}
}
}
if (filters) {
filters = Array.isArray(filters) ? filters : [filters];
for (const filter of filters) {
const visitor = visitorForFilter.bind(undefined, filter);
const dependencyMap = getDependencyMapForFilter(packages, filter);
visitPackageGraph(packages, dependencyMap, visitor, filter);
}
}
else {
const visitor = visitorForFilter.bind(undefined, undefined);
const dependencyMap = getDependencyMapForFilter(packages);
visitPackageGraph(packages, dependencyMap, visitor);
}
return { packages: [...packageSet], dependencies: edges };
/** Calculates a key for checking if an edge is already added */
function edgeKey(name, dependency) {
return `${name}->${dependency}`;
}
/** Gets the dependencyMap for a filter, using a cache based on filter options */
function getDependencyMapForFilter(packages, filter) {
const cacheKey = getCacheKeyForFilter(filter);
if (!dependencyMapCache.has(cacheKey)) {
const dependencyMap = (0, createDependencyMap_1.createDependencyMap)(packages, filter);
dependencyMapCache.set(cacheKey, dependencyMap);
}
return dependencyMapCache.get(cacheKey);
}
/** Generates a cache key based on the filter options */
function getCacheKeyForFilter(filter) {
if (!filter) {
return "default";
}
const options = [
filter.withDevDependencies ? "dev" : "",
filter.withPeerDependencies ? "peer" : "",
filter.withOptionalDependencies ? "optional" : "",
]
.filter(Boolean)
.join("_");
return options || "prod";
}
}
exports.createPackageGraph = createPackageGraph;
function visitPackageGraph(packages, dependencyMap, visitor, filter) {
const visited = new Set();
const packageNames = Object.keys(packages);
const stack = filter ? (0, micromatch_1.default)(packageNames, filter.namePatterns) : packageNames;
while (stack.length > 0) {
const pkg = stack.pop();
if (visited.has(pkg)) {
continue;
}
const nextPkgs = new Set();
let dependencies = [];
let dependents = [];
if (!filter || filter.includeDependencies) {
dependencies = [...(dependencyMap.dependencies.get(pkg) ?? [])];
for (const dep of dependencies) {
nextPkgs.add(dep);
}
}
if (!filter || filter.includeDependents) {
dependents = [...(dependencyMap.dependents.get(pkg) ?? [])];
for (const dep of dependents) {
nextPkgs.add(dep);
}
}
visitor(pkg, dependencies, dependents);
visited.add(pkg);
if (nextPkgs.size > 0) {
for (const nextPkg of nextPkgs) {
stack.push(nextPkg);
}
}
}
}
//# sourceMappingURL=createPackageGraph.js.map