UNPKG

@lerna/publish

Version:

Publish packages in the current project

293 lines (292 loc) 11.6 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var package_graph_exports = {}; __export(package_graph_exports, { PackageGraph: () => PackageGraph }); module.exports = __toCommonJS(package_graph_exports); var import_npm_package_arg = __toESM(require("npm-package-arg")); var import_validation_error = require("../validation-error"); var import_cyclic_package_graph_node = require("./cyclic-package-graph-node"); var import_package_graph_node = require("./package-graph-node"); var import_report_cycles = require("./report-cycles"); class PackageGraph extends Map { /** * @param {import("@lerna/package").Package[]} packages An array of Packages to build the graph out of. * @param {'allDependencies'|'dependencies'} [graphType] * Pass "dependencies" to create a graph of only dependencies, * excluding the devDependencies that would normally be included. * @param {boolean} [forceLocal] Force all local dependencies to be linked. */ constructor(packages, graphType = "allDependencies", forceLocal) { super(packages.map((pkg) => [pkg.name, new import_package_graph_node.PackageGraphNode(pkg)])); if (packages.length !== this.size) { const seen = /* @__PURE__ */ new Map(); for (const { name, location } of packages) { if (seen.has(name)) { seen.get(name).push(location); } else { seen.set(name, [location]); } } for (const [name, locations] of seen) { if (locations.length > 1) { throw new import_validation_error.ValidationError( "ENAME", [`Package name "${name}" used in multiple packages:`, ...locations].join("\n ") ); } } } this.forEach((currentNode, currentName) => { const graphDependencies = graphType === "dependencies" ? Object.assign({}, currentNode.pkg.optionalDependencies, currentNode.pkg.dependencies) : Object.assign( {}, currentNode.pkg.devDependencies, currentNode.pkg.optionalDependencies, currentNode.pkg.dependencies ); Object.keys(graphDependencies).forEach((depName) => { const depNode = this.get(depName); let spec = graphDependencies[depName].replace(/^link:/, "file:"); const isWorkspaceSpec = /^workspace:/.test(spec); let fullWorkspaceSpec; let workspaceAlias; if (isWorkspaceSpec) { fullWorkspaceSpec = spec; spec = spec.replace(/^workspace:/, ""); if (spec === "*" || spec === "^" || spec === "~") { workspaceAlias = spec; if (depNode?.version) { const prefix = spec === "*" ? "" : spec; const version = depNode.version; spec = `${prefix}${version}`; } else { spec = "*"; } } } const resolved = import_npm_package_arg.default.resolve(depName, spec, currentNode.location); resolved.workspaceSpec = fullWorkspaceSpec; resolved.workspaceAlias = workspaceAlias; if (!depNode) { return currentNode.externalDependencies.set(depName, resolved); } if (forceLocal || resolved.fetchSpec === depNode.location || depNode.satisfies(resolved)) { currentNode.localDependencies.set(depName, resolved); depNode.localDependents.set(currentName, currentNode); } else { if (isWorkspaceSpec) { throw new import_validation_error.ValidationError( "EWORKSPACE", `Package specification "${depName}@${spec}" could not be resolved within the workspace. To reference a non-matching, remote version of a local dependency, remove the 'workspace:' prefix.` ); } currentNode.externalDependencies.set(depName, resolved); } }); }); } get rawPackageList() { return Array.from(this.values()).map((node) => node.pkg); } /** * Takes a list of Packages and returns a list of those same Packages with any Packages * they depend on. i.e if packageA depended on packageB `graph.addDependencies([packageA])` * would return [packageA, packageB]. * * @param filteredPackages The packages to include dependencies for. */ addDependencies(filteredPackages) { return this.extendList(filteredPackages, "localDependencies"); } /** * Takes a list of Packages and returns a list of those same Packages with any Packages * that depend on them. i.e if packageC depended on packageD `graph.addDependents([packageD])` * would return [packageD, packageC]. * * @param filteredPackages The packages to include dependents for. */ addDependents(filteredPackages) { return this.extendList(filteredPackages, "localDependents"); } /** * Extends a list of packages by traversing on a given property, which must refer to a * `PackageGraphNode` property that is a collection of `PackageGraphNode`s. * Returns input packages with any additional packages found by traversing `nodeProp`. * * @param packageList The list of packages to extend * @param nodeProp The property on `PackageGraphNode` used to traverse */ extendList(packageList, nodeProp) { const search = new Set(packageList.map(({ name }) => this.get(name))); const result = []; search.forEach((currentNode) => { result.push(currentNode); currentNode[nodeProp].forEach((meta, depName) => { const depNode = this.get(depName); if (depNode !== currentNode && !search.has(depNode)) { search.add(depNode); } }); }); return result.map((node) => node.pkg); } /** * Return a tuple of cycle paths and nodes. * * @deprecated Use collapseCycles instead. * * @param rejectCycles Whether or not to reject cycles */ partitionCycles(rejectCycles) { const cyclePaths = /* @__PURE__ */ new Set(); const cycleNodes = /* @__PURE__ */ new Set(); this.forEach((currentNode, currentName) => { const seen = /* @__PURE__ */ new Set(); const visits = (walk) => (dependentNode, dependentName, siblingDependents) => { const step = walk.concat(dependentName); if (seen.has(dependentNode)) { return; } seen.add(dependentNode); if (dependentNode === currentNode) { cycleNodes.add(currentNode); cyclePaths.add(step); return; } if (siblingDependents.has(currentName)) { const cycleDependentName = Array.from(dependentNode.localDependencies.keys()).find( (key) => ( // TODO: refactor to address type issues // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore currentNode.localDependents.has(key) ) ); const pathToCycle = step.slice().reverse().concat(cycleDependentName); cycleNodes.add(dependentNode); cyclePaths.add(pathToCycle); } dependentNode.localDependents.forEach(visits(step)); }; currentNode.localDependents.forEach(visits([currentName])); }); (0, import_report_cycles.reportCycles)( // TODO: refactor to address type issues // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Array.from(cyclePaths, (cycle) => cycle.join(" -> ")), rejectCycles ); return [cyclePaths, cycleNodes]; } /** * Returns the cycles of this graph. If two cycles share some elements, they will * be returned as a single cycle. * * @param {boolean} rejectCycles Whether or not to reject cycles * @returns {Set<CyclicPackageGraphNode>} */ collapseCycles(rejectCycles) { const cyclePaths = []; const nodeToCycle = /* @__PURE__ */ new Map(); const cycles = /* @__PURE__ */ new Set(); const walkStack = []; const alreadyVisited = /* @__PURE__ */ new Set(); function visits(baseNode, dependentNode) { if (nodeToCycle.has(baseNode)) { return; } let topLevelDependent = dependentNode; while (nodeToCycle.has(topLevelDependent)) { topLevelDependent = nodeToCycle.get(topLevelDependent); } const identifier = `${baseNode.name}:${topLevelDependent.name}`; if (alreadyVisited.has(identifier)) { return; } alreadyVisited.add(identifier); if (topLevelDependent === baseNode || topLevelDependent.isCycle && topLevelDependent.has(baseNode.name)) { const cycle = new import_cyclic_package_graph_node.CyclicPackageGraphNode(); walkStack.forEach((nodeInCycle) => { nodeToCycle.set(nodeInCycle, cycle); cycle.insert(nodeInCycle); cycles.delete(nodeInCycle); }); cycles.add(cycle); cyclePaths.push(cycle.toString()); return; } if (walkStack.indexOf(topLevelDependent) === -1) { visitWithStack(baseNode, topLevelDependent); } } function visitWithStack(baseNode, currentNode = baseNode) { walkStack.push(currentNode); currentNode.localDependents.forEach(visits.bind(null, baseNode)); walkStack.pop(); } this.forEach((currentNode) => visitWithStack(currentNode)); cycles.forEach((collapsedNode) => visitWithStack(collapsedNode)); (0, import_report_cycles.reportCycles)(cyclePaths, rejectCycles); return cycles; } /** * Remove cycle nodes. * * @deprecated Spread set into prune() instead. */ pruneCycleNodes(cycleNodes) { return this.prune(...cycleNodes); } /** * Remove all candidate nodes. */ prune(...candidates) { if (candidates.length === this.size) { return this.clear(); } candidates.forEach((node) => this.remove(node)); } /** * Delete by value (instead of key), as well as removing pointers * to itself in the other node's internal collections. * @param candidateNode instance to remove */ remove(candidateNode) { this.delete(candidateNode.name); this.forEach((node) => { node.localDependencies.delete(candidateNode.name); node.localDependents.delete(candidateNode.name); }); } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { PackageGraph });