nx 23.0.0-beta.2 → 23.0.0-beta.21
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/init-local.js +11 -20
- package/dist/bin/nx.d.ts +1 -0
- package/dist/bin/nx.js +28 -2
- package/dist/plugins/package-json.js +4 -2
- package/dist/src/adapter/ngcli-adapter.d.ts +2 -1
- package/dist/src/adapter/ngcli-adapter.js +25 -2
- package/dist/src/ai/clone-ai-config-repo.js +20 -3
- package/dist/src/analytics/analytics.js +10 -1
- package/dist/src/command-line/add/completion.d.ts +1 -0
- package/dist/src/command-line/add/completion.js +15 -0
- package/dist/src/command-line/affected/completion.d.ts +1 -0
- package/dist/src/command-line/affected/completion.js +15 -0
- package/dist/src/command-line/completion/argv-layout.d.ts +6 -0
- package/dist/src/command-line/completion/argv-layout.js +19 -0
- package/dist/src/command-line/completion/command-completions.d.ts +19 -0
- package/dist/src/command-line/completion/command-completions.js +120 -0
- package/dist/src/command-line/completion/command-handlers.d.ts +30 -0
- package/dist/src/command-line/completion/command-handlers.js +69 -0
- package/dist/src/command-line/completion/command-object.d.ts +10 -0
- package/dist/src/command-line/completion/command-object.js +95 -0
- package/dist/src/command-line/completion/completion-providers.d.ts +21 -0
- package/dist/src/command-line/completion/completion-providers.js +194 -0
- package/dist/src/command-line/completion/infix-targets.d.ts +1 -0
- package/dist/src/command-line/completion/infix-targets.js +48 -0
- package/dist/src/command-line/completion/metadata.d.ts +22 -0
- package/dist/src/command-line/completion/metadata.js +71 -0
- package/dist/src/command-line/completion/registrations.d.ts +9 -0
- package/dist/src/command-line/completion/registrations.js +16 -0
- package/dist/src/command-line/completion/scripts/bash.sh +51 -0
- package/dist/src/command-line/completion/scripts/fish.fish +47 -0
- package/dist/src/command-line/completion/scripts/powershell.ps1 +52 -0
- package/dist/src/command-line/completion/scripts/zsh.zsh +69 -0
- package/dist/src/command-line/completion/scripts.d.ts +18 -0
- package/dist/src/command-line/completion/scripts.js +140 -0
- package/dist/src/command-line/completion/trigger.d.ts +3 -0
- package/dist/src/command-line/completion/trigger.js +21 -0
- package/dist/src/command-line/completion/value-completions.d.ts +3 -0
- package/dist/src/command-line/completion/value-completions.js +21 -0
- package/dist/src/command-line/examples.js +1 -1
- package/dist/src/command-line/format/format.js +15 -5
- package/dist/src/command-line/generate/completion.d.ts +1 -0
- package/dist/src/command-line/generate/completion.js +9 -0
- package/dist/src/command-line/graph/completion.d.ts +1 -0
- package/dist/src/command-line/graph/completion.js +13 -0
- package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +14 -18
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +1 -0
- package/dist/src/command-line/init/implementation/utils.d.ts +7 -1
- package/dist/src/command-line/init/implementation/utils.js +51 -14
- package/dist/src/command-line/migrate/agentic/capture-generator-output.d.ts +22 -0
- package/dist/src/command-line/migrate/agentic/capture-generator-output.js +100 -0
- package/dist/src/command-line/migrate/agentic/cli-args.d.ts +12 -0
- package/dist/src/command-line/migrate/agentic/cli-args.js +38 -0
- package/dist/src/command-line/migrate/agentic/definitions.d.ts +6 -0
- package/dist/src/command-line/migrate/agentic/definitions.js +98 -0
- package/dist/src/command-line/migrate/agentic/detect-installed.d.ts +10 -0
- package/dist/src/command-line/migrate/agentic/detect-installed.js +68 -0
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +46 -0
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +87 -0
- package/dist/src/command-line/migrate/agentic/handoff.d.ts +63 -0
- package/dist/src/command-line/migrate/agentic/handoff.js +183 -0
- package/dist/src/command-line/migrate/agentic/inception.d.ts +9 -0
- package/dist/src/command-line/migrate/agentic/inception.js +15 -0
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.d.ts +22 -0
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.js +50 -0
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.d.ts +51 -0
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.js +65 -0
- package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.d.ts +44 -0
- package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.js +52 -0
- package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.d.ts +21 -0
- package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.js +26 -0
- package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.d.ts +18 -0
- package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.js +130 -0
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.d.ts +46 -0
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.js +88 -0
- package/dist/src/command-line/migrate/agentic/run-step.d.ts +51 -0
- package/dist/src/command-line/migrate/agentic/run-step.js +121 -0
- package/dist/src/command-line/migrate/agentic/runner.d.ts +33 -0
- package/dist/src/command-line/migrate/agentic/runner.js +442 -0
- package/dist/src/command-line/migrate/agentic/select.d.ts +14 -0
- package/dist/src/command-line/migrate/agentic/select.js +150 -0
- package/dist/src/command-line/migrate/agentic/types.d.ts +102 -0
- package/dist/src/command-line/migrate/agentic/types.js +2 -0
- package/dist/src/command-line/migrate/command-object.d.ts +1 -0
- package/dist/src/command-line/migrate/command-object.js +32 -7
- package/dist/src/command-line/migrate/migrate-commits.d.ts +50 -0
- package/dist/src/command-line/migrate/migrate-commits.js +102 -0
- package/dist/src/command-line/migrate/migrate-output.d.ts +180 -0
- package/dist/src/command-line/migrate/migrate-output.js +258 -0
- package/dist/src/command-line/migrate/migrate.d.ts +122 -12
- package/dist/src/command-line/migrate/migrate.js +1036 -217
- package/dist/src/command-line/migrate/migration-shape.d.ts +8 -0
- package/dist/src/command-line/migrate/migration-shape.js +13 -0
- package/dist/src/command-line/migrate/multi-major.d.ts +30 -0
- package/dist/src/command-line/migrate/multi-major.js +185 -0
- package/dist/src/command-line/migrate/prompt-files.d.ts +31 -0
- package/dist/src/command-line/migrate/prompt-files.js +141 -0
- package/dist/src/command-line/migrate/run-migration-process.js +28 -6
- package/dist/src/command-line/migrate/safe-prompt.d.ts +28 -0
- package/dist/src/command-line/migrate/safe-prompt.js +49 -0
- package/dist/src/command-line/migrate/update-filters.d.ts +11 -0
- package/dist/src/command-line/migrate/update-filters.js +44 -0
- package/dist/src/command-line/migrate/version-utils.d.ts +6 -0
- package/dist/src/command-line/migrate/version-utils.js +59 -0
- package/dist/src/command-line/nx-commands.js +9 -0
- package/dist/src/command-line/release/config/config.d.ts +3 -6
- package/dist/src/command-line/release/config/config.js +77 -45
- package/dist/src/command-line/release/config/use-legacy-versioning.d.ts +2 -0
- package/dist/src/command-line/release/config/use-legacy-versioning.js +8 -0
- package/dist/src/command-line/release/utils/release-graph.js +2 -3
- package/dist/src/command-line/release/utils/repository-git-tags.js +1 -1
- package/dist/src/command-line/release/utils/resolve-changelog-renderer.js +7 -19
- package/dist/src/command-line/release/version/resolve-current-version.js +1 -1
- package/dist/src/command-line/release/version/version-actions.js +3 -7
- package/dist/src/command-line/report/report.js +2 -2
- package/dist/src/command-line/run/completion.d.ts +1 -0
- package/dist/src/command-line/run/completion.js +7 -0
- package/dist/src/command-line/run-many/completion.d.ts +1 -0
- package/dist/src/command-line/run-many/completion.js +13 -0
- package/dist/src/command-line/show/completion.d.ts +1 -0
- package/dist/src/command-line/show/completion.js +27 -0
- package/dist/src/command-line/show/show-target/info.d.ts +1 -0
- package/dist/src/command-line/show/show-target/info.js +100 -19
- package/dist/src/command-line/watch/command-object.js +24 -4
- package/dist/src/command-line/watch/completion.d.ts +1 -0
- package/dist/src/command-line/watch/completion.js +10 -0
- package/dist/src/command-line/watch/watch.d.ts +7 -0
- package/dist/src/command-line/watch/watch.js +1 -1
- package/dist/src/config/misc-interfaces.d.ts +25 -2
- package/dist/src/config/nx-json.d.ts +43 -56
- package/dist/src/config/schema-utils.d.ts +21 -0
- package/dist/src/config/schema-utils.js +92 -18
- package/dist/src/config/task-graph.d.ts +4 -107
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/core/graph/styles.css +2 -3
- package/dist/src/core/graph/styles.js +1 -1
- package/dist/src/daemon/client/client.d.ts +1 -1
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +1 -1
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +1 -1
- package/dist/src/daemon/server/file-watching/route-workspace-changes.d.ts +9 -0
- package/dist/src/daemon/server/file-watching/route-workspace-changes.js +76 -0
- package/dist/src/daemon/server/project-graph-incremental-recomputation.js +45 -11
- package/dist/src/daemon/server/server.js +4 -43
- package/dist/src/daemon/server/start.d.ts +1 -1
- package/dist/src/daemon/server/start.js +2 -0
- package/dist/src/devkit-exports.d.ts +2 -2
- package/dist/src/devkit-internals.d.ts +5 -1
- package/dist/src/devkit-internals.js +17 -1
- package/dist/src/executors/run-commands/running-tasks.d.ts +7 -0
- package/dist/src/executors/run-commands/running-tasks.js +178 -105
- package/dist/src/executors/run-script/run-script.impl.js +3 -10
- package/dist/src/executors/utils/convert-nx-executor.js +1 -1
- package/dist/src/hasher/hash-plan-inspector.d.ts +1 -1
- package/dist/src/hasher/task-hasher.js +6 -4
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +0 -3
- package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +6 -2
- package/dist/src/migrations/update-17-0-0/move-cache-directory.md +31 -0
- package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +20 -4
- package/dist/src/migrations/update-20-0-0/move-use-daemon-process.md +27 -0
- package/dist/src/migrations/update-20-0-1/use-legacy-cache.md +24 -0
- package/dist/src/migrations/update-21-0-0/release-changelog-config-changes.md +49 -0
- package/dist/src/migrations/update-21-0-0/release-version-config-changes.md +54 -0
- package/dist/src/migrations/update-21-0-0/remove-custom-tasks-runner.md +28 -0
- package/dist/src/migrations/update-21-0-0/remove-legacy-cache.md +22 -0
- package/dist/src/migrations/update-22-2-0/add-self-healing-to-gitignore.md +11 -0
- package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.d.ts +2 -0
- package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.js +16 -0
- package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.d.ts +9 -0
- package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.js +18 -0
- package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.d.ts +35 -0
- package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.js +139 -0
- package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.md +66 -0
- package/dist/src/native/index.d.ts +79 -2
- package/dist/src/native/native-bindings.js +3 -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 +37 -19
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +51 -4
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +12 -4
- package/dist/src/plugins/js/utils/packages.js +1 -1
- package/dist/src/plugins/js/utils/register.d.ts +103 -14
- package/dist/src/plugins/js/utils/register.js +434 -39
- package/dist/src/plugins/js/utils/typescript.d.ts +7 -0
- package/dist/src/plugins/js/utils/typescript.js +39 -0
- package/dist/src/plugins/package-json/create-nodes.d.ts +3 -2
- package/dist/src/plugins/package-json/create-nodes.js +7 -5
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +2 -1
- package/dist/src/project-graph/build-project-graph.d.ts +5 -0
- package/dist/src/project-graph/build-project-graph.js +6 -2
- package/dist/src/project-graph/file-map-utils.d.ts +5 -0
- package/dist/src/project-graph/file-map-utils.js +10 -1
- package/dist/src/project-graph/plugins/get-plugins.d.ts +7 -2
- package/dist/src/project-graph/plugins/get-plugins.js +8 -5
- package/dist/src/project-graph/plugins/isolation/plugin-worker.d.ts +1 -0
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +2 -0
- package/dist/src/project-graph/plugins/resolve-plugin.d.ts +7 -4
- package/dist/src/project-graph/plugins/resolve-plugin.js +152 -33
- package/dist/src/project-graph/plugins/tasks-execution-hooks.js +4 -2
- package/dist/src/project-graph/plugins/transpiler.d.ts +12 -0
- package/dist/src/project-graph/plugins/transpiler.js +37 -0
- package/dist/src/project-graph/plugins/utils.js +13 -7
- package/dist/src/project-graph/project-graph.js +1 -1
- package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +95 -4
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +515 -68
- package/dist/src/project-graph/utils/project-configuration-utils.d.ts +13 -5
- package/dist/src/project-graph/utils/project-configuration-utils.js +14 -6
- package/dist/src/project-graph/utils/retrieve-workspace-files.js +1 -1
- package/dist/src/tasks-runner/create-task-graph.d.ts +4 -4
- package/dist/src/tasks-runner/create-task-graph.js +1 -1
- package/dist/src/tasks-runner/default-tasks-runner.d.ts +0 -2
- package/dist/src/tasks-runner/forked-process-task-runner.d.ts +1 -1
- package/dist/src/tasks-runner/forked-process-task-runner.js +11 -6
- package/dist/src/tasks-runner/init-tasks-runner.d.ts +0 -15
- package/dist/src/tasks-runner/init-tasks-runner.js +0 -63
- package/dist/src/tasks-runner/legacy-depends-on-warning.d.ts +18 -0
- package/dist/src/tasks-runner/legacy-depends-on-warning.js +109 -0
- package/dist/src/tasks-runner/life-cycle.d.ts +7 -8
- package/dist/src/tasks-runner/life-cycles/invoke-runner-terminal-output-life-cycle.js +6 -6
- package/dist/src/tasks-runner/life-cycles/task-history-life-cycle-old.js +13 -2
- package/dist/src/tasks-runner/life-cycles/task-history-life-cycle.js +16 -5
- package/dist/src/tasks-runner/life-cycles/tui-summary-life-cycle.js +11 -2
- package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -1
- package/dist/src/tasks-runner/pseudo-terminal.js +22 -10
- package/dist/src/tasks-runner/run-command.js +8 -11
- package/dist/src/tasks-runner/running-tasks/batch-process.d.ts +1 -1
- package/dist/src/tasks-runner/running-tasks/batch-process.js +3 -5
- package/dist/src/tasks-runner/running-tasks/node-child-process.d.ts +2 -2
- package/dist/src/tasks-runner/running-tasks/node-child-process.js +5 -7
- package/dist/src/tasks-runner/task-env.d.ts +1 -1
- package/dist/src/tasks-runner/task-env.js +6 -1
- package/dist/src/tasks-runner/task-orchestrator.d.ts +11 -1
- package/dist/src/tasks-runner/task-orchestrator.js +112 -38
- package/dist/src/tasks-runner/tasks-schedule.js +3 -3
- package/dist/src/tasks-runner/utils.d.ts +7 -8
- package/dist/src/tasks-runner/utils.js +23 -27
- package/dist/src/utils/child-process.js +2 -2
- package/dist/src/utils/compile-cache.d.ts +24 -0
- package/dist/src/utils/compile-cache.js +49 -0
- package/dist/src/utils/enable-compile-cache.d.ts +1 -0
- package/dist/src/utils/enable-compile-cache.js +7 -0
- package/dist/src/utils/fileutils.d.ts +0 -8
- package/dist/src/utils/fileutils.js +0 -40
- package/dist/src/utils/git-utils.d.ts +15 -0
- package/dist/src/utils/git-utils.js +138 -0
- package/dist/src/utils/handle-import.d.ts +4 -1
- package/dist/src/utils/handle-import.js +56 -2
- package/dist/src/utils/has-nx-js-plugin.d.ts +9 -0
- package/dist/src/utils/has-nx-js-plugin.js +24 -0
- package/dist/src/utils/installed-nx-version.d.ts +14 -4
- package/dist/src/utils/installed-nx-version.js +54 -7
- package/dist/src/utils/logger.d.ts +12 -1
- package/dist/src/utils/logger.js +57 -36
- package/dist/src/utils/nx-key.d.ts +0 -1
- package/dist/src/utils/nx-key.js +20 -23
- package/dist/src/utils/nx-package-group.d.ts +8 -0
- package/dist/src/utils/nx-package-group.js +15 -0
- package/dist/src/utils/output.d.ts +3 -2
- package/dist/src/utils/output.js +29 -28
- package/dist/src/utils/package-json.d.ts +14 -1
- package/dist/src/utils/package-json.js +20 -21
- package/dist/src/utils/perf-logging.js +3 -1
- package/dist/src/utils/plugin-cache-utils.d.ts +13 -4
- package/dist/src/utils/plugin-cache-utils.js +23 -13
- package/dist/src/utils/plugins/local-plugins.d.ts +18 -0
- package/dist/src/utils/plugins/local-plugins.js +30 -0
- package/dist/src/utils/tar.d.ts +8 -0
- package/dist/src/utils/tar.js +44 -0
- package/migrations.json +16 -0
- package/package.json +28 -28
- package/schemas/nx-schema.json +114 -80
- package/dist/src/plugins/js/project-graph/build-dependencies/strip-source-code.d.ts +0 -7
- package/dist/src/plugins/js/project-graph/build-dependencies/strip-source-code.js +0 -155
- package/dist/src/plugins/js/project-graph/build-dependencies/typescript-import-locator.d.ts +0 -16
- package/dist/src/plugins/js/project-graph/build-dependencies/typescript-import-locator.js +0 -121
|
@@ -2,19 +2,51 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createTargetDefaultsResults = createTargetDefaultsResults;
|
|
4
4
|
exports.readTargetDefaultsForTarget = readTargetDefaultsForTarget;
|
|
5
|
+
exports.findBestTargetDefault = findBestTargetDefault;
|
|
6
|
+
exports.normalizeTargetDefaults = normalizeTargetDefaults;
|
|
7
|
+
exports.normalizeTargetDefaultsAgainstRootMaps = normalizeTargetDefaultsAgainstRootMaps;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
5
9
|
const minimatch_1 = require("minimatch");
|
|
10
|
+
const find_matching_projects_1 = require("../../../utils/find-matching-projects");
|
|
6
11
|
const globs_1 = require("../../../utils/globs");
|
|
12
|
+
const source_maps_1 = require("./source-maps");
|
|
7
13
|
const target_merging_1 = require("./target-merging");
|
|
8
14
|
const utils_1 = require("./utils");
|
|
15
|
+
const os_1 = require("os");
|
|
16
|
+
const pc = tslib_1.__importStar(require("picocolors"));
|
|
9
17
|
/**
|
|
10
18
|
* Builds a synthetic plugin result from nx.json's `targetDefaults`, layered
|
|
11
19
|
* between specified-plugin and default-plugin results during merging.
|
|
20
|
+
*
|
|
21
|
+
* Synthesis sees the two layers separately to avoid re-merging specified
|
|
22
|
+
* results into a parallel rootMap — for each (root, target) where both
|
|
23
|
+
* layers contribute, it computes the eventual executor/command on the
|
|
24
|
+
* fly. That's all the matcher needs; the full target merge happens
|
|
25
|
+
* downstream in the real merge.
|
|
12
26
|
*/
|
|
13
|
-
function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMap, nxJsonConfiguration) {
|
|
27
|
+
function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMap, nxJsonConfiguration, specifiedSourceMaps, defaultSourceMaps) {
|
|
14
28
|
const targetDefaultsConfig = nxJsonConfiguration.targetDefaults;
|
|
15
29
|
if (!targetDefaultsConfig) {
|
|
16
30
|
return [];
|
|
17
31
|
}
|
|
32
|
+
// Disambiguate `:`-shaped record keys against the actual targets and
|
|
33
|
+
// executors present in the rootMaps. This is the same idea the v23
|
|
34
|
+
// `convert-target-defaults-to-array` migration uses against the project
|
|
35
|
+
// graph — we just consult the rootMaps directly here since we don't have
|
|
36
|
+
// a graph yet during construction.
|
|
37
|
+
const entries = normalizeTargetDefaultsAgainstRootMaps(targetDefaultsConfig, specifiedPluginRootMap, defaultPluginRootMap);
|
|
38
|
+
if (entries.length === 0) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
// `projectNodesByName` and `rootToName` are only consulted when an entry
|
|
42
|
+
// has a `projects:` filter — that's the only matcher branch that needs
|
|
43
|
+
// either the project name or its node. Source-plugin attribution is
|
|
44
|
+
// root-keyed via `resolveSourcePlugin`, not name-keyed, so it doesn't
|
|
45
|
+
// need either map. Skip both builds in the common no-filter path.
|
|
46
|
+
const needsProjectNodes = entries.some((e) => e.projects !== undefined);
|
|
47
|
+
const projectNodes = needsProjectNodes
|
|
48
|
+
? buildProjectNodesAndRootToName(specifiedPluginRootMap, defaultPluginRootMap)
|
|
49
|
+
: undefined;
|
|
18
50
|
const syntheticProjects = {};
|
|
19
51
|
const allRoots = new Set([
|
|
20
52
|
...Object.keys(specifiedPluginRootMap),
|
|
@@ -23,8 +55,16 @@ function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMa
|
|
|
23
55
|
for (const root of allRoots) {
|
|
24
56
|
const specifiedTargets = specifiedPluginRootMap[root]?.targets ?? {};
|
|
25
57
|
const defaultTargets = defaultPluginRootMap[root]?.targets ?? {};
|
|
58
|
+
const projectName = projectNodes?.rootToName.get(root);
|
|
59
|
+
const projectNode = projectName
|
|
60
|
+
? projectNodes.projectNodesByName[projectName]
|
|
61
|
+
: undefined;
|
|
26
62
|
for (const targetName of (0, utils_1.uniqueKeysInObjects)(specifiedTargets, defaultTargets)) {
|
|
27
|
-
const
|
|
63
|
+
const effective = effectiveTargetForLookup(specifiedTargets[targetName], defaultTargets[targetName], root);
|
|
64
|
+
if (!effective)
|
|
65
|
+
continue;
|
|
66
|
+
const sourcePlugin = resolveSourcePlugin(root, targetName, specifiedSourceMaps, defaultSourceMaps);
|
|
67
|
+
const syntheticTarget = buildSyntheticTargetForRoot(targetName, root, effective, entries, projectName, projectNode, sourcePlugin);
|
|
28
68
|
if (!syntheticTarget)
|
|
29
69
|
continue;
|
|
30
70
|
syntheticProjects[root] ??= { root, targets: {} };
|
|
@@ -44,92 +84,499 @@ function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMa
|
|
|
44
84
|
],
|
|
45
85
|
];
|
|
46
86
|
}
|
|
47
|
-
// Returns the
|
|
48
|
-
// `root
|
|
49
|
-
//
|
|
50
|
-
|
|
87
|
+
// Returns the (executor, command) pair the real merge will land on at
|
|
88
|
+
// `(root, targetName)` — only the fields the matcher needs. Incompatible
|
|
89
|
+
// pairs wholesale-replace specified with default; compatible pairs let
|
|
90
|
+
// the default's executor win, otherwise the specified's.
|
|
91
|
+
function effectiveTargetForLookup(specifiedTarget, defaultTarget, root) {
|
|
51
92
|
const resolvedSpecified = specifiedTarget
|
|
52
93
|
? (0, target_merging_1.resolveCommandSyntacticSugar)(specifiedTarget, root)
|
|
53
94
|
: undefined;
|
|
54
95
|
const resolvedDefault = defaultTarget
|
|
55
96
|
? (0, target_merging_1.resolveCommandSyntacticSugar)(defaultTarget, root)
|
|
56
97
|
: undefined;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (resolvedSpecified && !resolvedDefault) {
|
|
64
|
-
const targetDefaults = readAndPrepareTargetDefaults(targetName, resolvedSpecified.executor, root, targetDefaultsConfig);
|
|
65
|
-
if (targetDefaults &&
|
|
66
|
-
!(0, target_merging_1.isCompatibleTarget)(resolvedSpecified, targetDefaults)) {
|
|
67
|
-
return undefined;
|
|
98
|
+
if (resolvedSpecified && resolvedDefault) {
|
|
99
|
+
if (!(0, target_merging_1.isCompatibleTarget)(resolvedSpecified, resolvedDefault)) {
|
|
100
|
+
return {
|
|
101
|
+
executor: resolvedDefault.executor,
|
|
102
|
+
command: resolvedDefault.command,
|
|
103
|
+
};
|
|
68
104
|
}
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return readAndPrepareTargetDefaults(targetName, resolvedDefault.executor, root, targetDefaultsConfig);
|
|
105
|
+
return {
|
|
106
|
+
executor: resolvedDefault.executor ?? resolvedSpecified.executor,
|
|
107
|
+
command: resolvedDefault.command ?? resolvedSpecified.command,
|
|
108
|
+
};
|
|
74
109
|
}
|
|
75
|
-
if (
|
|
76
|
-
return
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// back to a target-name keyed default with a foreign executor that
|
|
81
|
-
// would replace the inferred target. Skip the synthetic in that case.
|
|
82
|
-
if ((0, target_merging_1.isCompatibleTarget)(resolvedSpecified, resolvedDefault)) {
|
|
83
|
-
const targetDefaults = readAndPrepareTargetDefaults(targetName, resolvedDefault.executor || resolvedSpecified.executor, root, targetDefaultsConfig);
|
|
84
|
-
if (targetDefaults &&
|
|
85
|
-
!(0, target_merging_1.isCompatibleTarget)(resolvedSpecified, targetDefaults)) {
|
|
86
|
-
return undefined;
|
|
87
|
-
}
|
|
88
|
-
return targetDefaults;
|
|
110
|
+
if (resolvedSpecified) {
|
|
111
|
+
return {
|
|
112
|
+
executor: resolvedSpecified.executor,
|
|
113
|
+
command: resolvedSpecified.command,
|
|
114
|
+
};
|
|
89
115
|
}
|
|
90
|
-
|
|
91
|
-
// matching the default plugin's executor are useful.
|
|
92
|
-
const targetDefaults = readAndPrepareTargetDefaults(targetName, resolvedDefault.executor, root, targetDefaultsConfig);
|
|
93
|
-
if (targetDefaults && (0, target_merging_1.isCompatibleTarget)(resolvedDefault, targetDefaults)) {
|
|
94
|
-
// Stamp executor/command so the default layer merges cleanly on top.
|
|
116
|
+
if (resolvedDefault) {
|
|
95
117
|
return {
|
|
96
|
-
...targetDefaults,
|
|
97
118
|
executor: resolvedDefault.executor,
|
|
98
119
|
command: resolvedDefault.command,
|
|
99
120
|
};
|
|
100
121
|
}
|
|
101
122
|
return undefined;
|
|
102
123
|
}
|
|
103
|
-
|
|
104
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Returns the synthetic defaults target to insert for `targetName` at
|
|
126
|
+
* `root`, or undefined if no defaults apply. The synthetic stamps the
|
|
127
|
+
* effective executor/command so neither merge neighbor can
|
|
128
|
+
* incompatible-replace it and drop its contributions.
|
|
129
|
+
*
|
|
130
|
+
* @param effective The `(executor, command)` shape the real merge will
|
|
131
|
+
* land on. Used both to pick the highest-ranked compatible default
|
|
132
|
+
* (falling back to less-specific matches if the best one would be
|
|
133
|
+
* incompatible) and as the locked shape stamped onto the synthetic.
|
|
134
|
+
*/
|
|
135
|
+
function buildSyntheticTargetForRoot(targetName, root, effective, targetDefaults, projectName, projectNode, sourcePlugin) {
|
|
136
|
+
const rawTargetDefaults = findBestTargetDefault(targetName, effective.executor, projectName, projectNode, sourcePlugin, targetDefaults, effective.command, (candidate) => (0, target_merging_1.isCompatibleTarget)({ executor: effective.executor, command: effective.command }, candidate));
|
|
105
137
|
if (!rawTargetDefaults)
|
|
106
138
|
return undefined;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (executor
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
139
|
+
const synthetic = (0, target_merging_1.resolveCommandSyntacticSugar)((0, target_merging_1.deepClone)(rawTargetDefaults), root);
|
|
140
|
+
// Pre-stamp executor/command from the effective shape so the
|
|
141
|
+
// synthetic can't be incompatible-replaced during the real merge.
|
|
142
|
+
if (effective.executor !== undefined)
|
|
143
|
+
synthetic.executor = effective.executor;
|
|
144
|
+
if (effective.command !== undefined)
|
|
145
|
+
synthetic.command = effective.command;
|
|
146
|
+
return synthetic;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Public, backwards-compatible reader that looks up the most-specific
|
|
150
|
+
* target default for a given target. Accepts either the new array shape
|
|
151
|
+
* or the legacy record shape (devkit support).
|
|
152
|
+
*
|
|
153
|
+
* When called without project context, entries that require a `projects`
|
|
154
|
+
* filter or a `plugin` filter are skipped.
|
|
155
|
+
*
|
|
156
|
+
* The normalized entries are cached per `targetDefaults` reference so
|
|
157
|
+
* repeated reads against the same nx.json don't re-normalize (and don't
|
|
158
|
+
* re-fire the legacy-record-shape warning).
|
|
159
|
+
*/
|
|
160
|
+
function readTargetDefaultsForTarget(targetName, targetDefaults, executor, opts) {
|
|
161
|
+
if (!targetDefaults)
|
|
162
|
+
return null;
|
|
163
|
+
return findBestTargetDefault(targetName, executor, opts?.projectName, opts?.projectNode, opts?.sourcePlugin, getCachedNormalizedEntries(targetDefaults), opts?.command);
|
|
164
|
+
}
|
|
165
|
+
const normalizedEntriesCache = new WeakMap();
|
|
166
|
+
function getCachedNormalizedEntries(targetDefaults) {
|
|
167
|
+
// WeakMap keys must be objects — both array and record forms are objects,
|
|
168
|
+
// so this is safe regardless of shape.
|
|
169
|
+
const key = targetDefaults;
|
|
170
|
+
let entries = normalizedEntriesCache.get(key);
|
|
171
|
+
if (!entries) {
|
|
172
|
+
entries = normalizeTargetDefaults(targetDefaults);
|
|
173
|
+
normalizedEntriesCache.set(key, entries);
|
|
174
|
+
}
|
|
175
|
+
return entries;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Find the highest-specificity `targetDefaults` entry that applies to the
|
|
179
|
+
* given (target, project, sourcePlugin) tuple. Ties are broken by match
|
|
180
|
+
* kind, then by later array index. Returns the config slice with filter
|
|
181
|
+
* keys (`target`, `projects`, `plugin`) stripped.
|
|
182
|
+
*
|
|
183
|
+
* Tier = (1 if a target/executor locator matched, else 0) + 1 per
|
|
184
|
+
* applied filter (`projects`, `plugin`). So locator-bearing entries:
|
|
185
|
+
* - tier 3: target/executor + projects + plugin
|
|
186
|
+
* - tier 2: target/executor + projects, or target/executor + plugin
|
|
187
|
+
* - tier 1: target/executor alone
|
|
188
|
+
* And filter-only entries (no `target` and no `executor`):
|
|
189
|
+
* - tier 2: projects + plugin
|
|
190
|
+
* - tier 1: projects alone, or plugin alone
|
|
191
|
+
*
|
|
192
|
+
* `executor` matching contributes to matchKind only, not to tier — it's
|
|
193
|
+
* not a filter, it's a refinement of the match. Within the same tier,
|
|
194
|
+
* tie-break order (highest first):
|
|
195
|
+
* targetAndExecutor > executorOnly > exactTarget > globTarget > filterOnly
|
|
196
|
+
*
|
|
197
|
+
* `filterOnly` ranks below every locator-bearing kind, so a filter-only
|
|
198
|
+
* entry can never tie-break ahead of one that names a target or executor
|
|
199
|
+
* at the same tier.
|
|
200
|
+
*
|
|
201
|
+
* `executor` only acts as an "injector" (matches a target with neither
|
|
202
|
+
* executor nor command) when the entry also sets `target`. Executor-only
|
|
203
|
+
* entries require the workspace target to actually have an executor.
|
|
204
|
+
*
|
|
205
|
+
* When `predicate` is provided, ranked candidates are iterated and the
|
|
206
|
+
* first one that satisfies the predicate is returned. This lets synthesis
|
|
207
|
+
* fall back to a less-specific compatible default when the most-specific
|
|
208
|
+
* match would be incompatible with the target it's being applied to.
|
|
209
|
+
* Without a predicate, the highest-ranked candidate is returned directly.
|
|
210
|
+
*/
|
|
211
|
+
function findBestTargetDefault(targetName, executor, projectName, projectNode, sourcePlugin, entries, targetCommand, predicate) {
|
|
212
|
+
if (!entries?.length)
|
|
213
|
+
return null;
|
|
214
|
+
// Single greedy best-so-far loop in both the predicate and no-predicate
|
|
215
|
+
// paths. With a predicate, we filter candidates as they appear and only
|
|
216
|
+
// promote one to `best` when it passes — equivalent to the previous
|
|
217
|
+
// "collect-all + sort + first-passing" approach because `beats` is a
|
|
218
|
+
// total order, but without the sort allocation.
|
|
219
|
+
let best = null;
|
|
220
|
+
for (let i = 0; i < entries.length; i++) {
|
|
221
|
+
const candidate = matchEntry(entries[i], i, targetName, executor, projectName, projectNode, sourcePlugin, targetCommand);
|
|
222
|
+
if (!candidate)
|
|
223
|
+
continue;
|
|
224
|
+
if (predicate && !predicate(candidate.config))
|
|
225
|
+
continue;
|
|
226
|
+
if (!best || beats(candidate, best)) {
|
|
227
|
+
best = candidate;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return best ? best.config : null;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Classify the runtime intent of an entry's `projects:` value:
|
|
234
|
+
* - `none`: filter is absent — the entry is unscoped on the projects axis.
|
|
235
|
+
* - `empty`: filter is `[]` — matches no project, so the whole entry is
|
|
236
|
+
* dead. Treated as a never-match by the matcher rather than allowing
|
|
237
|
+
* the entry to silently apply nowhere (which is almost always a bug).
|
|
238
|
+
* - `wildcard`: filter is exactly `'*'` or `['*']` (or any combination of
|
|
239
|
+
* pure-wildcard patterns) — matches every project, equivalent to no
|
|
240
|
+
* filter at all. Doesn't count toward the broadcast guard or the
|
|
241
|
+
* specificity tier so the entry doesn't outrank a real, narrower one.
|
|
242
|
+
* - `filter`: a real pattern set the matcher needs to evaluate.
|
|
243
|
+
*/
|
|
244
|
+
function classifyProjectsFilter(projects) {
|
|
245
|
+
if (projects === undefined)
|
|
246
|
+
return 'none';
|
|
247
|
+
const arr = Array.isArray(projects) ? projects : [projects];
|
|
248
|
+
if (arr.length === 0)
|
|
249
|
+
return 'empty';
|
|
250
|
+
if (arr.every((p) => p === '*'))
|
|
251
|
+
return 'wildcard';
|
|
252
|
+
return 'filter';
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Test a single `targetDefaults` entry against the (target, executor,
|
|
256
|
+
* project, plugin, command) tuple of the target being resolved. Returns
|
|
257
|
+
* a `Candidate` with its tier and match kind, or null when the entry
|
|
258
|
+
* doesn't apply.
|
|
259
|
+
*
|
|
260
|
+
* The match facts (`targetName`, `executor`, `projectName`, `projectNode`,
|
|
261
|
+
* `sourcePlugin`, `targetCommand`) are passed in instead of being read
|
|
262
|
+
* from the graph node here because callers — `findBestTargetDefault` and
|
|
263
|
+
* `buildSyntheticTargetForRoot` — work in different graph contexts. The
|
|
264
|
+
* synthetic builder, in particular, evaluates against the *effective*
|
|
265
|
+
* executor/command (what the merge will land on), which doesn't always
|
|
266
|
+
* equal the node's current executor; threading the values explicitly
|
|
267
|
+
* keeps that asymmetry visible at the call sites.
|
|
268
|
+
*/
|
|
269
|
+
function matchEntry(entry, index, targetName, executor, projectName, projectNode, sourcePlugin, targetCommand) {
|
|
270
|
+
if (!entry)
|
|
271
|
+
return null;
|
|
272
|
+
// `normalizeTargetDefaults` already drops entries with neither locator
|
|
273
|
+
// nor real filter. Empty-array `projects:` is an explicit never-match
|
|
274
|
+
// shape — kept by the normalizer because it's named, rejected here.
|
|
275
|
+
const projectsKind = classifyProjectsFilter(entry.projects);
|
|
276
|
+
if (projectsKind === 'empty')
|
|
277
|
+
return null;
|
|
278
|
+
let targetKind = null;
|
|
279
|
+
if (entry.target !== undefined) {
|
|
280
|
+
if (entry.target === targetName)
|
|
281
|
+
targetKind = 'exact';
|
|
282
|
+
else if ((0, globs_1.isGlobPattern)(entry.target) && (0, minimatch_1.minimatch)(targetName, entry.target))
|
|
283
|
+
targetKind = 'glob';
|
|
284
|
+
else
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
let executorMatched = false;
|
|
288
|
+
if (entry.executor !== undefined) {
|
|
289
|
+
if (executor && executor === entry.executor) {
|
|
290
|
+
executorMatched = true;
|
|
291
|
+
}
|
|
292
|
+
else if (targetKind !== null && !executor && !targetCommand) {
|
|
293
|
+
// Bare target with no executor — safe to inject the entry's
|
|
294
|
+
// executor because the target locator has already narrowed the match.
|
|
295
|
+
executorMatched = true;
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Locator-bearing entries get a base tier of 1 (the locator match);
|
|
302
|
+
// filter-only entries start at 0 so a single filter doesn't tie a
|
|
303
|
+
// single locator. Filters then add 1 each — with the matchKind
|
|
304
|
+
// tie-break below, filter-only always loses to locator-bearing at
|
|
305
|
+
// the same final tier.
|
|
306
|
+
const hasLocator = targetKind !== null || executorMatched;
|
|
307
|
+
let tier = hasLocator ? 1 : 0;
|
|
308
|
+
if (projectsKind === 'filter') {
|
|
309
|
+
if (!projectName || !projectNode)
|
|
310
|
+
return null;
|
|
311
|
+
// Copy — `findMatchingProjects` prepends `*` for a leading negation
|
|
312
|
+
// and would otherwise mutate the shared nxJson entry.
|
|
313
|
+
const patterns = Array.isArray(entry.projects)
|
|
314
|
+
? [...entry.projects]
|
|
315
|
+
: [entry.projects];
|
|
316
|
+
const matched = (0, find_matching_projects_1.findMatchingProjects)(patterns, {
|
|
317
|
+
[projectName]: projectNode,
|
|
318
|
+
});
|
|
319
|
+
if (!matched.includes(projectName))
|
|
320
|
+
return null;
|
|
321
|
+
tier++;
|
|
322
|
+
}
|
|
323
|
+
if (entry.plugin !== undefined) {
|
|
324
|
+
if (entry.plugin !== sourcePlugin)
|
|
325
|
+
return null;
|
|
326
|
+
tier++;
|
|
327
|
+
}
|
|
328
|
+
// Safety net for callers (e.g. direct unit-test calls) that bypass
|
|
329
|
+
// `normalizeTargetDefaults`: an entry with no locator and no real
|
|
330
|
+
// filter has tier 0 after processing — it would broadcast to every
|
|
331
|
+
// (root, target) in the workspace.
|
|
332
|
+
if (!hasLocator && tier === 0)
|
|
333
|
+
return null;
|
|
334
|
+
const matchKind = targetKind !== null && executorMatched
|
|
335
|
+
? 'targetAndExecutor'
|
|
336
|
+
: executorMatched
|
|
337
|
+
? 'executorOnly'
|
|
338
|
+
: targetKind === 'exact'
|
|
339
|
+
? 'exactTarget'
|
|
340
|
+
: targetKind === 'glob'
|
|
341
|
+
? 'globTarget'
|
|
342
|
+
: 'filterOnly';
|
|
343
|
+
return {
|
|
344
|
+
config: stripFilterKeys(entry),
|
|
345
|
+
tier,
|
|
346
|
+
matchKind,
|
|
347
|
+
index,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Specificity ordering for two candidate matches. Higher specificity
|
|
352
|
+
* wins because the more specific entry is the one the user most likely
|
|
353
|
+
* wrote to override a broader rule.
|
|
354
|
+
*
|
|
355
|
+
* 1. Tier — entries with `projects` or `plugin` filters are scoped
|
|
356
|
+
* narrower than unfiltered entries, so they outrank.
|
|
357
|
+
* 2. Match kind — within the same tier, more locator slots is more
|
|
358
|
+
* specific: `target+executor` > `executor-only` > `exactTarget` >
|
|
359
|
+
* `globTarget` > `filterOnly`. Note `executor-only` outranks
|
|
360
|
+
* `exactTarget`: a workspace-wide rule keyed on a specific executor
|
|
361
|
+
* is treated as more intentional than a target-name rule that might
|
|
362
|
+
* accidentally catch unrelated executors. `filterOnly` (no `target`
|
|
363
|
+
* and no `executor`, just `projects` and/or `plugin`) sits at the
|
|
364
|
+
* bottom — it's the explicit "least specific" tier that lets a bare
|
|
365
|
+
* `plugin: '@nx/jest/plugin'` apply to every jest-attributed target
|
|
366
|
+
* while still losing to any entry that names the target or executor.
|
|
367
|
+
* 3. Tie-break — later array index wins, so users can append an entry
|
|
368
|
+
* to override earlier ones without rewriting them.
|
|
369
|
+
*/
|
|
370
|
+
function beats(a, b) {
|
|
371
|
+
if (a.tier !== b.tier)
|
|
372
|
+
return a.tier > b.tier;
|
|
373
|
+
const aRank = matchKindRank(a.matchKind);
|
|
374
|
+
const bRank = matchKindRank(b.matchKind);
|
|
375
|
+
if (aRank !== bRank)
|
|
376
|
+
return aRank > bRank;
|
|
377
|
+
return a.index > b.index;
|
|
378
|
+
}
|
|
379
|
+
function matchKindRank(kind) {
|
|
380
|
+
switch (kind) {
|
|
381
|
+
case 'targetAndExecutor':
|
|
382
|
+
return 4;
|
|
383
|
+
case 'executorOnly':
|
|
384
|
+
return 3;
|
|
385
|
+
case 'exactTarget':
|
|
386
|
+
return 2;
|
|
387
|
+
case 'globTarget':
|
|
388
|
+
return 1;
|
|
389
|
+
case 'filterOnly':
|
|
390
|
+
return 0;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/** Removes keys used only for locating the defaults, leaving the merge payload. */
|
|
394
|
+
function stripFilterKeys(entry) {
|
|
395
|
+
const { target, projects, plugin, ...rest } = entry;
|
|
396
|
+
return rest;
|
|
397
|
+
}
|
|
398
|
+
let hasWarnedAboutLegacyRecordShape = false;
|
|
399
|
+
/**
|
|
400
|
+
* Accept either the new array shape or the legacy record shape and return
|
|
401
|
+
* a normalized array. Record entries become `{ target: key, ...value }`
|
|
402
|
+
* — except executor-shaped keys (e.g. `@nx/vite:test`, `nx:run-commands`)
|
|
403
|
+
* which become `{ executor: key, ...value }` so the matcher treats them
|
|
404
|
+
* as executor matches rather than target-name matches.
|
|
405
|
+
*
|
|
406
|
+
* Disambiguation here is purely syntactic — `:` in a record key is
|
|
407
|
+
* genuinely ambiguous (target names can contain `:`). Callers that have
|
|
408
|
+
* access to the workspace's targets (the graph-construction path, the
|
|
409
|
+
* v23 migration) should prefer
|
|
410
|
+
* {@link normalizeTargetDefaultsAgainstRootMaps} or the migration's
|
|
411
|
+
* graph-based classifier so that ambiguous keys get classified by what
|
|
412
|
+
* the workspace actually contains. The warning below points end-users
|
|
413
|
+
* at `nx repair`, which runs the migration that durably resolves the
|
|
414
|
+
* ambiguity in nx.json on disk.
|
|
415
|
+
*/
|
|
416
|
+
function normalizeTargetDefaults(raw) {
|
|
417
|
+
if (!raw)
|
|
418
|
+
return [];
|
|
419
|
+
const entries = Array.isArray(raw) ? raw : recordToEntries(raw);
|
|
420
|
+
return entries.filter(isWellFormedEntry);
|
|
421
|
+
}
|
|
422
|
+
function recordToEntries(raw) {
|
|
423
|
+
warnAboutLegacyRecordShapeOnce();
|
|
424
|
+
const out = [];
|
|
425
|
+
for (const key of Object.keys(raw)) {
|
|
426
|
+
const value = raw[key] ?? {};
|
|
427
|
+
out.push(...syntacticallyClassifyLegacyKey(key, value));
|
|
428
|
+
}
|
|
429
|
+
return out;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* An entry is well-formed when it has at least one locator (`target` /
|
|
433
|
+
* `executor`) or a real filter (`projects` resolving to something other
|
|
434
|
+
* than empty/wildcard, or `plugin`). Pre-filtering here lets the matcher
|
|
435
|
+
* trust its inputs and skip the per-entry broadcast guard.
|
|
436
|
+
*/
|
|
437
|
+
function isWellFormedEntry(entry) {
|
|
438
|
+
if (entry.target !== undefined)
|
|
439
|
+
return true;
|
|
440
|
+
if (entry.executor !== undefined)
|
|
441
|
+
return true;
|
|
442
|
+
if (entry.plugin !== undefined)
|
|
443
|
+
return true;
|
|
444
|
+
return classifyProjectsFilter(entry.projects) === 'filter';
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Same shape contract as {@link normalizeTargetDefaults}, but classifies
|
|
448
|
+
* `:`-shaped record keys against the targets and executors actually
|
|
449
|
+
* present in the supplied rootMaps. When a key matches a target name in
|
|
450
|
+
* the workspace, it becomes a `target:` entry; when it matches an
|
|
451
|
+
* executor, an `executor:` entry; when it matches both, both entries are
|
|
452
|
+
* emitted (matching the v23 migration's "duplicate rather than guess"
|
|
453
|
+
* behavior so neither side of the match silently drops). Falls back to
|
|
454
|
+
* the syntactic heuristic when there's no evidence either way.
|
|
455
|
+
*/
|
|
456
|
+
function normalizeTargetDefaultsAgainstRootMaps(raw, ...rootMaps) {
|
|
457
|
+
if (!raw)
|
|
458
|
+
return [];
|
|
459
|
+
if (Array.isArray(raw))
|
|
460
|
+
return raw;
|
|
461
|
+
warnAboutLegacyRecordShapeOnce();
|
|
462
|
+
const targetNames = new Set();
|
|
463
|
+
const executors = new Set();
|
|
464
|
+
for (const map of rootMaps) {
|
|
465
|
+
for (const cfg of Object.values(map)) {
|
|
466
|
+
const targets = cfg?.targets;
|
|
467
|
+
if (!targets)
|
|
468
|
+
continue;
|
|
469
|
+
for (const [name, target] of Object.entries(targets)) {
|
|
470
|
+
targetNames.add(name);
|
|
471
|
+
if (target?.executor)
|
|
472
|
+
executors.add(target.executor);
|
|
128
473
|
}
|
|
129
474
|
}
|
|
130
475
|
}
|
|
131
|
-
|
|
132
|
-
|
|
476
|
+
const out = [];
|
|
477
|
+
for (const key of Object.keys(raw)) {
|
|
478
|
+
const value = raw[key] ?? {};
|
|
479
|
+
if ((0, globs_1.isGlobPattern)(key)) {
|
|
480
|
+
out.push({ ...value, target: key });
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
const matchesTarget = targetNames.has(key);
|
|
484
|
+
const matchesExecutor = executors.has(key);
|
|
485
|
+
if (matchesTarget && matchesExecutor) {
|
|
486
|
+
out.push({ ...value, target: key }, { ...value, executor: key });
|
|
487
|
+
}
|
|
488
|
+
else if (matchesExecutor) {
|
|
489
|
+
out.push({ ...value, executor: key });
|
|
490
|
+
}
|
|
491
|
+
else if (matchesTarget) {
|
|
492
|
+
out.push({ ...value, target: key });
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
out.push(...syntacticallyClassifyLegacyKey(key, value));
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return out;
|
|
499
|
+
}
|
|
500
|
+
function syntacticallyClassifyLegacyKey(key, value) {
|
|
501
|
+
return [
|
|
502
|
+
key.includes(':') && !(0, globs_1.isGlobPattern)(key)
|
|
503
|
+
? { ...value, executor: key }
|
|
504
|
+
: { ...value, target: key },
|
|
505
|
+
];
|
|
506
|
+
}
|
|
507
|
+
function warnAboutLegacyRecordShapeOnce() {
|
|
508
|
+
if (hasWarnedAboutLegacyRecordShape)
|
|
509
|
+
return;
|
|
510
|
+
hasWarnedAboutLegacyRecordShape = true;
|
|
511
|
+
// Written to stderr (not stdout) so commands with structured stdout —
|
|
512
|
+
// e.g. `nx show project --json` — remain parseable.
|
|
513
|
+
const title = pc.yellow('NX nx.json uses the legacy record-shape `targetDefaults`');
|
|
514
|
+
const bodyLines = [
|
|
515
|
+
'The object/record form of `targetDefaults` is deprecated. Nx still reads it for now, but the array form is required to use the new `projects` and `plugin` filters.',
|
|
516
|
+
'Run `nx repair` to automatically convert `targetDefaults` to the array shape.',
|
|
517
|
+
];
|
|
518
|
+
process.stderr.write(`${os_1.EOL}${title}${os_1.EOL}${os_1.EOL}${bodyLines
|
|
519
|
+
.map((l) => ` ${l}`)
|
|
520
|
+
.join(os_1.EOL)}${os_1.EOL}${os_1.EOL}`);
|
|
521
|
+
}
|
|
522
|
+
function resolveSourcePlugin(root, targetName, specifiedSourceMaps, defaultSourceMaps) {
|
|
523
|
+
// Default-plugin attribution overrides specified-plugin attribution in
|
|
524
|
+
// the merge, so we check it first. Only the executor/command keys are
|
|
525
|
+
// reliable — the top-level `targets.<name>` key tracks the last writer.
|
|
526
|
+
const executorKey = (0, source_maps_1.targetOptionSourceMapKey)(targetName, 'executor');
|
|
527
|
+
const commandKey = (0, source_maps_1.targetOptionSourceMapKey)(targetName, 'command');
|
|
528
|
+
const candidates = [
|
|
529
|
+
pluginFromSourceMap(defaultSourceMaps, root, executorKey),
|
|
530
|
+
pluginFromSourceMap(defaultSourceMaps, root, commandKey),
|
|
531
|
+
pluginFromSourceMap(specifiedSourceMaps, root, executorKey),
|
|
532
|
+
pluginFromSourceMap(specifiedSourceMaps, root, commandKey),
|
|
533
|
+
];
|
|
534
|
+
for (const candidate of candidates) {
|
|
535
|
+
if (candidate && candidate !== 'nx/target-defaults')
|
|
536
|
+
return candidate;
|
|
133
537
|
}
|
|
134
|
-
return
|
|
538
|
+
return undefined;
|
|
539
|
+
}
|
|
540
|
+
function pluginFromSourceMap(maps, root, key) {
|
|
541
|
+
const entry = maps?.[root]?.[key];
|
|
542
|
+
return entry?.[1];
|
|
543
|
+
}
|
|
544
|
+
// Walks both layered rootMaps and produces a name → ProjectGraphProjectNode
|
|
545
|
+
// view for `findMatchingProjects` to consult. Default-plugin-only
|
|
546
|
+
// projects are included — they're the bulk of typical workspaces and
|
|
547
|
+
// `projects:` filters need to apply to them too. Tags are unioned across
|
|
548
|
+
// layers so tag-based filters see all contributions.
|
|
549
|
+
//
|
|
550
|
+
// We don't reuse `mergeProjectConfigurationIntoRootMap` here: it does a
|
|
551
|
+
// full project-config merge (targets, named inputs, source maps, ...)
|
|
552
|
+
// keyed by root, while this function only needs name + tags keyed by
|
|
553
|
+
// name. The full merge would be substantial wasted work on every graph
|
|
554
|
+
// build.
|
|
555
|
+
function buildProjectNodesAndRootToName(specifiedPluginRootMap, defaultPluginRootMap) {
|
|
556
|
+
const projectNodesByName = {};
|
|
557
|
+
const rootToName = new Map();
|
|
558
|
+
const addFromMap = (map) => {
|
|
559
|
+
for (const root of Object.keys(map)) {
|
|
560
|
+
const cfg = map[root];
|
|
561
|
+
const name = cfg?.name;
|
|
562
|
+
if (!name)
|
|
563
|
+
continue;
|
|
564
|
+
if (projectNodesByName[name]) {
|
|
565
|
+
const existingTags = projectNodesByName[name].data.tags ?? [];
|
|
566
|
+
const newTags = cfg.tags ?? [];
|
|
567
|
+
projectNodesByName[name].data.tags = Array.from(new Set([...existingTags, ...newTags]));
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
projectNodesByName[name] = {
|
|
571
|
+
name,
|
|
572
|
+
type: cfg.projectType === 'application' ? 'app' : 'lib',
|
|
573
|
+
data: { root, tags: cfg.tags ?? [] },
|
|
574
|
+
};
|
|
575
|
+
rootToName.set(root, name);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
addFromMap(specifiedPluginRootMap);
|
|
580
|
+
addFromMap(defaultPluginRootMap);
|
|
581
|
+
return { projectNodesByName, rootToName };
|
|
135
582
|
}
|
|
@@ -60,11 +60,19 @@ export type MergeError = AggregateCreateNodesError | MergeNodesError | ProjectsW
|
|
|
60
60
|
/**
|
|
61
61
|
* Merges create nodes results into a single rootMap.
|
|
62
62
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
63
|
+
* Specified plugin results are merged once into the manager. Default
|
|
64
|
+
* plugin results are first staged into an intermediate rootMap (with
|
|
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.
|
|
70
|
+
*
|
|
71
|
+
* Synthesis itself doesn't materialize a second rootMap. Per
|
|
72
|
+
* (root, target) it does an on-the-fly merge of the two layered
|
|
73
|
+
* contributions to learn the eventual executor/command, then matches
|
|
74
|
+
* defaults against that merged shape. This keeps specified-plugin
|
|
75
|
+
* merge work to a single pass.
|
|
68
76
|
*/
|
|
69
77
|
export declare function mergeCreateNodesResults(specifiedResults: CreateNodesResultEntry[][], defaultResults: CreateNodesResultEntry[][], nxJsonConfiguration: NxJsonConfiguration, workspaceRoot: string, errors: MergeError[]): {
|
|
70
78
|
projectRootMap: Record<string, ProjectConfiguration>;
|