Skip to content

fix(devkit): only rewrite deep-import paths in real import sites#35566

Merged
FrozenPandaz merged 4 commits into
masterfrom
fix-deep-imports-regex-fallback
May 5, 2026
Merged

fix(devkit): only rewrite deep-import paths in real import sites#35566
FrozenPandaz merged 4 commits into
masterfrom
fix-deep-imports-regex-fallback

Conversation

@FrozenPandaz
Copy link
Copy Markdown
Contributor

Current Behavior

The 23.0.0-beta.6 @nx/devkit deep-import migration (#35541) catches non-named-import shapes (default / namespace / side-effect / require() / dynamic import() / jest.mock-style calls) by running a regex sweep over the file:

const FALLBACK_RE = /(['"])@nx\/devkit\/src\/[^'"\n]+?\1/g;
updated = updated.replace(
  FALLBACK_RE,
  (_match, quote: string) => `${quote}${INTERNAL_SPECIFIER}${quote}`
);

That sweep matches any '@nx/devkit/src/...' literal anywhere in the file, regardless of context. As a result the migration mangled:

  • Test fixtures inside template literals — including the migration's own update-deep-imports.spec.ts. Examples observed in the wild: packages/devkit/src/migrations/update-23-0-0/update-deep-imports.spec.ts, packages/expo/src/utils/expo-project-detection.spec.ts, packages/nuxt/src/plugins/plugin.spec.ts, packages/react-native/src/utils/react-native-project-detection.spec.ts, etc. (nrwl/nx#35565)
  • typeof import('@nx/devkit/src/...') type queries — e.g. libs/shared/npm/src/lib/local-nx-utils/parse-target-string.ts in nrwl/nx-console, where the type now claims @nx/devkit/internal while the runtime importPath next to it is built dynamically and still points at src/.... (nrwl/nx-console#3131)
  • Deep-import paths in comments, doc strings, and arbitrary string-literal arguments to unrelated functions.

Expected Behavior

The migration only rewrites deep-import paths that are actually import sites. Everything else (template strings, type queries, comments, unrelated calls) is left alone.

This is implemented by replacing the regex sweep with a TypeScript-AST visitor that only rewrites the string-literal argument of CallExpression nodes whose callee is one of:

  • require (identifier)
  • the dynamic-import keyword
  • jest.mock / jest.unmock / jest.doMock / jest.dontMock / jest.requireActual / jest.requireMock
  • vi.mock / vi.unmock / vi.doMock / vi.dontMock / vi.requireActual / vi.requireMock / vi.importActual / vi.importMock

Type queries (ImportTypeNode), template literals, and comments are all naturally untouched because they are not CallExpression nodes — no allowlist needed. Quote style is preserved per literal.

The named-import bucketing pass and the duplicate-collapse pass are unchanged.

Tests

10 new unit tests:

  • 5 in a new non-runtime string literals block guarding template literals, typeof import(...) type queries, block comments, line comments, and unrelated call expressions.
  • 5 in a new mock helper calls block covering jest.mock, jest.requireActual, vi.mock, vi.importActual, and a paired import + jest.mock + jest.requireActual combination.

All 39 unit tests pass; nx build devkit is clean.

Related Issue(s)

Follow-up to #35541. Workspaces that have already merged the bad rewrites need to revert those files by hand — there's no general way to undo the over-rewrites without losing the legitimate ones.

The 23.0.0-beta.6 deep-import migration used a regex sweep to handle
non-named-import shapes (default / namespace / side-effect / require /
dynamic import / jest.mock-style calls). The sweep was too aggressive
and rewrote any `'@nx/devkit/src/...'` literal it found, including:

- Test fixtures inside template literals (mangled the migration's own
  spec file as well as several plugin specs in nrwl/nx and downstream
  repos).
- `typeof import('@nx/devkit/src/...')` type queries.
- Deep-import paths mentioned in comments.
- String-literal arguments to unrelated functions.

Replace the regex pass with a TypeScript-AST visitor that only rewrites
string-literal arguments to call expressions whose callee is `require`,
the dynamic-`import` keyword, or one of the `jest.*` / `vi.*` mock
helpers (`mock`, `unmock`, `doMock`, `dontMock`, `requireActual`,
`requireMock`, `importActual`, `importMock`). Type queries, template
literals, and comments are all naturally untouched because they aren't
`CallExpression` nodes. Quote style is preserved per literal.

Adds 10 new unit tests covering the previously-mangled cases and the
mock-helper rewrites.
@FrozenPandaz FrozenPandaz requested a review from a team as a code owner May 5, 2026 02:50
@FrozenPandaz FrozenPandaz requested a review from AgentEnder May 5, 2026 02:50
@netlify
Copy link
Copy Markdown

netlify Bot commented May 5, 2026

Deploy Preview for nx-dev ready!

Name Link
🔨 Latest commit f50401a
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/69f993915d28220008dd2075
😎 Deploy Preview https://deploy-preview-35566--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 May 5, 2026

Deploy Preview for nx-docs ready!

Name Link
🔨 Latest commit f50401a
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/69f99391bb86960008c568b8
😎 Deploy Preview https://deploy-preview-35566--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 May 5, 2026

View your CI Pipeline Execution ↗ for commit 59d3f7f

Command Status Duration Result
nx affected --targets=lint,test,build,e2e,e2e-c... ✅ Succeeded 10m 40s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 3s View ↗
nx-cloud record -- pnpm nx-cloud conformance:check ✅ Succeeded 18s View ↗
nx build workspace-plugin ✅ Succeeded 2m 11s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded 24s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 7s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-05 07:08:51 UTC

The `tools/workspace-plugin` repo generator was last meaningfully
touched well before the strict `@nx/devkit` exports map landed and the
templates it scaffolds rely on a deep import
(\`@nx/devkit/src/utils/replace-project-configuration-with-plugin\`)
pointing at a function that is not re-exported from any current devkit
entry point. Anything generated from this template would fail to
compile under 23.0.0-beta.6, so removing the generator outright rather
than expanding the semi-private surface to keep it alive.

Drops:
- \`tools/workspace-plugin/src/generators/create-nodes-plugin/\` (full directory)
- The \`create-nodes-plugin\` entry from \`tools/workspace-plugin/generators.json\`
- The \"Creating a New Plugin\" example in
  \`.claude/skills/run-nx-generator/SKILL.md\`
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.

✅ The fix from Nx Cloud was applied

We removed the stale @nx/plugin dependency from tools/workspace-plugin/package.json to fix the workspace-plugin:lint failure. The create-nodes-plugin generator — the sole consumer of @nx/plugin — was deleted by this PR, leaving the dependency declared but unused and causing the @nx/dependency-checks ESLint rule to error.

Tip

We verified this fix by re-running workspace-plugin:lint, e2e-eslint:e2e-ci--src/linter-legacy.test.ts.

Suggested Fix changes
diff --git a/tools/workspace-plugin/package.json b/tools/workspace-plugin/package.json
index 001cba59..ada4e553 100644
--- a/tools/workspace-plugin/package.json
+++ b/tools/workspace-plugin/package.json
@@ -8,7 +8,6 @@
     "@nx/conformance": "5.0.4",
     "@nx/devkit": "23.0.0-beta.4",
     "@nx/js": "23.0.0-beta.4",
-    "@nx/plugin": "23.0.0-beta.4",
     "@xmldom/xmldom": "^0.8.10",
     "glob": "7.1.4",
     "semver": "catalog:",

Revert fix via Nx Cloud  

View interactive diff ↗

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

nx-cloud Bot and others added 2 commits May 5, 2026 06:40
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
@FrozenPandaz FrozenPandaz merged commit 7b15a56 into master May 5, 2026
17 checks passed
@FrozenPandaz FrozenPandaz deleted the fix-deep-imports-regex-fallback branch May 5, 2026 14:42
@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 May 11, 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