import { EmitContext } from "@typespec/compiler"; import { TypraEmitterOptions, FormatterOption } from "../lib.js"; export interface GeneratedManifestEntry { outputRoot: string; path: string; marker: boolean; } export interface GeneratedManifest { emitter: "typra-emitter"; version: 1; generatedAt: string; files: GeneratedManifestEntry[]; } export interface SkippedGeneratedFileEntry { path: string; reason: "empty" | "not-regenerated"; action: "none" | "removed-marker-owned" | "preserved-unmarked" | "preserved-editable-seam" | "preserved-foreign-target"; ownership: "not-present" | "marker-owned" | "unmarked-existing" | "editable-seam-owned" | "foreign-target-owned"; status: "skipped-empty" | "removed-stale-marker-owned" | "preserved-unmarked" | "preserved-editable-seam" | "preserved-foreign-target"; nextAction: string; } /** * Marker that hand-owned, consumer-editable files carry so the cleaner can allow-list them. * This is deliberately distinct from the generated marker: seam files are created once and * then owned by the consumer, so they must never be deleted or rewritten as generated output. */ export declare const EDITABLE_SEAM_MARKER = ""; export declare function hasEditableSeamMarker(content: string): boolean; export interface GeneratedOutputReport { emitter: "typra-emitter"; version: 1; generatedAt: string; summary: { emittedFiles: number; skippedFiles: number; staleMarkerOwnedRemovals: number; preservedUnmarkedSkippedFiles: number; preservedEditableSeamFiles: number; warnings: number; protectedPathTouches: number; hygiene: "clean" | "warnings"; }; generation: { deterministicOutput: boolean; rootObject: string; rootNamespace?: string; rootAlias?: string; emitTargets: Array<{ type: string; outputDir?: string; testDir?: string; packageName?: string; namespace?: string; format?: FormatterOption; enumParsing?: "case-sensitive" | "case-insensitive"; protocolScaffolds?: "none" | "compile-only"; }>; protectedPaths: string[]; hydrationZones: string[]; }; emittedFiles: GeneratedManifestEntry[]; skippedFiles: SkippedGeneratedFileEntry[]; staleMarkerOwnedRemovals: string[]; preservedUnmarkedSkippedFiles: string[]; preservedEditableSeamFiles: string[]; warnings: string[]; hygiene: { lineEndings: "lf"; finalNewline: true; trailingWhitespace: "trimmed"; emptyArtifacts: "skipped-unless-allowed"; marker: "typra-emitter"; }; protectedPathTouches: { status: "requires-verifier-baseline"; configuredPatterns: string[]; matchedFiles: string[]; guidance: string; }; formatter: { status: "not-recorded"; note: string; }; cleanup: { status: "safe-noop" | "review-recommended"; suggestions: string[]; }; driftGuidance: { updateBaselineWhen: string; fixGenerationWhen: string; metadataToCompare: string[]; optionDriftSignals: string[]; versionDriftSignals: string[]; }; } export declare function emitGeneratedFile(context: EmitContext, filePath: string, content: string, options?: { marker?: boolean; outputRoot?: string; allowEmpty?: boolean; }): Promise; export declare function manifestPath(context: EmitContext): string; /** * The output the current run produced, used to scope stale-file reconciliation. `paths` are the * files emitted this run; `roots` are the output roots those files were emitted into. Pruning is * confined to `roots` so a run scoped to a subset of targets never reconciles — and never deletes * — files owned by a target it did not emit. */ export interface CurrentRunOutputs { paths: Set; roots: Set; } /** * Delete files a previous run generated that this run no longer produces. * * When a type is renamed or removed its generated source stops being emitted, but the file * left on disk from the previous run keeps compiling and keeps running — a generated test for * a deleted type becomes a phantom failure in the consumer that reads as an emitter * regression. Nothing else can notice this: a run only knows what it emitted, so the previous * run's manifest is the only record of what used to exist. * * Ownership is deliberately conservative and mirrors `removeSkippedGeneratedFile`: a file is * removed only when the previous manifest records that Typra marked it, it still carries the * generated marker on disk, and it is not an editable seam. Anything the consumer has taken * ownership of is preserved and reported instead of deleted. * * Must run before the new manifest is written, since it reads the previous one. */ export declare function pruneStaleGeneratedFiles(context: EmitContext): void; /** * Core of {@link pruneStaleGeneratedFiles}, with the current run's output passed in explicitly * so the ownership rules can be exercised directly. */ export declare function pruneStaleGeneratedFilesAgainst(context: EmitContext, current: CurrentRunOutputs): void; export declare function emitGeneratedManifest(context: EmitContext): Promise; export declare function emitGeneratedOutputReport(context: EmitContext, manifest: GeneratedManifest): Promise; export declare function buildGeneratedManifest(context: EmitContext): GeneratedManifest; export declare function buildGeneratedOutputReport(context: EmitContext, manifest: GeneratedManifest): GeneratedOutputReport;