@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.
Files changed (77) hide show
  1. package/README.md +3 -3
  2. package/bin/nx.js +8 -5
  3. package/changes.json +2 -2
  4. package/package.json +15 -15
  5. package/release/changelog-renderer/index.d.ts +2 -1
  6. package/release/changelog-renderer/index.d.ts.map +1 -1
  7. package/schemas/nx-schema.json +102 -0
  8. package/src/adapter/ngcli-adapter.js +4 -4
  9. package/src/command-line/migrate/migrate.d.ts.map +1 -1
  10. package/src/command-line/migrate/migrate.js +25 -9
  11. package/src/command-line/release/utils/remote-release-clients/github.d.ts +1 -0
  12. package/src/command-line/release/utils/remote-release-clients/github.d.ts.map +1 -1
  13. package/src/command-line/release/utils/remote-release-clients/github.js +37 -1
  14. package/src/command-line/run/run-one.d.ts.map +1 -1
  15. package/src/command-line/run/run-one.js +1 -1
  16. package/src/command-line/show/target.js +5 -2
  17. package/src/core/graph/main.js +1 -1
  18. package/src/daemon/client/client.d.ts +1 -1
  19. package/src/daemon/client/client.d.ts.map +1 -1
  20. package/src/daemon/server/project-graph-incremental-recomputation.d.ts +1 -1
  21. package/src/daemon/server/project-graph-incremental-recomputation.d.ts.map +1 -1
  22. package/src/daemon/server/project-graph-listener-sockets.d.ts +1 -1
  23. package/src/daemon/server/project-graph-listener-sockets.d.ts.map +1 -1
  24. package/src/devkit-internals.d.ts +3 -2
  25. package/src/devkit-internals.d.ts.map +1 -1
  26. package/src/devkit-internals.js +5 -4
  27. package/src/executors/utils/convert-nx-executor.js +2 -2
  28. package/src/generators/utils/project-configuration.js +4 -4
  29. package/src/hasher/hash-plan-inspector.d.ts.map +1 -1
  30. package/src/hasher/hash-plan-inspector.js +1 -1
  31. package/src/native/index.d.ts +1 -1
  32. package/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  33. package/src/native/nx.wasm32-wasi.wasm +0 -0
  34. package/src/project-graph/build-project-graph.d.ts +1 -1
  35. package/src/project-graph/build-project-graph.d.ts.map +1 -1
  36. package/src/project-graph/build-project-graph.js +2 -2
  37. package/src/project-graph/error-types.d.ts +2 -1
  38. package/src/project-graph/error-types.d.ts.map +1 -1
  39. package/src/project-graph/nx-deps-cache.d.ts +1 -1
  40. package/src/project-graph/nx-deps-cache.d.ts.map +1 -1
  41. package/src/project-graph/plugins/isolation/isolated-plugin.js +5 -5
  42. package/src/project-graph/project-graph.d.ts +2 -2
  43. package/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +23 -18
  44. package/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts.map +1 -1
  45. package/src/project-graph/utils/project-configuration/name-substitution-manager.js +129 -87
  46. package/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +40 -0
  47. package/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts.map +1 -0
  48. package/src/project-graph/utils/project-configuration/project-nodes-manager.js +264 -0
  49. package/src/project-graph/utils/project-configuration/target-merging.d.ts +32 -0
  50. package/src/project-graph/utils/project-configuration/target-merging.d.ts.map +1 -0
  51. package/src/project-graph/utils/project-configuration/target-merging.js +332 -0
  52. package/src/project-graph/utils/project-configuration/target-normalization.d.ts +13 -0
  53. package/src/project-graph/utils/project-configuration/target-normalization.d.ts.map +1 -0
  54. package/src/project-graph/utils/project-configuration/target-normalization.js +177 -0
  55. package/src/project-graph/utils/project-configuration-utils.d.ts +16 -41
  56. package/src/project-graph/utils/project-configuration-utils.d.ts.map +1 -1
  57. package/src/project-graph/utils/project-configuration-utils.js +56 -734
  58. package/src/tasks-runner/default-tasks-runner.js +1 -1
  59. package/src/tasks-runner/life-cycle.d.ts +4 -0
  60. package/src/tasks-runner/life-cycle.d.ts.map +1 -1
  61. package/src/tasks-runner/life-cycles/tui-summary-life-cycle.d.ts.map +1 -1
  62. package/src/tasks-runner/life-cycles/tui-summary-life-cycle.js +4 -0
  63. package/src/tasks-runner/task-orchestrator.d.ts +8 -2
  64. package/src/tasks-runner/task-orchestrator.d.ts.map +1 -1
  65. package/src/tasks-runner/task-orchestrator.js +64 -36
  66. package/src/tasks-runner/tasks-schedule.d.ts +1 -1
  67. package/src/tasks-runner/tasks-schedule.d.ts.map +1 -1
  68. package/src/tasks-runner/tasks-schedule.js +14 -3
  69. package/src/tasks-runner/utils.d.ts +2 -2
  70. package/src/tasks-runner/utils.d.ts.map +1 -1
  71. package/src/tasks-runner/utils.js +5 -7
  72. package/src/utils/package-json.js +2 -2
  73. package/src/utils/provenance.d.ts.map +1 -1
  74. package/src/utils/provenance.js +2 -2
  75. package/src/utils/split-target.d.ts +13 -2
  76. package/src/utils/split-target.d.ts.map +1 -1
  77. 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. Scanning each plugin's results for project-name references in
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
- * Substitutors are indexed by the **referenced name as it appeared in
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 *referenced project name at registration time* → set of
34
- // substitutor entries that should run when a project is renamed FROM
35
- // that name. Keying by name (not root) means no project-map lookup is
36
- // needed at registration time, and ordering between result entries does
37
- // not matter.
38
- this.projectNameSubstitutors = new Map();
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
- // Projects whose names changed during the merge phase. Key = root of the
54
- // renamed project, value = all names it previously held in this merge.
55
- // These are used in applySubstitutions to locate substitutors keyed by
56
- // old names.
57
- this.dirtyEntries = new Map();
58
- // Partial project graph nodes accumulated across plugin registrations.
59
- // Used by splitTargetFromNodes to properly parse string-form dependsOn
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
- const substitutors = this.projectNameSubstitutors.get(item.referencedName);
66
- if (!substitutors) {
67
- return;
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
- substitutors.delete(item.entry);
70
- if (substitutors.size === 0) {
71
- this.projectNameSubstitutors.delete(item.referencedName);
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 keyed by `referencedName` (the project name
169
- // as it appears in the reference), tracked at (arrayKey, index, subIndex)
170
- // for deduplication and tail-clearing.
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
- substitutorsForName.add(entry);
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
- // Single project reference — store directly
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] = { referencedName, entry };
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
- * Project nodes from each call are accumulated internally so that
205
- * string-form `dependsOn` entries (e.g. `"project:target"`) can be
206
- * properly parsed with {@link splitTargetFromNodes}, even when project
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 splitTargetFromNodes with accumulated project nodes
346
- // to properly handle project / target names containing colons.
347
- if (!dep.startsWith('^')) {
348
- const [maybeProject, ...rest] = (0, split_target_1.splitTargetFromNodes)(dep, this.knownProjectNodes);
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 the project at `root` was renamed from `previousName`.
388
- * Substitutors registered for `previousName` will fire during
389
- * {@link applySubstitutions}.
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
- markDirty(root, previousName) {
392
- let previousNames = this.dirtyEntries.get(root);
393
- if (!previousNames) {
394
- previousNames = new Set();
395
- this.dirtyEntries.set(root, previousNames);
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 [root, previousNames] of this.dirtyEntries) {
451
+ for (const root of this.dirtyRoots) {
406
452
  const finalName = rootMap[root]?.name;
407
453
  if (!finalName) {
408
454
  continue;
409
455
  }
410
- for (const previousName of previousNames) {
411
- const substitutors = this.projectNameSubstitutors.get(previousName);
412
- if (!substitutors) {
413
- continue;
414
- }
415
- for (const { ownerRoot, substitutor } of substitutors) {
416
- // Each entry stores the ownerRoot of the project holding the stale
417
- // reference so we can look up its final merged config here.
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