MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / ScopeIgnore

Class ScopeIgnore

src/extraction/index.ts:627–688  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

625 * Single source of truth for indexer and watcher scope — they must not diverge.
626 */
627export class ScopeIgnore {
628 private embedded: Array<{ root: string; matcher: Ignore }>;
629 private defaults: Ignore = defaultsOnlyIgnore();
630 constructor(
631 private rootMatcher: Ignore,
632 embedded: Array<{ root: string; matcher: Ignore }>,
633 /**
634 * Project `codegraph.json` `exclude` patterns (#999), matched against the
635 * full root-relative path. Wins over everything else — an explicit user
636 * exclude applies even to tracked files and even inside embedded repos.
637 */
638 private exclude: Ignore | null = null,
639 /**
640 * Project `codegraph.json` `include` patterns — first-party source forced
641 * INTO the index despite `.gitignore`. When a path matches, it is NOT
642 * ignored (so the watcher watches it), overriding `.gitignore`/`rootMatcher`
643 * — but never `exclude` (checked first) and never a built-in default-ignored
644 * dir. `includeRoots` are the static prefixes so a gitignored ANCESTOR
645 * directory of an included subtree still isn't pruned by the directory
646 * walker/watcher.
647 */
648 private include: Ignore | null = null,
649 private includeRoots: string[] = [],
650 ) {
651 // Longest root first so paths in nested embedded repos hit the innermost matcher.
652 this.embedded = [...embedded].sort((a, b) => b.root.length - a.root.length);
653 }
654
655 ignores(rel: string): boolean {
656 // User `exclude` (#999) is checked first and against the full root-relative
657 // path: it must drop git-TRACKED paths (which `.gitignore` can't) and apply
658 // everywhere, including ancestors of embedded repos.
659 if (this.exclude && this.exclude.ignores(rel)) return true;
660 // User `include`: force first-party source in despite `.gitignore`. Never
661 // resurfaces a built-in default-ignored dir (node_modules/dist/…), so an
662 // include pattern can't accidentally pull in dependency/build trees.
663 if (this.include && !this.defaults.ignores(rel)) {
664 if (rel.endsWith('/')) {
665 // A directory on (or leading to) an included subtree must stay walkable
666 // so the watcher/walker descends to reach the forced-in files.
667 if (this.includeRoots.some((r) => r.startsWith(rel) || rel.startsWith(r))) return false;
668 } else if (this.include.ignores(rel)) {
669 return false;
670 }
671 }
672 for (const { root, matcher } of this.embedded) {
673 if (rel.startsWith(root)) {
674 const inner = rel.slice(root.length);
675 if (inner === '') return false;
676 // Built-in defaults apply to the FULL path uniformly (#407) — an
677 // embedded repo inside node_modules (an npm git-dependency) must stay
678 // excluded even though its own rules wouldn't ignore its files.
679 return this.defaults.ignores(rel) || matcher.ignores(inner);
680 }
681 }
682 // Never prune a directory that leads to an embedded repo.
683 if (rel.endsWith('/') && this.embedded.some(({ root }) => root.startsWith(rel))) {
684 return false;

Callers

nothing calls this directly

Calls 1

defaultsOnlyIgnoreFunction · 0.85

Tested by

no test coverage detected