MCPcopy Create free account
hub / github.com/freecodexyz/free-code / matchWildcardPattern

Function matchWildcardPattern

src/utils/permissions/shellRuleMatching.ts:90–154  ·  view source on GitHub ↗
(
  pattern: string,
  command: string,
  caseInsensitive = false,
)

Source from the content-addressed store, hash-verified

88 * @returns true if the command matches the pattern
89 */
90export function matchWildcardPattern(
91 pattern: string,
92 command: string,
93 caseInsensitive = false,
94): boolean {
95 // Trim leading/trailing whitespace from pattern
96 const trimmedPattern = pattern.trim()
97
98 // Process the pattern to handle escape sequences: \* and \\
99 let processed = ''
100 let i = 0
101
102 while (i < trimmedPattern.length) {
103 const char = trimmedPattern[i]
104
105 // Handle escape sequences
106 if (char === '\\' && i + 1 < trimmedPattern.length) {
107 const nextChar = trimmedPattern[i + 1]
108 if (nextChar === '*') {
109 // \* -> literal asterisk placeholder
110 processed += ESCAPED_STAR_PLACEHOLDER
111 i += 2
112 continue
113 } else if (nextChar === '\\') {
114 // \\ -> literal backslash placeholder
115 processed += ESCAPED_BACKSLASH_PLACEHOLDER
116 i += 2
117 continue
118 }
119 }
120
121 processed += char
122 i++
123 }
124
125 // Escape regex special characters except *
126 const escaped = processed.replace(/[.+?^${}()|[\]\\'"]/g, '\\$&')
127
128 // Convert unescaped * to .* for wildcard matching
129 const withWildcards = escaped.replace(/\*/g, '.*')
130
131 // Convert placeholders back to escaped regex literals
132 let regexPattern = withWildcards
133 .replace(ESCAPED_STAR_PLACEHOLDER_RE, '\\*')
134 .replace(ESCAPED_BACKSLASH_PLACEHOLDER_RE, '\\\\')
135
136 // When a pattern ends with ' *' (space + unescaped wildcard) AND the trailing
137 // wildcard is the ONLY unescaped wildcard, make the trailing space-and-args
138 // optional so 'git *' matches both 'git add' and bare 'git'.
139 // This aligns wildcard matching with prefix rule semantics (git:*).
140 // Multi-wildcard patterns like '* run *' are excluded — making the last
141 // wildcard optional would incorrectly match 'npm run' (no trailing arg).
142 const unescapedStarCount = (processed.match(/\*/g) || []).length
143 if (regexPattern.endsWith(' .*') && unescapedStarCount === 1) {
144 regexPattern = regexPattern.slice(0, -3) + '( .*)?'
145 }
146
147 // Create regex that matches the entire string.

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected