UNPKG

@sprucelabs/spruce-cli

Version:

Command line interface for building Spruce skills.

260 lines • 9.59 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils"); const test_utils_1 = require("@sprucelabs/test-utils"); const test_utility_1 = __importDefault(require("../tests/utilities/test.utility")); const duration_utility_1 = __importDefault(require("../utilities/duration.utility")); const TerminalInterface_1 = __importDefault(require("./TerminalInterface")); class SpyInterface { invocations = []; cursorPosition = { x: 0, y: 0 }; promptResolver; confirmResolver; waitForEnterResolver; promptDefaultValue; term; startTime; promptTimeout; error; constructor() { this.startTime = new Date().getTime(); this.term = this.shouldRenderTestLogs() ? new TerminalInterface_1.default(process.cwd(), true, (...strs) => { this.optionallyRenderLine(strs.join(' ')); }) : undefined; } setTitle(_title) { } shouldRenderTestLogs() { return process.env.SHOULD_RENDER_TEST_LOGS === 'true'; } renderWarning(message, effects) { this.trackInvocation('renderWarning', { message, effects }); this.term?.renderWarning(message); } renderHint(message, effects) { this.trackInvocation('renderHint', { message, effects }); this.optionallyRenderLine(`Hint: ${message}`); this.term?.renderHint(message); } trackInvocation(command, options) { // testUtil.log(command, JSON.stringify(options), '\n') this.invocations.push({ command, options }); } isWaitingForInput() { return !!(this.promptResolver || this.confirmResolver || this.waitForEnterResolver); } reset() { this.promptResolver = undefined; this.confirmResolver = undefined; this.waitForEnterResolver = undefined; clearTimeout(this.promptTimeout); } setError(err) { this.error = err; } getLastInvocation() { return this.invocations[this.invocations.length - 1]; } async sendInput(input) { this.trackInvocation('sendInput', input); this.optionallyRenderLine(`Sending input: "${input.path ? input.path : input.length > 0 ? input : 'ENTER'}"`); if (this.waitForEnterResolver) { const resolver = this.waitForEnterResolver; this.waitForEnterResolver = undefined; resolver(); } else if (this.promptResolver) { const resolver = this.promptResolver; this.promptResolver = undefined; resolver(input !== '\n' && input !== '' ? input : this.promptDefaultValue); } else if (this.confirmResolver) { const resolver = this.confirmResolver; this.confirmResolver = undefined; resolver(input === '\n' || input.length === 0 || (typeof input === 'string' && input.toLowerCase() === 'y')); } else { throw new Error('Sent input before prompted for input'); } return new Promise((resolve) => { setTimeout(resolve, 50); }); } renderSection(options) { this.trackInvocation('renderSection', options); this.term?.renderSection(options); } renderObject(obj) { this.trackInvocation('renderObject', obj); this.term?.renderObject(obj); } renderError(err) { this.trackInvocation('renderError', err); this.term?.renderError(err); } renderCodeSample(code) { this.trackInvocation('renderCodeSample', code); this.term?.renderCodeSample(code); } renderActionSummary(results) { this.trackInvocation('renderCommandSummary', results); this.term?.renderActionSummary(results); } renderHero(message, effects) { this.trackInvocation('renderHero', { message, effects }); this.term?.renderHero(message, effects); } renderHeadline(message, effects, dividerEffects) { this.trackInvocation('renderHeadline', { message, effects, dividerEffects, }); this.term?.renderHeadline(message, effects, dividerEffects); } renderDivider(effects) { this.trackInvocation('renderDivider', effects); this.term?.renderDivider(effects); } renderLine(message, effects) { this.trackInvocation('renderLine', { message, effects }); message && message.length > 0 && this.optionallyRenderLine(message); } optionallyRenderLine(message) { if (this.shouldRenderTestLogs()) { const duration = new Date().getTime() - this.startTime; const friendly = duration_utility_1.default.msToFriendly(duration); spruce_skill_utils_1.testLog.info(`${ //@ts-ignore global.activeTest?.test ? //@ts-ignore global.activeTest?.test + ' :: ' : ''}${friendly} :: ${message}`); } } async renderImage(path, options) { this.trackInvocation('renderImage', { path, options }); } renderLines(messages, effects) { this.trackInvocation('renderLines', { messages, effects }); this.term?.renderLines(messages, effects); } async prompt(definition) { this.trackInvocation('prompt', definition); if (this.promptResolver) { throw new Error('Tried to double prompt. Try this.term?.sendInput() before calling prompt next.'); } let msg = `${spruce_skill_utils_1.namesUtil.toPascal(definition.type)} Prompt: ${definition.label}`; if (definition.type === 'select') { msg += '\n\nChoices:\n'; definition.options.choices.forEach((choice) => { msg += `\n${choice.value}: ${choice.label}`; }); msg += '\n'; } this.optionallyRenderLine(msg); return new Promise((resolve, reject) => { this.promptResolver = (...args) => { clearTimeout(this.promptTimeout); //@ts-ignore resolve(...args); }; this.promptTimeout = setTimeout(() => { this.reset(); try { test_utils_1.assert.fail(`Timed out waiting for input with label: '${definition.label}'\n\nConsider passing what you need to Action().execute({ something })`); } catch (err) { reject(err); } }, 10000); this.promptDefaultValue = definition.defaultValue; }); } startLoading(message) { this.trackInvocation('startLoading', message); this.optionallyRenderLine(message ? `${message}` : 'Start loading...'); } stopLoading() { this.trackInvocation('stopLoading'); this.optionallyRenderLine('Stop loading...'); } async waitForEnter(message) { this.trackInvocation('waitForEnter', message); this.optionallyRenderLine(`${message ? ` ${message}\n\n` : ``}Waiting for enter...`); return new Promise((resolve) => { this.waitForEnterResolver = resolve; }); } async waitForInput() { const ttl = 1000 * 60 * 2; const checkInterval = 100; let loops = ttl / checkInterval; let lastWriteCount = this.invocations.length; while (!this.isWaitingForInput()) { if (loops-- === 0) { test_utils_1.assert.fail(`Waiting for input timed out.`); } const hasWritten = lastWriteCount != this.invocations.length; if (hasWritten) { loops = ttl / checkInterval; lastWriteCount = this.invocations.length; if (this.shouldRenderTestLogs()) { test_utility_1.default.log('waitForInput timeout reset because of new output.'); } } if (this.error) { throw this.error; } await new Promise((resolve) => setTimeout(resolve, checkInterval)); } } confirm(question) { this.trackInvocation('confirm', question); this.optionallyRenderLine(`${question} :: Y/N...`); return new Promise((resolve) => { this.confirmResolver = resolve; }); } clear() { this.trackInvocation('clear'); } renderProgressBar(options) { this.trackInvocation('renderProgressBar', options); this.optionallyRenderLine(`Showing progress${options.title ? ` ${options.title}` : ``}`); } updateProgressBar(options) { this.trackInvocation('updateProgressBar', options); } removeProgressBar() { this.trackInvocation('removeProgressBar'); this.optionallyRenderLine(`Hiding progress`); } async getCursorPosition() { this.trackInvocation('getCursorPosition'); return this.cursorPosition; } setCursorPosition(pos) { this.cursorPosition = pos; } moveCursorTo(x, y) { this.trackInvocation('moveCursorTo', { x, y }); } clearBelowCursor() { this.trackInvocation('clearBelowCursor'); } } exports.default = SpyInterface; //# sourceMappingURL=SpyInterface.js.map