socraticode
Version:
SocratiCode — MCP server for local codebase indexing, semantic search, and code dependency graphs. All private, all local via Docker.
117 lines • 6.04 kB
TypeScript
/**
* What `createIgnoreFilter` answers with: one question, on a path relative to
* the project root and written with forward slashes.
*
* Two kinds of rule stand behind it. Patterns — the defaults, `.gitignore`
* files and `.socraticodeignore` — are gitignore syntax and go to the `ignore`
* package. The environments the walk *discovers* are not patterns, they are
* directories that exist, and they are kept as the literal prefixes they are.
* Writing one as a pattern meant escaping it, and the escape is only as good as
* the package's reading of it: `\?` is not understood by the installed
* version, so an environment at `env?/` was scanned despite its marker
* (review finding), while `\[`, `\*`, `\!`, `\#` and `\\` happened to work.
* A prefix compare has no syntax to get wrong.
*
* The one thing the pattern route allowed that a bare prefix would not: a
* negation written later — `!tests/fixtures/sample-venv/**` in
* `.socraticodeignore`, for a checked-in fixture that any tool parsing
* `pyvenv.cfg` has — re-included the environment. That precedence is kept
* (review finding): a path an explicit negation claims is not excluded by a
* discovered prefix either. `unignored` is what the package answers exactly
* when a negative rule spoke last and no positive one stands over it.
*/
export interface IgnoreFilter {
/** Whether the path, relative to the project root, is excluded. */
ignores(relativePath: string): boolean;
/**
* Whether the path, with or without its trailing slash, is the root of an
* environment the walk discovered. The watcher asks this of a directory
* event, since an environment moved away arrives as one event on the
* directory and nothing on the marker inside it.
*/
isEnvironmentRoot(relativePath: string): boolean;
/**
* The ignore files this filter read, project-relative and in the order they
* were applied, each with the bytes it was built from.
*
* A filter's answers are read off the tree once, when it is built, so
* anything caching a walk this filter shaped has to know which files to
* watch — the code graph records them as build inputs. The content comes
* with the path rather than being read again by the caller: a second read
* would both cost a second pass and leave a window in which the file changes
* between the two, recording a state the walk never actually ran under.
* Reported from where they are read, so a new source cannot be added without
* appearing here.
*/
sources: IgnoreSource[];
/**
* The environment roots the walk discovered, each as `dir/` relative to the
* project root.
*
* Reported for the same reason as {@link IgnoreFilter.sources}: they are an
* input to what this filter answers, and unlike the ignore files they are
* not files at all — a directory is an environment because of a marker
* *inside* it, somewhere nothing that reads the tree will ever look again.
* A caller caching a walk has to watch them, or a `pyvenv.cfg` deleted
* re-admits a whole subtree with nothing observable having changed.
*/
environments: string[];
}
/** One ignore file a filter was built from. */
export interface IgnoreSource {
/** Project-relative, forward-slashed. */
path: string;
/** The bytes the filter was built from. */
content: string;
}
/**
* Build an ignore filter for a project directory.
*
* Combines (in order):
* 1. Built-in defaults (node_modules, .git, dist, build, lock files, etc.)
* 2. .gitignore files (root + nested) — unless RESPECT_GITIGNORE=false
* 3. Python and conda environments found by their markers, as literal prefixes
* 4. .socraticodeignore — optional project-specific exclusions
*
* Set env RESPECT_GITIGNORE=false to skip .gitignore processing entirely.
*
* The two status lines below log at debug, not info: context-artifact reads
* build a filter per artifact on every staleness check, so an info line here
* would fire once per artifact per context search.
*/
export declare function createIgnoreFilter(projectPath: string): IgnoreFilter;
/**
* Whether a change at this path can change what the filter answers: it is one
* of the environment markers the walk looks for, or lies inside one.
*
* The rules a filter carries are read off the tree once, when it is built, and
* an environment is recognised by a file or directory that may appear or
* vanish while the tree is being watched. A watcher that ran every event
* through its filter first never saw either: a new `pyvenv.cfg` is not an
* indexable file, and the one being deleted sits under a directory the stale
* filter still excludes (review finding). The name is enough here — the event
* only schedules a reconciliation, and the rebuilt filter reads the shape.
* `conda-meta` is matched as any segment, since the directory's creation
* arrives with the files inside it.
*/
export declare function isEnvironmentMarker(relativePath: string): boolean;
/**
* Whether the directory is an environment: it carries a marker, in the shape
* its tool writes it. Two markers, because two tools build these directories —
* `pyvenv.cfg` for a PEP 405 virtualenv, `conda-meta/` for a conda
* environment. Both hold installed libraries and neither is source.
*
* The shape matters. Merely existing is not enough: a source directory holding
* a file named `conda-meta` would otherwise disappear whole, and a discarded
* source file costs far more than a kept one.
*
* Shared with the watcher, which asks it of a directory that has just
* appeared: an environment moved into place arrives as one event on the
* directory, and nothing on the marker inside it.
*/
export declare function isEnvironmentDirectory(dirPath: string): boolean;
/**
* Check if a relative path should be ignored.
*/
export declare function shouldIgnore(ig: IgnoreFilter, relativePath: string): boolean;
//# sourceMappingURL=ignore.d.ts.map