@lerna-lite/core 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -12
- package/dist/child-process.d.ts +62 -62
- package/dist/child-process.js +165 -165
- package/dist/command.d.ts +37 -35
- package/dist/command.js +266 -266
- package/dist/command.js.map +1 -1
- package/dist/conventional-commits/constants.d.ts +4 -4
- package/dist/conventional-commits/constants.js +12 -12
- package/dist/conventional-commits/get-changelog-config.d.ts +12 -12
- package/dist/conventional-commits/get-changelog-config.js +98 -98
- package/dist/conventional-commits/index.d.ts +6 -6
- package/dist/conventional-commits/index.js +22 -22
- package/dist/conventional-commits/make-bump-only-filter.d.ts +6 -6
- package/dist/conventional-commits/make-bump-only-filter.js +22 -22
- package/dist/conventional-commits/read-existing-changelog.d.ts +7 -7
- package/dist/conventional-commits/read-existing-changelog.js +32 -32
- package/dist/conventional-commits/recommend-version.d.ts +11 -11
- package/dist/conventional-commits/recommend-version.js +86 -86
- package/dist/conventional-commits/update-changelog.d.ts +11 -11
- package/dist/conventional-commits/update-changelog.js +83 -83
- package/dist/git-clients/GitLabClient.d.ts +8 -8
- package/dist/git-clients/GitLabClient.js +39 -39
- package/dist/git-clients/github-client.d.ts +6 -6
- package/dist/git-clients/github-client.js +40 -40
- package/dist/git-clients/gitlab-client.d.ts +6 -6
- package/dist/git-clients/gitlab-client.js +21 -21
- package/dist/git-clients/index.d.ts +2 -2
- package/dist/git-clients/index.js +18 -18
- package/dist/index.d.ts +12 -12
- package/dist/index.js +30 -30
- package/dist/models/command-options.d.ts +206 -0
- package/dist/models/command-options.js +3 -0
- package/dist/models/command-options.js.map +1 -0
- package/dist/models/index.d.ts +2 -186
- package/dist/models/index.js +18 -2
- package/dist/models/index.js.map +1 -1
- package/dist/models/interfaces.d.ts +201 -0
- package/dist/models/interfaces.js +3 -0
- package/dist/models/interfaces.js.map +1 -0
- package/dist/otplease.d.ts +14 -14
- package/dist/otplease.js +108 -108
- package/dist/package-graph/index.d.ts +2 -2
- package/dist/package-graph/index.js +18 -18
- package/dist/package-graph/lib/cyclic-package-graph-node.d.ts +42 -42
- package/dist/package-graph/lib/cyclic-package-graph-node.js +97 -97
- package/dist/package-graph/lib/index.d.ts +3 -3
- package/dist/package-graph/lib/index.js +19 -19
- package/dist/package-graph/lib/package-graph-node.d.ts +33 -33
- package/dist/package-graph/lib/package-graph-node.js +58 -58
- package/dist/package-graph/lib/report-cycles.d.ts +1 -1
- package/dist/package-graph/lib/report-cycles.js +19 -19
- package/dist/package-graph/package-graph.d.ts +79 -79
- package/dist/package-graph/package-graph.js +276 -276
- package/dist/package.d.ts +91 -85
- package/dist/package.js +282 -276
- package/dist/package.js.map +1 -1
- package/dist/project/index.d.ts +2 -2
- package/dist/project/index.js +18 -18
- package/dist/project/lib/apply-extends.d.ts +10 -10
- package/dist/project/lib/apply-extends.js +37 -37
- package/dist/project/lib/index.d.ts +3 -3
- package/dist/project/lib/index.js +19 -19
- package/dist/project/lib/make-file-finder.d.ts +3 -3
- package/dist/project/lib/make-file-finder.js +71 -71
- package/dist/project/lib/shallow-extend.d.ts +11 -11
- package/dist/project/lib/shallow-extend.js +24 -24
- package/dist/project/project.d.ts +45 -45
- package/dist/project/project.js +195 -195
- package/dist/prompt.d.ts +23 -23
- package/dist/prompt.js +75 -75
- package/dist/utils/check-working-tree.d.ts +8 -8
- package/dist/utils/check-working-tree.js +41 -41
- package/dist/utils/clean-stack.d.ts +5 -5
- package/dist/utils/clean-stack.js +18 -18
- package/dist/utils/collect-uncommitted.d.ts +18 -18
- package/dist/utils/collect-uncommitted.js +40 -40
- package/dist/utils/collect-updates/collect-updates.d.ts +11 -11
- package/dist/utils/collect-updates/collect-updates.js +82 -82
- package/dist/utils/collect-updates/index.d.ts +2 -2
- package/dist/utils/collect-updates/index.js +18 -18
- package/dist/utils/collect-updates/lib/collect-dependents.d.ts +11 -11
- package/dist/utils/collect-updates/lib/collect-dependents.js +45 -45
- package/dist/utils/collect-updates/lib/collect-packages.d.ts +13 -13
- package/dist/utils/collect-updates/lib/collect-packages.js +33 -33
- package/dist/utils/collect-updates/lib/get-packages-for-option.d.ts +5 -5
- package/dist/utils/collect-updates/lib/get-packages-for-option.js +30 -30
- package/dist/utils/collect-updates/lib/has-tags.d.ts +5 -5
- package/dist/utils/collect-updates/lib/has-tags.js +26 -26
- package/dist/utils/collect-updates/lib/index.d.ts +5 -5
- package/dist/utils/collect-updates/lib/index.js +21 -21
- package/dist/utils/collect-updates/lib/make-diff-predicate.d.ts +7 -7
- package/dist/utils/collect-updates/lib/make-diff-predicate.js +64 -64
- package/dist/utils/conf.d.ts +25 -25
- package/dist/utils/conf.js +255 -255
- package/dist/utils/defaults.d.ts +1 -1
- package/dist/utils/defaults.js +182 -182
- package/dist/utils/defaults.js.map +1 -1
- package/dist/utils/describe-ref.d.ts +37 -37
- package/dist/utils/describe-ref.js +80 -80
- package/dist/utils/env-replace.d.ts +1 -1
- package/dist/utils/env-replace.js +22 -22
- package/dist/utils/find-prefix.d.ts +2 -2
- package/dist/utils/find-prefix.js +48 -48
- package/dist/utils/index.d.ts +23 -22
- package/dist/utils/index.js +39 -38
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/log-package-error.d.ts +5 -5
- package/dist/utils/log-package-error.js +35 -35
- package/dist/utils/nerf-dart.d.ts +1 -1
- package/dist/utils/nerf-dart.js +18 -18
- package/dist/utils/npm-conf.d.ts +4 -4
- package/dist/utils/npm-conf.js +55 -55
- package/dist/utils/output.d.ts +1 -1
- package/dist/utils/output.js +13 -13
- package/dist/utils/parse-field.d.ts +1 -1
- package/dist/utils/parse-field.js +65 -65
- package/dist/utils/prerelease-id-from-version.d.ts +5 -5
- package/dist/utils/prerelease-id-from-version.js +15 -15
- package/dist/utils/pulse-till-done.d.ts +1 -1
- package/dist/utils/pulse-till-done.js +40 -40
- package/dist/utils/query-graph.d.ts +36 -36
- package/dist/utils/query-graph.js +77 -77
- package/dist/utils/query-graph.js.map +1 -1
- package/dist/utils/run-lifecycle.d.ts +10 -10
- package/dist/utils/run-lifecycle.js +131 -107
- package/dist/utils/run-lifecycle.js.map +1 -1
- package/dist/utils/run-topologically.d.ts +12 -12
- package/dist/utils/run-topologically.js +36 -36
- package/dist/utils/temp-write.d.ts +13 -0
- package/dist/utils/temp-write.js +50 -0
- package/dist/utils/temp-write.js.map +1 -0
- package/dist/utils/types.d.ts +131 -129
- package/dist/utils/types.js +138 -138
- package/dist/utils/warn-if-hanging.d.ts +1 -1
- package/dist/utils/warn-if-hanging.js +17 -17
- package/dist/utils/write-log-file.d.ts +1 -1
- package/dist/utils/write-log-file.js +32 -32
- package/dist/validation-error.d.ts +4 -4
- package/dist/validation-error.js +18 -18
- package/package.json +14 -10
|
@@ -1,277 +1,277 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.PackageGraph = void 0;
|
|
7
|
-
const npm_package_arg_1 = __importDefault(require("npm-package-arg"));
|
|
8
|
-
const lib_1 = require("./lib");
|
|
9
|
-
const validation_error_1 = require("../validation-error");
|
|
10
|
-
/**
|
|
11
|
-
* A graph of packages in the current project.
|
|
12
|
-
*
|
|
13
|
-
* @extends {Map<string, PackageGraphNode>}
|
|
14
|
-
*/
|
|
15
|
-
class PackageGraph extends Map {
|
|
16
|
-
/**
|
|
17
|
-
* @param {import("@lerna/package").Package[]} packages An array of Packages to build the graph out of.
|
|
18
|
-
* @param {'allDependencies'|'dependencies'} [graphType]
|
|
19
|
-
* Pass "dependencies" to create a graph of only dependencies,
|
|
20
|
-
* excluding the devDependencies that would normally be included.
|
|
21
|
-
* @param {boolean|'auto'|'force'|'explicit'} [localDependencies] Treatment of local sibling dependencies, default "auto"
|
|
22
|
-
*/
|
|
23
|
-
constructor(packages, graphType = 'allDependencies', localDependencies = 'auto') {
|
|
24
|
-
// For backward compatibility
|
|
25
|
-
if (localDependencies === true || localDependencies === 'forceLocal') {
|
|
26
|
-
localDependencies = 'force'; // eslint-disable-line
|
|
27
|
-
}
|
|
28
|
-
// @ts-ignore
|
|
29
|
-
super(packages.map((pkg) => { var _a; return [(_a = pkg === null || pkg === void 0 ? void 0 : pkg.name) !== null && _a !== void 0 ? _a : '', new lib_1.PackageGraphNode(pkg)]; }));
|
|
30
|
-
if (packages.length !== this.size) {
|
|
31
|
-
// weed out the duplicates
|
|
32
|
-
const seen = new Map();
|
|
33
|
-
for (const { name, location } of packages) {
|
|
34
|
-
if (seen.has(name)) {
|
|
35
|
-
seen.get(name).push(location);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
seen.set(name, [location]);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
for (const [name, locations] of seen) {
|
|
42
|
-
if (locations.length > 1) {
|
|
43
|
-
throw new validation_error_1.ValidationError('ENAME', [`Package name "${name}" used in multiple packages:`, ...locations].join('\n\t'));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
this.forEach((currentNode, currentName) => {
|
|
48
|
-
const graphDependencies = graphType === 'dependencies'
|
|
49
|
-
? Object.assign({}, currentNode.pkg.optionalDependencies, currentNode.pkg.dependencies)
|
|
50
|
-
: Object.assign({}, currentNode.pkg.devDependencies, currentNode.pkg.optionalDependencies, currentNode.pkg.dependencies);
|
|
51
|
-
Object.keys(graphDependencies).forEach((depName) => {
|
|
52
|
-
const depNode = this.get(depName);
|
|
53
|
-
// Yarn decided to ignore https://github.com/npm/npm/pull/15900 and implemented "link:"
|
|
54
|
-
// As they apparently have no intention of being compatible, we have to do it for them.
|
|
55
|
-
// @see https://github.com/yarnpkg/yarn/issues/4212
|
|
56
|
-
let spec = graphDependencies[depName].replace(/^link:/, 'file:');
|
|
57
|
-
// npa doesn't support the explicit workspace: protocol, supported by
|
|
58
|
-
// pnpm and Yarn.
|
|
59
|
-
const explicitWorkspace = /^workspace:/.test(spec);
|
|
60
|
-
let workspaceTarget;
|
|
61
|
-
if (explicitWorkspace) {
|
|
62
|
-
workspaceTarget = spec;
|
|
63
|
-
spec = spec.replace(/^workspace:/, '');
|
|
64
|
-
// when dependency is defined as target workspace, like `workspace:*`,
|
|
65
|
-
// we'll have to pull the version from its parent package version property
|
|
66
|
-
// example with `1.5.0`, ws:* => "1.5.0", ws:^ => "^1.5.0", ws:~ => "~1.5.0", ws:^1.5.0 => "^1.5.0"
|
|
67
|
-
if (spec === '*' || spec === '^' || spec === '~') {
|
|
68
|
-
const depPkg = packages.find(pkg => pkg.name === depName);
|
|
69
|
-
const version = depPkg === null || depPkg === void 0 ? void 0 : depPkg.version;
|
|
70
|
-
const specTarget = spec === '*' ? '' : spec;
|
|
71
|
-
spec = depPkg ? `${specTarget}${version}` : '';
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const resolved = npm_package_arg_1.default.resolve(depName, spec, currentNode.location);
|
|
75
|
-
resolved.explicitWorkspace = explicitWorkspace;
|
|
76
|
-
if (resolved.explicitWorkspace) {
|
|
77
|
-
resolved.workspaceTarget = workspaceTarget;
|
|
78
|
-
}
|
|
79
|
-
if (!depNode) {
|
|
80
|
-
// it's an external dependency, store the resolution and bail
|
|
81
|
-
return currentNode.externalDependencies.set(depName, resolved);
|
|
82
|
-
}
|
|
83
|
-
if (explicitWorkspace ||
|
|
84
|
-
localDependencies === 'force' ||
|
|
85
|
-
resolved.fetchSpec === depNode.location ||
|
|
86
|
-
(localDependencies !== 'explicit' && depNode.satisfies(resolved))) {
|
|
87
|
-
// a local file: specifier, a matching semver or a workspace: version
|
|
88
|
-
currentNode.localDependencies.set(depName, resolved);
|
|
89
|
-
depNode.localDependents.set(currentName, currentNode);
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
// non-matching semver of a local dependency
|
|
93
|
-
currentNode.externalDependencies.set(depName, resolved);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
get rawPackageList() {
|
|
99
|
-
return Array.from(this.values()).map((node) => node.pkg);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Takes a list of Packages and returns a list of those same Packages with any Packages
|
|
103
|
-
* they depend on. i.e if packageA depended on packageB `graph.addDependencies([packageA])`
|
|
104
|
-
* would return [packageA, packageB].
|
|
105
|
-
*
|
|
106
|
-
* @param {import("@lerna/package").Package[]} filteredPackages The packages to include dependencies for.
|
|
107
|
-
*/
|
|
108
|
-
addDependencies(filteredPackages) {
|
|
109
|
-
return this.extendList(filteredPackages, 'localDependencies');
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Takes a list of Packages and returns a list of those same Packages with any Packages
|
|
113
|
-
* that depend on them. i.e if packageC depended on packageD `graph.addDependents([packageD])`
|
|
114
|
-
* would return [packageD, packageC].
|
|
115
|
-
*
|
|
116
|
-
* @param {import("@lerna/package").Package[]} filteredPackages The packages to include dependents for.
|
|
117
|
-
*/
|
|
118
|
-
addDependents(filteredPackages) {
|
|
119
|
-
return this.extendList(filteredPackages, 'localDependents');
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Extends a list of packages by traversing on a given property, which must refer to a
|
|
123
|
-
* `PackageGraphNode` property that is a collection of `PackageGraphNode`s.
|
|
124
|
-
* Returns input packages with any additional packages found by traversing `nodeProp`.
|
|
125
|
-
*
|
|
126
|
-
* @param {import("@lerna/package").Package[]} packageList The list of packages to extend
|
|
127
|
-
* @param {'localDependencies'|'localDependents'} nodeProp The property on `PackageGraphNode` used to traverse
|
|
128
|
-
*/
|
|
129
|
-
extendList(packageList, nodeProp) {
|
|
130
|
-
// the current list of packages we are expanding using breadth-first-search
|
|
131
|
-
const search = new Set(packageList.map(({ name }) => this.get(name)));
|
|
132
|
-
// an intermediate list of matched PackageGraphNodes
|
|
133
|
-
/** @type {PackageGraphNode[]} */
|
|
134
|
-
const result = [];
|
|
135
|
-
search.forEach((currentNode) => {
|
|
136
|
-
// anything searched for is always a result
|
|
137
|
-
result.push(currentNode);
|
|
138
|
-
currentNode[nodeProp].forEach((meta, depName) => {
|
|
139
|
-
const depNode = this.get(depName);
|
|
140
|
-
if (depNode !== currentNode && !search.has(depNode)) {
|
|
141
|
-
search.add(depNode);
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
// actual Package instances, not PackageGraphNodes
|
|
146
|
-
return result.map((node) => node.pkg);
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Return a tuple of cycle paths and nodes.
|
|
150
|
-
*
|
|
151
|
-
* @deprecated Use collapseCycles instead.
|
|
152
|
-
*
|
|
153
|
-
* @param {boolean} rejectCycles Whether or not to reject cycles
|
|
154
|
-
* @returns {[Set<string[]>, Set<PackageGraphNode>]}
|
|
155
|
-
*/
|
|
156
|
-
partitionCycles(rejectCycles) {
|
|
157
|
-
const cyclePaths = new Set();
|
|
158
|
-
const cycleNodes = new Set();
|
|
159
|
-
this.forEach((currentNode, currentName) => {
|
|
160
|
-
const seen = new Set();
|
|
161
|
-
const visits = (walk) => (dependentNode, dependentName, siblingDependents) => {
|
|
162
|
-
const step = walk.concat(dependentName);
|
|
163
|
-
if (seen.has(dependentNode)) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
seen.add(dependentNode);
|
|
167
|
-
if (dependentNode === currentNode) {
|
|
168
|
-
// a direct cycle
|
|
169
|
-
cycleNodes.add(currentNode);
|
|
170
|
-
cyclePaths.add(step);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
if (siblingDependents.has(currentName)) {
|
|
174
|
-
// a transitive cycle
|
|
175
|
-
const cycleDependentName = Array.from(dependentNode.localDependencies.keys()).find((key) => currentNode.localDependents.has(key));
|
|
176
|
-
const pathToCycle = step.slice().reverse().concat(cycleDependentName);
|
|
177
|
-
cycleNodes.add(dependentNode);
|
|
178
|
-
cyclePaths.add(pathToCycle);
|
|
179
|
-
}
|
|
180
|
-
dependentNode.localDependents.forEach(visits(step));
|
|
181
|
-
};
|
|
182
|
-
currentNode.localDependents.forEach(visits([currentName]));
|
|
183
|
-
});
|
|
184
|
-
(0, lib_1.reportCycles)(Array.from(cyclePaths, (cycle) => cycle.join(' -> ')), rejectCycles);
|
|
185
|
-
return [cyclePaths, cycleNodes];
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Returns the cycles of this graph. If two cycles share some elements, they will
|
|
189
|
-
* be returned as a single cycle.
|
|
190
|
-
*
|
|
191
|
-
* @param {boolean} rejectCycles Whether or not to reject cycles
|
|
192
|
-
* @returns {Set<CyclicPackageGraphNode>}
|
|
193
|
-
*/
|
|
194
|
-
collapseCycles(rejectCycles) {
|
|
195
|
-
const cyclePaths = [];
|
|
196
|
-
const nodeToCycle = new Map();
|
|
197
|
-
const cycles = new Set();
|
|
198
|
-
const alreadyVisited = new Set();
|
|
199
|
-
const walkStack = [];
|
|
200
|
-
function visits(baseNode, dependentNode) {
|
|
201
|
-
if (nodeToCycle.has(baseNode)) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
let topLevelDependent = dependentNode;
|
|
205
|
-
while (nodeToCycle.has(topLevelDependent)) {
|
|
206
|
-
topLevelDependent = nodeToCycle.get(topLevelDependent);
|
|
207
|
-
}
|
|
208
|
-
// Otherwise the same node is checked multiple times which is very wasteful in a large repository
|
|
209
|
-
if (alreadyVisited.has(topLevelDependent)) {
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
alreadyVisited.add(topLevelDependent);
|
|
213
|
-
if (topLevelDependent === baseNode ||
|
|
214
|
-
(topLevelDependent.isCycle && topLevelDependent.has(baseNode.name))) {
|
|
215
|
-
const cycle = new lib_1.CyclicPackageGraphNode();
|
|
216
|
-
walkStack.forEach((nodeInCycle) => {
|
|
217
|
-
nodeToCycle.set(nodeInCycle, cycle);
|
|
218
|
-
cycle.insert(nodeInCycle);
|
|
219
|
-
cycles.delete(nodeInCycle);
|
|
220
|
-
});
|
|
221
|
-
cycles.add(cycle);
|
|
222
|
-
// @ts-ignore
|
|
223
|
-
cyclePaths.push(cycle.toString());
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
if (walkStack.indexOf(topLevelDependent) === -1) {
|
|
227
|
-
// eslint-disable-next-line no-use-before-define
|
|
228
|
-
visitWithStack(baseNode, topLevelDependent);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
function visitWithStack(baseNode, currentNode = baseNode) {
|
|
232
|
-
walkStack.push(currentNode);
|
|
233
|
-
currentNode.localDependents.forEach(visits.bind(null, baseNode));
|
|
234
|
-
walkStack.pop();
|
|
235
|
-
}
|
|
236
|
-
this.forEach((currentNode) => visitWithStack(currentNode));
|
|
237
|
-
cycles.forEach((collapsedNode) => visitWithStack(collapsedNode));
|
|
238
|
-
(0, lib_1.reportCycles)(cyclePaths, rejectCycles);
|
|
239
|
-
return cycles;
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Remove cycle nodes.
|
|
243
|
-
*
|
|
244
|
-
* @deprecated Spread set into prune() instead.
|
|
245
|
-
*
|
|
246
|
-
* @param {Set<PackageGraphNode>} cycleNodes
|
|
247
|
-
*/
|
|
248
|
-
pruneCycleNodes(cycleNodes) {
|
|
249
|
-
return this.prune(...cycleNodes);
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Remove all candidate nodes.
|
|
253
|
-
* @param {PackageGraphNode[]} candidates
|
|
254
|
-
*/
|
|
255
|
-
prune(...candidates) {
|
|
256
|
-
if (candidates.length === this.size) {
|
|
257
|
-
return this.clear();
|
|
258
|
-
}
|
|
259
|
-
candidates.forEach((node) => this.remove(node));
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Delete by value (instead of key), as well as removing pointers
|
|
263
|
-
* to itself in the other node's internal collections.
|
|
264
|
-
* @param {PackageGraphNode} candidateNode instance to remove
|
|
265
|
-
*/
|
|
266
|
-
remove(candidateNode) {
|
|
267
|
-
this.delete(candidateNode.name);
|
|
268
|
-
this.forEach((node) => {
|
|
269
|
-
// remove incoming edges ("indegree")
|
|
270
|
-
node.localDependencies.delete(candidateNode.name);
|
|
271
|
-
// remove outgoing edges ("outdegree")
|
|
272
|
-
node.localDependents.delete(candidateNode.name);
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
exports.PackageGraph = PackageGraph;
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PackageGraph = void 0;
|
|
7
|
+
const npm_package_arg_1 = __importDefault(require("npm-package-arg"));
|
|
8
|
+
const lib_1 = require("./lib");
|
|
9
|
+
const validation_error_1 = require("../validation-error");
|
|
10
|
+
/**
|
|
11
|
+
* A graph of packages in the current project.
|
|
12
|
+
*
|
|
13
|
+
* @extends {Map<string, PackageGraphNode>}
|
|
14
|
+
*/
|
|
15
|
+
class PackageGraph extends Map {
|
|
16
|
+
/**
|
|
17
|
+
* @param {import("@lerna/package").Package[]} packages An array of Packages to build the graph out of.
|
|
18
|
+
* @param {'allDependencies'|'dependencies'} [graphType]
|
|
19
|
+
* Pass "dependencies" to create a graph of only dependencies,
|
|
20
|
+
* excluding the devDependencies that would normally be included.
|
|
21
|
+
* @param {boolean|'auto'|'force'|'explicit'} [localDependencies] Treatment of local sibling dependencies, default "auto"
|
|
22
|
+
*/
|
|
23
|
+
constructor(packages, graphType = 'allDependencies', localDependencies = 'auto') {
|
|
24
|
+
// For backward compatibility
|
|
25
|
+
if (localDependencies === true || localDependencies === 'forceLocal') {
|
|
26
|
+
localDependencies = 'force'; // eslint-disable-line
|
|
27
|
+
}
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
super(packages.map((pkg) => { var _a; return [(_a = pkg === null || pkg === void 0 ? void 0 : pkg.name) !== null && _a !== void 0 ? _a : '', new lib_1.PackageGraphNode(pkg)]; }));
|
|
30
|
+
if (packages.length !== this.size) {
|
|
31
|
+
// weed out the duplicates
|
|
32
|
+
const seen = new Map();
|
|
33
|
+
for (const { name, location } of packages) {
|
|
34
|
+
if (seen.has(name)) {
|
|
35
|
+
seen.get(name).push(location);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
seen.set(name, [location]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const [name, locations] of seen) {
|
|
42
|
+
if (locations.length > 1) {
|
|
43
|
+
throw new validation_error_1.ValidationError('ENAME', [`Package name "${name}" used in multiple packages:`, ...locations].join('\n\t'));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
this.forEach((currentNode, currentName) => {
|
|
48
|
+
const graphDependencies = graphType === 'dependencies'
|
|
49
|
+
? Object.assign({}, currentNode.pkg.optionalDependencies, currentNode.pkg.dependencies)
|
|
50
|
+
: Object.assign({}, currentNode.pkg.devDependencies, currentNode.pkg.optionalDependencies, currentNode.pkg.dependencies);
|
|
51
|
+
Object.keys(graphDependencies).forEach((depName) => {
|
|
52
|
+
const depNode = this.get(depName);
|
|
53
|
+
// Yarn decided to ignore https://github.com/npm/npm/pull/15900 and implemented "link:"
|
|
54
|
+
// As they apparently have no intention of being compatible, we have to do it for them.
|
|
55
|
+
// @see https://github.com/yarnpkg/yarn/issues/4212
|
|
56
|
+
let spec = graphDependencies[depName].replace(/^link:/, 'file:');
|
|
57
|
+
// npa doesn't support the explicit workspace: protocol, supported by
|
|
58
|
+
// pnpm and Yarn.
|
|
59
|
+
const explicitWorkspace = /^workspace:/.test(spec);
|
|
60
|
+
let workspaceTarget;
|
|
61
|
+
if (explicitWorkspace) {
|
|
62
|
+
workspaceTarget = spec;
|
|
63
|
+
spec = spec.replace(/^workspace:/, '');
|
|
64
|
+
// when dependency is defined as target workspace, like `workspace:*`,
|
|
65
|
+
// we'll have to pull the version from its parent package version property
|
|
66
|
+
// example with `1.5.0`, ws:* => "1.5.0", ws:^ => "^1.5.0", ws:~ => "~1.5.0", ws:^1.5.0 => "^1.5.0"
|
|
67
|
+
if (spec === '*' || spec === '^' || spec === '~') {
|
|
68
|
+
const depPkg = packages.find(pkg => pkg.name === depName);
|
|
69
|
+
const version = depPkg === null || depPkg === void 0 ? void 0 : depPkg.version;
|
|
70
|
+
const specTarget = spec === '*' ? '' : spec;
|
|
71
|
+
spec = depPkg ? `${specTarget}${version}` : '';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const resolved = npm_package_arg_1.default.resolve(depName, spec, currentNode.location);
|
|
75
|
+
resolved.explicitWorkspace = explicitWorkspace;
|
|
76
|
+
if (resolved.explicitWorkspace) {
|
|
77
|
+
resolved.workspaceTarget = workspaceTarget;
|
|
78
|
+
}
|
|
79
|
+
if (!depNode) {
|
|
80
|
+
// it's an external dependency, store the resolution and bail
|
|
81
|
+
return currentNode.externalDependencies.set(depName, resolved);
|
|
82
|
+
}
|
|
83
|
+
if (explicitWorkspace ||
|
|
84
|
+
localDependencies === 'force' ||
|
|
85
|
+
resolved.fetchSpec === depNode.location ||
|
|
86
|
+
(localDependencies !== 'explicit' && depNode.satisfies(resolved))) {
|
|
87
|
+
// a local file: specifier, a matching semver or a workspace: version
|
|
88
|
+
currentNode.localDependencies.set(depName, resolved);
|
|
89
|
+
depNode.localDependents.set(currentName, currentNode);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// non-matching semver of a local dependency
|
|
93
|
+
currentNode.externalDependencies.set(depName, resolved);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
get rawPackageList() {
|
|
99
|
+
return Array.from(this.values()).map((node) => node.pkg);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Takes a list of Packages and returns a list of those same Packages with any Packages
|
|
103
|
+
* they depend on. i.e if packageA depended on packageB `graph.addDependencies([packageA])`
|
|
104
|
+
* would return [packageA, packageB].
|
|
105
|
+
*
|
|
106
|
+
* @param {import("@lerna/package").Package[]} filteredPackages The packages to include dependencies for.
|
|
107
|
+
*/
|
|
108
|
+
addDependencies(filteredPackages) {
|
|
109
|
+
return this.extendList(filteredPackages, 'localDependencies');
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Takes a list of Packages and returns a list of those same Packages with any Packages
|
|
113
|
+
* that depend on them. i.e if packageC depended on packageD `graph.addDependents([packageD])`
|
|
114
|
+
* would return [packageD, packageC].
|
|
115
|
+
*
|
|
116
|
+
* @param {import("@lerna/package").Package[]} filteredPackages The packages to include dependents for.
|
|
117
|
+
*/
|
|
118
|
+
addDependents(filteredPackages) {
|
|
119
|
+
return this.extendList(filteredPackages, 'localDependents');
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Extends a list of packages by traversing on a given property, which must refer to a
|
|
123
|
+
* `PackageGraphNode` property that is a collection of `PackageGraphNode`s.
|
|
124
|
+
* Returns input packages with any additional packages found by traversing `nodeProp`.
|
|
125
|
+
*
|
|
126
|
+
* @param {import("@lerna/package").Package[]} packageList The list of packages to extend
|
|
127
|
+
* @param {'localDependencies'|'localDependents'} nodeProp The property on `PackageGraphNode` used to traverse
|
|
128
|
+
*/
|
|
129
|
+
extendList(packageList, nodeProp) {
|
|
130
|
+
// the current list of packages we are expanding using breadth-first-search
|
|
131
|
+
const search = new Set(packageList.map(({ name }) => this.get(name)));
|
|
132
|
+
// an intermediate list of matched PackageGraphNodes
|
|
133
|
+
/** @type {PackageGraphNode[]} */
|
|
134
|
+
const result = [];
|
|
135
|
+
search.forEach((currentNode) => {
|
|
136
|
+
// anything searched for is always a result
|
|
137
|
+
result.push(currentNode);
|
|
138
|
+
currentNode[nodeProp].forEach((meta, depName) => {
|
|
139
|
+
const depNode = this.get(depName);
|
|
140
|
+
if (depNode !== currentNode && !search.has(depNode)) {
|
|
141
|
+
search.add(depNode);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
// actual Package instances, not PackageGraphNodes
|
|
146
|
+
return result.map((node) => node.pkg);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Return a tuple of cycle paths and nodes.
|
|
150
|
+
*
|
|
151
|
+
* @deprecated Use collapseCycles instead.
|
|
152
|
+
*
|
|
153
|
+
* @param {boolean} rejectCycles Whether or not to reject cycles
|
|
154
|
+
* @returns {[Set<string[]>, Set<PackageGraphNode>]}
|
|
155
|
+
*/
|
|
156
|
+
partitionCycles(rejectCycles) {
|
|
157
|
+
const cyclePaths = new Set();
|
|
158
|
+
const cycleNodes = new Set();
|
|
159
|
+
this.forEach((currentNode, currentName) => {
|
|
160
|
+
const seen = new Set();
|
|
161
|
+
const visits = (walk) => (dependentNode, dependentName, siblingDependents) => {
|
|
162
|
+
const step = walk.concat(dependentName);
|
|
163
|
+
if (seen.has(dependentNode)) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
seen.add(dependentNode);
|
|
167
|
+
if (dependentNode === currentNode) {
|
|
168
|
+
// a direct cycle
|
|
169
|
+
cycleNodes.add(currentNode);
|
|
170
|
+
cyclePaths.add(step);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (siblingDependents.has(currentName)) {
|
|
174
|
+
// a transitive cycle
|
|
175
|
+
const cycleDependentName = Array.from(dependentNode.localDependencies.keys()).find((key) => currentNode.localDependents.has(key));
|
|
176
|
+
const pathToCycle = step.slice().reverse().concat(cycleDependentName);
|
|
177
|
+
cycleNodes.add(dependentNode);
|
|
178
|
+
cyclePaths.add(pathToCycle);
|
|
179
|
+
}
|
|
180
|
+
dependentNode.localDependents.forEach(visits(step));
|
|
181
|
+
};
|
|
182
|
+
currentNode.localDependents.forEach(visits([currentName]));
|
|
183
|
+
});
|
|
184
|
+
(0, lib_1.reportCycles)(Array.from(cyclePaths, (cycle) => cycle.join(' -> ')), rejectCycles);
|
|
185
|
+
return [cyclePaths, cycleNodes];
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Returns the cycles of this graph. If two cycles share some elements, they will
|
|
189
|
+
* be returned as a single cycle.
|
|
190
|
+
*
|
|
191
|
+
* @param {boolean} rejectCycles Whether or not to reject cycles
|
|
192
|
+
* @returns {Set<CyclicPackageGraphNode>}
|
|
193
|
+
*/
|
|
194
|
+
collapseCycles(rejectCycles) {
|
|
195
|
+
const cyclePaths = [];
|
|
196
|
+
const nodeToCycle = new Map();
|
|
197
|
+
const cycles = new Set();
|
|
198
|
+
const alreadyVisited = new Set();
|
|
199
|
+
const walkStack = [];
|
|
200
|
+
function visits(baseNode, dependentNode) {
|
|
201
|
+
if (nodeToCycle.has(baseNode)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
let topLevelDependent = dependentNode;
|
|
205
|
+
while (nodeToCycle.has(topLevelDependent)) {
|
|
206
|
+
topLevelDependent = nodeToCycle.get(topLevelDependent);
|
|
207
|
+
}
|
|
208
|
+
// Otherwise the same node is checked multiple times which is very wasteful in a large repository
|
|
209
|
+
if (alreadyVisited.has(topLevelDependent)) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
alreadyVisited.add(topLevelDependent);
|
|
213
|
+
if (topLevelDependent === baseNode ||
|
|
214
|
+
(topLevelDependent.isCycle && topLevelDependent.has(baseNode.name))) {
|
|
215
|
+
const cycle = new lib_1.CyclicPackageGraphNode();
|
|
216
|
+
walkStack.forEach((nodeInCycle) => {
|
|
217
|
+
nodeToCycle.set(nodeInCycle, cycle);
|
|
218
|
+
cycle.insert(nodeInCycle);
|
|
219
|
+
cycles.delete(nodeInCycle);
|
|
220
|
+
});
|
|
221
|
+
cycles.add(cycle);
|
|
222
|
+
// @ts-ignore
|
|
223
|
+
cyclePaths.push(cycle.toString());
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (walkStack.indexOf(topLevelDependent) === -1) {
|
|
227
|
+
// eslint-disable-next-line no-use-before-define
|
|
228
|
+
visitWithStack(baseNode, topLevelDependent);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function visitWithStack(baseNode, currentNode = baseNode) {
|
|
232
|
+
walkStack.push(currentNode);
|
|
233
|
+
currentNode.localDependents.forEach(visits.bind(null, baseNode));
|
|
234
|
+
walkStack.pop();
|
|
235
|
+
}
|
|
236
|
+
this.forEach((currentNode) => visitWithStack(currentNode));
|
|
237
|
+
cycles.forEach((collapsedNode) => visitWithStack(collapsedNode));
|
|
238
|
+
(0, lib_1.reportCycles)(cyclePaths, rejectCycles);
|
|
239
|
+
return cycles;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Remove cycle nodes.
|
|
243
|
+
*
|
|
244
|
+
* @deprecated Spread set into prune() instead.
|
|
245
|
+
*
|
|
246
|
+
* @param {Set<PackageGraphNode>} cycleNodes
|
|
247
|
+
*/
|
|
248
|
+
pruneCycleNodes(cycleNodes) {
|
|
249
|
+
return this.prune(...cycleNodes);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Remove all candidate nodes.
|
|
253
|
+
* @param {PackageGraphNode[]} candidates
|
|
254
|
+
*/
|
|
255
|
+
prune(...candidates) {
|
|
256
|
+
if (candidates.length === this.size) {
|
|
257
|
+
return this.clear();
|
|
258
|
+
}
|
|
259
|
+
candidates.forEach((node) => this.remove(node));
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Delete by value (instead of key), as well as removing pointers
|
|
263
|
+
* to itself in the other node's internal collections.
|
|
264
|
+
* @param {PackageGraphNode} candidateNode instance to remove
|
|
265
|
+
*/
|
|
266
|
+
remove(candidateNode) {
|
|
267
|
+
this.delete(candidateNode.name);
|
|
268
|
+
this.forEach((node) => {
|
|
269
|
+
// remove incoming edges ("indegree")
|
|
270
|
+
node.localDependencies.delete(candidateNode.name);
|
|
271
|
+
// remove outgoing edges ("outdegree")
|
|
272
|
+
node.localDependents.delete(candidateNode.name);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
exports.PackageGraph = PackageGraph;
|
|
277
277
|
//# sourceMappingURL=package-graph.js.map
|