diff --git a/packages/rstack/src/fmt/runner.ts b/packages/rstack/src/fmt/runner.ts index dbef5ba..d880223 100644 --- a/packages/rstack/src/fmt/runner.ts +++ b/packages/rstack/src/fmt/runner.ts @@ -1,41 +1,79 @@ -import type { FmtExitCode, FmtFileResult, FmtRunResult, RunFmtFilesOptions } from './types.ts'; +import type { + FmtExitCode, + FmtFileRequest, + FmtFileResult, + FmtRunResult, + RunFmtFilesOptions, +} from './types.ts'; import { formatFileSerial } from './serial.ts'; -const runFmtFiles = async ({ files, mode }: RunFmtFilesOptions): Promise => { +/** Formats one file and reports whether its contents differ. */ +type FormatFile = (file: FmtFileRequest, shouldWrite: boolean) => Promise; + +/** Converts a formatter outcome into the shared per-file result. */ +const runFmtFile = async ( + file: FmtFileRequest, + shouldWrite: boolean, + formatFile: FormatFile, +): Promise => { const startTime = performance.now(); - const shouldWrite = mode === 'write'; + + try { + const changed = await formatFile(file, shouldWrite); + + return { + path: file.path, + status: changed ? (shouldWrite ? 'written' : 'different') : 'unchanged', + durationMs: performance.now() - startTime, + }; + } catch (error) { + return { + path: file.path, + status: 'error', + error, + durationMs: performance.now() - startTime, + }; + } +}; + +/** Processes files sequentially while preserving input order. */ +const runFmtFilesSerial = async ( + files: FmtFileRequest[], + shouldWrite: boolean, +): Promise => { const results: FmtFileResult[] = []; + + for (const file of files) { + results.push(await runFmtFile(file, shouldWrite, formatFileSerial)); + } + + return results; +}; + +/** Maps file results to the Prettier-compatible CLI exit code. */ +const getFmtExitCode = (files: FmtFileResult[]): FmtExitCode => { let exitCode: FmtExitCode = 0; for (const file of files) { - const fileStartTime = performance.now(); - - try { - const changed = await formatFileSerial(file, shouldWrite); - - if (changed && !shouldWrite && exitCode === 0) { - exitCode = 1; - } - - results.push({ - path: file.path, - status: changed ? (shouldWrite ? 'written' : 'different') : 'unchanged', - durationMs: performance.now() - fileStartTime, - }); - } catch (error) { - exitCode = 2; - results.push({ - path: file.path, - status: 'error', - error, - durationMs: performance.now() - fileStartTime, - }); + if (file.status === 'error') { + return 2; + } + if (file.status === 'different') { + exitCode = 1; } } + return exitCode; +}; + +/** Runs resolved files and summarizes their outcomes for the CLI. */ +const runFmtFiles = async ({ files, mode }: RunFmtFilesOptions): Promise => { + const startTime = performance.now(); + const results = await runFmtFilesSerial(files, mode === 'write'); + return { files: results, - exitCode, + exitCode: getFmtExitCode(results), durationMs: performance.now() - startTime, }; };