/** * A generator's opt-in to orphan reconciliation, and the namespace it applies to. * * Declaring this is the ONLY way in: `.gen-state/.hashes.json` records paths, not * which generator produced each one, so the runner genuinely cannot work out who * owns what. Deriving ownership from the output directory instead would be worse * than useless — every generator in a single-target project writes to the same * `outDir`, so one generator narrowing its output would delete its siblings' * files. The generator has to say. */ export interface OrphanPolicy { /** * True when `relPathInTarget` — a path relative to this generator's own output * directory, always `/`-separated — is inside the namespace this generator is * the sole producer of. * * Be narrow. This predicate is the blast radius: every previously-generated * path it accepts and this run did not re-emit is a deletion candidate. */ readonly owns: (relPathInTarget: string) => boolean; /** * Delete a hand-edited orphan instead of refusing it. Default false. * * The seam exists because §6 requires every default to have one, not because * it is advisable: the refusal already names the file and deleting it by hand * is a one-line answer, whereas this flag makes the destructive outcome the * automatic one. */ readonly force?: boolean; } export interface OrphanDecision { /** No longer emitted, on disk, and byte-identical to the snapshot we wrote. * Safe to delete — the generator is removing only its own untouched output. */ readonly remove: readonly string[]; /** No longer emitted and CHANGED since we wrote it (or with no snapshot to * compare against). Left alone and reported, never deleted. */ readonly refused: readonly string[]; /** No longer emitted and already absent from disk. Nothing to delete; the * caller should just drop the stale snapshot. */ readonly vanished: readonly string[]; } export interface ReconcileOrphansArgs { /** Relative paths this generator emitted on some previous run — in practice the * keys of `.gen-state/.hashes.json`. */ readonly previouslyGenerated: readonly string[]; /** Relative paths emitted on THIS run. */ readonly emitted: readonly string[]; /** Namespace guard. Orphan reconciliation is opt-in and scoped: a generator must * never delete another generator's output just because it stopped emitting its * own. */ readonly owns: (relPath: string) => boolean; /** Whether the file is still on disk at all. */ readonly exists: (relPath: string) => boolean; /** * Whether the file is byte-for-byte what we recorded writing. * * MUST fail closed — false when it cannot be proven. This is deliberately the * same question the write path asks (`isPristineGenerated`), of the same * evidence: the committed hash manifest. Before they were unified, one feature * refused to DELETE a hand-edited file while silently OVERWRITING one, which is * the same uncertainty answered two opposite ways. */ readonly isUntouched: (relPath: string) => boolean; } export declare function reconcileOrphans(args: ReconcileOrphansArgs): OrphanDecision; /** * The message shown when a hand-edited orphan is refused. * * It has to say what happened, why nothing was deleted, and what the two ways out * are — otherwise the reasonable reaction to an unexplained refusal is to delete * the file, which is the outcome the refusal exists to prevent. */ export declare function refusedOrphanMessage(paths: readonly string[], /** Which generator's namespace these came from. `orphanPolicy` is a generic * `Generator` field and `sweepOrphans`/`OrphanPolicy` are exported precisely so an * app can compose its own — so this message must not hardcode `requirement-tests`, * naming a generator the project may not even use and a cause ("the requirement was * removed") that may not apply. */ generatorName?: string): string; //# sourceMappingURL=reconcile-orphans.d.ts.map