Changeset 33517cc for node_modules/picomatch/lib/parse.js
- Timestamp:
- 09/19/26 10:30:30 (11 days ago)
- Branches:
- finki-main, main
- Children:
- 06ebe74
- Parents:
- 62b2964
- File:
-
- 1 edited
-
node_modules/picomatch/lib/parse.js (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
node_modules/picomatch/lib/parse.js
r62b2964 r33517cc 44 44 const syntaxError = (type, char) => { 45 45 return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; 46 }; 47 48 const splitTopLevel = input => { 49 const parts = []; 50 let bracket = 0; 51 let paren = 0; 52 let quote = 0; 53 let value = ''; 54 let escaped = false; 55 56 for (const ch of input) { 57 if (escaped === true) { 58 value += ch; 59 escaped = false; 60 continue; 61 } 62 63 if (ch === '\\') { 64 value += ch; 65 escaped = true; 66 continue; 67 } 68 69 if (ch === '"') { 70 quote = quote === 1 ? 0 : 1; 71 value += ch; 72 continue; 73 } 74 75 if (quote === 0) { 76 if (ch === '[') { 77 bracket++; 78 } else if (ch === ']' && bracket > 0) { 79 bracket--; 80 } else if (bracket === 0) { 81 if (ch === '(') { 82 paren++; 83 } else if (ch === ')' && paren > 0) { 84 paren--; 85 } else if (ch === '|' && paren === 0) { 86 parts.push(value); 87 value = ''; 88 continue; 89 } 90 } 91 } 92 93 value += ch; 94 } 95 96 parts.push(value); 97 return parts; 98 }; 99 100 const isPlainBranch = branch => { 101 let escaped = false; 102 103 for (const ch of branch) { 104 if (escaped === true) { 105 escaped = false; 106 continue; 107 } 108 109 if (ch === '\\') { 110 escaped = true; 111 continue; 112 } 113 114 if (/[?*+@!()[\]{}]/.test(ch)) { 115 return false; 116 } 117 } 118 119 return true; 120 }; 121 122 const normalizeSimpleBranch = branch => { 123 let value = branch.trim(); 124 let changed = true; 125 126 while (changed === true) { 127 changed = false; 128 129 if (/^@\([^\\()[\]{}|]+\)$/.test(value)) { 130 value = value.slice(2, -1); 131 changed = true; 132 } 133 } 134 135 if (!isPlainBranch(value)) { 136 return; 137 } 138 139 return value.replace(/\\(.)/g, '$1'); 140 }; 141 142 const hasRepeatedCharPrefixOverlap = branches => { 143 const values = branches.map(normalizeSimpleBranch).filter(Boolean); 144 145 for (let i = 0; i < values.length; i++) { 146 for (let j = i + 1; j < values.length; j++) { 147 const a = values[i]; 148 const b = values[j]; 149 const char = a[0]; 150 151 if (!char || a !== char.repeat(a.length) || b !== char.repeat(b.length)) { 152 continue; 153 } 154 155 if (a === b || a.startsWith(b) || b.startsWith(a)) { 156 return true; 157 } 158 } 159 } 160 161 return false; 162 }; 163 164 const parseRepeatedExtglob = (pattern, requireEnd = true) => { 165 if ((pattern[0] !== '+' && pattern[0] !== '*') || pattern[1] !== '(') { 166 return; 167 } 168 169 let bracket = 0; 170 let paren = 0; 171 let quote = 0; 172 let escaped = false; 173 174 for (let i = 1; i < pattern.length; i++) { 175 const ch = pattern[i]; 176 177 if (escaped === true) { 178 escaped = false; 179 continue; 180 } 181 182 if (ch === '\\') { 183 escaped = true; 184 continue; 185 } 186 187 if (ch === '"') { 188 quote = quote === 1 ? 0 : 1; 189 continue; 190 } 191 192 if (quote === 1) { 193 continue; 194 } 195 196 if (ch === '[') { 197 bracket++; 198 continue; 199 } 200 201 if (ch === ']' && bracket > 0) { 202 bracket--; 203 continue; 204 } 205 206 if (bracket > 0) { 207 continue; 208 } 209 210 if (ch === '(') { 211 paren++; 212 continue; 213 } 214 215 if (ch === ')') { 216 paren--; 217 218 if (paren === 0) { 219 if (requireEnd === true && i !== pattern.length - 1) { 220 return; 221 } 222 223 return { 224 type: pattern[0], 225 body: pattern.slice(2, i), 226 end: i 227 }; 228 } 229 } 230 } 231 }; 232 233 const getStarExtglobSequenceOutput = pattern => { 234 let index = 0; 235 const chars = []; 236 237 while (index < pattern.length) { 238 const match = parseRepeatedExtglob(pattern.slice(index), false); 239 240 if (!match || match.type !== '*') { 241 return; 242 } 243 244 const branches = splitTopLevel(match.body).map(branch => branch.trim()); 245 if (branches.length !== 1) { 246 return; 247 } 248 249 const branch = normalizeSimpleBranch(branches[0]); 250 if (!branch || branch.length !== 1) { 251 return; 252 } 253 254 chars.push(branch); 255 index += match.end + 1; 256 } 257 258 if (chars.length < 1) { 259 return; 260 } 261 262 const source = chars.length === 1 263 ? utils.escapeRegex(chars[0]) 264 : `[${chars.map(ch => utils.escapeRegex(ch)).join('')}]`; 265 266 return `${source}*`; 267 }; 268 269 const repeatedExtglobRecursion = pattern => { 270 let depth = 0; 271 let value = pattern.trim(); 272 let match = parseRepeatedExtglob(value); 273 274 while (match) { 275 depth++; 276 value = match.body.trim(); 277 match = parseRepeatedExtglob(value); 278 } 279 280 return depth; 281 }; 282 283 const analyzeRepeatedExtglob = (body, options) => { 284 if (options.maxExtglobRecursion === false) { 285 return { risky: false }; 286 } 287 288 const max = 289 typeof options.maxExtglobRecursion === 'number' 290 ? options.maxExtglobRecursion 291 : constants.DEFAULT_MAX_EXTGLOB_RECURSION; 292 293 const branches = splitTopLevel(body).map(branch => branch.trim()); 294 295 if (branches.length > 1) { 296 if ( 297 branches.some(branch => branch === '') || 298 branches.some(branch => /^[*?]+$/.test(branch)) || 299 hasRepeatedCharPrefixOverlap(branches) 300 ) { 301 return { risky: true }; 302 } 303 } 304 305 for (const branch of branches) { 306 const safeOutput = getStarExtglobSequenceOutput(branch); 307 if (safeOutput) { 308 return { risky: true, safeOutput }; 309 } 310 311 if (repeatedExtglobRecursion(branch) > max) { 312 return { risky: true }; 313 } 314 } 315 316 return { risky: false }; 46 317 }; 47 318 … … 227 498 token.parens = state.parens; 228 499 token.output = state.output; 500 token.startIndex = state.index; 501 token.tokensIndex = tokens.length; 229 502 const output = (opts.capture ? '(' : '') + token.open; 230 503 … … 236 509 237 510 const extglobClose = token => { 511 const literal = input.slice(token.startIndex, state.index + 1); 512 const body = input.slice(token.startIndex + 2, state.index); 513 const analysis = analyzeRepeatedExtglob(body, opts); 514 515 if ((token.type === 'plus' || token.type === 'star') && analysis.risky) { 516 const safeOutput = analysis.safeOutput 517 ? (token.output ? '' : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput) 518 : undefined; 519 const open = tokens[token.tokensIndex]; 520 521 open.type = 'text'; 522 open.value = literal; 523 open.output = safeOutput || utils.escapeRegex(literal); 524 525 for (let i = token.tokensIndex + 1; i < tokens.length; i++) { 526 tokens[i].value = ''; 527 tokens[i].output = ''; 528 delete tokens[i].suffix; 529 } 530 531 state.output = token.output + open.output; 532 state.backtrack = true; 533 534 push({ type: 'paren', extglob: true, value, output: '' }); 535 decrement('parens'); 536 return; 537 } 538 238 539 let output = token.close + (opts.capture ? ')' : ''); 239 540 let rest;
Note:
See TracChangeset
for help on using the changeset viewer.
