nx 22.7.0 → 23.0.0-beta.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/dist/src/config/workspace-json-project-json.d.ts +10 -0
- package/dist/src/daemon/server/handle-hash-tasks.js +1 -1
- package/dist/src/daemon/server/project-graph-incremental-recomputation.d.ts +1 -4
- package/dist/src/daemon/server/project-graph-incremental-recomputation.js +11 -20
- package/dist/src/executors/utils/convert-nx-executor.js +2 -2
- package/dist/src/hasher/create-task-hasher.js +1 -1
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/project-graph/build-project-graph.d.ts +2 -4
- package/dist/src/project-graph/build-project-graph.js +2 -7
- package/dist/src/project-graph/file-map-utils.d.ts +2 -4
- package/dist/src/project-graph/file-map-utils.js +0 -3
- package/dist/src/project-graph/plugins/get-plugins.d.ts +15 -0
- package/dist/src/project-graph/plugins/get-plugins.js +21 -3
- package/dist/src/project-graph/project-graph.js +7 -6
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +40 -64
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.js +182 -411
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +10 -4
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +22 -8
- package/dist/src/project-graph/utils/project-configuration/source-maps.d.ts +4 -61
- package/dist/src/project-graph/utils/project-configuration/source-maps.js +14 -59
- package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +16 -0
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +117 -0
- package/dist/src/project-graph/utils/project-configuration/target-merging.d.ts +1 -4
- package/dist/src/project-graph/utils/project-configuration/target-merging.js +261 -136
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +0 -7
- package/dist/src/project-graph/utils/project-configuration/utils.d.ts +23 -0
- package/dist/src/project-graph/utils/project-configuration/utils.js +164 -0
- package/dist/src/project-graph/utils/project-configuration-utils.d.ts +33 -9
- package/dist/src/project-graph/utils/project-configuration-utils.js +153 -65
- package/dist/src/project-graph/utils/retrieve-workspace-files.d.ts +6 -3
- package/dist/src/project-graph/utils/retrieve-workspace-files.js +32 -13
- package/package.json +11 -11
|
@@ -1,468 +1,239 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ProjectNameInNodePropsManager = void 0;
|
|
3
|
+
exports.ProjectNameInNodePropsManager = exports.UsageRef = exports.RootRef = exports.NameRef = void 0;
|
|
4
|
+
exports.isNameRef = isNameRef;
|
|
5
|
+
exports.isRootRef = isRootRef;
|
|
6
|
+
exports.isUsageRef = isUsageRef;
|
|
4
7
|
const globs_1 = require("../../../utils/globs");
|
|
5
8
|
const split_target_1 = require("../../../utils/split-target");
|
|
6
|
-
const minimatch_1 = require("minimatch");
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* `dependsOn`
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
* Sentinel placed in `inputs` / `dependsOn` for a pending project-name
|
|
11
|
+
* reference. `RootRef` carries the referenced project's root (resolved
|
|
12
|
+
* via nameMap lookup); `UsageRef` carries the raw written name (for
|
|
13
|
+
* forward refs, promoted to `RootRef` in place when the name is
|
|
14
|
+
* identified). `parent` + `key` let the final pass write the resolved
|
|
15
|
+
* name back; `targetPart` preserves the `:target` suffix from
|
|
16
|
+
* `dependsOn` strings.
|
|
17
|
+
*/
|
|
18
|
+
class NameRef {
|
|
19
|
+
constructor(value, parent, key, targetPart) {
|
|
20
|
+
this.value = value;
|
|
21
|
+
this.parent = parent;
|
|
22
|
+
this.key = key;
|
|
23
|
+
this.targetPart = targetPart;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.NameRef = NameRef;
|
|
27
|
+
class RootRef extends NameRef {
|
|
28
|
+
}
|
|
29
|
+
exports.RootRef = RootRef;
|
|
30
|
+
class UsageRef extends NameRef {
|
|
31
|
+
}
|
|
32
|
+
exports.UsageRef = UsageRef;
|
|
33
|
+
function isNameRef(value) {
|
|
34
|
+
return value instanceof NameRef;
|
|
35
|
+
}
|
|
36
|
+
function isRootRef(value) {
|
|
37
|
+
return value instanceof RootRef;
|
|
38
|
+
}
|
|
39
|
+
function isUsageRef(value) {
|
|
40
|
+
return value instanceof UsageRef;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Replaces project-name refs in plugin results with in-place sentinels,
|
|
44
|
+
* then resolves them after all merging is done.
|
|
18
45
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* `inputs` and `dependsOn` ({@link registerSubstitutorsForNodeResults}).
|
|
26
|
-
* 4. After all results are merged, applying the substitutors for every
|
|
27
|
-
* renamed project so that references are updated to the final name
|
|
28
|
-
* ({@link applySubstitutions}).
|
|
46
|
+
* Tracking by array position breaks once `'...'` spreads shuffle indices,
|
|
47
|
+
* so each ref becomes a sentinel object. Arrays spread-merge by pushing
|
|
48
|
+
* element references, so sentinel identity survives any downstream
|
|
49
|
+
* merges — the final pass walks a flat registry and writes the resolved
|
|
50
|
+
* name back through each sentinel's `parent` back-reference. Orphaned
|
|
51
|
+
* sentinels (from arrays dropped by a full-replace) write harmlessly.
|
|
29
52
|
*/
|
|
30
53
|
class ProjectNameInNodePropsManager {
|
|
31
54
|
constructor(getNameMap) {
|
|
32
|
-
|
|
33
|
-
|
|
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();
|
|
38
|
-
// Tracks substitutor entries by (array path, index, subIndex). This
|
|
39
|
-
// serves two purposes:
|
|
40
|
-
//
|
|
41
|
-
// 1. Per-index deduplication: if the same array index is registered
|
|
42
|
-
// again (e.g. two plugin results contribute to the same position),
|
|
43
|
-
// the old substitutor is evicted before the new one is added.
|
|
44
|
-
//
|
|
45
|
-
// 2. Tail-clearing: when a later plugin provides a shorter array at the
|
|
46
|
-
// same path, splice removes all tail entries in one call.
|
|
47
|
-
//
|
|
48
|
-
// Outer key: array path (e.g. "proj-a:targets.build.inputs")
|
|
49
|
-
// Inner array: indexed by position; each slot holds an array so that a
|
|
50
|
-
// single `projects` array can hold multiple name references.
|
|
51
|
-
this.substitutorsByArrayKey = new Map();
|
|
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();
|
|
55
|
+
this.allRefs = new Set();
|
|
56
|
+
this.pendingByName = new Map();
|
|
58
57
|
this.getNameMap = getNameMap ?? (() => ({}));
|
|
59
58
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (substitutors.size === 0) {
|
|
66
|
-
this.substitutorsByReferencedRoot.delete(item.referencedRoot);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
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
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
// Removes the substitutor registered at the given index (and optional
|
|
81
|
-
// subIndex) of an array, if any. Used when re-registering for the same
|
|
82
|
-
// position (overwritten by a later plugin).
|
|
83
|
-
clearSubstitutorAtIndex(arrayKey, index, subIndex) {
|
|
84
|
-
const byIndex = this.substitutorsByArrayKey.get(arrayKey);
|
|
85
|
-
const atIndex = byIndex?.[index];
|
|
86
|
-
if (!atIndex) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
if (subIndex === undefined) {
|
|
90
|
-
// Clear the entire index entry (single project reference)
|
|
91
|
-
for (const item of atIndex) {
|
|
92
|
-
if (item) {
|
|
93
|
-
this.removeSubstitutorEntry(item);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
byIndex[index] = undefined;
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
// Clear only the specific subIndex (within a projects array)
|
|
100
|
-
const existing = atIndex[subIndex];
|
|
101
|
-
if (existing) {
|
|
102
|
-
this.removeSubstitutorEntry(existing);
|
|
103
|
-
atIndex[subIndex] = undefined;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// Removes all substitutors at indices >= `fromIndex` for the given array
|
|
108
|
-
// path. Uses splice so the tail is dropped in one operation.
|
|
109
|
-
clearSubstitutorsFromIndex(arrayKey, fromIndex) {
|
|
110
|
-
const byIndex = this.substitutorsByArrayKey.get(arrayKey);
|
|
111
|
-
if (!byIndex) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
const removed = byIndex.splice(fromIndex);
|
|
115
|
-
for (const atIndex of removed) {
|
|
116
|
-
if (atIndex) {
|
|
117
|
-
for (const item of atIndex) {
|
|
118
|
-
if (item) {
|
|
119
|
-
this.removeSubstitutorEntry(item);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
// Removes all substitutors at sub-indices >= `fromSubIndex` for one
|
|
126
|
-
// specific array index of the given array key.
|
|
127
|
-
clearSubstitutorsFromSubIndex(arrayKey, index, fromSubIndex) {
|
|
128
|
-
const byIndex = this.substitutorsByArrayKey.get(arrayKey);
|
|
129
|
-
const atIndex = byIndex?.[index];
|
|
130
|
-
if (!atIndex) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
const removed = atIndex.splice(fromSubIndex);
|
|
134
|
-
for (const item of removed) {
|
|
135
|
-
if (item) {
|
|
136
|
-
this.removeSubstitutorEntry(item);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
let hasAnyItem = false;
|
|
140
|
-
for (const item of atIndex) {
|
|
141
|
-
if (item) {
|
|
142
|
-
hasAnyItem = true;
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
if (!hasAnyItem) {
|
|
147
|
-
byIndex[index] = undefined;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
forEachTargetConfig(ownerConfig, targetName, callback) {
|
|
151
|
-
const ownerTargets = ownerConfig.targets;
|
|
152
|
-
if (!ownerTargets) {
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
const exactMatch = ownerTargets[targetName];
|
|
156
|
-
if (exactMatch && typeof exactMatch === 'object') {
|
|
157
|
-
callback(exactMatch);
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
if (!(0, globs_1.isGlobPattern)(targetName)) {
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
for (const candidateTargetName in ownerTargets) {
|
|
164
|
-
if (!(0, minimatch_1.minimatch)(candidateTargetName, targetName)) {
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
const targetConfig = ownerTargets[candidateTargetName];
|
|
168
|
-
if (!targetConfig || typeof targetConfig !== 'object') {
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
callback(targetConfig);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
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.
|
|
178
|
-
registerProjectNameSubstitutor(referencedName, ownerRoot, arrayKey, index, substitutor, subIndex) {
|
|
179
|
-
// Evict any existing substitutor at this exact position first.
|
|
180
|
-
this.clearSubstitutorAtIndex(arrayKey, index, subIndex);
|
|
181
|
-
const entry = { ownerRoot, substitutor };
|
|
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
|
-
}
|
|
205
|
-
let byIndex = this.substitutorsByArrayKey.get(arrayKey);
|
|
206
|
-
if (!byIndex) {
|
|
207
|
-
byIndex = [];
|
|
208
|
-
this.substitutorsByArrayKey.set(arrayKey, byIndex);
|
|
209
|
-
}
|
|
210
|
-
if (subIndex === undefined) {
|
|
211
|
-
byIndex[index] = [trackingItem];
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
if (!byIndex[index]) {
|
|
215
|
-
byIndex[index] = [];
|
|
216
|
-
}
|
|
217
|
-
const subArray = byIndex[index];
|
|
218
|
-
subArray[subIndex] = trackingItem;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Scans `pluginResultProjects` for `inputs` and `dependsOn` entries that
|
|
223
|
-
* reference another project by name, and registers substitutors so those
|
|
224
|
-
* references are updated if the target project is later renamed.
|
|
225
|
-
*
|
|
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.
|
|
229
|
-
*
|
|
230
|
-
* @param pluginResultProjects Projects from a single plugin's createNodes call.
|
|
231
|
-
*/
|
|
232
|
-
registerSubstitutorsForNodeResults(pluginResultProjects) {
|
|
233
|
-
if (!pluginResultProjects) {
|
|
59
|
+
// Replaces each project-name ref in `inputs`/`dependsOn` with a sentinel.
|
|
60
|
+
// Call after `identifyProjectWithRoot` for the batch so same-batch forward
|
|
61
|
+
// refs resolve straight to RootRefs.
|
|
62
|
+
registerNameRefs(pluginResultProjects) {
|
|
63
|
+
if (!pluginResultProjects)
|
|
234
64
|
return;
|
|
235
|
-
}
|
|
236
65
|
for (const ownerRoot in pluginResultProjects) {
|
|
237
66
|
const project = pluginResultProjects[ownerRoot];
|
|
238
|
-
if (!project
|
|
67
|
+
if (!project?.targets)
|
|
239
68
|
continue;
|
|
240
|
-
}
|
|
241
69
|
for (const targetName in project.targets) {
|
|
242
70
|
const targetConfig = project.targets[targetName];
|
|
243
|
-
if (!targetConfig || typeof targetConfig !== 'object')
|
|
71
|
+
if (!targetConfig || typeof targetConfig !== 'object')
|
|
244
72
|
continue;
|
|
245
|
-
}
|
|
246
73
|
if (Array.isArray(targetConfig.inputs)) {
|
|
247
|
-
this.
|
|
74
|
+
this.processInputs(targetConfig.inputs);
|
|
248
75
|
}
|
|
249
76
|
if (Array.isArray(targetConfig.dependsOn)) {
|
|
250
|
-
this.
|
|
77
|
+
this.processDependsOn(targetConfig.dependsOn, project.targets, project.name);
|
|
251
78
|
}
|
|
252
79
|
}
|
|
253
80
|
}
|
|
254
81
|
}
|
|
255
|
-
|
|
256
|
-
// ensures that index variables (i, j) are captured as function parameters
|
|
257
|
-
// (always by value), preventing closure-over-loop-variable bugs.
|
|
258
|
-
createInputsStringSubstitutor(targetName, i) {
|
|
259
|
-
return (finalName, ownerConfig) => {
|
|
260
|
-
this.forEachTargetConfig(ownerConfig, targetName, (targetConfig) => {
|
|
261
|
-
const finalInput = targetConfig.inputs?.[i];
|
|
262
|
-
if (finalInput &&
|
|
263
|
-
typeof finalInput === 'object' &&
|
|
264
|
-
'projects' in finalInput) {
|
|
265
|
-
finalInput.projects = finalName;
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
createInputsArraySubstitutor(targetName, i, j) {
|
|
271
|
-
return (finalName, ownerConfig) => {
|
|
272
|
-
this.forEachTargetConfig(ownerConfig, targetName, (targetConfig) => {
|
|
273
|
-
const finalInput = targetConfig.inputs?.[i];
|
|
274
|
-
if (finalInput &&
|
|
275
|
-
typeof finalInput === 'object' &&
|
|
276
|
-
'projects' in finalInput) {
|
|
277
|
-
finalInput['projects'][j] = finalName;
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
createDependsOnStringSubstitutor(targetName, i) {
|
|
283
|
-
return (finalName, ownerConfig) => {
|
|
284
|
-
this.forEachTargetConfig(ownerConfig, targetName, (targetConfig) => {
|
|
285
|
-
const finalDep = targetConfig.dependsOn?.[i];
|
|
286
|
-
if (finalDep &&
|
|
287
|
-
typeof finalDep === 'object' &&
|
|
288
|
-
'projects' in finalDep) {
|
|
289
|
-
finalDep.projects = finalName;
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
createDependsOnArraySubstitutor(targetName, i, j) {
|
|
295
|
-
return (finalName, ownerConfig) => {
|
|
296
|
-
this.forEachTargetConfig(ownerConfig, targetName, (targetConfig) => {
|
|
297
|
-
const finalDep = targetConfig.dependsOn?.[i];
|
|
298
|
-
if (finalDep &&
|
|
299
|
-
typeof finalDep === 'object' &&
|
|
300
|
-
'projects' in finalDep) {
|
|
301
|
-
finalDep['projects'][j] = finalName;
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
createDependsOnTargetStringSubstitutor(targetName, i, targetPart) {
|
|
307
|
-
return (finalName, ownerConfig) => {
|
|
308
|
-
this.forEachTargetConfig(ownerConfig, targetName, (targetConfig) => {
|
|
309
|
-
const finalDep = targetConfig.dependsOn?.[i];
|
|
310
|
-
if (typeof finalDep === 'string') {
|
|
311
|
-
targetConfig.dependsOn[i] =
|
|
312
|
-
`${finalName}:${targetPart}`;
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
registerSubstitutorsForInputs(ownerRoot, targetName, inputs) {
|
|
318
|
-
const arrayKey = `${ownerRoot}:targets.${targetName}.inputs`;
|
|
82
|
+
processInputs(inputs) {
|
|
319
83
|
for (let i = 0; i < inputs.length; i++) {
|
|
320
|
-
const
|
|
321
|
-
|
|
84
|
+
const entry = inputs[i];
|
|
85
|
+
// Existing sentinel: spread merges may have copied it out of its
|
|
86
|
+
// original array, so rebind parent to this one.
|
|
87
|
+
if (isNameRef(entry)) {
|
|
88
|
+
entry.parent = inputs;
|
|
322
89
|
continue;
|
|
323
90
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
91
|
+
if (!entry || typeof entry !== 'object')
|
|
92
|
+
continue;
|
|
93
|
+
if (!('projects' in entry))
|
|
94
|
+
continue;
|
|
95
|
+
const element = entry;
|
|
96
|
+
const projects = element.projects;
|
|
97
|
+
if (isNameRef(projects)) {
|
|
98
|
+
// Object-parent sentinel — element identity is stable across spread.
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (typeof projects === 'string') {
|
|
102
|
+
if (projects === 'self' || projects === 'dependencies')
|
|
329
103
|
continue;
|
|
330
|
-
|
|
331
|
-
this.registerProjectNameSubstitutor(inputProjectNames, ownerRoot, arrayKey, i, this.createInputsStringSubstitutor(targetName, i));
|
|
104
|
+
element.projects = this.createRef(projects, element, 'projects');
|
|
332
105
|
}
|
|
333
|
-
else if (Array.isArray(
|
|
334
|
-
|
|
335
|
-
const projectName = inputProjectNames[j];
|
|
336
|
-
this.registerProjectNameSubstitutor(projectName, ownerRoot, arrayKey, i, this.createInputsArraySubstitutor(targetName, i, j), j // subIndex for array elements
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
|
-
// Clear stale sub-indices if a later plugin shrinks the array.
|
|
340
|
-
this.clearSubstitutorsFromSubIndex(arrayKey, i, inputProjectNames.length);
|
|
106
|
+
else if (Array.isArray(projects)) {
|
|
107
|
+
this.processProjectsArray(projects);
|
|
341
108
|
}
|
|
342
109
|
}
|
|
343
|
-
// Evict any dangling substitutors at indices beyond the new array length —
|
|
344
|
-
// the array may have shrunk compared to a previous plugin's contribution.
|
|
345
|
-
this.clearSubstitutorsFromIndex(arrayKey, inputs.length);
|
|
346
110
|
}
|
|
347
|
-
|
|
348
|
-
const arrayKey = `${ownerRoot}:targets.${targetName}.dependsOn`;
|
|
111
|
+
processDependsOn(dependsOn, ownerTargets, ownerName) {
|
|
349
112
|
for (let i = 0; i < dependsOn.length; i++) {
|
|
350
113
|
const dep = dependsOn[i];
|
|
114
|
+
// Existing sentinel: rebind parent to this array in case a spread
|
|
115
|
+
// merge copied it out of its original.
|
|
116
|
+
if (isNameRef(dep)) {
|
|
117
|
+
dep.parent = dependsOn;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
351
120
|
if (typeof dep === 'string') {
|
|
352
|
-
//
|
|
353
|
-
|
|
354
|
-
|
|
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 });
|
|
362
|
-
if (rest.length > 0) {
|
|
363
|
-
const targetPart = rest.join(':');
|
|
364
|
-
this.registerProjectNameSubstitutor(maybeProject, ownerRoot, arrayKey, i, this.createDependsOnTargetStringSubstitutor(targetName, i, targetPart));
|
|
365
|
-
}
|
|
121
|
+
// `^target` and same-project targets aren't cross-project refs.
|
|
122
|
+
if (dep.startsWith('^') || (ownerTargets && dep in ownerTargets)) {
|
|
123
|
+
continue;
|
|
366
124
|
}
|
|
125
|
+
const [maybeProject, ...rest] = (0, split_target_1.splitTargetFromConfigurations)(dep, this.getNameMap(), { silent: true, currentProject: ownerName });
|
|
126
|
+
if (rest.length === 0)
|
|
127
|
+
continue;
|
|
128
|
+
const targetPart = rest.join(':');
|
|
129
|
+
dependsOn[i] = this.createRef(maybeProject, dependsOn, undefined, targetPart);
|
|
367
130
|
continue;
|
|
368
131
|
}
|
|
369
|
-
if (typeof dep !== 'object' || !dep
|
|
132
|
+
if (!dep || typeof dep !== 'object' || !('projects' in dep))
|
|
133
|
+
continue;
|
|
134
|
+
const element = dep;
|
|
135
|
+
const projects = element.projects;
|
|
136
|
+
if (isNameRef(projects)) {
|
|
370
137
|
continue;
|
|
371
138
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
139
|
+
if (typeof projects === 'string') {
|
|
140
|
+
if (projects === '*' ||
|
|
141
|
+
projects === 'self' ||
|
|
142
|
+
projects === 'dependencies') {
|
|
376
143
|
continue;
|
|
377
144
|
}
|
|
378
|
-
|
|
145
|
+
element.projects = this.createRef(projects, element, 'projects');
|
|
379
146
|
}
|
|
380
|
-
else if (Array.isArray(
|
|
381
|
-
|
|
382
|
-
// to a single project name at this stage, so we skip them.
|
|
383
|
-
for (let j = 0; j < depProjects.length; j++) {
|
|
384
|
-
const projectName = depProjects[j];
|
|
385
|
-
if ((0, globs_1.isGlobPattern)(projectName)) {
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
this.registerProjectNameSubstitutor(projectName, ownerRoot, arrayKey, i, this.createDependsOnArraySubstitutor(targetName, i, j), j // subIndex for array elements
|
|
389
|
-
);
|
|
390
|
-
}
|
|
391
|
-
// Clear stale sub-indices if a later plugin shrinks the array.
|
|
392
|
-
this.clearSubstitutorsFromSubIndex(arrayKey, i, depProjects.length);
|
|
147
|
+
else if (Array.isArray(projects)) {
|
|
148
|
+
this.processProjectsArray(projects);
|
|
393
149
|
}
|
|
394
150
|
}
|
|
395
|
-
// Evict any dangling substitutors at indices beyond the new array length —
|
|
396
|
-
// the array may have shrunk compared to a previous plugin's contribution.
|
|
397
|
-
this.clearSubstitutorsFromIndex(arrayKey, dependsOn.length);
|
|
398
151
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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.
|
|
408
|
-
*/
|
|
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);
|
|
152
|
+
processProjectsArray(projects) {
|
|
153
|
+
for (let j = 0; j < projects.length; j++) {
|
|
154
|
+
const name = projects[j];
|
|
155
|
+
if (isNameRef(name)) {
|
|
156
|
+
name.parent = projects;
|
|
157
|
+
continue;
|
|
427
158
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
159
|
+
if (typeof name !== 'string')
|
|
160
|
+
continue;
|
|
161
|
+
if ((0, globs_1.isGlobPattern)(name))
|
|
162
|
+
continue;
|
|
163
|
+
projects[j] = this.createRef(name, projects, undefined);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Builds a sentinel and registers it.
|
|
167
|
+
createRef(referencedName, parent, key, targetPart) {
|
|
168
|
+
const referencedRoot = this.getNameMap()[referencedName]?.root;
|
|
169
|
+
const ref = referencedRoot !== undefined
|
|
170
|
+
? new RootRef(referencedRoot, parent, key, targetPart)
|
|
171
|
+
: new UsageRef(referencedName, parent, key, targetPart);
|
|
172
|
+
this.allRefs.add(ref);
|
|
173
|
+
if (ref instanceof UsageRef) {
|
|
174
|
+
let set = this.pendingByName.get(referencedName);
|
|
175
|
+
if (!set) {
|
|
176
|
+
set = new Set();
|
|
177
|
+
this.pendingByName.set(referencedName, set);
|
|
442
178
|
}
|
|
179
|
+
set.add(ref);
|
|
443
180
|
}
|
|
181
|
+
return ref;
|
|
444
182
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
183
|
+
// Records `name` → `root` and promotes any waiting UsageRef sentinels to
|
|
184
|
+
// RootRef by prototype swap. Sentinel identity across spread copies means
|
|
185
|
+
// one promotion updates every array the sentinel reached.
|
|
186
|
+
identifyProjectWithRoot(root, name) {
|
|
187
|
+
const pending = this.pendingByName.get(name);
|
|
188
|
+
if (!pending)
|
|
189
|
+
return;
|
|
190
|
+
this.pendingByName.delete(name);
|
|
191
|
+
for (const ref of pending) {
|
|
192
|
+
if (!(ref instanceof UsageRef))
|
|
454
193
|
continue;
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
194
|
+
Object.setPrototypeOf(ref, RootRef.prototype);
|
|
195
|
+
ref.value = root;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Writes each sentinel's current resolved name back into its owning slot.
|
|
199
|
+
// Called once after all plugin results have been merged.
|
|
200
|
+
applySubstitutions(rootMap) {
|
|
201
|
+
const nameByRoot = {};
|
|
202
|
+
for (const root in rootMap) {
|
|
203
|
+
nameByRoot[root] = rootMap[root]?.name;
|
|
204
|
+
}
|
|
205
|
+
for (const ref of this.allRefs) {
|
|
206
|
+
const finalName = this.resolveFinalName(ref, nameByRoot);
|
|
207
|
+
if (finalName === undefined)
|
|
458
208
|
continue;
|
|
209
|
+
const replacement = ref.targetPart !== undefined
|
|
210
|
+
? `${finalName}:${ref.targetPart}`
|
|
211
|
+
: finalName;
|
|
212
|
+
this.writeReplacement(ref, replacement);
|
|
213
|
+
}
|
|
214
|
+
this.allRefs.clear();
|
|
215
|
+
this.pendingByName.clear();
|
|
216
|
+
}
|
|
217
|
+
resolveFinalName(ref, nameByRoot) {
|
|
218
|
+
if (ref instanceof RootRef) {
|
|
219
|
+
return nameByRoot[ref.value];
|
|
220
|
+
}
|
|
221
|
+
// Unpromoted forward ref — best effort, fall back to the written name.
|
|
222
|
+
return this.getNameMap()[ref.value]?.name ?? ref.value;
|
|
223
|
+
}
|
|
224
|
+
writeReplacement(ref, replacement) {
|
|
225
|
+
const parent = ref.parent;
|
|
226
|
+
if (Array.isArray(parent)) {
|
|
227
|
+
// One sentinel may appear at multiple indices (e.g. `[..., ...]`
|
|
228
|
+
// pushed the same reference twice via spread), so replace all.
|
|
229
|
+
for (let i = 0; i < parent.length; i++) {
|
|
230
|
+
if (parent[i] === ref)
|
|
231
|
+
parent[i] = replacement;
|
|
459
232
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
}
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (parent && typeof parent === 'object' && ref.key !== undefined) {
|
|
236
|
+
parent[ref.key] = replacement;
|
|
466
237
|
}
|
|
467
238
|
}
|
|
468
239
|
}
|