@depup/nx 22.6.1-depup.0 → 22.6.2-depup.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 +3 -3
- package/bin/nx.js +8 -5
- package/changes.json +2 -2
- package/package.json +15 -15
- package/release/changelog-renderer/index.d.ts +2 -1
- package/release/changelog-renderer/index.d.ts.map +1 -1
- package/schemas/nx-schema.json +102 -0
- package/src/adapter/ngcli-adapter.js +4 -4
- package/src/command-line/migrate/migrate.d.ts.map +1 -1
- package/src/command-line/migrate/migrate.js +25 -9
- package/src/command-line/release/utils/remote-release-clients/github.d.ts +1 -0
- package/src/command-line/release/utils/remote-release-clients/github.d.ts.map +1 -1
- package/src/command-line/release/utils/remote-release-clients/github.js +37 -1
- package/src/command-line/run/run-one.d.ts.map +1 -1
- package/src/command-line/run/run-one.js +1 -1
- package/src/command-line/show/target.js +5 -2
- package/src/core/graph/main.js +1 -1
- package/src/daemon/client/client.d.ts +1 -1
- package/src/daemon/client/client.d.ts.map +1 -1
- package/src/daemon/server/project-graph-incremental-recomputation.d.ts +1 -1
- package/src/daemon/server/project-graph-incremental-recomputation.d.ts.map +1 -1
- package/src/daemon/server/project-graph-listener-sockets.d.ts +1 -1
- package/src/daemon/server/project-graph-listener-sockets.d.ts.map +1 -1
- package/src/devkit-internals.d.ts +3 -2
- package/src/devkit-internals.d.ts.map +1 -1
- package/src/devkit-internals.js +5 -4
- package/src/executors/utils/convert-nx-executor.js +2 -2
- package/src/generators/utils/project-configuration.js +4 -4
- package/src/hasher/hash-plan-inspector.d.ts.map +1 -1
- package/src/hasher/hash-plan-inspector.js +1 -1
- package/src/native/index.d.ts +1 -1
- package/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/src/native/nx.wasm32-wasi.wasm +0 -0
- package/src/project-graph/build-project-graph.d.ts +1 -1
- package/src/project-graph/build-project-graph.d.ts.map +1 -1
- package/src/project-graph/build-project-graph.js +2 -2
- package/src/project-graph/error-types.d.ts +2 -1
- package/src/project-graph/error-types.d.ts.map +1 -1
- package/src/project-graph/nx-deps-cache.d.ts +1 -1
- package/src/project-graph/nx-deps-cache.d.ts.map +1 -1
- package/src/project-graph/plugins/isolation/isolated-plugin.js +5 -5
- package/src/project-graph/project-graph.d.ts +2 -2
- package/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +23 -18
- package/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts.map +1 -1
- package/src/project-graph/utils/project-configuration/name-substitution-manager.js +129 -87
- package/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +40 -0
- package/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts.map +1 -0
- package/src/project-graph/utils/project-configuration/project-nodes-manager.js +264 -0
- package/src/project-graph/utils/project-configuration/target-merging.d.ts +32 -0
- package/src/project-graph/utils/project-configuration/target-merging.d.ts.map +1 -0
- package/src/project-graph/utils/project-configuration/target-merging.js +332 -0
- package/src/project-graph/utils/project-configuration/target-normalization.d.ts +13 -0
- package/src/project-graph/utils/project-configuration/target-normalization.d.ts.map +1 -0
- package/src/project-graph/utils/project-configuration/target-normalization.js +177 -0
- package/src/project-graph/utils/project-configuration-utils.d.ts +16 -41
- package/src/project-graph/utils/project-configuration-utils.d.ts.map +1 -1
- package/src/project-graph/utils/project-configuration-utils.js +56 -734
- package/src/tasks-runner/default-tasks-runner.js +1 -1
- package/src/tasks-runner/life-cycle.d.ts +4 -0
- package/src/tasks-runner/life-cycle.d.ts.map +1 -1
- package/src/tasks-runner/life-cycles/tui-summary-life-cycle.d.ts.map +1 -1
- package/src/tasks-runner/life-cycles/tui-summary-life-cycle.js +4 -0
- package/src/tasks-runner/task-orchestrator.d.ts +8 -2
- package/src/tasks-runner/task-orchestrator.d.ts.map +1 -1
- package/src/tasks-runner/task-orchestrator.js +64 -36
- package/src/tasks-runner/tasks-schedule.d.ts +1 -1
- package/src/tasks-runner/tasks-schedule.d.ts.map +1 -1
- package/src/tasks-runner/tasks-schedule.js +14 -3
- package/src/tasks-runner/utils.d.ts +2 -2
- package/src/tasks-runner/utils.d.ts.map +1 -1
- package/src/tasks-runner/utils.js +5 -7
- package/src/utils/package-json.js +2 -2
- package/src/utils/provenance.d.ts.map +1 -1
- package/src/utils/provenance.js +2 -2
- package/src/utils/split-target.d.ts +13 -2
- package/src/utils/split-target.d.ts.map +1 -1
- package/src/utils/split-target.js +180 -31
|
@@ -17,25 +17,24 @@ const minimatch_1 = require("minimatch");
|
|
|
17
17
|
* hold a stale reference to the now-nonexistent name `B`.
|
|
18
18
|
*
|
|
19
19
|
* This class solves that by:
|
|
20
|
-
* 1.
|
|
20
|
+
* 1. Receiving a live nameMap accessor (maintained by ProjectNodesManager)
|
|
21
|
+
* for name → root resolution and colon-delimited string parsing.
|
|
22
|
+
* 2. Tracking dirty roots via {@link identifyProjectWithRoot} when a
|
|
23
|
+
* project name changes at a root.
|
|
24
|
+
* 3. Scanning each plugin's results for project-name references in
|
|
21
25
|
* `inputs` and `dependsOn` ({@link registerSubstitutorsForNodeResults}).
|
|
22
|
-
*
|
|
23
|
-
* the plugin result** — no lookup into any project map is needed at
|
|
24
|
-
* registration time.
|
|
25
|
-
* 2. When a project's name changes during the merge, recording that change
|
|
26
|
-
* via {@link markDirty} so substitutors for the old name can be located.
|
|
27
|
-
* 3. After all results are merged, applying the substitutors for every
|
|
26
|
+
* 4. After all results are merged, applying the substitutors for every
|
|
28
27
|
* renamed project so that references are updated to the final name
|
|
29
28
|
* ({@link applySubstitutions}).
|
|
30
29
|
*/
|
|
31
30
|
class ProjectNameInNodePropsManager {
|
|
32
|
-
constructor() {
|
|
33
|
-
// Maps the *
|
|
34
|
-
//
|
|
35
|
-
// that
|
|
36
|
-
//
|
|
37
|
-
// not
|
|
38
|
-
this.
|
|
31
|
+
constructor(getNameMap) {
|
|
32
|
+
// Maps the *root of the referenced project* → set of substitutor entries
|
|
33
|
+
// that should run when that project is renamed. Keying by root (not name)
|
|
34
|
+
// ensures that when project "A" is renamed to "B" and a *new* project
|
|
35
|
+
// takes the name "A" at a different root, references to the new "A" are
|
|
36
|
+
// not incorrectly rewritten.
|
|
37
|
+
this.substitutorsByReferencedRoot = new Map();
|
|
39
38
|
// Tracks substitutor entries by (array path, index, subIndex). This
|
|
40
39
|
// serves two purposes:
|
|
41
40
|
//
|
|
@@ -50,25 +49,32 @@ class ProjectNameInNodePropsManager {
|
|
|
50
49
|
// Inner array: indexed by position; each slot holds an array so that a
|
|
51
50
|
// single `projects` array can hold multiple name references.
|
|
52
51
|
this.substitutorsByArrayKey = new Map();
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// entries like "project:target" — including project / target names that
|
|
61
|
-
// contain colons.
|
|
62
|
-
this.knownProjectNodes = {};
|
|
52
|
+
// Holds substitutors for project names that haven't been identified yet
|
|
53
|
+
// (forward references). When identifyProjectWithRoot is later called for
|
|
54
|
+
// a name in this map, the entries are promoted to substitutorsByReferencedRoot.
|
|
55
|
+
this.pendingSubstitutorsByName = new Map();
|
|
56
|
+
// Roots of projects whose names changed during the merge phase.
|
|
57
|
+
this.dirtyRoots = new Set();
|
|
58
|
+
this.getNameMap = getNameMap ?? (() => ({}));
|
|
63
59
|
}
|
|
64
60
|
removeSubstitutorEntry(item) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
61
|
+
if (item.referencedRoot !== undefined) {
|
|
62
|
+
const substitutors = this.substitutorsByReferencedRoot.get(item.referencedRoot);
|
|
63
|
+
if (substitutors) {
|
|
64
|
+
substitutors.delete(item.entry);
|
|
65
|
+
if (substitutors.size === 0) {
|
|
66
|
+
this.substitutorsByReferencedRoot.delete(item.referencedRoot);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
if (item.referencedName !== undefined) {
|
|
71
|
+
const substitutors = this.pendingSubstitutorsByName.get(item.referencedName);
|
|
72
|
+
if (substitutors) {
|
|
73
|
+
substitutors.delete(item.entry);
|
|
74
|
+
if (substitutors.size === 0) {
|
|
75
|
+
this.pendingSubstitutorsByName.delete(item.referencedName);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
72
78
|
}
|
|
73
79
|
}
|
|
74
80
|
// Removes the substitutor registered at the given index (and optional
|
|
@@ -165,35 +171,51 @@ class ProjectNameInNodePropsManager {
|
|
|
165
171
|
callback(targetConfig);
|
|
166
172
|
}
|
|
167
173
|
}
|
|
168
|
-
// Registers a new substitutor
|
|
169
|
-
//
|
|
170
|
-
//
|
|
174
|
+
// Registers a new substitutor for `referencedName`, tracked at
|
|
175
|
+
// (arrayKey, index, subIndex) for deduplication and tail-clearing.
|
|
176
|
+
// The substitutor is keyed by root when the referenced project is
|
|
177
|
+
// already in the nameMap, otherwise parked in pendingSubstitutorsByName.
|
|
171
178
|
registerProjectNameSubstitutor(referencedName, ownerRoot, arrayKey, index, substitutor, subIndex) {
|
|
172
179
|
// Evict any existing substitutor at this exact position first.
|
|
173
180
|
this.clearSubstitutorAtIndex(arrayKey, index, subIndex);
|
|
174
|
-
let substitutorsForName = this.projectNameSubstitutors.get(referencedName);
|
|
175
|
-
if (!substitutorsForName) {
|
|
176
|
-
substitutorsForName = new Set();
|
|
177
|
-
this.projectNameSubstitutors.set(referencedName, substitutorsForName);
|
|
178
|
-
}
|
|
179
181
|
const entry = { ownerRoot, substitutor };
|
|
180
|
-
|
|
182
|
+
const nameMap = this.getNameMap();
|
|
183
|
+
const referencedRoot = nameMap[referencedName]?.root;
|
|
184
|
+
let trackingItem;
|
|
185
|
+
if (referencedRoot !== undefined) {
|
|
186
|
+
// Project is already known — key directly by root.
|
|
187
|
+
let substitutorsForRoot = this.substitutorsByReferencedRoot.get(referencedRoot);
|
|
188
|
+
if (!substitutorsForRoot) {
|
|
189
|
+
substitutorsForRoot = new Set();
|
|
190
|
+
this.substitutorsByReferencedRoot.set(referencedRoot, substitutorsForRoot);
|
|
191
|
+
}
|
|
192
|
+
substitutorsForRoot.add(entry);
|
|
193
|
+
trackingItem = { referencedRoot, entry };
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// Forward reference — park in pending map keyed by name.
|
|
197
|
+
let pendingSet = this.pendingSubstitutorsByName.get(referencedName);
|
|
198
|
+
if (!pendingSet) {
|
|
199
|
+
pendingSet = new Set();
|
|
200
|
+
this.pendingSubstitutorsByName.set(referencedName, pendingSet);
|
|
201
|
+
}
|
|
202
|
+
pendingSet.add(entry);
|
|
203
|
+
trackingItem = { referencedName, entry };
|
|
204
|
+
}
|
|
181
205
|
let byIndex = this.substitutorsByArrayKey.get(arrayKey);
|
|
182
206
|
if (!byIndex) {
|
|
183
207
|
byIndex = [];
|
|
184
208
|
this.substitutorsByArrayKey.set(arrayKey, byIndex);
|
|
185
209
|
}
|
|
186
210
|
if (subIndex === undefined) {
|
|
187
|
-
|
|
188
|
-
byIndex[index] = [{ referencedName, entry }];
|
|
211
|
+
byIndex[index] = [trackingItem];
|
|
189
212
|
}
|
|
190
213
|
else {
|
|
191
|
-
// Multiple projects in an array — ensure the slot exists
|
|
192
214
|
if (!byIndex[index]) {
|
|
193
215
|
byIndex[index] = [];
|
|
194
216
|
}
|
|
195
217
|
const subArray = byIndex[index];
|
|
196
|
-
subArray[subIndex] =
|
|
218
|
+
subArray[subIndex] = trackingItem;
|
|
197
219
|
}
|
|
198
220
|
}
|
|
199
221
|
/**
|
|
@@ -201,10 +223,9 @@ class ProjectNameInNodePropsManager {
|
|
|
201
223
|
* reference another project by name, and registers substitutors so those
|
|
202
224
|
* references are updated if the target project is later renamed.
|
|
203
225
|
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
* or target names contain colons.
|
|
226
|
+
* **Important**: call {@link identifyProjectWithRoot} for all projects in
|
|
227
|
+
* this result (and all prior results) before calling this method, so that
|
|
228
|
+
* referenced project names can be resolved to roots.
|
|
208
229
|
*
|
|
209
230
|
* @param pluginResultProjects Projects from a single plugin's createNodes call.
|
|
210
231
|
*/
|
|
@@ -212,18 +233,6 @@ class ProjectNameInNodePropsManager {
|
|
|
212
233
|
if (!pluginResultProjects) {
|
|
213
234
|
return;
|
|
214
235
|
}
|
|
215
|
-
// Accumulate partial project graph nodes for splitTargetFromNodes.
|
|
216
|
-
for (const root in pluginResultProjects) {
|
|
217
|
-
const project = pluginResultProjects[root];
|
|
218
|
-
const name = project.name;
|
|
219
|
-
if (name) {
|
|
220
|
-
this.knownProjectNodes[name] = {
|
|
221
|
-
type: 'lib',
|
|
222
|
-
name,
|
|
223
|
-
data: { root, ...project },
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
236
|
for (const ownerRoot in pluginResultProjects) {
|
|
228
237
|
const project = pluginResultProjects[ownerRoot];
|
|
229
238
|
if (!project.targets) {
|
|
@@ -238,7 +247,7 @@ class ProjectNameInNodePropsManager {
|
|
|
238
247
|
this.registerSubstitutorsForInputs(ownerRoot, targetName, targetConfig.inputs);
|
|
239
248
|
}
|
|
240
249
|
if (Array.isArray(targetConfig.dependsOn)) {
|
|
241
|
-
this.registerSubstitutorsForDependsOn(ownerRoot, targetName, targetConfig.dependsOn);
|
|
250
|
+
this.registerSubstitutorsForDependsOn(ownerRoot, targetName, targetConfig.dependsOn, project.targets, project.name);
|
|
242
251
|
}
|
|
243
252
|
}
|
|
244
253
|
}
|
|
@@ -335,17 +344,21 @@ class ProjectNameInNodePropsManager {
|
|
|
335
344
|
// the array may have shrunk compared to a previous plugin's contribution.
|
|
336
345
|
this.clearSubstitutorsFromIndex(arrayKey, inputs.length);
|
|
337
346
|
}
|
|
338
|
-
registerSubstitutorsForDependsOn(ownerRoot, targetName, dependsOn) {
|
|
347
|
+
registerSubstitutorsForDependsOn(ownerRoot, targetName, dependsOn, ownerTargets, ownerProjectName) {
|
|
339
348
|
const arrayKey = `${ownerRoot}:targets.${targetName}.dependsOn`;
|
|
340
349
|
for (let i = 0; i < dependsOn.length; i++) {
|
|
341
350
|
const dep = dependsOn[i];
|
|
342
351
|
if (typeof dep === 'string') {
|
|
343
352
|
// String-form dependsOn entries like "project:target". Strings
|
|
344
353
|
// starting with '^' are dependency-mode references (no project
|
|
345
|
-
// name). Use
|
|
346
|
-
//
|
|
347
|
-
|
|
348
|
-
|
|
354
|
+
// name). Use splitTargetFromConfigurations with the nameMap to
|
|
355
|
+
// properly handle project / target names containing colons.
|
|
356
|
+
//
|
|
357
|
+
// However, if the string matches a target name in the owning
|
|
358
|
+
// project, it is a same-project target reference (e.g. a target
|
|
359
|
+
// literally named "nx:echo"), not a cross-project reference.
|
|
360
|
+
if (!dep.startsWith('^') && !(ownerTargets && dep in ownerTargets)) {
|
|
361
|
+
const [maybeProject, ...rest] = (0, split_target_1.splitTargetFromConfigurations)(dep, this.getNameMap(), { silent: true, currentProject: ownerProjectName });
|
|
349
362
|
if (rest.length > 0) {
|
|
350
363
|
const targetPart = rest.join(':');
|
|
351
364
|
this.registerProjectNameSubstitutor(maybeProject, ownerRoot, arrayKey, i, this.createDependsOnTargetStringSubstitutor(targetName, i, targetPart));
|
|
@@ -384,17 +397,50 @@ class ProjectNameInNodePropsManager {
|
|
|
384
397
|
this.clearSubstitutorsFromIndex(arrayKey, dependsOn.length);
|
|
385
398
|
}
|
|
386
399
|
/**
|
|
387
|
-
* Records that
|
|
388
|
-
*
|
|
389
|
-
*
|
|
400
|
+
* Records that a project with `name` exists at the given `root`. Call
|
|
401
|
+
* this during the merge phase whenever a project's name changes at a
|
|
402
|
+
* root — **before** calling
|
|
403
|
+
* {@link registerSubstitutorsForNodeResults} for that result.
|
|
404
|
+
*
|
|
405
|
+
* The nameMap (maintained externally by ProjectNodesManager) is always
|
|
406
|
+
* current — this method only needs to mark the root as dirty and
|
|
407
|
+
* promote any pending substitutors keyed by name.
|
|
390
408
|
*/
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
409
|
+
identifyProjectWithRoot(root, name) {
|
|
410
|
+
// Always mark dirty when called — the caller only invokes this when
|
|
411
|
+
// the name actually changed at this root (first identification or
|
|
412
|
+
// rename). If there are pending substitutors for this name, those
|
|
413
|
+
// forward refs need updating. If it's a rename, existing refs need
|
|
414
|
+
// updating. Either way, the root is dirty.
|
|
415
|
+
this.dirtyRoots.add(root);
|
|
416
|
+
// Promote any pending substitutors that were waiting for this name.
|
|
417
|
+
const pending = this.pendingSubstitutorsByName.get(name);
|
|
418
|
+
if (pending) {
|
|
419
|
+
this.pendingSubstitutorsByName.delete(name);
|
|
420
|
+
let substitutorsForRoot = this.substitutorsByReferencedRoot.get(root);
|
|
421
|
+
if (!substitutorsForRoot) {
|
|
422
|
+
substitutorsForRoot = new Set();
|
|
423
|
+
this.substitutorsByReferencedRoot.set(root, substitutorsForRoot);
|
|
424
|
+
}
|
|
425
|
+
for (const entry of pending) {
|
|
426
|
+
substitutorsForRoot.add(entry);
|
|
427
|
+
}
|
|
428
|
+
// Update tracking items to reflect the promotion from name → root.
|
|
429
|
+
for (const [, byIndex] of this.substitutorsByArrayKey) {
|
|
430
|
+
for (const atIndex of byIndex) {
|
|
431
|
+
if (!atIndex)
|
|
432
|
+
continue;
|
|
433
|
+
for (const item of atIndex) {
|
|
434
|
+
if (item &&
|
|
435
|
+
item.referencedName === name &&
|
|
436
|
+
pending.has(item.entry)) {
|
|
437
|
+
item.referencedName = undefined;
|
|
438
|
+
item.referencedRoot = root;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
396
443
|
}
|
|
397
|
-
previousNames.add(previousName);
|
|
398
444
|
}
|
|
399
445
|
/**
|
|
400
446
|
* Executes all registered substitutors for renamed projects, updating
|
|
@@ -402,23 +448,19 @@ class ProjectNameInNodePropsManager {
|
|
|
402
448
|
* called once after all plugin results have been merged.
|
|
403
449
|
*/
|
|
404
450
|
applySubstitutions(rootMap) {
|
|
405
|
-
for (const
|
|
451
|
+
for (const root of this.dirtyRoots) {
|
|
406
452
|
const finalName = rootMap[root]?.name;
|
|
407
453
|
if (!finalName) {
|
|
408
454
|
continue;
|
|
409
455
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
const ownerConfig = rootMap[ownerRoot];
|
|
419
|
-
if (ownerConfig) {
|
|
420
|
-
substitutor(finalName, ownerConfig);
|
|
421
|
-
}
|
|
456
|
+
const substitutors = this.substitutorsByReferencedRoot.get(root);
|
|
457
|
+
if (!substitutors) {
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
for (const { ownerRoot, substitutor } of substitutors) {
|
|
461
|
+
const ownerConfig = rootMap[ownerRoot];
|
|
462
|
+
if (ownerConfig) {
|
|
463
|
+
substitutor(finalName, ownerConfig);
|
|
422
464
|
}
|
|
423
465
|
}
|
|
424
466
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ProjectConfiguration } from '../../../config/workspace-json-project-json';
|
|
2
|
+
import type { ConfigurationSourceMaps, SourceInformation } from './source-maps';
|
|
3
|
+
export { validateProject } from './target-normalization';
|
|
4
|
+
export declare function mergeProjectConfigurationIntoRootMap(projectRootMap: Record<string, ProjectConfiguration>, project: ProjectConfiguration, configurationSourceMaps?: ConfigurationSourceMaps, sourceInformation?: SourceInformation, skipTargetNormalization?: boolean): {
|
|
5
|
+
nameChanged: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function readProjectConfigurationsFromRootMap(projectRootMap: Record<string, ProjectConfiguration>): Record<string, ProjectConfiguration>;
|
|
8
|
+
export declare function createRootMap(projectRootMap: Record<string, ProjectConfiguration>): Record<string, string>;
|
|
9
|
+
/**
|
|
10
|
+
* Owns the rootMap (root → ProjectConfiguration) and nameMap
|
|
11
|
+
* (name → ProjectConfiguration), coordinating merges with the
|
|
12
|
+
* {@link ProjectNameInNodePropsManager} for deferred name substitutions.
|
|
13
|
+
*
|
|
14
|
+
* The nameMap entries are the *same object references* as the rootMap
|
|
15
|
+
* entries, so when a merge adds targets to a rootMap entry the nameMap
|
|
16
|
+
* entry automatically has them too — no copying, no staleness.
|
|
17
|
+
*/
|
|
18
|
+
export declare class ProjectNodesManager {
|
|
19
|
+
private rootMap;
|
|
20
|
+
private nameMap;
|
|
21
|
+
private nameSubstitutionManager;
|
|
22
|
+
constructor();
|
|
23
|
+
getRootMap(): Record<string, ProjectConfiguration>;
|
|
24
|
+
/**
|
|
25
|
+
* Merges a project into the rootMap, updates the nameMap, and notifies
|
|
26
|
+
* the substitution manager if the name changed at this root.
|
|
27
|
+
*/
|
|
28
|
+
mergeProjectNode(project: ProjectConfiguration, configurationSourceMaps?: ConfigurationSourceMaps, sourceInformation?: SourceInformation): void;
|
|
29
|
+
/**
|
|
30
|
+
* Registers substitutors for a plugin result's project references
|
|
31
|
+
* in `inputs` and `dependsOn`.
|
|
32
|
+
*/
|
|
33
|
+
registerSubstitutors(pluginResultProjects?: Record<string, Omit<ProjectConfiguration, 'root'> & Partial<ProjectConfiguration>>): void;
|
|
34
|
+
/**
|
|
35
|
+
* Applies all pending name substitutions. Call once after all plugin
|
|
36
|
+
* results have been merged.
|
|
37
|
+
*/
|
|
38
|
+
applySubstitutions(): void;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=project-nodes-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-nodes-manager.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nx/src/project-graph/utils/project-configuration/project-nodes-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAcnF,OAAO,KAAK,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAMhF,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,wBAAgB,oCAAoC,CAClD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,EACpD,OAAO,EAAE,oBAAoB,EAC7B,uBAAuB,CAAC,EAAE,uBAAuB,EACjD,iBAAiB,CAAC,EAAE,iBAAiB,EAGrC,uBAAuB,CAAC,EAAE,OAAO,GAChC;IACD,WAAW,EAAE,OAAO,CAAC;CACtB,CAqLA;AAED,wBAAgB,oCAAoC,CAClD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,wCAwCrD;AAED,wBAAgB,aAAa,CAC3B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,0BAQrD;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAmB;IAE9B,OAAO,CAAC,OAAO,CAA4C;IAE3D,OAAO,CAAC,OAAO,CAA4C;IAC3D,OAAO,CAAC,uBAAuB,CAAgC;;IAU/D,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC;IAIlD;;;OAGG;IACH,gBAAgB,CACd,OAAO,EAAE,oBAAoB,EAC7B,uBAAuB,CAAC,EAAE,uBAAuB,EACjD,iBAAiB,CAAC,EAAE,iBAAiB,GACpC,IAAI;IA+BP;;;OAGG;IACH,oBAAoB,CAClB,oBAAoB,CAAC,EAAE,MAAM,CAC3B,MAAM,EACN,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CACnE,GACA,IAAI;IAMP;;;OAGG;IACH,kBAAkB,IAAI,IAAI;CAG3B"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProjectNodesManager = exports.validateProject = void 0;
|
|
4
|
+
exports.mergeProjectConfigurationIntoRootMap = mergeProjectConfigurationIntoRootMap;
|
|
5
|
+
exports.readProjectConfigurationsFromRootMap = readProjectConfigurationsFromRootMap;
|
|
6
|
+
exports.createRootMap = createRootMap;
|
|
7
|
+
const error_types_1 = require("../../error-types");
|
|
8
|
+
const target_merging_1 = require("./target-merging");
|
|
9
|
+
const target_normalization_1 = require("./target-normalization");
|
|
10
|
+
const name_substitution_manager_1 = require("./name-substitution-manager");
|
|
11
|
+
const source_maps_1 = require("./source-maps");
|
|
12
|
+
const minimatch_1 = require("minimatch");
|
|
13
|
+
const globs_1 = require("../../../utils/globs");
|
|
14
|
+
var target_normalization_2 = require("./target-normalization");
|
|
15
|
+
Object.defineProperty(exports, "validateProject", { enumerable: true, get: function () { return target_normalization_2.validateProject; } });
|
|
16
|
+
function mergeProjectConfigurationIntoRootMap(projectRootMap, project, configurationSourceMaps, sourceInformation,
|
|
17
|
+
// This function is used when reading project configuration
|
|
18
|
+
// in generators, where we don't want to do this.
|
|
19
|
+
skipTargetNormalization) {
|
|
20
|
+
project.root = project.root === '' ? '.' : project.root;
|
|
21
|
+
if (configurationSourceMaps && !configurationSourceMaps[project.root]) {
|
|
22
|
+
configurationSourceMaps[project.root] = {};
|
|
23
|
+
}
|
|
24
|
+
const sourceMap = configurationSourceMaps?.[project.root];
|
|
25
|
+
let matchingProject = projectRootMap[project.root];
|
|
26
|
+
if (!matchingProject) {
|
|
27
|
+
projectRootMap[project.root] = {
|
|
28
|
+
root: project.root,
|
|
29
|
+
};
|
|
30
|
+
matchingProject = projectRootMap[project.root];
|
|
31
|
+
if (sourceMap) {
|
|
32
|
+
sourceMap[`root`] = sourceInformation;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// This handles top level properties that are overwritten.
|
|
36
|
+
// e.g. `srcRoot`, `projectType`, or other fields that shouldn't be extended
|
|
37
|
+
// Note: `name` is set specifically here to keep it from changing. The name is
|
|
38
|
+
// always determined by the first inference plugin to ID a project, unless it has
|
|
39
|
+
// a project.json in which case it was already updated above.
|
|
40
|
+
const updatedProjectConfiguration = {
|
|
41
|
+
...matchingProject,
|
|
42
|
+
};
|
|
43
|
+
for (const k in project) {
|
|
44
|
+
if (![
|
|
45
|
+
'tags',
|
|
46
|
+
'implicitDependencies',
|
|
47
|
+
'generators',
|
|
48
|
+
'targets',
|
|
49
|
+
'metadata',
|
|
50
|
+
'namedInputs',
|
|
51
|
+
].includes(k)) {
|
|
52
|
+
updatedProjectConfiguration[k] = project[k];
|
|
53
|
+
if (sourceMap) {
|
|
54
|
+
sourceMap[`${k}`] = sourceInformation;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// The next blocks handle properties that should be themselves merged (e.g. targets, tags, and implicit dependencies)
|
|
59
|
+
if (project.tags) {
|
|
60
|
+
updatedProjectConfiguration.tags = Array.from(new Set((matchingProject.tags ?? []).concat(project.tags)));
|
|
61
|
+
if (sourceMap) {
|
|
62
|
+
sourceMap['tags'] ??= sourceInformation;
|
|
63
|
+
project.tags.forEach((tag) => {
|
|
64
|
+
sourceMap[`tags.${tag}`] = sourceInformation;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (project.implicitDependencies) {
|
|
69
|
+
updatedProjectConfiguration.implicitDependencies = (matchingProject.implicitDependencies ?? []).concat(project.implicitDependencies);
|
|
70
|
+
if (sourceMap) {
|
|
71
|
+
sourceMap['implicitDependencies'] ??= sourceInformation;
|
|
72
|
+
project.implicitDependencies.forEach((implicitDependency) => {
|
|
73
|
+
sourceMap[`implicitDependencies.${implicitDependency}`] =
|
|
74
|
+
sourceInformation;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (project.generators) {
|
|
79
|
+
// Start with generators config in new project.
|
|
80
|
+
updatedProjectConfiguration.generators = { ...project.generators };
|
|
81
|
+
if (sourceMap) {
|
|
82
|
+
sourceMap['generators'] ??= sourceInformation;
|
|
83
|
+
for (const generator in project.generators) {
|
|
84
|
+
sourceMap[`generators.${generator}`] = sourceInformation;
|
|
85
|
+
for (const property in project.generators[generator]) {
|
|
86
|
+
sourceMap[`generators.${generator}.${property}`] = sourceInformation;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (matchingProject.generators) {
|
|
91
|
+
// For each generator that was already defined, shallow merge the options.
|
|
92
|
+
// Project contains the new info, so it has higher priority.
|
|
93
|
+
for (const generator in matchingProject.generators) {
|
|
94
|
+
updatedProjectConfiguration.generators[generator] = {
|
|
95
|
+
...matchingProject.generators[generator],
|
|
96
|
+
...project.generators[generator],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (project.namedInputs) {
|
|
102
|
+
updatedProjectConfiguration.namedInputs = {
|
|
103
|
+
...matchingProject.namedInputs,
|
|
104
|
+
...project.namedInputs,
|
|
105
|
+
};
|
|
106
|
+
if (sourceMap) {
|
|
107
|
+
sourceMap['namedInputs'] ??= sourceInformation;
|
|
108
|
+
for (const namedInput in project.namedInputs) {
|
|
109
|
+
sourceMap[`namedInputs.${namedInput}`] = sourceInformation;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (project.metadata) {
|
|
114
|
+
updatedProjectConfiguration.metadata = (0, target_merging_1.mergeMetadata)(sourceMap, sourceInformation, 'metadata', project.metadata, matchingProject.metadata);
|
|
115
|
+
}
|
|
116
|
+
if (project.targets) {
|
|
117
|
+
// We merge the targets with special handling, so clear this back to the
|
|
118
|
+
// targets as defined originally before merging.
|
|
119
|
+
updatedProjectConfiguration.targets = matchingProject?.targets ?? {};
|
|
120
|
+
if (sourceMap) {
|
|
121
|
+
sourceMap['targets'] ??= sourceInformation;
|
|
122
|
+
}
|
|
123
|
+
// For each target defined in the new config
|
|
124
|
+
for (const targetName in project.targets) {
|
|
125
|
+
// Always set source map info for the target, but don't overwrite info already there
|
|
126
|
+
// if augmenting an existing target.
|
|
127
|
+
const target = project.targets?.[targetName];
|
|
128
|
+
if (sourceMap) {
|
|
129
|
+
sourceMap[(0, source_maps_1.targetSourceMapKey)(targetName)] = sourceInformation;
|
|
130
|
+
}
|
|
131
|
+
const normalizedTarget = skipTargetNormalization
|
|
132
|
+
? target
|
|
133
|
+
: (0, target_merging_1.resolveCommandSyntacticSugar)(target, project.root);
|
|
134
|
+
let matchingTargets = [];
|
|
135
|
+
if ((0, globs_1.isGlobPattern)(targetName)) {
|
|
136
|
+
// find all targets matching the glob pattern
|
|
137
|
+
// this will map atomized targets to the glob pattern same as it does for targetDefaults
|
|
138
|
+
matchingTargets = Object.keys(updatedProjectConfiguration.targets).filter((key) => (0, minimatch_1.minimatch)(key, targetName));
|
|
139
|
+
}
|
|
140
|
+
// If no matching targets were found, we can assume that the target name is not (meant to be) a glob pattern
|
|
141
|
+
if (!matchingTargets.length) {
|
|
142
|
+
matchingTargets = [targetName];
|
|
143
|
+
}
|
|
144
|
+
for (const matchingTargetName of matchingTargets) {
|
|
145
|
+
updatedProjectConfiguration.targets[matchingTargetName] =
|
|
146
|
+
(0, target_merging_1.mergeTargetConfigurations)(normalizedTarget, matchingProject.targets?.[matchingTargetName], sourceMap, sourceInformation, `targets.${matchingTargetName}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
projectRootMap[updatedProjectConfiguration.root] =
|
|
151
|
+
updatedProjectConfiguration;
|
|
152
|
+
const nameChanged = !!updatedProjectConfiguration.name &&
|
|
153
|
+
updatedProjectConfiguration.name !== matchingProject?.name;
|
|
154
|
+
return { nameChanged };
|
|
155
|
+
}
|
|
156
|
+
function readProjectConfigurationsFromRootMap(projectRootMap) {
|
|
157
|
+
const projects = {};
|
|
158
|
+
// If there are projects that have the same name, that is an error.
|
|
159
|
+
// This object tracks name -> (all roots of projects with that name)
|
|
160
|
+
// to provide better error messaging.
|
|
161
|
+
const conflicts = new Map();
|
|
162
|
+
const projectRootsWithNoName = [];
|
|
163
|
+
for (const root in projectRootMap) {
|
|
164
|
+
const project = projectRootMap[root];
|
|
165
|
+
// We're setting `// targets` as a comment `targets` is empty due to Project Crystal.
|
|
166
|
+
// Strip it before returning configuration for usage.
|
|
167
|
+
if (project['// targets'])
|
|
168
|
+
delete project['// targets'];
|
|
169
|
+
try {
|
|
170
|
+
(0, target_normalization_1.validateProject)(project, projects);
|
|
171
|
+
projects[project.name] = project;
|
|
172
|
+
}
|
|
173
|
+
catch (e) {
|
|
174
|
+
if ((0, error_types_1.isProjectWithNoNameError)(e)) {
|
|
175
|
+
projectRootsWithNoName.push(e.projectRoot);
|
|
176
|
+
}
|
|
177
|
+
else if ((0, error_types_1.isProjectWithExistingNameError)(e)) {
|
|
178
|
+
const rootErrors = conflicts.get(e.projectName) ?? [
|
|
179
|
+
projects[e.projectName].root,
|
|
180
|
+
];
|
|
181
|
+
rootErrors.push(e.projectRoot);
|
|
182
|
+
conflicts.set(e.projectName, rootErrors);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
throw e;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (conflicts.size > 0) {
|
|
190
|
+
throw new error_types_1.MultipleProjectsWithSameNameError(conflicts, projects);
|
|
191
|
+
}
|
|
192
|
+
if (projectRootsWithNoName.length > 0) {
|
|
193
|
+
throw new error_types_1.ProjectsWithNoNameError(projectRootsWithNoName, projects);
|
|
194
|
+
}
|
|
195
|
+
return projects;
|
|
196
|
+
}
|
|
197
|
+
function createRootMap(projectRootMap) {
|
|
198
|
+
const map = {};
|
|
199
|
+
for (const projectRoot in projectRootMap) {
|
|
200
|
+
const projectName = projectRootMap[projectRoot].name;
|
|
201
|
+
map[projectRoot] = projectName;
|
|
202
|
+
}
|
|
203
|
+
return map;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Owns the rootMap (root → ProjectConfiguration) and nameMap
|
|
207
|
+
* (name → ProjectConfiguration), coordinating merges with the
|
|
208
|
+
* {@link ProjectNameInNodePropsManager} for deferred name substitutions.
|
|
209
|
+
*
|
|
210
|
+
* The nameMap entries are the *same object references* as the rootMap
|
|
211
|
+
* entries, so when a merge adds targets to a rootMap entry the nameMap
|
|
212
|
+
* entry automatically has them too — no copying, no staleness.
|
|
213
|
+
*/
|
|
214
|
+
class ProjectNodesManager {
|
|
215
|
+
constructor() {
|
|
216
|
+
// root → ProjectConfiguration (the merge target)
|
|
217
|
+
this.rootMap = {};
|
|
218
|
+
// name → ProjectConfiguration (same object references as rootMap)
|
|
219
|
+
this.nameMap = {};
|
|
220
|
+
// Pass a lazy accessor so the substitution manager always sees
|
|
221
|
+
// the current nameMap without manual synchronization.
|
|
222
|
+
this.nameSubstitutionManager = new name_substitution_manager_1.ProjectNameInNodePropsManager(() => this.nameMap);
|
|
223
|
+
}
|
|
224
|
+
getRootMap() {
|
|
225
|
+
return this.rootMap;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Merges a project into the rootMap, updates the nameMap, and notifies
|
|
229
|
+
* the substitution manager if the name changed at this root.
|
|
230
|
+
*/
|
|
231
|
+
mergeProjectNode(project, configurationSourceMaps, sourceInformation) {
|
|
232
|
+
const previousName = this.rootMap[project.root]?.name;
|
|
233
|
+
mergeProjectConfigurationIntoRootMap(this.rootMap, project, configurationSourceMaps, sourceInformation);
|
|
234
|
+
const merged = this.rootMap[project.root];
|
|
235
|
+
const currentName = merged?.name;
|
|
236
|
+
if (currentName) {
|
|
237
|
+
// Remove old nameMap entry on rename
|
|
238
|
+
if (previousName && previousName !== currentName) {
|
|
239
|
+
delete this.nameMap[previousName];
|
|
240
|
+
}
|
|
241
|
+
// Point nameMap at the same object as rootMap
|
|
242
|
+
this.nameMap[currentName] = merged;
|
|
243
|
+
// Notify substitution manager of name change
|
|
244
|
+
if (currentName !== previousName) {
|
|
245
|
+
this.nameSubstitutionManager.identifyProjectWithRoot(project.root, currentName);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Registers substitutors for a plugin result's project references
|
|
251
|
+
* in `inputs` and `dependsOn`.
|
|
252
|
+
*/
|
|
253
|
+
registerSubstitutors(pluginResultProjects) {
|
|
254
|
+
this.nameSubstitutionManager.registerSubstitutorsForNodeResults(pluginResultProjects);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Applies all pending name substitutions. Call once after all plugin
|
|
258
|
+
* results have been merged.
|
|
259
|
+
*/
|
|
260
|
+
applySubstitutions() {
|
|
261
|
+
this.nameSubstitutionManager.applySubstitutions(this.rootMap);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
exports.ProjectNodesManager = ProjectNodesManager;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ProjectConfiguration, ProjectMetadata, TargetConfiguration, TargetMetadata } from '../../../config/workspace-json-project-json';
|
|
2
|
+
import { TargetDefaults } from '../../../config/nx-json';
|
|
3
|
+
import type { SourceInformation } from './source-maps';
|
|
4
|
+
export declare function deepClone<T>(obj: T): T;
|
|
5
|
+
export declare function resolveCommandSyntacticSugar(target: TargetConfiguration, key: string): TargetConfiguration;
|
|
6
|
+
export declare function mergeMetadata<T = ProjectMetadata | TargetMetadata>(sourceMap: Record<string, [file: string, plugin: string]>, sourceInformation: [file: string, plugin: string], baseSourceMapPath: string, metadata: T, matchingMetadata?: T): T;
|
|
7
|
+
/**
|
|
8
|
+
* Merges two targets.
|
|
9
|
+
*
|
|
10
|
+
* Most properties from `target` will overwrite any properties from `baseTarget`.
|
|
11
|
+
* Options and configurations are treated differently - they are merged together if the executor definition is compatible.
|
|
12
|
+
*
|
|
13
|
+
* @param target The target definition with higher priority
|
|
14
|
+
* @param baseTarget The target definition that should be overwritten. Can be undefined, in which case the target is returned as-is.
|
|
15
|
+
* @param projectConfigSourceMap The source map to be filled with metadata about where each property came from
|
|
16
|
+
* @param sourceInformation The metadata about where the new target was defined
|
|
17
|
+
* @param targetIdentifier The identifier for the target to merge, used for source map
|
|
18
|
+
* @returns A merged target configuration
|
|
19
|
+
*/
|
|
20
|
+
export declare function mergeTargetConfigurations(target: TargetConfiguration, baseTarget?: TargetConfiguration, projectConfigSourceMap?: Record<string, SourceInformation>, sourceInformation?: SourceInformation, targetIdentifier?: string): TargetConfiguration;
|
|
21
|
+
/**
|
|
22
|
+
* Checks if targets options are compatible - used when merging configurations
|
|
23
|
+
* to avoid merging options for @nx/js:tsc into something like @nx/webpack:webpack.
|
|
24
|
+
*
|
|
25
|
+
* If the executors are both specified and don't match, the options aren't considered
|
|
26
|
+
* "compatible" and shouldn't be merged.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isCompatibleTarget(a: TargetConfiguration, b: TargetConfiguration): boolean;
|
|
29
|
+
export declare function mergeTargetDefaultWithTargetDefinition(targetName: string, project: ProjectConfiguration, targetDefault: Partial<TargetConfiguration>, sourceMap: Record<string, SourceInformation>): TargetConfiguration;
|
|
30
|
+
export declare function resolveNxTokensInOptions<T extends Object | Array<unknown>>(object: T, project: ProjectConfiguration, key: string): T;
|
|
31
|
+
export declare function readTargetDefaultsForTarget(targetName: string, targetDefaults: TargetDefaults, executor?: string): TargetDefaults[string];
|
|
32
|
+
//# sourceMappingURL=target-merging.d.ts.map
|