@quenty/cli-output-helpers
Version:
Helpers to generate Nevermore package and game templates
108 lines (89 loc) • 2.9 kB
text/typescript
import { type PackageResult, type PackageStatus, type JobPhase, type ProgressSummary, BaseReporter } from '../reporter.js';
import { type IStateTracker, type PackageState } from './state-tracker.js';
export type { PackageState } from './state-tracker.js';
/**
* Centralized state container for a live batch run.
* Extends BaseReporter to receive lifecycle hooks and mutate state.
* Reporters read from it via the IStateTracker interface.
*/
export class LiveStateTracker
extends BaseReporter
implements IStateTracker
{
private _packages: Map<string, PackageState>;
private _startTimeMs = 0;
private _completed = 0;
private _failures: PackageResult[] = [];
private _allResults: PackageResult[] = [];
constructor(packageNames: string[]) {
super();
this._packages = new Map();
for (const name of packageNames) {
this._packages.set(name, { name, status: 'pending' });
}
}
get total(): number {
return this._packages.size;
}
get completed(): number {
return this._completed;
}
get startTimeMs(): number {
return this._startTimeMs;
}
getPackage(name: string): PackageState | undefined {
return this._packages.get(name);
}
getAllPackages(): PackageState[] {
return [...this._packages.values()];
}
getResults(): PackageResult[] {
return this._allResults;
}
getFailures(): PackageResult[] {
return this._failures;
}
getCurrentPhase(name: string): PackageStatus | undefined {
return this._packages.get(name)?.status;
}
override async startAsync(): Promise<void> {
this._startTimeMs = Date.now();
}
override onPackageStart(name: string): void {
const state = this._packages.get(name);
if (!state) return;
state.status = 'building';
state.startMs = Date.now();
}
override onPackagePhaseChange(name: string, phase: JobPhase): void {
const state = this._packages.get(name);
if (!state) return;
if (state.status === 'passed' || state.status === 'failed') return; // don't regress terminal states
state.status = phase;
state.progress = undefined; // clear progress on phase transition
}
override onPackageProgressUpdate(name: string, progress: ProgressSummary): void {
const state = this._packages.get(name);
if (!state) return;
state.progress = progress;
}
override onPackageResult(
result: PackageResult,
bufferedOutput?: string[]
): void {
const state = this._packages.get(result.packageName);
if (!state) return;
state.status = result.success ? 'passed' : 'failed';
state.durationMs = result.durationMs;
state.result = result;
state.bufferedOutput = bufferedOutput;
if (result.progressSummary) {
state.progress = result.progressSummary;
}
this._completed++;
this._allResults.push(result);
if (!result.success) {
this._failures.push(result);
}
}
}