nx 23.1.0 → 23.1.1
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/bin/nx.js +2 -1
- package/dist/src/ai/configure-ai-agents-disclaimer.d.ts +5 -0
- package/dist/src/ai/configure-ai-agents-disclaimer.js +31 -0
- package/dist/src/analytics/analytics.d.ts +6 -0
- package/dist/src/analytics/analytics.js +16 -8
- package/dist/src/analytics/index.d.ts +1 -1
- package/dist/src/analytics/index.js +2 -1
- package/dist/src/command-line/add/add.js +8 -1
- package/dist/src/command-line/graph/graph.d.ts +1 -0
- package/dist/src/command-line/graph/graph.js +15 -6
- package/dist/src/command-line/import/import.js +1 -1
- package/dist/src/command-line/init/ai-agent-prompts.d.ts +1 -1
- package/dist/src/command-line/init/ai-agent-prompts.js +7 -6
- package/dist/src/command-line/init/command-object.js +10 -2
- package/dist/src/command-line/init/configure-plugins.js +3 -2
- package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +4 -2
- package/dist/src/command-line/init/implementation/add-nx-to-nest.js +4 -3
- package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +4 -3
- package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +4 -3
- package/dist/src/command-line/init/implementation/angular/index.js +4 -2
- package/dist/src/command-line/init/implementation/angular/integrated-workspace.js +2 -5
- package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +3 -0
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +4 -1
- package/dist/src/command-line/init/implementation/utils.d.ts +3 -3
- package/dist/src/command-line/init/implementation/utils.js +22 -3
- package/dist/src/command-line/migrate/execute-migration.d.ts +72 -0
- package/dist/src/command-line/migrate/execute-migration.js +389 -0
- package/dist/src/command-line/migrate/migrate-ui-api.js +17 -12
- package/dist/src/command-line/migrate/migrate.d.ts +1 -45
- package/dist/src/command-line/migrate/migrate.js +33 -376
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +1 -1
- package/dist/src/command-line/nx-cloud/connect/view-logs.js +2 -0
- package/dist/src/command-line/release/utils/git.js +6 -2
- package/dist/src/command-line/release/utils/release-graph.d.ts +2 -2
- package/dist/src/command-line/release/utils/remote-release-clients/github.js +1 -1
- package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +1 -1
- package/dist/src/command-line/release/utils/shared.d.ts +2 -2
- package/dist/src/command-line/show/show-target/info.js +11 -2
- package/dist/src/command-line/show/show-target/inputs.js +50 -153
- package/dist/src/command-line/show/show-target/outputs.js +48 -173
- package/dist/src/command-line/show/show-target/utils.d.ts +28 -0
- package/dist/src/command-line/show/show-target/utils.js +83 -3
- package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
- package/dist/src/commands-runner/create-command-graph.js +5 -0
- package/dist/src/config/nx-json.d.ts +5 -3
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/daemon/client/client.d.ts +0 -2
- package/dist/src/daemon/client/client.js +17 -19
- package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +1 -1
- package/dist/src/daemon/server/server.js +7 -4
- package/dist/src/devkit-internals.d.ts +3 -0
- package/dist/src/devkit-internals.js +10 -1
- package/dist/src/generators/utils/nx-json.js +13 -3
- package/dist/src/hasher/check-task-files.d.ts +86 -0
- package/dist/src/hasher/check-task-files.js +378 -0
- package/dist/src/native/index.d.ts +21 -2
- package/dist/src/native/native-bindings.js +2 -0
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/plugins/js/lock-file/npm-parser.js +71 -27
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +50 -17
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +1 -1
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +3 -0
- package/dist/src/plugins/js/lock-file/yarn-parser.js +32 -5
- package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +12 -4
- package/dist/src/plugins/js/utils/register.d.ts +18 -0
- package/dist/src/plugins/js/utils/register.js +81 -0
- package/dist/src/plugins/js/utils/typescript.d.ts +9 -0
- package/dist/src/plugins/js/utils/typescript.js +15 -0
- package/dist/src/project-graph/build-project-graph.js +7 -1
- package/dist/src/project-graph/error-types.js +41 -1
- package/dist/src/project-graph/file-utils.js +6 -1
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +4 -0
- package/dist/src/project-graph/plugins/loaded-nx-plugin.js +1 -0
- package/dist/src/project-graph/plugins/transpiler.js +4 -0
- package/dist/src/project-graph/project-graph.js +3 -0
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +10 -12
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.js +93 -63
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +5 -8
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +11 -14
- package/dist/src/project-graph/utils/project-configuration/source-maps.d.ts +12 -5
- package/dist/src/project-graph/utils/project-configuration/source-maps.js +21 -7
- package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +1 -1
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +26 -27
- package/dist/src/project-graph/utils/project-configuration/target-merging.js +50 -8
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +16 -3
- package/dist/src/project-graph/utils/project-configuration/utils.d.ts +15 -0
- package/dist/src/project-graph/utils/project-configuration/utils.js +42 -6
- package/dist/src/project-graph/utils/project-configuration-utils.d.ts +15 -12
- package/dist/src/project-graph/utils/project-configuration-utils.js +79 -101
- package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +11 -4
- package/dist/src/tasks-runner/life-cycles/performance-analysis.js +15 -6
- package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +5 -4
- package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +18 -8
- package/dist/src/tasks-runner/life-cycles/performance-report.js +66 -29
- package/dist/src/tasks-runner/run-command.js +4 -2
- package/dist/src/tasks-runner/task-env.d.ts +9 -0
- package/dist/src/tasks-runner/task-env.js +26 -2
- package/dist/src/tasks-runner/task-orchestrator.d.ts +4 -1
- package/dist/src/tasks-runner/task-orchestrator.js +23 -10
- package/dist/src/utils/acknowledge-build-scripts.d.ts +13 -0
- package/dist/src/utils/acknowledge-build-scripts.js +102 -0
- package/dist/src/utils/analytics-prompt.d.ts +0 -6
- package/dist/src/utils/analytics-prompt.js +0 -51
- package/dist/src/utils/catalog/manager-utils.d.ts +1 -2
- package/dist/src/utils/catalog/manager-utils.js +22 -5
- package/dist/src/utils/catalog/pnpm-manager.d.ts +1 -0
- package/dist/src/utils/catalog/pnpm-manager.js +3 -15
- package/dist/src/utils/catalog/yarn-manager.d.ts +1 -0
- package/dist/src/utils/catalog/yarn-manager.js +3 -15
- package/dist/src/utils/command-line-utils.js +30 -20
- package/dist/src/utils/git-revision.d.ts +12 -0
- package/dist/src/utils/git-revision.js +25 -0
- package/dist/src/utils/git-utils.d.ts +16 -3
- package/dist/src/utils/git-utils.js +146 -52
- package/dist/src/utils/min-release-age/behavior/pnpm.js +9 -7
- package/dist/src/utils/package-json.js +11 -7
- package/dist/src/utils/package-manager.d.ts +3 -1
- package/dist/src/utils/package-manager.js +28 -4
- package/dist/src/utils/provenance.js +12 -2
- package/dist/src/utils/workspace-id.d.ts +20 -0
- package/dist/src/utils/workspace-id.js +54 -0
- package/migrations.json +7 -1
- package/package.json +22 -17
- package/dist/src/migrations/update-17-3-0/nx-release-path.d.ts +0 -3
- package/dist/src/migrations/update-17-3-0/nx-release-path.js +0 -47
|
@@ -21,14 +21,28 @@ exports.targetConfigurationsSourceMapKey = targetConfigurationsSourceMapKey;
|
|
|
21
21
|
*/
|
|
22
22
|
exports.TARGET_DEFAULTS_PLUGIN_NAME = 'nx/target-defaults';
|
|
23
23
|
/**
|
|
24
|
-
* Write the source for
|
|
25
|
-
* its
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* Write the source for the target node key (`targets.<name>`). Ownership of a
|
|
25
|
+
* target follows its identity, not the last writer:
|
|
26
|
+
*
|
|
27
|
+
* - An unowned key goes to whoever writes it first (the creator).
|
|
28
|
+
* - A target-defaults stamp is weak — it never authors a target's existence,
|
|
29
|
+
* so any real plugin reclaims the key from it, and it can never take the
|
|
30
|
+
* key from a real plugin.
|
|
31
|
+
* - Between real plugins, the key only changes hands when the merge changed
|
|
32
|
+
* the target's identity (executor/command) — a plugin that merely layers
|
|
33
|
+
* fields (dependsOn, options, …) onto an existing target does not become
|
|
34
|
+
* its owner.
|
|
28
35
|
*/
|
|
29
|
-
function recordTargetIdentitySourceMapInfo(sourceMap, key, sourceInfo) {
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
function recordTargetIdentitySourceMapInfo(sourceMap, key, sourceInfo, identityChanged = false) {
|
|
37
|
+
const existing = sourceMap[key];
|
|
38
|
+
if (existing === undefined) {
|
|
39
|
+
sourceMap[key] = sourceInfo;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (sourceInfo[1] === exports.TARGET_DEFAULTS_PLUGIN_NAME) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (existing[1] === exports.TARGET_DEFAULTS_PLUGIN_NAME || identityChanged) {
|
|
32
46
|
sourceMap[key] = sourceInfo;
|
|
33
47
|
}
|
|
34
48
|
}
|
|
@@ -19,7 +19,7 @@ type CreateNodesResultEntry = readonly [
|
|
|
19
19
|
* fly. That's all the matcher needs; the full target merge happens
|
|
20
20
|
* downstream in the real merge.
|
|
21
21
|
*/
|
|
22
|
-
export declare function createTargetDefaultsResults(specifiedPluginRootMap: Record<string, ProjectConfiguration>, defaultPluginRootMap: Record<string, ProjectConfiguration>, nxJsonConfiguration: NxJsonConfiguration, specifiedSourceMaps?: ConfigurationSourceMaps
|
|
22
|
+
export declare function createTargetDefaultsResults(specifiedPluginRootMap: Record<string, ProjectConfiguration>, defaultPluginRootMap: Record<string, ProjectConfiguration>, nxJsonConfiguration: NxJsonConfiguration, specifiedSourceMaps?: ConfigurationSourceMaps): CreateNodesResultEntry[];
|
|
23
23
|
/**
|
|
24
24
|
* Public reader that resolves the target defaults applying to a given
|
|
25
25
|
* target. Accepts the nested map shape (a value is either a plain config
|
|
@@ -21,7 +21,7 @@ const utils_1 = require("./utils");
|
|
|
21
21
|
* fly. That's all the matcher needs; the full target merge happens
|
|
22
22
|
* downstream in the real merge.
|
|
23
23
|
*/
|
|
24
|
-
function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMap, nxJsonConfiguration, specifiedSourceMaps
|
|
24
|
+
function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMap, nxJsonConfiguration, specifiedSourceMaps) {
|
|
25
25
|
const targetDefaultsConfig = nxJsonConfiguration.targetDefaults;
|
|
26
26
|
if (!targetDefaultsConfig) {
|
|
27
27
|
return [];
|
|
@@ -65,7 +65,7 @@ function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMa
|
|
|
65
65
|
if (!effective)
|
|
66
66
|
continue;
|
|
67
67
|
const sourcePlugin = needsSourcePlugin
|
|
68
|
-
? resolveSourcePlugin(root, targetName,
|
|
68
|
+
? resolveSourcePlugin(root, targetName, defaultTargets[targetName], specifiedSourceMaps)
|
|
69
69
|
: undefined;
|
|
70
70
|
const syntheticTargets = buildSyntheticTargetsForRoot(targetName, root, effective, targetDefaults, projectName, projectNode, sourcePlugin);
|
|
71
71
|
for (const { key, index, target } of syntheticTargets) {
|
|
@@ -372,34 +372,33 @@ function normalizeTargetDefaultValue(value) {
|
|
|
372
372
|
// A bare config object is functionally a one-element array.
|
|
373
373
|
return [value ?? {}];
|
|
374
374
|
}
|
|
375
|
-
function resolveSourcePlugin(root, targetName,
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
//
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
//
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
375
|
+
function resolveSourcePlugin(root, targetName, defaultTarget, specifiedSourceMaps) {
|
|
376
|
+
// `filter.plugin` ("targets originated by X") can only name a plugin from
|
|
377
|
+
// nx.json's `plugins` — the specified set. When the default layer authors
|
|
378
|
+
// the target's identity (its merged config carries an executor or command,
|
|
379
|
+
// which the merge lets win), the originator is a default plugin and the
|
|
380
|
+
// target has no matchable source plugin; no source maps are needed to see
|
|
381
|
+
// that. Otherwise the specified layer's executor/command attribution names
|
|
382
|
+
// the originator. The top-level `targets.<name>` node key is deliberately
|
|
383
|
+
// NOT used as a fallback: it tracks ownership, so a later plugin augmenting
|
|
384
|
+
// the target would mis-attribute it. The trade-off is that a target with
|
|
385
|
+
// neither an executor nor a command (a rare, non-runnable shape) resolves to
|
|
386
|
+
// no source plugin and won't match a `filter.plugin` default — accepted,
|
|
387
|
+
// since every runnable target carries one of these keys.
|
|
388
|
+
if (defaultTarget &&
|
|
389
|
+
(defaultTarget.executor !== undefined ||
|
|
390
|
+
defaultTarget.command !== undefined)) {
|
|
391
|
+
return undefined;
|
|
392
|
+
}
|
|
393
|
+
const sourceMap = specifiedSourceMaps?.[root];
|
|
394
|
+
for (const identityKey of ['executor', 'command']) {
|
|
395
|
+
const plugin = sourceMap?.[`${(0, source_maps_1.targetSourceMapKey)(targetName)}.${identityKey}`]?.[1];
|
|
396
|
+
if (plugin && plugin !== source_maps_1.TARGET_DEFAULTS_PLUGIN_NAME) {
|
|
397
|
+
return plugin;
|
|
398
|
+
}
|
|
396
399
|
}
|
|
397
400
|
return undefined;
|
|
398
401
|
}
|
|
399
|
-
function pluginFromSourceMap(maps, root, key) {
|
|
400
|
-
const entry = maps?.[root]?.[key];
|
|
401
|
-
return entry?.[1];
|
|
402
|
-
}
|
|
403
402
|
// Builds a name → MatcherProjectNode view for `findMatchingProjects` to
|
|
404
403
|
// consult, across both layered rootMaps. Tags are unioned across layers. A
|
|
405
404
|
// full `mergeProjectConfigurationIntoRootMap` would be overkill — the matcher
|
|
@@ -170,6 +170,11 @@ function mergeConfigurations(newConfigurations, baseConfigurations, projectConfi
|
|
|
170
170
|
// Before '...': base wins for shared names. Keep base's source-map
|
|
171
171
|
// entries when it owns the config.
|
|
172
172
|
if (baseHasConfig) {
|
|
173
|
+
// Base wins, so the incoming config is dropped without reaching
|
|
174
|
+
// `mergeConfigurationValue`. Validate its nested spread here so an
|
|
175
|
+
// integer-like-key ambiguity throws regardless of which side owns
|
|
176
|
+
// the config name (mirrors the base-independent target-level check).
|
|
177
|
+
(0, utils_1.assertNoIntegerLikeSpreadKey)(newConfigurations?.[configName], configIdentifier ? `Object at "${configIdentifier}"` : 'Object');
|
|
173
178
|
mergedConfigurations[configName] = baseConfigurations[configName];
|
|
174
179
|
}
|
|
175
180
|
else {
|
|
@@ -282,8 +287,11 @@ function mergeTargetConfigurations(target, baseTarget, projectConfigSourceMap, s
|
|
|
282
287
|
? new Set(targetKeys.slice(0, spreadPosInTarget))
|
|
283
288
|
: new Set();
|
|
284
289
|
// Integer-like keys get hoisted to targetKeys[0], making their position
|
|
285
|
-
// relative to '...' unrecoverable.
|
|
286
|
-
|
|
290
|
+
// relative to '...' unrecoverable. This is a property of the authored
|
|
291
|
+
// config, not of the base, so it throws regardless of compatibility —
|
|
292
|
+
// which also keeps the error identical between the target-defaults staging
|
|
293
|
+
// merge and the real merge, whose bases differ.
|
|
294
|
+
if (spreadPosInTarget >= 0 &&
|
|
287
295
|
targetKeys[0] &&
|
|
288
296
|
utils_1.INTEGER_LIKE_KEY_PATTERN.test(targetKeys[0])) {
|
|
289
297
|
throw new utils_1.IntegerLikeSpreadKeyError(targetKeys[0], targetIdentifier ? `Target at "${targetIdentifier}"` : 'Target');
|
|
@@ -304,6 +312,13 @@ function mergeTargetConfigurations(target, baseTarget, projectConfigSourceMap, s
|
|
|
304
312
|
return;
|
|
305
313
|
if (hasSpread && keysBeforeSpread.has(key)) {
|
|
306
314
|
// Before '...': base wins; fall through to target only if base lacks it.
|
|
315
|
+
// When base wins, the incoming `target[key]` is dropped without ever
|
|
316
|
+
// reaching `getMergeValueResult`, so validate its nested spread here —
|
|
317
|
+
// the integer-like-key ambiguity is a property of the authored value,
|
|
318
|
+
// not of which side owns the key, and must throw either way.
|
|
319
|
+
(0, utils_1.assertNoIntegerLikeSpreadKey)(target[key], projectConfigSourceMap
|
|
320
|
+
? `Object at "${targetIdentifier}.${key}"`
|
|
321
|
+
: 'Object');
|
|
307
322
|
result[key] =
|
|
308
323
|
key in mergeBase
|
|
309
324
|
? mergeBase[key]
|
|
@@ -381,13 +396,20 @@ function mergeTargetConfigurations(target, baseTarget, projectConfigSourceMap, s
|
|
|
381
396
|
processKey(key);
|
|
382
397
|
}
|
|
383
398
|
}
|
|
384
|
-
// Update
|
|
385
|
-
//
|
|
386
|
-
//
|
|
387
|
-
//
|
|
388
|
-
//
|
|
399
|
+
// Update the node key once after the loop. Ownership follows identity: this
|
|
400
|
+
// merge claims `targets.<name>` only when it changed the target's identity
|
|
401
|
+
// (a new/different executor or command, or an incompatible replace — whose
|
|
402
|
+
// key purge above empties the slot anyway). A plugin that only layers fields
|
|
403
|
+
// onto an existing target leaves the node with its creator; weak
|
|
404
|
+
// target-defaults stamps are always reclaimable.
|
|
389
405
|
if (projectConfigSourceMap) {
|
|
390
|
-
|
|
406
|
+
const identityChanged = !isCompatible ||
|
|
407
|
+
(target.executor !== undefined &&
|
|
408
|
+
target.executor !== baseTarget?.executor) ||
|
|
409
|
+
(target.command !== undefined &&
|
|
410
|
+
target.command !== baseTarget?.command) ||
|
|
411
|
+
suppliesNewOptionsIdentity(baseTarget, target);
|
|
412
|
+
(0, source_maps_1.recordTargetIdentitySourceMapInfo)(projectConfigSourceMap, targetIdentifier, sourceInformation, identityChanged);
|
|
391
413
|
}
|
|
392
414
|
// merge options if there are any
|
|
393
415
|
// if the targets aren't compatible, we simply discard the old options during the merge
|
|
@@ -443,6 +465,26 @@ function isCompatibleTarget(a, b) {
|
|
|
443
465
|
}
|
|
444
466
|
return true;
|
|
445
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* Run-commands and run-script targets carry their runnable identity in
|
|
470
|
+
* `options` (see {@link isCompatibleTarget}). A layer that supplies that
|
|
471
|
+
* identity where the base had none changed what the target runs — the same
|
|
472
|
+
* identity change as setting an executor on a target that had none.
|
|
473
|
+
*/
|
|
474
|
+
function suppliesNewOptionsIdentity(baseTarget, target) {
|
|
475
|
+
const executor = target.executor ?? baseTarget?.executor;
|
|
476
|
+
if (executor === 'nx:run-commands') {
|
|
477
|
+
const baseCommand = baseTarget?.options?.command ??
|
|
478
|
+
baseTarget?.options?.commands?.join(' && ');
|
|
479
|
+
const targetCommand = target.options?.command ?? target.options?.commands?.join(' && ');
|
|
480
|
+
return !!targetCommand && targetCommand !== baseCommand;
|
|
481
|
+
}
|
|
482
|
+
if (executor === 'nx:run-script') {
|
|
483
|
+
const targetScript = target.options?.script;
|
|
484
|
+
return !!targetScript && targetScript !== baseTarget?.options?.script;
|
|
485
|
+
}
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
446
488
|
function resolveNxTokensInOptions(object, project, key) {
|
|
447
489
|
const result = Array.isArray(object) ? [...object] : { ...object };
|
|
448
490
|
for (let [opt, value] of Object.entries(object ?? {})) {
|
|
@@ -115,9 +115,22 @@ function validateAndNormalizeProjectRootMap(workspaceRoot, projectRootMap, nxJso
|
|
|
115
115
|
// We initially did this in the project.json plugin, but
|
|
116
116
|
// that resulted in project.json files without names causing
|
|
117
117
|
// the resulting project to change names from earlier plugins...
|
|
118
|
-
if (!project.name
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
if (!project.name) {
|
|
119
|
+
const projectJsonPath = (0, path_1.join)(workspaceRoot, project.root, 'project.json');
|
|
120
|
+
if ((0, node_fs_1.existsSync)(projectJsonPath)) {
|
|
121
|
+
// The project.json plugin may not have run (e.g. when a single
|
|
122
|
+
// plugin is run in isolation via `addPlugin` from a generator), so
|
|
123
|
+
// prefer the name declared in project.json before deriving one from
|
|
124
|
+
// the directory name.
|
|
125
|
+
let nameFromProjectJson;
|
|
126
|
+
try {
|
|
127
|
+
nameFromProjectJson =
|
|
128
|
+
(0, fileutils_1.readJsonFile)(projectJsonPath).name;
|
|
129
|
+
}
|
|
130
|
+
catch { }
|
|
131
|
+
project.name =
|
|
132
|
+
nameFromProjectJson ?? (0, to_project_name_1.toProjectName)((0, path_1.join)(root, 'project.json'));
|
|
133
|
+
}
|
|
121
134
|
}
|
|
122
135
|
try {
|
|
123
136
|
validateProject(project, projects);
|
|
@@ -8,6 +8,21 @@ export declare const INTEGER_LIKE_KEY_PATTERN: RegExp;
|
|
|
8
8
|
export declare class IntegerLikeSpreadKeyError extends Error {
|
|
9
9
|
constructor(key: string, context: string);
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Throws `IntegerLikeSpreadKeyError` when `value` is a `'...'` spread object
|
|
13
|
+
* whose enumeration hoists an integer-like key ahead of the spread, making its
|
|
14
|
+
* authored position ambiguous.
|
|
15
|
+
*
|
|
16
|
+
* The ambiguity is a property of the authored value alone, not of any merge
|
|
17
|
+
* base. `mergeObjectWithSpread` runs this the moment it merges such a value —
|
|
18
|
+
* but a merge layer that lets the base win a key drops the incoming value
|
|
19
|
+
* without merging it, so the check must also be run eagerly at those
|
|
20
|
+
* base-owns-key shortcuts. Otherwise the error would surface or vanish
|
|
21
|
+
* depending on which side owns the key (e.g. it fires in the target-defaults
|
|
22
|
+
* staging merge but not the real merge), which is exactly the divergence that
|
|
23
|
+
* makes discarding staging errors unsafe.
|
|
24
|
+
*/
|
|
25
|
+
export declare function assertNoIntegerLikeSpreadKey(value: unknown, errorContext: string): void;
|
|
11
26
|
type SourceMapContext = {
|
|
12
27
|
sourceMap: Record<string, SourceInformation>;
|
|
13
28
|
key: string;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.IntegerLikeSpreadKeyError = exports.INTEGER_LIKE_KEY_PATTERN = exports.NX_SPREAD_TOKEN = void 0;
|
|
4
4
|
exports.uniqueKeysInObjects = uniqueKeysInObjects;
|
|
5
|
+
exports.assertNoIntegerLikeSpreadKey = assertNoIntegerLikeSpreadKey;
|
|
5
6
|
exports.getMergeValueResult = getMergeValueResult;
|
|
6
7
|
const source_maps_1 = require("./source-maps");
|
|
7
8
|
exports.NX_SPREAD_TOKEN = '...';
|
|
@@ -30,6 +31,29 @@ class IntegerLikeSpreadKeyError extends Error {
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
exports.IntegerLikeSpreadKeyError = IntegerLikeSpreadKeyError;
|
|
34
|
+
/**
|
|
35
|
+
* Throws `IntegerLikeSpreadKeyError` when `value` is a `'...'` spread object
|
|
36
|
+
* whose enumeration hoists an integer-like key ahead of the spread, making its
|
|
37
|
+
* authored position ambiguous.
|
|
38
|
+
*
|
|
39
|
+
* The ambiguity is a property of the authored value alone, not of any merge
|
|
40
|
+
* base. `mergeObjectWithSpread` runs this the moment it merges such a value —
|
|
41
|
+
* but a merge layer that lets the base win a key drops the incoming value
|
|
42
|
+
* without merging it, so the check must also be run eagerly at those
|
|
43
|
+
* base-owns-key shortcuts. Otherwise the error would surface or vanish
|
|
44
|
+
* depending on which side owns the key (e.g. it fires in the target-defaults
|
|
45
|
+
* staging merge but not the real merge), which is exactly the divergence that
|
|
46
|
+
* makes discarding staging errors unsafe.
|
|
47
|
+
*/
|
|
48
|
+
function assertNoIntegerLikeSpreadKey(value, errorContext) {
|
|
49
|
+
if (!isObject(value) || value[exports.NX_SPREAD_TOKEN] !== true) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const keys = Object.keys(value);
|
|
53
|
+
if (keys[0] && exports.INTEGER_LIKE_KEY_PATTERN.test(keys[0])) {
|
|
54
|
+
throw new IntegerLikeSpreadKeyError(keys[0], errorContext);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
33
57
|
/**
|
|
34
58
|
* `"..."` in `newValue` (as an array element or a key set to `true`)
|
|
35
59
|
* expands the base at that position; otherwise `newValue` replaces
|
|
@@ -52,11 +76,25 @@ function getMergeValueResult(baseValue, newValue, sourceMapContext, deferSpreads
|
|
|
52
76
|
// plugin already set, purely as a merge guard — must not steal provenance
|
|
53
77
|
// from the layer that introduced the value. A genuinely new value (no base,
|
|
54
78
|
// or a different one) still attributes to the new layer.
|
|
55
|
-
|
|
79
|
+
//
|
|
80
|
+
// The exception cuts the other way too: when the *existing* attribution is a
|
|
81
|
+
// target-defaults stamp (TD merges before the plugin whose value it
|
|
82
|
+
// predicted, so its stamp lands first), a real plugin re-stating that value
|
|
83
|
+
// is the genuine author and reclaims the key.
|
|
84
|
+
if (!isUnchangedPrimitive(newValue, baseValue) ||
|
|
85
|
+
isReclaimableTargetDefaultsStamp(sourceMapContext)) {
|
|
56
86
|
writeTopLevelSourceMap(sourceMapContext);
|
|
57
87
|
}
|
|
58
88
|
return newValue;
|
|
59
89
|
}
|
|
90
|
+
// Whether the key's current attribution is a weak target-defaults stamp that
|
|
91
|
+
// the (non-target-defaults) writer should reclaim despite the value being
|
|
92
|
+
// unchanged.
|
|
93
|
+
function isReclaimableTargetDefaultsStamp(ctx) {
|
|
94
|
+
return (!!ctx &&
|
|
95
|
+
ctx.sourceMap[ctx.key]?.[1] === source_maps_1.TARGET_DEFAULTS_PLUGIN_NAME &&
|
|
96
|
+
ctx.sourceInformation[1] !== source_maps_1.TARGET_DEFAULTS_PLUGIN_NAME);
|
|
97
|
+
}
|
|
60
98
|
// Whether `newValue` leaves a defined primitive base untouched. Objects fall
|
|
61
99
|
// through (always re-attributed) to preserve the existing replace semantics —
|
|
62
100
|
// the regression this guards is scalar executor/command re-stamping.
|
|
@@ -120,12 +158,10 @@ function mergeObjectWithSpread(baseValue, newValue, sourceMapContext, deferSprea
|
|
|
120
158
|
const errorContext = sourceMapContext?.key
|
|
121
159
|
? `Object at "${sourceMapContext.key}"`
|
|
122
160
|
: 'Object';
|
|
161
|
+
// Integer-like keys are hoisted to the front of enumeration, so one
|
|
162
|
+
// alongside `'...'` makes its authored position ambiguous.
|
|
163
|
+
assertNoIntegerLikeSpreadKey(newValue, errorContext);
|
|
123
164
|
const newKeys = Object.keys(newValue);
|
|
124
|
-
// Integer-like keys are hoisted to the front of enumeration, so if one
|
|
125
|
-
// exists alongside `'...'` it must be newKeys[0].
|
|
126
|
-
if (newKeys[0] && exports.INTEGER_LIKE_KEY_PATTERN.test(newKeys[0])) {
|
|
127
|
-
throw new IntegerLikeSpreadKeyError(newKeys[0], errorContext);
|
|
128
|
-
}
|
|
129
165
|
// Base per-key sources captured lazily — only for shared keys the new
|
|
130
166
|
// object overwrites before `'...'`, since writing their new source
|
|
131
167
|
// clobbers the base entry the spread will need to restore.
|
|
@@ -60,19 +60,22 @@ export type MergeError = AggregateCreateNodesError | MergeNodesError | ProjectsW
|
|
|
60
60
|
/**
|
|
61
61
|
* Merges create nodes results into a single rootMap.
|
|
62
62
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* `'...'` spreads deferred) so that synthesis can read each layer's
|
|
66
|
-
* contribution without re-running the merge. The synthetic result from
|
|
67
|
-
* `createTargetDefaultsResults` is then merged into the manager, and
|
|
68
|
-
* the staged intermediate is replayed on top — that replay is where
|
|
69
|
-
* deferred spreads expand against the final (specified + synth) base.
|
|
63
|
+
* Every layer merges into the manager through the same source-map-aware
|
|
64
|
+
* merge, in precedence order:
|
|
70
65
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
66
|
+
* specified plugins → synthetic target defaults → default plugins
|
|
67
|
+
*
|
|
68
|
+
* so field-level provenance is decided by the merge itself for all three
|
|
69
|
+
* layers — whichever layer a field's final value came from owns its
|
|
70
|
+
* attribution, and `'...'` spreads in default-plugin configs resolve against
|
|
71
|
+
* the accumulated specified + target-defaults base.
|
|
72
|
+
*
|
|
73
|
+
* Target-default synthesis needs the *merged* shape of the default layer
|
|
74
|
+
* (to predict each target's eventual executor/command) before that layer
|
|
75
|
+
* merges into the manager. To get it, default results are first staged into
|
|
76
|
+
* a throwaway intermediate rootMap with unresolvable `'...'` spreads
|
|
77
|
+
* deferred. The staging output feeds only `createTargetDefaultsResults`; the
|
|
78
|
+
* default plugins then merge into the manager from their original results.
|
|
76
79
|
*/
|
|
77
80
|
export declare function mergeCreateNodesResults(specifiedResults: CreateNodesResultEntry[][], defaultResults: CreateNodesResultEntry[][], nxJsonConfiguration: NxJsonConfiguration, workspaceRoot: string, errors: MergeError[]): {
|
|
78
81
|
projectRootMap: Record<string, ProjectConfiguration>;
|