-
Notifications
You must be signed in to change notification settings - Fork 662
feat: more flexible glob patterns #1180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
davidturnbull
wants to merge
15
commits into
main
Choose a base branch
from
davidt-picomatch
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
c1831bf to
a56c5bd
Compare
vrcprl
approved these changes
Sep 22, 2025
Contributor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
This PR enhances the glob pattern matching system to support more flexible patterns with
[locale]placeholders and glob wildcards. The implementation uses recursive backtracking algorithms to bidirectionally transform between concrete file paths and placeholder patterns.Key Innovation: Recursive Pattern Matching
The core challenge solved by this PR is reconstructing template patterns from matched file paths when templates contain a mix of placeholders, globs, and literals. This requires sophisticated recursive algorithms because:
*.jsoncould matchapp.jsonorconfig-prod.jsonsrc/en/app.jsoncorresponds to[locale]How
expandPlaceholderedGlobWorksStep 1: Forward Expansion (Finding Files)
Step 2: Reverse Reconstruction (Restoring Placeholders via Recursion)
This is where the recursion happens. The algorithm uses depth-first search with memoization to match template segments against source path segments.
The Recursive Algorithms
1.
matchTemplateToSource(lines 191-252) - Path-Level RecursionThis function recursively matches template segments to source path segments:
Recursive Strategy:
Key recursive behaviors:
For regular segments:
For globstar (
**) - This is particularly clever:The globstar recursion tries every possible number of segments the
**could match, using backtracking to find the correct solution.2.
renderSegment(lines 111-175) - Character-Level RecursionWhen a segment contains placeholders or globs within a single path component (e.g.,
app-[locale]-*.json), this function recursively matches character by character:Recursive Strategy:
For literals:
For placeholders:
For globs - Most complex, tries every possible match length:
Why Recursion + Memoization?
The Problem:
Without recursion, you'd need to enumerate all possible ways to split a path, which is exponential. For example, matching
**/*.jsonagainsta/b/c/d/file.jsonhas multiple valid splits for where**ends and*.jsonbegins.The Solution:
Complete Example
Caveats and Trade-offs
While the algorithm is functionally correct for practical use cases, there are important behavioral characteristics and edge cases to understand:
1. Lazy Matching Strategy
The algorithm uses lazy (shortest-first) matching for globs and globstars. When multiple valid matches exist, it returns the first solution found.
Example:
Impact: Results are deterministic but may not match user intuition about which path segments correspond to which pattern parts.
2. Ambiguous Patterns Can Fail
Patterns where placeholders and globs could match the same content may fail to restore correctly:
Problematic pattern:
Mitigation: The algorithm will throw a
CLIErrorif it cannot restore placeholders, preventing silent incorrect behavior:3. Empty Glob Matches
Globs can match empty strings, which may be unexpected:
Impact: Patterns may match more liberally than expected. This follows standard glob behavior where
*means "zero or more characters."4. Performance with Complex Patterns
Deeply nested patterns with many wildcards can have exponential worst-case complexity:
Impact: For most i18n projects (< 10,000 files, simple patterns), this is negligible. Very complex patterns on large codebases may be slow.
5. Greedy Matching within Segments
Within a single path segment, glob matching is greedy but uses backtracking:
Impact: Generally correct, but understanding the backtracking behavior helps when debugging unexpected matches.
6. Non-Deterministic Choice
When multiple valid interpretations exist, the search order (lazy matching, left-to-right) determines which is returned:
Impact: All outputs are technically correct, but users might expect different behavior. The algorithm is consistent but the choice is somewhat arbitrary.
Recommended Pattern Guidelines
Based on these caveats, here are recommended patterns:
✅ Safe Patterns
Technical Details
templateIndex|sourceIndexorpartIndex|positionas keysTest Plan
src/[locale]/messages.jsonsrc/**/*.jsonsrc/[locale]/**/*.jsonconfig/[locale]/app-*.json**/[locale]/**/*.json🤖 Generated with Claude Code