UNPKG

@oclif/multi-stage-output

Version:

Terminal output for oclif commands with multiple stages

102 lines (101 loc) 3.4 kB
import { Performance } from '@oclif/core/performance'; export class StageTracker { stages; current = []; allowParallelTasks; map = new Map(); markers = new Map(); constructor(stages, opts) { this.stages = stages; this.map = new Map(stages.map((stage) => [stage, 'pending'])); this.allowParallelTasks = opts?.allowParallelTasks ?? false; } get size() { return this.map.size; } entries() { return this.map.entries(); } get(stage) { return this.map.get(stage); } indexOf(stage) { return this.stages.indexOf(stage); } refresh(nextStage, opts) { const stages = [...this.map.keys()]; for (const stage of stages) { if (this.map.get(stage) === 'skipped') continue; if (this.map.get(stage) === 'failed') continue; // .stop() was called with a finalStatus if (nextStage === stage && opts?.finalStatus) { this.stopStage(stage, opts.finalStatus); continue; } // set the current stage if (nextStage === stage) { this.set(stage, 'current'); // create a marker for the current stage if it doesn't exist if (!this.markers.has(stage)) { this.markers.set(stage, Performance.mark('MultiStageComponent', stage.replaceAll(' ', '-').toLowerCase())); } continue; } // any pending stage before the current stage should be marked using opts.bypassStatus if (stages.indexOf(stage) < stages.indexOf(nextStage) && this.map.get(stage) === 'pending') { this.set(stage, opts?.bypassStatus ?? 'completed'); continue; } // any stage before the current stage should be marked as completed (if it hasn't been marked as skipped or failed yet) if (stages.indexOf(nextStage) > stages.indexOf(stage)) { this.stopStage(stage, 'completed'); continue; } // default to pending this.set(stage, 'pending'); } } set(stage, status) { if (status === 'current') { if (!this.current.includes(stage)) { this.current.push(stage); } } else { this.current = this.current.filter((s) => s !== stage); } this.map.set(stage, status); } stop(currentStage, finalStatus) { if (this.allowParallelTasks) { for (const [stage, status] of this.entries()) { if (status === 'current') { this.stopStage(stage, finalStatus); } } } else { this.refresh(currentStage, { finalStatus }); } } update(stage, status) { if (status === 'completed' || status === 'failed' || status === 'aborted') { this.stopStage(stage, status); } else { this.set(stage, status); } } values() { return this.map.values(); } stopStage(stage, status) { this.set(stage, status); const marker = this.markers.get(stage); if (marker && !marker.stopped) { marker.stop(); } } }