(i: number, j: number)
| 337 | const forbid = options?.forbid; |
| 338 | const key = (i: number, j: number) => `${i}|${j}`; |
| 339 | const dfs = (i: number, j: number): boolean => { |
| 340 | const memoKey = key(i, j); |
| 341 | if (memo.has(memoKey)) { |
| 342 | return memo.get(memoKey)!; |
| 343 | } |
| 344 | if (i === patternLength) { |
| 345 | const done = j === sourceLength; |
| 346 | memo.set(memoKey, done); |
| 347 | return done; |
| 348 | } |
| 349 | let matched = false; |
| 350 | if (isDoubleStar(pattern[i])) { |
| 351 | for (let k = j; k <= sourceLength; k += 1) { |
| 352 | if (dfs(i + 1, k)) { |
| 353 | parent.set(memoKey, { i2: i + 1, j2: k }); |
| 354 | matched = true; |
| 355 | break; |
| 356 | } |
| 357 | } |
| 358 | } else if (j < sourceLength && segmentMatches(pattern[i], source[j])) { |
| 359 | const blocked = |
| 360 | forbid && forbid.patternIndex === i && forbid.sourceIndex === j; |
| 361 | if (!blocked && dfs(i + 1, j + 1)) { |
| 362 | parent.set(memoKey, { i2: i + 1, j2: j + 1 }); |
| 363 | matched = true; |
| 364 | } |
| 365 | } |
| 366 | memo.set(memoKey, matched); |
| 367 | return matched; |
| 368 | }; |
| 369 | |
| 370 | if (!dfs(0, 0)) { |
| 371 | return null; |
no test coverage detected