| 458 | * Single source of truth for indexer and watcher scope — they must not diverge. |
| 459 | */ |
| 460 | export class ScopeIgnore { |
| 461 | private embedded: Array<{ root: string; matcher: Ignore }>; |
| 462 | private defaults: Ignore = defaultsOnlyIgnore(); |
| 463 | constructor( |
| 464 | private rootMatcher: Ignore, |
| 465 | embedded: Array<{ root: string; matcher: Ignore }>, |
| 466 | /** |
| 467 | * Project `codegraph.json` `exclude` patterns (#999), matched against the |
| 468 | * full root-relative path. Wins over everything else — an explicit user |
| 469 | * exclude applies even to tracked files and even inside embedded repos. |
| 470 | */ |
| 471 | private exclude: Ignore | null = null, |
| 472 | ) { |
| 473 | // Longest root first so paths in nested embedded repos hit the innermost matcher. |
| 474 | this.embedded = [...embedded].sort((a, b) => b.root.length - a.root.length); |
| 475 | } |
| 476 | |
| 477 | ignores(rel: string): boolean { |
| 478 | // User `exclude` (#999) is checked first and against the full root-relative |
| 479 | // path: it must drop git-TRACKED paths (which `.gitignore` can't) and apply |
| 480 | // everywhere, including ancestors of embedded repos. |
| 481 | if (this.exclude && this.exclude.ignores(rel)) return true; |
| 482 | for (const { root, matcher } of this.embedded) { |
| 483 | if (rel.startsWith(root)) { |
| 484 | const inner = rel.slice(root.length); |
| 485 | if (inner === '') return false; |
| 486 | // Built-in defaults apply to the FULL path uniformly (#407) — an |
| 487 | // embedded repo inside node_modules (an npm git-dependency) must stay |
| 488 | // excluded even though its own rules wouldn't ignore its files. |
| 489 | return this.defaults.ignores(rel) || matcher.ignores(inner); |
| 490 | } |
| 491 | } |
| 492 | // Never prune a directory that leads to an embedded repo. |
| 493 | if (rel.endsWith('/') && this.embedded.some(({ root }) => root.startsWith(rel))) { |
| 494 | return false; |
| 495 | } |
| 496 | return this.rootMatcher.ignores(rel); |
| 497 | } |
| 498 | } |
| 499 | |
| 500 | /** |
| 501 | * Build the workspace-scope matcher. When the caller already knows the |
nothing calls this directly
no test coverage detected