Skip to content

Support !-prefix exclusions in filter entries#222

Merged
petehauge merged 2 commits into
mainfrom
petehauge-filter-exclusion-prefix
Jul 3, 2026
Merged

Support !-prefix exclusions in filter entries#222
petehauge merged 2 commits into
mainfrom
petehauge-filter-exclusion-prefix

Conversation

@petehauge

Copy link
Copy Markdown
Contributor

Summary

Adds a negation operator to filter allowlists. Any filter entry whose first character is ! is treated as an exclusion rather than an inclusion, letting users concisely say "include everything matching this pattern, except these specific ones."

apis:
  - 'prod-*'
  - '!prod-legacy-billing'      # exact-name exclusion
  - '!prod-*-deprecated'        # wildcard exclusion

namedValues:
  - '!keyvault-*'               # pure-exclusion list = include-all-minus

Semantics

  • ! must be the first character of an entry to be interpreted as negation; foo!bar is a literal name. (APIM resource names cannot contain !, so this is unambiguous.)
  • A resource is included iff at least one inclusion matches and no exclusion matches.
  • A list containing only exclusions is treated as "include everything, then subtract" — equivalent to an implicit leading *.
  • Applies uniformly to every top-level string list (apis, backends, products, namedValues, …) and to nested lists inside apiSubFilters and workspaceSubFiltersworkspaceSubFilters reuse FilterConfig under the hood, so no separate wiring is needed.
  • Existing semantics preserved: case-insensitive matching, API root-name matching (revision suffixes stripped), parent → child inheritance (excluding a parent cascades to its children).

Changes

  • src/services/filter-service.tsmatchesFilter now partitions each allowlist into includes / excludes by leading-! prefix and evaluates (no includes OR any include matches) AND no exclude matches. A small entryMatches helper deduplicates wildcard vs. exact matching logic.
  • tests/unit/services/filter-service.test.ts — new negation suite (9 tests) covering pure-exclusion, mixed inclusion + exclusion, wildcard exclusion, case-insensitivity, revision-suffix matching, parent → child cascade, non-leading ! treated as a literal character, and exclusions inside apiSubFilters.
  • docs/guides/filtering-resources.md — new "Excluding resources with !" section with worked examples for top-level and sub-filter usage.

No schema changes — !-prefixed strings are already valid string entries, so config-loader doesn't need to know about the operator.

Related Issue(s)

Closes #216

Verification

  • npm test — 1075 tests pass (49 test files).
  • npm run lint — clean.

Entries in filter allowlists whose first character is `!` are now treated
as exclusions. A resource is included iff at least one inclusion matches
and no exclusion matches. Pure-exclusion lists behave as
"include-all, then subtract" (implicit `*` include).

- Localized to `matchesFilter` in filter-service.ts; no schema changes.
- Works uniformly for top-level fields (apiNames, backendNames, ...) and
  for `apiSubFilters` / `workspaceSubFilters` string lists.
- Respects existing semantics: case-insensitive, API revision-suffix
  stripping, parent-to-child cascading.
- New unit tests cover pure-exclusion, mixed inclusion + exclusion,
  wildcard exclusion, revision matching, parent cascade, non-leading
  `!` as literal, and sub-filter exclusions.
- Docs: filtering-resources.md gains a negation section with examples.

Closes #216

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

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.

Pull request overview

This PR extends the existing filter matching logic to support !-prefixed entries as exclusions, enabling “include-all-minus” and mixed include/exclude allowlists across top-level filter lists and nested sub-filter lists (e.g., apiSubFilters operations).

Changes:

  • Updated matchesFilter to split allowlists into inclusion vs. exclusion entries and apply (implicit/explicit include) AND (no exclude match) semantics.
  • Added a dedicated unit-test suite covering exclusion behavior (pure exclusion, wildcard exclusion, case-insensitivity, API revision-root matching, parent→child cascade, and apiSubFilters).
  • Documented ! exclusions in the filtering guide with semantics and examples.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/services/filter-service.ts Implements !-prefixed exclusions in allowlist matching via include/exclude evaluation.
tests/unit/services/filter-service.test.ts Adds unit tests validating exclusion semantics across key scenarios.
docs/guides/filtering-resources.md Documents the new exclusion operator with examples and semantics.

Comment thread src/services/filter-service.ts
Comment thread docs/guides/filtering-resources.md
EMaher
EMaher previously approved these changes Jul 2, 2026
@petehauge petehauge changed the title feat: support !-prefix exclusions in filter entries Support !-prefix exclusions in filter entries Jul 2, 2026
Address Copilot review feedback on #216 / PR #222: an unquoted leading
`!` in a YAML sequence is parsed as a YAML tag and produces a confusing
load error before the filter code ever sees the value. Add an explicit
"always quote `!` entries" note wherever we show filter syntax, so
users copying examples don't hit that.

Places updated:
- docs/guides/filtering-resources.md (main filter guide)
- docs/commands/extract.md (mentions `!` exclusion + quoting alongside
  the existing wildcard docs)
- src/templates/configs/filter-config.yaml (the init-scaffolded filter
  template; adds an exclusion example with the quoting note)
- src/templates/copilot/configure-filter-prompt.md (teaches the
  configure-filter Copilot prompt about `!` exclusions + quoting)

Refs #216, PR #222.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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.

Support !-prefix exclusions in filter entries

3 participants