import { type FieldName, type FormState, type Problem, type Row } from "./form.js"; import { type GraderDraft } from "./graders.js"; /** The file-system questions validation asks, injectable so the pure cases * test without a disk. `realPath` resolves every symlink in a path that * exists. */ export type FileChecks = { exists: (file: string) => boolean; isDirectory: (file: string) => boolean; realPath: (file: string) => string; }; export declare const realFileChecks: FileChecks; /** A write that stopped for a reason the user can fix, naming the row. */ export declare class TestWriteError extends Error { readonly row: Row; constructor(row: Row, message: string); } export declare function testDirFor(suiteDir: string, id: string): string; export declare function validateForm(state: FormState, checks?: FileChecks): Problem[]; /** The text of `graders.json` for the drafts. */ export declare function gradersJsonText(graders: GraderDraft[]): string; /** The `test.json` object: `base` (what the file held, when editing) with * every written field set from its value, or deleted when the value is * empty. `files` is never a key, because the loader finds `./files` on * its own; an empty `input` is left out, because the loader refuses an * empty string and reads a missing key as "takes no input". A locked * field (a structured input) is left as the base has it. */ export declare function testJsonFor(values: Record, base?: Record, locks?: FormState["locks"]): Record; /** Write the test and return its folder. Callers validate first; this * re-checks only what a race could change. Both modes build the files in * a staging folder under the suite; how they reach their place is the * mode's entry in `COMMITS`. A problem the user can fix is thrown as a * `TestWriteError` naming the row. */ export declare function writeTest(state: FormState): string; /** What to run next, shown after a save. */ export declare function nextCommands(suiteDir: string, id: string): string[];