Skip to content

fix(core): split-target should handle projects with colons in name better#34725

Merged
FrozenPandaz merged 11 commits intomasterfrom
fix/split-target-fixes
Mar 21, 2026
Merged

fix(core): split-target should handle projects with colons in name better#34725
FrozenPandaz merged 11 commits intomasterfrom
fix/split-target-fixes

Conversation

@AgentEnder
Copy link
Copy Markdown
Member

@AgentEnder AgentEnder commented Mar 5, 2026

Current Behavior

  • splitTarget causes issues when a project name has more than one colon
  • Project name substitution is triggered when a project depends on the orginal name of a renamed project, even if the renamed project was renamed before the dep was registered

That second one is hard to understand. Imagine the real scenario below:

  • @nx/gradle was reading settings.gradle.kts and naming the root project nx
  • The package.json inference plugin renames it to @nx/nx-source
  • The package.json inference plugin infers the nx project in packages/nx
  • The package.json inference plugin reads a config that has dependsOn: [nx:build]
  • The substitutors run, and update the dependsOn to @nx/nx-source:build

Expected Behavior

splitTarget follows the below precedence:

  • If splitting a target string thats embedded in a specific project configuration, targets on that project are preferred
  • Targets belonging to the project with the longest name that is valid from joining segments left to right
  • Targets that have the longest name from joining segments are preferred
  • Configuration is the remaining segments after picking off the longest valid project containing a valid target.

Substitutors prefer registering by root if a project with a given name exists, and only register by name if no project with that root exists (e.g. if a plugin adds a dependsOn to a project that was inferred by a later plugin, this would be common if a custom plugin is reading project.json to get a name or smth).

AI Summary

Branch Analysis: fix/split-target-fixes vs master

Summary

Metric Lines
Total raw diff (added+removed, non-test) 2,840 + 1,221 = 4,061
Lines that were just moved (file split) ~960
Truly new/changed lines (non-test) ~570
Test file changes (raw diff) 3,109 added / 2,242 removed

Commits

SHA Message
57ec87b3c4 fix(core): split-target should handle projects with colons in name better
af1ebc90ab fix(core): avoid renaming projects based on former name if they were rooted when dep is drawn
b2fffc60c7 cleanup(core): split project-configuration-utils into focused modules
3bae3048d8 fix(core): fixup name substitution manager

File Split: project-configuration-utils.ts -> 4 modules

The original project-configuration-utils.ts (1,407 lines) was split into focused modules. ~960 lines were moved as-is (identical minus whitespace/formatting) into the new files. The remaining changes are actual logic modifications.

File Total Lines Moved from original Truly new/changed
project-configuration-utils.ts (remaining) 444 ~395 ~49
target-merging.ts 494 ~430 }
target-normalization.ts 282 ~250 } ~111 combined
project-nodes-manager.ts 365 ~285 }
Subtotal 1,585 ~1,360 ~160

Additionally, ~39 lines were removed from the original and not moved anywhere (dead code removal or refactored away).

Actual Code Changes (non-test, excluding moved lines)

Major changes

File New Removed Net Description
split-target.ts ~211 ~38 +173 New logic for handling projects with colons in names
name-substitution-manager.ts ~152 ~85 +67 Fix: avoid renaming rooted projects based on former name
Split files (combined, new logic only) ~111 +111 New code introduced during the split refactor
project-configuration-utils.ts (new logic only) ~49 ~39 +10 Residual new code after split

Minor edits (import path updates, small fixes)

File Added Removed
parse-target-string.ts 7 1
command-line/show/target.ts 11 7
devkit-internals.ts 3 5
tasks-runner/utils.ts 5 3
build-project-graph.ts 2 4
error-types.ts 2 4
command-line/run/run-one.ts 2 1
ngcli-adapter.ts 1 1
convert-nx-executor.ts 1 1
project-configuration.ts (generators) 1 1
package-json.ts 1 1
settings.gradle.kts 1 1
Minor edits subtotal 37 30

Other new files

File Lines Description
packages/devkit/CLAUDE.md 62 Dev documentation
__fixtures__/merge-create-nodes-args.json 100 Test fixture data

Final Tally: True Non-Test Changes

Category Lines
New logic in split-target.ts ~211
New logic in name-substitution-manager.ts ~152
New logic in split module files ~111
New logic in remaining project-configuration-utils.ts ~49
Minor import/path updates across 12 files ~37 added / ~30 removed
New non-code files (CLAUDE.md, fixture JSON) 162
Total truly new/changed lines ~570 added, ~160 removed
Moved lines (file split, not real changes) ~960

Related Issue(s)

Fixes #

@AgentEnder AgentEnder requested review from a team, FrozenPandaz, MaxKless and lourw as code owners March 5, 2026 18:13
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 5, 2026

Deploy Preview for nx-dev ready!

Name Link
🔨 Latest commit 71a7d43
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/69bddaa0706c5b0008385fc4
😎 Deploy Preview https://deploy-preview-34725--nx-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
Copy Markdown

netlify bot commented Mar 5, 2026

Deploy Preview for nx-docs ready!

Name Link
🔨 Latest commit 71a7d43
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/69bddaa0e698950008c9936d
😎 Deploy Preview https://deploy-preview-34725--nx-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@nx-cloud
Copy link
Copy Markdown
Contributor

nx-cloud bot commented Mar 5, 2026

View your CI Pipeline Execution ↗ for commit 71a7d43

Command Status Duration Result
nx affected --targets=lint,test,build,e2e,e2e-c... ✅ Succeeded 50m 26s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 8s View ↗
nx-cloud record -- pnpm nx conformance:check ✅ Succeeded 6s View ↗
nx build workspace-plugin ✅ Succeeded 2m 15s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 3s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded <1s View ↗

☁️ Nx Cloud last updated this comment at 2026-03-21 00:36:08 UTC

// substitutors that actually need it. Root-keyed substitutors are
// looked up by root directly and don't need the name at all.
if (this.substitutorsByUnresolvedName.has(previousName)) {
this.dirtyEntries.get(root).add(previousName);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TypeScript compilation error: this.dirtyEntries.get(root) returns Set<string> | undefined, but the code attempts to call .add() without a non-null assertion. Although line 614-616 ensures the entry exists, TypeScript cannot infer this.

Fix:

this.dirtyEntries.get(root)!.add(previousName);

This will cause the build to fail.

Suggested change
this.dirtyEntries.get(root).add(previousName);
this.dirtyEntries.get(root)!.add(previousName);

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

nx-cloud[bot]

This comment was marked as outdated.

@AgentEnder AgentEnder force-pushed the fix/split-target-fixes branch from 3bae304 to 3aae869 Compare March 6, 2026 04:05
@FrozenPandaz FrozenPandaz force-pushed the fix/split-target-fixes branch from 3aae869 to af4b552 Compare March 20, 2026 20:16
@FrozenPandaz FrozenPandaz requested a review from a team as a code owner March 20, 2026 20:16
Copy link
Copy Markdown
Contributor

@nx-cloud nx-cloud bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nx Cloud has identified a flaky task in your failed CI:

🔂 Since the failure was identified as flaky, we triggered a CI rerun by adding an empty commit to this branch.

Nx Cloud View detailed reasoning in Nx Cloud ↗

🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.


🎓 Learn more about Self-Healing CI on nx.dev

AgentEnder and others added 11 commits March 20, 2026 19:38
Decompose the monolithic project-configuration-utils.ts (~1400 lines)
into focused modules with a clear dependency DAG:

- target-merging.ts: target-level merge utilities (leaf module)
- target-normalization.ts: normalization, validation, target defaults
- project-nodes-manager.ts: project-level merge and read operations

Split the corresponding spec file into sibling spec files for each
new module. All 143 tests continue to pass.
Point consumers directly at source modules instead of
re-exporting through the old barrel file.
…pass bestMatch

Replace sort-based precedence selection with a single-pass bestMatch
to avoid unnecessary allocation. Thread currentProject from
normalizeDependencyConfigDefinition through expandDependencyConfigSyntaxSugar
and readProjectAndTargetFromTargetString so splitTarget can disambiguate
bare-target matches.
@FrozenPandaz FrozenPandaz force-pushed the fix/split-target-fixes branch from 2d38b16 to 71a7d43 Compare March 20, 2026 23:39
@FrozenPandaz FrozenPandaz enabled auto-merge (squash) March 20, 2026 23:40
@FrozenPandaz FrozenPandaz merged commit 1fc3841 into master Mar 21, 2026
24 checks passed
@FrozenPandaz FrozenPandaz deleted the fix/split-target-fixes branch March 21, 2026 00:37
FrozenPandaz pushed a commit that referenced this pull request Mar 26, 2026
…tter (#34725)

## Current Behavior
- `splitTarget` causes issues when a project name has more than one
colon
- Project name substitution is triggered when a project depends on the
orginal name of a renamed project, even if the renamed project was
renamed before the dep was registered

That second one is hard to understand. Imagine the real scenario below:

- @nx/gradle was reading settings.gradle.kts and naming the root project
`nx`
- The package.json inference plugin renames it to `@nx/nx-source`
- The package.json inference plugin infers the `nx` project in
`packages/nx`
- The package.json inference plugin reads a config that has `dependsOn:
[nx:build]`
- The substitutors run, and update the dependsOn to
`@nx/nx-source:build`

## Expected Behavior
splitTarget follows the below precedence:

- If splitting a target string thats embedded in a specific project
configuration, targets on that project are preferred
- Targets belonging to the project with the longest name that is valid
from joining segments left to right
- Targets that have the longest name from joining segments are preferred
- Configuration is the remaining segments after picking off the longest
valid project containing a valid target.

Substitutors prefer registering by root if a project with a given name
exists, and only register by name if no project with that root exists
(e.g. if a plugin adds a dependsOn to a project that was inferred by a
later plugin, this would be common if a custom plugin is reading
project.json to get a name or smth).

## AI Summary

> # Branch Analysis: `fix/split-target-fixes` vs `master`
>
> ## Summary
>
> | Metric | Lines |
> |--------|------:|
> | **Total raw diff (added+removed, non-test)** | 2,840 + 1,221 = 4,061
|
> | **Lines that were just moved (file split)** | ~960 |
> | **Truly new/changed lines (non-test)** | ~570 |
> | **Test file changes (raw diff)** | 3,109 added / 2,242 removed |
>
> ## Commits
>
> | SHA | Message |
> |-----|---------|
> | `57ec87b3c4` | fix(core): split-target should handle projects with
colons in name better |
> | `af1ebc90ab` | fix(core): avoid renaming projects based on former
name if they were rooted when dep is drawn |
> | `b2fffc60c7` | cleanup(core): split project-configuration-utils into
focused modules |
> | `3bae3048d8` | fix(core): fixup name substitution manager |
>
> ## File Split: `project-configuration-utils.ts` -> 4 modules
>
> The original `project-configuration-utils.ts` (1,407 lines) was split
into focused modules. **~960 lines were moved as-is** (identical minus
whitespace/formatting) into the new files. The remaining changes are
actual logic modifications.
>
> | File | Total Lines | Moved from original | Truly new/changed |
> |------|------------:|--------------------:|------------------:|
> | `project-configuration-utils.ts` (remaining) | 444 | ~395 | ~49 |
> | `target-merging.ts` | 494 | ~430 | } |
> | `target-normalization.ts` | 282 | ~250 | } ~111 combined |
> | `project-nodes-manager.ts` | 365 | ~285 | } |
> | **Subtotal** | 1,585 | ~1,360 | ~160 |
>
> Additionally, ~39 lines were removed from the original and not moved
anywhere (dead code removal or refactored away).
>
> ## Actual Code Changes (non-test, excluding moved lines)
>
> ### Major changes
>
> | File | New | Removed | Net | Description |
> |------|----:|--------:|----:|-------------|
> | `split-target.ts` | ~211 | ~38 | +173 | New logic for handling
projects with colons in names |
> | `name-substitution-manager.ts` | ~152 | ~85 | +67 | Fix: avoid
renaming rooted projects based on former name |
> | Split files (combined, new logic only) | ~111 | — | +111 | New code
introduced during the split refactor |
> | `project-configuration-utils.ts` (new logic only) | ~49 | ~39 | +10
| Residual new code after split |
>
> ### Minor edits (import path updates, small fixes)
>
> | File | Added | Removed |
> |------|------:|--------:|
> | `parse-target-string.ts` | 7 | 1 |
> | `command-line/show/target.ts` | 11 | 7 |
> | `devkit-internals.ts` | 3 | 5 |
> | `tasks-runner/utils.ts` | 5 | 3 |
> | `build-project-graph.ts` | 2 | 4 |
> | `error-types.ts` | 2 | 4 |
> | `command-line/run/run-one.ts` | 2 | 1 |
> | `ngcli-adapter.ts` | 1 | 1 |
> | `convert-nx-executor.ts` | 1 | 1 |
> | `project-configuration.ts` (generators) | 1 | 1 |
> | `package-json.ts` | 1 | 1 |
> | `settings.gradle.kts` | 1 | 1 |
> | **Minor edits subtotal** | **37** | **30** |
>
> ### Other new files
>
> | File | Lines | Description |
> |------|------:|-------------|
> | `packages/devkit/CLAUDE.md` | 62 | Dev documentation |
> | `__fixtures__/merge-create-nodes-args.json` | 100 | Test fixture
data |
>
> ## Final Tally: True Non-Test Changes
>
> | Category | Lines |
> |----------|------:|
> | New logic in `split-target.ts` | ~211 |
> | New logic in `name-substitution-manager.ts` | ~152 |
> | New logic in split module files | ~111 |
> | New logic in remaining `project-configuration-utils.ts` | ~49 |
> | Minor import/path updates across 12 files | ~37 added / ~30 removed
|
> | New non-code files (CLAUDE.md, fixture JSON) | 162 |
> | **Total truly new/changed lines** | **~570 added, ~160 removed** |
> | Moved lines (file split, not real changes) | **~960** |

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>

(cherry picked from commit 1fc3841)
@github-actions
Copy link
Copy Markdown
Contributor

This pull request has already been merged/closed. If you experience issues related to these changes, please open a new issue referencing this pull request.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants