Skip to content

Fix glob translation: leading/embedded **/ matches zero or more dirs#4

Merged
jongjesse merged 2 commits into
mainfrom
fix/glob-15-zero-leading-dirs
Jun 22, 2026
Merged

Fix glob translation: leading/embedded **/ matches zero or more dirs#4
jongjesse merged 2 commits into
mainfrom
fix/glob-15-zero-leading-dirs

Conversation

@jongjesse

@jongjesse jongjesse commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Finding #15 (from /review)

globToRegExp in src/comment/suppress.ts translated ** to .*
unconditionally. A gitignore-style path:**/Button.tsx became
^.*/Button.tsx$, which requires a leading slash and therefore does not
match a top-level Button.tsx. Likewise src/** did not match src itself.

Fix

Translate the ** variants with gitignore semantics:

glob becomes matches
leading/embedded **/ (?:.*/)? zero or more path segments — **/Button.tsx matches Button.tsx and a/b/Button.tsx
trailing /** (?:/.*)? the directory itself plus everything under it — src/** matches src and src/a.tsx
bare ** .* across / (unchanged)
single * [^/]* within one segment (unchanged)

The glob is tokenised with control-char sentinels before escaping regex
specials, so each variant is translated exactly once with no collisions.

Tests

Added cases to tests/comment-core.test.ts covering:

  • leading **/ matching top-level and nested files (and * not crossing /)
  • trailing /** matching the directory itself + nested, without prefix-name false positives
  • embedded **/ collapsing to zero-or-more middle segments
  • single * staying within one path segment

npm run typecheck && npm test && npm run build:all all pass (121 tests); rebuilt dist/ is included.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Tests
    • Enhanced test coverage for suppression path-glob matching behavior with additional test cases validating pattern matching across various file paths and directory depths.

`globToRegExp` in suppress.ts translated `**` to `.*` unconditionally, so a
gitignore-style `**/Button.tsx` became `^.*/Button.tsx$` — which requires a
slash and therefore failed to match a top-level `Button.tsx`. Likewise
`src/**` did not match `src` itself.

Translate the `**` variants with gitignore semantics:
  - leading/embedded `**/` -> `(?:.*/)?`  (zero or more path segments), so
    `**/Button.tsx` matches both `Button.tsx` and `a/b/Button.tsx`.
  - trailing `/**` -> `(?:/.*)?`, so `src/**` matches `src` and `src/a.tsx`.
  - bare `**` -> `.*`; single `*` -> `[^/]*` (unchanged).

Tokenise via control-char sentinels before escaping regex specials so each
variant is translated exactly once with no collisions.

Adds tests for top-level, nested, embedded, and single-segment matches.
Finding #15 from /review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (2)
  • dist/cli/index.js is excluded by !**/dist/**, !dist/**
  • dist/index.js is excluded by !**/dist/**, !dist/**

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4d6a20be-cb5b-4b01-8068-540f4256b409

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds 36 lines to tests/comment-core.test.ts: a small at(file) helper that builds a local-shadow Finding, followed by test cases asserting suppression behavior for **/, /**, embedded **/, and single * glob patterns against various file path depths and root mismatches. No production code is changed.

Changes

Glob suppression path-matching tests

Layer / File(s) Summary
Glob pattern suppression test cases
tests/comment-core.test.ts
Introduces at(file) helper and adds suppression tests for path:**/Button.tsx, src/**, path:src/**/Button.tsx, and path:src/*.tsx covering positive and negative match scenarios across file path depths.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

A bunny hops through paths so deep,
**/ catches what * can't leap,
Globs that match and globs that fail,
Each test case follows pattern's trail.
🐇✨ No prod code hurt, just coverage grown!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main fix: glob translation handling of leading and embedded **/ patterns to match zero or more directories.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/glob-15-zero-leading-dirs

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/comment-core.test.ts`:
- Around line 86-117: Add a new test case after the existing pattern tests that
explicitly tests bare ** glob semantics, which is not currently covered. Create
a test with a description like 'bare ** matches files and directories at any
nesting level' and test patterns such as path:**Button.tsx or path:** using the
same structure as the other tests (parseSuppressions followed by multiple
isSuppressed assertions with different file paths to verify the expected
matching behavior).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ec5f1a2-50af-46b0-b1de-3ce0eabdaf19

📥 Commits

Reviewing files that changed from the base of the PR and between 42663d9 and b7022fd.

⛔ Files ignored due to path filters (2)
  • dist/cli/index.js is excluded by !**/dist/**
  • dist/index.js is excluded by !**/dist/**
📒 Files selected for processing (2)
  • src/comment/suppress.ts
  • tests/comment-core.test.ts

Comment on lines +86 to +117
it('leading **/ matches a top-level file and any nested depth', () => {
const s = parseSuppressions('path:**/Button.tsx');
expect(isSuppressed(at('Button.tsx'), s)).toBe(true); // top-level, no slash
expect(isSuppressed(at('a/Button.tsx'), s)).toBe(true); // one dir deep
expect(isSuppressed(at('a/b/Button.tsx'), s)).toBe(true); // many dirs deep
expect(isSuppressed(at('a/Card.tsx'), s)).toBe(false); // different file
expect(isSuppressed(at('a/NotButton.tsx'), s)).toBe(false); // * stays within a segment
});

it('trailing /** matches the directory itself and everything under it', () => {
const s = parseSuppressions('src/**');
expect(isSuppressed(at('src'), s)).toBe(true); // the directory itself
expect(isSuppressed(at('src/a.tsx'), s)).toBe(true); // a file under it
expect(isSuppressed(at('src/legacy/b.tsx'), s)).toBe(true); // nested under it
expect(isSuppressed(at('source/a.tsx'), s)).toBe(false); // not a prefix-name match
expect(isSuppressed(at('lib/a.tsx'), s)).toBe(false); // unrelated dir
});

it('embedded **/ collapses to zero or more middle segments', () => {
const s = parseSuppressions('path:src/**/Button.tsx');
expect(isSuppressed(at('src/Button.tsx'), s)).toBe(true); // zero middle dirs
expect(isSuppressed(at('src/ui/Button.tsx'), s)).toBe(true); // one middle dir
expect(isSuppressed(at('src/ui/forms/Button.tsx'), s)).toBe(true); // several middle dirs
expect(isSuppressed(at('lib/Button.tsx'), s)).toBe(false); // wrong root
});

it('single * stays within one path segment', () => {
const s = parseSuppressions('path:src/*.tsx');
expect(isSuppressed(at('src/Button.tsx'), s)).toBe(true);
expect(isSuppressed(at('src/legacy/Button.tsx'), s)).toBe(false); // * does not cross /
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add an explicit regression test for bare ** glob semantics.

These tests cover **/, /**, embedded **/, and *, but not bare ** (which has distinct translation logic). Adding one case (e.g., path:**Button.tsx or path:**) would lock down the remaining branch and prevent silent regressions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/comment-core.test.ts` around lines 86 - 117, Add a new test case after
the existing pattern tests that explicitly tests bare ** glob semantics, which
is not currently covered. Create a test with a description like 'bare ** matches
files and directories at any nesting level' and test patterns such as
path:**Button.tsx or path:** using the same structure as the other tests
(parseSuppressions followed by multiple isSuppressed assertions with different
file paths to verify the expected matching behavior).

…ing-dirs

# Conflicts:
#	dist/cli/index.js
#	dist/index.js
#	src/comment/suppress.ts
@jongjesse jongjesse merged commit 69f6cfa into main Jun 22, 2026
2 checks passed
@jongjesse jongjesse deleted the fix/glob-15-zero-leading-dirs branch June 22, 2026 10:04
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.

1 participant