Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(core): add negation pattern support for plugin include/exclude#34160

Merged
llwt merged 5 commits intomasterfrom
support-plugin-project-negations
Feb 12, 2026
Merged

feat(core): add negation pattern support for plugin include/exclude#34160
llwt merged 5 commits intomasterfrom
support-plugin-project-negations

Conversation

@llwt
Copy link
Member

@llwt llwt commented Jan 20, 2026

Current Behavior

Negation patterns are ignored in plugin configuration for the include and exclude properties.

Expected Behavior

  • Negation patterns should work in the same way that they do for other include/exclude configurations

Example: Excluding all e2e projects except one

// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/jest/plugin",
      "exclude": ["**/*-e2e/**/*", "!**/toolkit-workspace-e2e/**/*"],
    },
  ],
}

This will exclude all e2e projects except toolkit-workspace-e2e.

Example: Including packages except legacy ones

// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/vite/plugin",
      "include": ["packages/**/*", "!packages/legacy/**/*"],
    },
  ],
}

How negation patterns work:

  • Patterns are processed in order from first to last
  • A pattern starting with ! removes files from the match set
  • A pattern without ! adds files to the match set
  • The last matching pattern determines if a file is included
  • If the first pattern is a negation, all files are matched initially

@vercel
Copy link

vercel bot commented Jan 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nx-dev Ready Ready Preview Feb 4, 2026 6:52pm

Request Review

@netlify
Copy link

netlify bot commented Jan 20, 2026

Deploy Preview for nx-docs ready!

Name Link
🔨 Latest commit 33a380a
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/6989f9dfda57030008051a37
😎 Deploy Preview https://deploy-preview-34160--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
Contributor

nx-cloud bot commented Jan 20, 2026

View your CI Pipeline Execution ↗ for commit 33a380a

Command Status Duration Result
nx affected --targets=lint,test,test-kt,build,e... ✅ Succeeded 49m 15s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 3m View ↗
nx-cloud record -- nx-cloud conformance:check ✅ Succeeded 11s 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-02-09 16:08:55 UTC

Comment on lines 625 to 627
// Process include patterns with negation support
if (include && include.length > 0) {
if (!matchesPatternArray(file, include)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

@AgentEnder So to do this we have to move from .some to always checking all patterns.

This feels like it should be ok, but I worry that someone might have a project config doing something weird like enumerating all projects they want a plugin enabled for 😅

Thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, in a repo I've not tuned at all, just using our generators to create some buildable and some non-buildable projects, the ts plugin is configureded as below:

{
  "plugins": [
    {
      "plugin": "@nx/js/typescript",
      "options": {
        "typecheck": {
          "targetName": "typecheck"
        },
        "build": {
          "targetName": "build",
          "configName": "tsconfig.lib.json",
          "buildDepsName": "build-deps",
          "watchDepsName": "watch-deps"
        }
      },
      "exclude": [
        "packages/model/*",
        "packages/env-schemas/*",
        "packages/schema-utils/*",
        "e2e/*"
      ]
    },
    {
      "plugin": "@nx/js/typescript",
      "include": [
        "packages/model/*",
        "packages/env-schemas/*",
        "packages/schema-utils/*"
      ],
      "options": {
        "typecheck": {
          "targetName": "typecheck"
        }
      }
    },
  ]
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a check for negations in the patterns before doing the more expensive check. With this the current perf should at least be maintained for anyone not using negations.

nx-cloud[bot]

This comment was marked as outdated.

@llwt llwt marked this pull request as ready for review February 3, 2026 15:46
@llwt llwt requested review from a team as code owners February 3, 2026 15:46
@llwt llwt requested review from AgentEnder and MaxKless February 3, 2026 15:46
Copy link
Contributor

@barbados-clemens barbados-clemens left a comment

Choose a reason for hiding this comment

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

docs are fine 👍

nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

Copy link
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.

Important

At least one additional CI pipeline execution has run since the conclusion below was written and it may no longer be applicable.

Nx Cloud has identified a possible root cause for your failed CI:

We're classifying this react-native:test failure as environment_state because it's caused by a corrupted ESLint cache file (empty JSON file) in .nx/workspace-data/, not by the pattern matching changes in this PR. The failing project wasn't modified by this PR, and the error occurs in cache file reading logic that this PR doesn't touch. This requires clearing the workspace cache rather than code changes.

No code changes were suggested for this issue.

Trigger a rerun:

Rerun CI

Nx Cloud View detailed reasoning on Nx Cloud ↗


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

if (!included) {
continue;
}
if (!includes(file)) {
Copy link
Member

Choose a reason for hiding this comment

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

I honestly kind of hate that we are doing this whole if matches, check matches, then check other matches thing, but its existing code and I don't know of a good way to combine them off the top of my head, nor that it'd be faster if we did... In any case, that's not your PRs fault. I think this is fine?

@AgentEnder AgentEnder force-pushed the support-plugin-project-negations branch from e15cb6e to 7e51623 Compare February 4, 2026 17:45
@netlify
Copy link

netlify bot commented Feb 4, 2026

Deploy Preview for nx-dev ready!

Name Link
🔨 Latest commit 33a380a
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/6989f9df603a180008d0d08d
😎 Deploy Preview https://deploy-preview-34160--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.

llwt and others added 4 commits February 4, 2026 13:42
Add support for negation patterns (patterns starting with '!') in the
include and exclude fields of plugin configurations. This allows more
precise control over which files plugins process.

Example usage:
```json
{
  "plugin": "@nx/jest/plugin",
  "exclude": ["**/*-e2e/**/*", "!**/toolkit-workspace-e2e/**/*"]
}
```

This will exclude all e2e projects except toolkit-workspace-e2e.

Implementation follows the same negation pattern algorithm used by
findMatchingProjects:
- Patterns are processed sequentially
- Patterns starting with '!' remove files from the match set
- Positive patterns add files to the match set
- Last matching pattern wins
- If first pattern is a negation, all files are matched initially

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
…clude

Add documentation for the newly added negation pattern feature in
plugin include/exclude configuration. Includes examples and explanation
of how the patterns are processed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
…terns

Add a fast path for pattern matching when no negation patterns are present.
This maintains backward-compatible performance while supporting the new
negation pattern feature.

Performance impact (1500 files, 4 patterns):
- Non-negation patterns: 18% faster than before (26.8ms vs 32.7ms)
- With negation patterns: Acceptable overhead for new feature (23.6ms)

The fast path uses short-circuit evaluation (.some()) which exits early
on first match, while the slow path processes all patterns sequentially
to handle negation logic correctly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Refactor pattern matching to check for negation patterns once upfront
instead of on every file iteration. Creates specialized matcher functions
that eliminate null checks and branching in the hot loop.

Changes:
- Split into matchesSimplePatterns (fast) and matchesNegationPatterns (full)
- createIncludeMatcher() returns function that always returns true if empty
- createExcludeMatcher() returns function that always returns false if empty
- Eliminates null checks and conditional logic in the file iteration loop
- Matchers created outside the file loop in findMatchingConfigFiles

Performance impact (1500 files, 4 patterns):
- Before: 32.1ms (checking negation per file)
- After: 26.0ms (checking negation once)
- Improvement: 19% faster

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@llwt llwt merged commit 754b01a into master Feb 12, 2026
24 checks passed
@llwt llwt deleted the support-plugin-project-negations branch February 12, 2026 15:03
FrozenPandaz pushed a commit that referenced this pull request Feb 13, 2026
…34160)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
Negation patterns are ignored in plugin configuration for the `include`
and `exclude` properties.

## Expected Behavior

- Negation patterns should work in the same way that they do for other
`include`/`exclude` configurations

**Example: Excluding all e2e projects except one**

```jsonc
// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/jest/plugin",
      "exclude": ["**/*-e2e/**/*", "!**/toolkit-workspace-e2e/**/*"],
    },
  ],
}
```

This will exclude all e2e projects except `toolkit-workspace-e2e`.

**Example: Including packages except legacy ones**

```jsonc
// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/vite/plugin",
      "include": ["packages/**/*", "!packages/legacy/**/*"],
    },
  ],
}
```

**How negation patterns work:**

- Patterns are processed in order from first to last
- A pattern starting with `!` removes files from the match set
- A pattern without `!` adds files to the match set
- The last matching pattern determines if a file is included
- If the first pattern is a negation, all files are matched initially

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
FrozenPandaz pushed a commit that referenced this pull request Feb 13, 2026
…34160)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
Negation patterns are ignored in plugin configuration for the `include`
and `exclude` properties.

## Expected Behavior

- Negation patterns should work in the same way that they do for other
`include`/`exclude` configurations

**Example: Excluding all e2e projects except one**

```jsonc
// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/jest/plugin",
      "exclude": ["**/*-e2e/**/*", "!**/toolkit-workspace-e2e/**/*"],
    },
  ],
}
```

This will exclude all e2e projects except `toolkit-workspace-e2e`.

**Example: Including packages except legacy ones**

```jsonc
// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/vite/plugin",
      "include": ["packages/**/*", "!packages/legacy/**/*"],
    },
  ],
}
```

**How negation patterns work:**

- Patterns are processed in order from first to last
- A pattern starting with `!` removes files from the match set
- A pattern without `!` adds files to the match set
- The last matching pattern determines if a file is included
- If the first pattern is a negation, all files are matched initially

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
(cherry picked from commit 754b01a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants