import * as os from 'os'; import { CliBaseCommandDefinition, CliCommandDefinition, CliCommandDefinitionOption, CliProgramDefinition, } from '../types'; import { initCommandDefinition, initCommandDefinitionOptions } from './init'; import { ProgramValidator } from './ProgramValidator'; /** * Run-time CliProgram, takes raw input defining a CliProgramDefinition, performs * pre-processing, initialization, validation, and generates some helper values (ie indexes) for * use during parsing */ export class CliProgram implements CliProgramDefinition { public get validationErrors(): string[] { if (!this._validationErrors) { const validator = new ProgramValidator(this, this.internalOptions); // validate definition, get an array of errors for any invalid values this._validationErrors = validator.validate(); } return this._validationErrors; } public get commands(): CliCommandDefinition[] { return this._commands; } public get options(): CliCommandDefinitionOption[] { return this._options; } public get commandsMap(): Map { return this._commandsMap; } public static create = (def: CliProgramDefinition, internalOptions: CliCommandDefinitionOption[] = []) => { return new CliProgram(def, internalOptions); }; public readonly name: string; public readonly defaultCommandName: string; public readonly description: string; public readonly examples: string[]; private _validationErrors: string[]; private _commands: CliCommandDefinition[] = []; private _options: CliCommandDefinitionOption[] = []; private _commandsMap: Map = new Map(); constructor( private programDefinition: CliProgramDefinition, private internalOptions: CliCommandDefinitionOption[] = [] ) { if (!programDefinition.name) { throw new Error(`Program must have a name.`); } this.name = programDefinition.name; this.defaultCommandName = programDefinition.defaultCommandName; this.description = programDefinition.description || ''; this.examples = programDefinition.examples || []; this.init(); } private init = () => { // init program (global) options Object.assign(this._options, this.programDefinition.options); initCommandDefinitionOptions(this._options); // init command definitions, along with a map keyed on command name (this.programDefinition.commands || []).forEach(d => { if (this._commandsMap.has(d.name)) { throw new Error(`Duplicate Command Definition for '${d.name}'`); } let cloned: CliCommandDefinition = { ...d }; cloned = initCommandDefinition(cloned); this._commands.push(cloned); this._commandsMap.set(cloned.name, cloned); }); }; }