UNPKG

@sprucelabs/spruce-cli

Version:

Command line interface for building Spruce skills.

108 lines (90 loc) 3.25 kB
import { GraphicsInterface } from '../../types/cli.types' import OnboardingStore from './stores/OnboardingStore' export type Script = ScriptItem[] type ScriptItem = string | ScriptItemCallback type ScriptRedirect = string type ScriptItemCallback = ( player: CallbackPlayer ) => Promise<void | ScriptRedirect> | void | ScriptRedirect export interface CallbackPlayer { ui: GraphicsInterface redirect(toScriptKey: string): ScriptRedirect onboardingStore: OnboardingStore executeCommand: CommandExecuter } export type CommandExecuter = (command: string) => Promise<void> export default class ScriptPlayer { private ui: GraphicsInterface private scriptsByKey: Record<string, Script> = {} private onboardingStore: OnboardingStore private commandExecuter: CommandExecuter public constructor(options: { ui: GraphicsInterface onboardingStore: OnboardingStore commandExecuter: CommandExecuter }) { this.ui = options.ui this.onboardingStore = options.onboardingStore this.commandExecuter = options.commandExecuter } public async playScriptWithKey(key: string) { const script = this.scriptsByKey[key] if (!script) { throw new Error(`Onboarding script '${key}' not found.`) } await this.playScript(script) } public loadScript(key: string, script: Script) { this.scriptsByKey[key] = script } public async playScript(script: Script) { for (let item of script) { let possibleRedirect: ScriptRedirect | undefined switch (typeof item) { case 'string': if (this.isRedirect(item)) { possibleRedirect = item } else { this.ui.renderLine(item) this.ui.renderLine('') } break case 'function': { const r = await item(this.buildCallbackOptions()) if (r) { possibleRedirect = r } break } default: possibleRedirect = item } if (this.isRedirect(possibleRedirect)) { await this.redirectAndPlay(possibleRedirect) } } } private buildCallbackOptions(): CallbackPlayer { return { ui: this.ui, redirect: ScriptPlayer.redirect, onboardingStore: this.onboardingStore, executeCommand: this.commandExecuter, } } private async redirectAndPlay(possibleRedirect: string) { const destination = this.extractDestination(possibleRedirect) if (destination) { await this.playScriptWithKey(destination) } } public static redirect(toScriptKey: string) { return `redirect->${toScriptKey}` } private extractDestination(possibleRedirect: string) { return possibleRedirect.split('->').pop() } private isRedirect(item: string | undefined): item is string { return !!(item && item.substr(0, 10) === 'redirect->') } }