# src/core

Internal pure engine: no Pi imports and no public API. It trusts input already filtered by the tool layer and does not re-validate it. Core's report references are type-only and erased at runtime.

## Modules

- `hash.ts` computes position-dependent line checksums (line number + content → `LINE#HASH`). `lines.ts` handles splitting, line-ending detection, and physical line counts. `text.ts` does strict and lossy UTF-8 decoding and decides which text cannot be written.
- `apply.ts` `applyEdits` validates a whole batch of `Edit` ops (see `types.ts`) against a single snapshot: anchor checks, overlap and conflict detection, and shifted-anchor recovery (`AnchorRecovery`: local `shiftRadius` search, then full file). It returns new text or structured anchor failures, throws `OVERLAPPING_EDITS` for an overlap, and never touches the filesystem.
- `regex.ts` builds JavaScript regexes on the LF view (`regexSource`, `buildRegex`) for both grep and replace; neither engine imports the other.
- `replace.ts` is replace's engine: literal and JavaScript-regex matching on the LF view, separator restoration, and overlap rejection. `replace-schema.ts` defines the tool's replacement schema and the engine's result schema, with their derived types.
- `search.ts` evaluates native JavaScript queries on the LF view and returns bounded physical rows; `search-schema.ts` defines its result.
- `search-analysis.ts` parses patterns with regexpp (V8 has already accepted them at tool entry), decides smart case, and derives the literals every match must contain; `case-fold.ts` supplies JavaScript's case equivalence; `character-set.ts` owns character-class sets and shared AST surrogate-pair decoding for both candidate strategies.
- `errors.ts` holds the classified `HashlineError`, typed by code so its facts and `next` alternative must match the code's schema, and errno classification.
- `ranges.ts` provides overlap detection for both engines and range merging for failure neighborhoods.

## Constraints

- Own interval algebra, bounded membership caching, and explicit class-string enumeration in `character-set.ts`; derive Unicode properties, `v` sets, and case closure from the running V8 rather than separate Unicode tables. Intersections may enumerate either string operand, subtractions only the left, and unions require every operand. Keep original scoped case flags for membership even when translating a backreference; apply repetition case widening afterward through the existing byte translator. Unknown string properties remain widened.
- Derive one necessary file condition in `search-analysis.ts`: an AND keeps its most selective side, because extra rg passes cost more than they save. Preserve every OR alternative, retain necessary prefixes or suffixes when expansion is too large, and cut literals where bytes can differ from the LF view. Unknown constructs widen candidates, never narrow them.
