From 5105f43ea8093bce82fe4703c4c14a8210721924 Mon Sep 17 00:00:00 2001 From: escapedcat Date: Sat, 6 Nov 2021 13:29:25 +0800 Subject: [PATCH] feat(prompt): rewrite codebase to use inquirer - UPDATED with current master (#2697) * feat(prompt): rewrite codebase to use inquirer * fix(prompt): simplify logic used to compute maxLength * test(prompt): add basic input test * fix(prompt): small code refactor * fix: correct linting issues, add missing dependencies * fix: add missing tsconfig reference * fix: update lock file after merge * fix: correct issue with mac-os tab completion * chore: code review * fix: integrate review feedback * style: prettier Co-authored-by: Armano --- .eslintrc.js | 1 + @commitlint/prompt-cli/cli.js | 6 +- @commitlint/prompt-cli/package.json | 1 + @commitlint/prompt/package.json | 10 +- @commitlint/prompt/src/index.ts | 16 +- @commitlint/prompt/src/input.test.ts | 96 ++++++ @commitlint/prompt/src/input.ts | 65 ++-- .../prompt/src/inquirer/InputCustomPrompt.ts | 117 ++++++++ @commitlint/prompt/src/inquirer/inquirer.d.ts | 23 ++ @commitlint/prompt/src/library/format.test.ts | 55 ++++ @commitlint/prompt/src/library/format.ts | 28 +- .../prompt/src/library/get-prompt.test.ts | 100 ------- @commitlint/prompt/src/library/get-prompt.ts | 282 ++++++------------ @commitlint/prompt/src/library/types.ts | 35 +-- @commitlint/prompt/tsconfig.json | 2 +- yarn.lock | 217 +++----------- 16 files changed, 474 insertions(+), 580 deletions(-) create mode 100644 @commitlint/prompt/src/input.test.ts create mode 100644 @commitlint/prompt/src/inquirer/InputCustomPrompt.ts create mode 100644 @commitlint/prompt/src/inquirer/inquirer.d.ts create mode 100644 @commitlint/prompt/src/library/format.test.ts delete mode 100644 @commitlint/prompt/src/library/get-prompt.test.ts diff --git a/.eslintrc.js b/.eslintrc.js index 148b0fa619..8191939429 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,6 +52,7 @@ module.exports = { '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-inferrable-types': 'off', '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/triple-slash-reference': 'off', // TODO: enable those rules? 'no-empty': 'off', diff --git a/@commitlint/prompt-cli/cli.js b/@commitlint/prompt-cli/cli.js index 16f957e07a..716bb4dde7 100755 --- a/@commitlint/prompt-cli/cli.js +++ b/@commitlint/prompt-cli/cli.js @@ -1,10 +1,8 @@ #!/usr/bin/env node const execa = require('execa'); +const inquirer = require('inquirer'); const {prompter} = require('@commitlint/prompt'); -const _ = undefined; -const prompt = () => prompter(_, commit); - main().catch((err) => { setTimeout(() => { throw err; @@ -21,7 +19,7 @@ function main() { process.exit(1); } }) - .then(() => prompt()); + .then(() => prompter(inquirer, commit)); } function isStageEmpty() { diff --git a/@commitlint/prompt-cli/package.json b/@commitlint/prompt-cli/package.json index deedb393a5..329eb125f8 100644 --- a/@commitlint/prompt-cli/package.json +++ b/@commitlint/prompt-cli/package.json @@ -37,6 +37,7 @@ }, "dependencies": { "@commitlint/prompt": "^14.1.0", + "inquirer": "^6.5.2", "execa": "^5.0.0" }, "gitHead": "70f7f4688b51774e7ac5e40e896cdaa3f132b2bc" diff --git a/@commitlint/prompt/package.json b/@commitlint/prompt/package.json index 04ed72c757..c421069da7 100644 --- a/@commitlint/prompt/package.json +++ b/@commitlint/prompt/package.json @@ -38,15 +38,19 @@ }, "devDependencies": { "@commitlint/utils": "^14.0.0", - "commitizen": "4.2.4" + "@commitlint/types": "^13.2.0", + "@commitlint/config-angular": "^13.2.0", + "@types/inquirer": "^6.5.0", + "inquirer": "^6.5.2", + "commitizen": "^4.2.4" }, "dependencies": { "@commitlint/ensure": "^14.1.0", "@commitlint/load": "^14.1.0", "@commitlint/types": "^14.0.0", "chalk": "^4.0.0", - "throat": "^6.0.0", - "vorpal": "^1.12.0" + "lodash": "^4.17.19", + "inquirer": "^6.5.2" }, "gitHead": "70f7f4688b51774e7ac5e40e896cdaa3f132b2bc" } diff --git a/@commitlint/prompt/src/index.ts b/@commitlint/prompt/src/index.ts index 134c621e59..ca85678b1a 100644 --- a/@commitlint/prompt/src/index.ts +++ b/@commitlint/prompt/src/index.ts @@ -1,18 +1,10 @@ -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -import vorpal from 'vorpal'; -import input from './input'; +import inquirer from 'inquirer'; +import {input} from './input'; type Commit = (input: string) => void; -/** - * Entry point for commitizen - * @param _ inquirer instance passed by commitizen, unused - * @param commit callback to execute with complete commit message - * @return {void} - */ -export function prompter(_: unknown, commit: Commit): void { - input(vorpal).then((message) => { +export function prompter(cz: typeof inquirer, commit: Commit): void { + input(cz.prompt).then((message) => { commit(message); }); } diff --git a/@commitlint/prompt/src/input.test.ts b/@commitlint/prompt/src/input.test.ts new file mode 100644 index 0000000000..cde2a5efb2 --- /dev/null +++ b/@commitlint/prompt/src/input.test.ts @@ -0,0 +1,96 @@ +import {Answers, PromptModule, QuestionCollection} from 'inquirer'; +/// +import {input} from './input'; +import chalk from 'chalk'; + +jest.mock( + '@commitlint/load', + () => { + return () => require('@commitlint/config-angular'); + }, + { + virtual: true, + } +); + +test('should work with all fields filled', async () => { + const prompt = stub({ + 'input-custom': { + type: 'fix', + scope: 'test', + subject: 'subject', + body: 'body', + footer: 'footer', + }, + }); + const message = await input(prompt); + expect(message).toEqual('fix(test): subject\n' + 'body\n' + 'footer'); +}); + +test('should work without scope', async () => { + const prompt = stub({ + 'input-custom': { + type: 'fix', + scope: '', + subject: 'subject', + body: 'body', + footer: 'footer', + }, + }); + const message = await input(prompt); + expect(message).toEqual('fix: subject\n' + 'body\n' + 'footer'); +}); + +test('should fail without type', async () => { + const spy = jest.spyOn(console, 'error').mockImplementation(); + const prompt = stub({ + 'input-custom': { + type: '', + scope: '', + subject: '', + body: '', + footer: '', + }, + }); + const message = await input(prompt); + expect(message).toEqual(''); + expect(console.error).toHaveBeenCalledTimes(1); + expect(console.error).toHaveBeenLastCalledWith( + new Error(`⚠ ${chalk.bold('type')} may not be empty.`) + ); + spy.mockRestore(); +}); + +function stub(config: Record>): PromptModule { + const prompt = async (questions: QuestionCollection): Promise => { + const result: Answers = {}; + const resolvedConfig = Array.isArray(questions) ? questions : [questions]; + for (const promptConfig of resolvedConfig) { + const configType = promptConfig.type || 'input'; + const questions = config[configType]; + if (!questions) { + throw new Error(`Unexpected config type: ${configType}`); + } + const answer = questions[promptConfig.name!]; + if (answer == null) { + throw new Error(`Unexpected config name: ${promptConfig.name}`); + } + const validate = promptConfig.validate; + if (validate) { + const validationResult = validate(answer, result); + if (validationResult !== true) { + throw new Error(validationResult || undefined); + } + } + + result[promptConfig.name!] = answer; + } + return result; + }; + prompt.registerPrompt = () => { + return prompt; + }; + prompt.restoreDefaultPrompts = () => true; + prompt.prompts = {}; + return prompt as any as PromptModule; +} diff --git a/@commitlint/prompt/src/input.ts b/@commitlint/prompt/src/input.ts index bb34fcf62f..ff7db40901 100644 --- a/@commitlint/prompt/src/input.ts +++ b/@commitlint/prompt/src/input.ts @@ -1,13 +1,13 @@ import load from '@commitlint/load'; -import throat from 'throat'; +import {DistinctQuestion, PromptModule} from 'inquirer'; import format from './library/format'; import getPrompt from './library/get-prompt'; import settings from './settings'; -import {InputSetting, Prompter, Result} from './library/types'; -import {getHasName, getMaxLength, getRules} from './library/utils'; +import type {InputSetting, Result} from './library/types'; -export default input; +import {getHasName, getMaxLength, getRules} from './library/utils'; +import InputCustomPrompt from './inquirer/InputCustomPrompt'; /** * Get user input by interactive prompt based on @@ -15,15 +15,7 @@ export default input; * @param prompter * @return commit message */ -async function input(prompter: () => Prompter): Promise { - const results: Result = { - type: null, - scope: null, - subject: null, - body: null, - footer: null, - }; - +export async function input(prompter: PromptModule): Promise { const {rules} = await load(); const parts = ['type', 'scope', 'subject', 'body', 'footer'] as const; const headerParts = ['type', 'scope', 'subject']; @@ -33,31 +25,28 @@ async function input(prompter: () => Prompter): Promise { ); const maxLength = getMaxLength(headerLengthRule); - await Promise.all( - parts.map( - throat(1, async (input) => { - const inputRules = getRules(input, rules); - const inputSettings: InputSetting = settings[input]; - - if (headerParts.includes(input) && maxLength < Infinity) { - inputSettings.header = { - length: maxLength, - }; - } - - results[input] = await getPrompt(input, { - rules: inputRules, - settings: inputSettings, - results, - prompter, - }); - }) - ) - ).catch((err) => { + try { + const questions: DistinctQuestion[] = []; + prompter.registerPrompt('input-custom', InputCustomPrompt); + + for (const input of parts) { + const inputSetting: InputSetting = settings[input]; + const inputRules = getRules(input, rules); + if (headerParts.includes(input) && maxLength < Infinity) { + inputSetting.header = { + length: maxLength, + }; + } + const question = getPrompt(input, inputRules, inputSetting); + if (question) { + questions.push(question); + } + } + + const results = await prompter(questions); + return format(results); + } catch (err) { console.error(err); return ''; - }); - - // Return the results - return format(results); + } } diff --git a/@commitlint/prompt/src/inquirer/InputCustomPrompt.ts b/@commitlint/prompt/src/inquirer/InputCustomPrompt.ts new file mode 100644 index 0000000000..036bb78cc3 --- /dev/null +++ b/@commitlint/prompt/src/inquirer/InputCustomPrompt.ts @@ -0,0 +1,117 @@ +/// +import chalk from 'chalk'; +import inquirer from 'inquirer'; +import InputPrompt from 'inquirer/lib/prompts/input'; +import observe from 'inquirer/lib/utils/events'; +import {Interface as ReadlineInterface, Key} from 'readline'; +import type {Subscription} from 'rxjs/internal/Subscription'; + +import Answers = inquirer.Answers; +import InputCustomOptions = inquirer.InputCustomOptions; +import SuccessfulPromptStateData = inquirer.prompts.SuccessfulPromptStateData; + +interface KeyDescriptor { + value: string; + key: Key; +} + +export default class InputCustomPrompt< + TQuestion extends InputCustomOptions = InputCustomOptions +> extends InputPrompt { + private lineSubscription: Subscription; + private readonly tabCompletion: string[]; + + constructor( + question: TQuestion, + readLine: ReadlineInterface, + answers: Answers + ) { + super(question, readLine, answers); + + if (this.opt.log) { + this.rl.write(this.opt.log(answers)); + } + + if (!this.opt.maxLength) { + this.throwParamError('maxLength'); + } + + const events = observe(this.rl); + this.lineSubscription = events.keypress.subscribe( + this.onKeyPress2.bind(this) + ); + this.tabCompletion = (this.opt.tabCompletion || []) + .map((item) => item.value) + .sort((a, b) => a.localeCompare(b)); + } + + onEnd(state: SuccessfulPromptStateData): void { + this.lineSubscription.unsubscribe(); + super.onEnd(state); + } + + /** + * @see https://nodejs.org/api/readline.html#readline_rl_write_data_key + * @see https://nodejs.org/api/readline.html#readline_rl_line + */ + updateLine(line: string): void { + this.rl.write(null as any, {ctrl: true, name: 'b'}); + this.rl.write(null as any, {ctrl: true, name: 'd'}); + this.rl.write(line.substr(this.rl.line.length)); + } + + onKeyPress2(e: KeyDescriptor): void { + if (e.key.name === 'tab' && this.tabCompletion.length > 0) { + let line = this.rl.line.trim(); + if (line.length > 0) { + for (const item of this.tabCompletion) { + if (item.startsWith(line) && item !== line) { + line = item; + break; + } + } + } + this.updateLine(line); + } + } + + measureInput(input: string): number { + if (this.opt.filter) { + return this.opt.filter(input).length; + } + return input.length; + } + + render(error?: string): void { + const answered = this.status === 'answered'; + + let message = this.getQuestion(); + const length = this.measureInput(this.rl.line); + + if (answered) { + message += chalk.cyan(this.answer); + } else if (this.opt.transformer) { + message += this.opt.transformer(this.rl.line, this.answers, {}); + } + + let bottomContent = ''; + + if (error) { + bottomContent = chalk.red('>> ') + error; + } else if (!answered) { + const maxLength = this.opt.maxLength(this.answers); + if (maxLength < Infinity) { + const lengthRemaining = maxLength - length; + const color = + lengthRemaining <= 5 + ? chalk.red + : lengthRemaining <= 10 + ? chalk.yellow + : chalk.grey; + bottomContent = color(`${lengthRemaining} characters left`); + } + } + + this.screen.render(message, bottomContent); + } +} diff --git a/@commitlint/prompt/src/inquirer/inquirer.d.ts b/@commitlint/prompt/src/inquirer/inquirer.d.ts new file mode 100644 index 0000000000..06d2304ab2 --- /dev/null +++ b/@commitlint/prompt/src/inquirer/inquirer.d.ts @@ -0,0 +1,23 @@ +import {Answers, InputQuestionOptions} from 'inquirer'; + +declare module 'inquirer' { + interface InputCustomCompletionOption { + value: string; + description?: string; + } + + export interface InputCustomOptions + extends InputQuestionOptions { + /** + * @inheritdoc + */ + type?: 'input-custom'; + log?(answers?: T): string; + tabCompletion?: InputCustomCompletionOption[]; + maxLength(answers?: T): number; + } + + interface QuestionMap { + 'input-custom': InputCustomOptions; + } +} diff --git a/@commitlint/prompt/src/library/format.test.ts b/@commitlint/prompt/src/library/format.test.ts new file mode 100644 index 0000000000..ae20b3b1ab --- /dev/null +++ b/@commitlint/prompt/src/library/format.test.ts @@ -0,0 +1,55 @@ +import {Result} from './types'; +import format from './format'; + +test('should return empty string', () => { + const result: Result = {}; + expect(format(result)).toBe(' '); +}); + +test('should omit scope', () => { + const result: Result = { + type: 'fix', + subject: 'test', + }; + expect(format(result)).toBe('fix: test'); +}); + +test('should include scope', () => { + const result: Result = { + type: 'fix', + scope: 'prompt', + subject: 'test', + }; + expect(format(result)).toBe('fix(prompt): test'); +}); + +test('should include body', () => { + const result: Result = { + type: 'fix', + scope: 'prompt', + subject: 'test', + body: 'some body', + }; + expect(format(result)).toBe('fix(prompt): test\nsome body'); +}); + +test('should include footer', () => { + const result: Result = { + type: 'fix', + scope: 'prompt', + subject: 'test', + footer: 'some footer', + }; + expect(format(result)).toBe('fix(prompt): test\nsome footer'); +}); + +test('should include body and footer', () => { + const result: Result = { + type: 'fix', + scope: 'prompt', + subject: 'test', + body: 'some body', + footer: 'some footer', + }; + expect(format(result)).toBe('fix(prompt): test\nsome body\nsome footer'); +}); diff --git a/@commitlint/prompt/src/library/format.ts b/@commitlint/prompt/src/library/format.ts index 54f7cf9355..e2d3076b9b 100644 --- a/@commitlint/prompt/src/library/format.ts +++ b/@commitlint/prompt/src/library/format.ts @@ -1,7 +1,5 @@ import chalk from 'chalk'; -import {Result} from './types'; - -export default format; +import {Result, ResultPart} from './types'; /** * Get formatted commit message @@ -9,21 +7,29 @@ export default format; * @param debug show debug information in commit message * @return formatted debug message */ -function format(input: Result, debug = false): string { +export default function format(input: Result, debug = false): string { + const defaultInput = { + type: undefined, + scope: undefined, + subject: undefined, + body: undefined, + footer: undefined, + ...input, + }; const results = debug - ? Object.entries(input).reduce((registry, [name, value]) => { - registry[name as 'type' | 'scope' | 'subject' | 'body' | 'footer'] = - value === null ? chalk.grey(`<${name}>`) : chalk.bold(value); + ? Object.entries(defaultInput).reduce((registry, [name, value]) => { + registry[name as ResultPart] = + value === undefined ? chalk.grey(`<${name}>`) : chalk.bold(value); return registry; }, {}) - : input; + : defaultInput; // Return formatted string const {type, scope, subject, body, footer} = results; return [ - `${type}${scope ? '(' : ''}${scope}${scope ? ')' : ''}${ - type || scope ? ':' : '' - } ${subject}`, + `${type || ''}${scope ? `(${scope})` : ''}${type || scope ? ':' : ''} ${ + subject || '' + }`, body, footer, ] diff --git a/@commitlint/prompt/src/library/get-prompt.test.ts b/@commitlint/prompt/src/library/get-prompt.test.ts deleted file mode 100644 index 831fbcab8a..0000000000 --- a/@commitlint/prompt/src/library/get-prompt.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -import getPrompt from './get-prompt'; -import {Prompter, PrompterCommand} from './types'; - -test('throws without params', () => { - expect(() => (getPrompt as any)()).toThrow('Missing prompter function'); -}); - -test('throws with incompatible prompter', () => { - expect(() => - getPrompt('type', { - prompter: (() => ({})) as any, - }) - ).toThrow('prompt.removeAllListeners'); -}); - -test('returns input unaltered without rules', async () => { - const message = await getPrompt('type', { - prompter: stub('foobar'), - }); - - expect(message).toEqual('foobar'); -}); - -function stub(input = '') { - return function stubPrompter(): Prompter { - const called: any[] = []; - const actions: any[] = []; - - const instanceCommand: PrompterCommand = { - description(...args) { - called.push([instanceCommand.description, args]); - return instanceCommand; - }, - action(...args) { - actions.push(args[0]); - called.push([instanceCommand.action, args]); - return instanceCommand; - }, - }; - - function redraw(...args: any[]): void { - called.push([instance.log, args]); - } - redraw.done = function (...args: any[]) { - called.push([instance.ui.redraw.done, args]); - }; - - const instance: Prompter & {called: any[]} = { - called, - addListener(...args): void { - called.push([instance.addListener, args]); - }, - catch(...args) { - called.push([instance.catch, args]); - return instanceCommand; - }, - command(...args) { - called.push([instance.command, args]); - return instanceCommand; - }, - exec(...args) { - called.push([instance.command, args]); - return Promise.resolve(); - }, - delimiter(...args) { - called.push([instance.delimiter, args]); - return instance; - }, - log(...args) { - called.push([instance.log, args]); - return instance; - }, - removeAllListeners(...args) { - called.push([instance.removeAllListeners, args]); - }, - show(...args) { - called.push([instance.show, args]); - return instance; - }, - ui: { - log(...args) { - called.push([instance.log, args]); - }, - input(...args) { - called.push([instance.log, args]); - return args[0]!; - }, - redraw, - }, - }; - - setTimeout(() => { - actions[0]({ - text: Array.isArray(input) ? input : [input], - }); - }, 0); - - return instance; - }; -} diff --git a/@commitlint/prompt/src/library/get-prompt.ts b/@commitlint/prompt/src/library/get-prompt.ts index 73a9cb7f15..81abe7fc73 100644 --- a/@commitlint/prompt/src/library/get-prompt.ts +++ b/@commitlint/prompt/src/library/get-prompt.ts @@ -1,6 +1,7 @@ import chalk from 'chalk'; +import {InputCustomOptions} from 'inquirer'; -import type {InputSetting, Prompter, Result, RuleEntry} from './types'; +import type {InputSetting, RuleEntry, Result, ResultPart} from './types'; import format from './format'; import getForcedCaseFn from './get-forced-case-fn'; @@ -8,232 +9,115 @@ import getForcedLeadingFn from './get-forced-leading-fn'; import meta from './meta'; import { enumRuleIsActive, - ruleIsNotApplicable, - ruleIsApplicable, - ruleIsActive, getHasName, getMaxLength, + ruleIsActive, + ruleIsApplicable, + ruleIsNotApplicable, } from './utils'; +const EOL = '\n'; + /** * Get a cli prompt based on rule configuration * @param type type of the data to gather - * @param context rules to parse + * @param rules + * @param settings * @return prompt instance */ export default function getPrompt( - type: string, - context: { - rules?: RuleEntry[]; - settings?: InputSetting; - results?: Result; - prompter?: () => Prompter; - } = {} -): Promise { - const {rules = [], settings = {}, results = {}, prompter} = context; - - if (typeof prompter !== 'function') { - throw new TypeError('Missing prompter function in getPrompt context'); - } - - const prompt = prompter(); - - if (typeof prompt.removeAllListeners !== 'function') { - throw new TypeError( - 'getPrompt: prompt.removeAllListeners is not a function' - ); - } - - if (typeof prompt.command !== 'function') { - throw new TypeError('getPrompt: prompt.command is not a function'); - } - - if (typeof prompt.catch !== 'function') { - throw new TypeError('getPrompt: prompt.catch is not a function'); - } - - if (typeof prompt.addListener !== 'function') { - throw new TypeError('getPrompt: prompt.addListener is not a function'); - } - - if (typeof prompt.log !== 'function') { - throw new TypeError('getPrompt: prompt.log is not a function'); - } - - if (typeof prompt.delimiter !== 'function') { - throw new TypeError('getPrompt: prompt.delimiter is not a function'); - } - - if (typeof prompt.show !== 'function') { - throw new TypeError('getPrompt: prompt.show is not a function'); - } - - const enumRule = rules.filter(getHasName('enum')).find(enumRuleIsActive); - - const emptyRule = rules.find(getHasName('empty')); - - const mustBeEmpty = - emptyRule && ruleIsActive(emptyRule) && ruleIsApplicable(emptyRule); + type: ResultPart, + rules: RuleEntry[] = [], + settings: InputSetting = {} +): InputCustomOptions | null { + const emptyRule = rules.filter(getHasName('empty')).find(ruleIsActive); - const mayNotBeEmpty = - emptyRule && ruleIsActive(emptyRule) && ruleIsNotApplicable(emptyRule); - - const mayBeEmpty = !mayNotBeEmpty; + const mustBeEmpty = emptyRule ? ruleIsApplicable(emptyRule) : false; if (mustBeEmpty) { - prompt.removeAllListeners('keypress'); - prompt.removeAllListeners('client_prompt_submit'); - prompt.ui.redraw.done(); - return Promise.resolve(undefined); + return null; } - const caseRule = rules.find(getHasName('case')); - - const forceCaseFn = getForcedCaseFn(caseRule); + const required = emptyRule ? ruleIsNotApplicable(emptyRule) : false; - const leadingBlankRule = rules.find(getHasName('leading-blank')); - - const forceLeadingBlankFn = getForcedLeadingFn(leadingBlankRule); + const forceCaseFn = getForcedCaseFn(rules.find(getHasName('case'))); + const forceLeadingBlankFn = getForcedLeadingFn( + rules.find(getHasName('leading-blank')) + ); const maxLengthRule = rules.find(getHasName('max-length')); const inputMaxLength = getMaxLength(maxLengthRule); - const headerLength = settings.header ? settings.header.length : Infinity; - - const remainingHeaderLength = headerLength - ? headerLength - - [ - results.type, - results.scope, - results.scope ? '()' : '', - results.type && results.scope ? ':' : '', - results.subject, - ].join('').length - : Infinity; - - const maxLength = Math.min(inputMaxLength, remainingHeaderLength); - - return new Promise((resolve) => { - // Add the defined enums as sub commands if applicable - if (enumRule) { - const [, [, , enums]] = enumRule; + const enumRule = rules.filter(getHasName('enum')).find(enumRuleIsActive); - enums.forEach((enumerable) => { + const tabCompletion = enumRule + ? enumRule[1][2].map((enumerable) => { const enumSettings = (settings.enumerables || {})[enumerable] || {}; - prompt - .command(enumerable) - .description(enumSettings.description || '') - .action(() => { - prompt.removeAllListeners(); - prompt.ui.redraw.done(); - return resolve(forceLeadingBlankFn(forceCaseFn(enumerable))); - }); + return { + value: forceLeadingBlankFn(forceCaseFn(enumerable)), + description: enumSettings.description || '', + }; + }) + : []; + + const maxLength = (res: Result) => { + let remainingHeaderLength = Infinity; + if (settings.header && settings.header.length) { + const header = format({ + type: res.type, + scope: res.scope, + subject: res.subject, }); - } else { - prompt.catch('[text...]').action((parameters) => { - const {text = ''} = parameters; - prompt.removeAllListeners(); - prompt.ui.redraw.done(); - return resolve(forceLeadingBlankFn(forceCaseFn(text.join(' ')))); - }); - } - - if (mayBeEmpty) { - // Add an easy exit command - prompt - .command(':skip') - .description('Skip the input if possible.') - .action(() => { - prompt.removeAllListeners(); - prompt.ui.redraw.done(); - resolve(''); - }); + remainingHeaderLength = settings.header.length - header.length; } - - // Handle empty input - const onSubmit = (input: string) => { - if (input.length > 0) { - return; + return Math.min(inputMaxLength, remainingHeaderLength); + }; + + return { + type: 'input-custom', + name: type, + message: `${type}:`, + validate(input, answers) { + if (input.length > maxLength(answers || {})) { + return 'Input contains too many characters!'; } - - // Show help if enum is defined and input may not be empty - if (mayNotBeEmpty) { - prompt.ui.log(chalk.yellow(`⚠ ${chalk.bold(type)} may not be empty.`)); + if (required && input.trim().length === 0) { + // Show help if enum is defined and input may not be empty + return `⚠ ${chalk.bold(type)} may not be empty.`; } - if (mayBeEmpty) { - prompt.ui.log( - chalk.blue( - `ℹ Enter ${chalk.bold(':skip')} to omit ${chalk.bold(type)}.` - ) - ); + const tabValues = tabCompletion.map((item) => item.value); + if ( + input.length > 0 && + tabValues.length > 0 && + !tabValues.includes(input) + ) { + return `⚠ ${chalk.bold(type)} must be one of ${tabValues.join(', ')}.`; } - - if (enumRule) { - prompt.exec('help'); + return true; + }, + tabCompletion, + log(answers?: Result) { + let prefix = + `${chalk.white('Please enter a')} ${chalk.bold(type)}: ${meta({ + optional: !required, + required: required, + 'tab-completion': typeof enumRule !== 'undefined', + header: typeof settings.header !== 'undefined', + 'multi-line': settings.multiline, + })}` + EOL; + + if (settings.description) { + prefix += chalk.grey(`${settings.description}`) + EOL; } - }; - - const drawRemaining = (length: number) => { - if (length < Infinity) { - const colors = [ - { - threshold: 5, - color: chalk.red, - }, - { - threshold: 10, - color: chalk.yellow, - }, - { - threshold: Infinity, - color: chalk.grey, - }, - ]; - - const el = colors.find((item) => item.threshold >= length); - const color = el ? el.color : chalk.grey; - prompt.ui.redraw(color(`${length} characters left`)); + if (answers) { + prefix += EOL + `${format(answers, true)}` + EOL; } - }; - - const onKey = (event: {value: string}) => { - const sanitized = forceCaseFn(event.value); - const cropped = sanitized.slice(0, maxLength); - - // We **could** do live editing, but there are some quirks to solve - /* const live = merge({}, results, { - [type]: cropped - }); - prompt.ui.redraw(`\n\n${format(live, true)}\n\n`); */ - - if (maxLength) { - drawRemaining(maxLength - cropped.length); - } - prompt.ui.input(cropped); - }; - - prompt.addListener('keypress', onKey); - prompt.addListener('client_prompt_submit', onSubmit); - - prompt.log( - `\n\nPlease enter a ${chalk.bold(type)}: ${meta({ - optional: !mayNotBeEmpty, - required: mayNotBeEmpty, - 'tab-completion': typeof enumRule !== 'undefined', - header: typeof settings.header !== 'undefined', - 'multi-line': settings.multiline, - })}` - ); - - if (settings.description) { - prompt.log(chalk.grey(`${settings.description}\n`)); - } - - prompt.log(`\n\n${format(results, true)}\n\n`); - - drawRemaining(maxLength); - - prompt.delimiter(`❯ ${type}:`).show(); - }); + return prefix + EOL; + }, + maxLength, + transformer(value: string) { + return forceCaseFn(value); + }, + }; } diff --git a/@commitlint/prompt/src/library/types.ts b/@commitlint/prompt/src/library/types.ts index 0f05c3cd6f..e873e4a36a 100644 --- a/@commitlint/prompt/src/library/types.ts +++ b/@commitlint/prompt/src/library/types.ts @@ -19,37 +19,6 @@ export type InputSetting = { }; }; -export type Result = Partial< - Record<'type' | 'scope' | 'subject' | 'body' | 'footer', null | string> ->; +export type ResultPart = 'type' | 'scope' | 'subject' | 'body' | 'footer'; -export interface PrompterCommand { - description(value: string): this; - action( - action: (args: { - [key: string]: any; - options: { - [key: string]: any; - }; - }) => Promise | void - ): this; -} - -export interface Prompter { - delimiter(value: string): this; - show(): this; - exec(command: string): Promise; - log(text?: string): void; - catch(command: string, description?: string): PrompterCommand; - command(command: string, description?: string): PrompterCommand; - removeAllListeners(input?: string): void; - addListener(input: string, cb: (event: any) => void): void; - ui: { - log(text?: string): void; - input(text?: string): string; - redraw: { - (text: string, ...texts: string[]): void; - done(): void; - }; - }; -} +export type Result = Partial>; diff --git a/@commitlint/prompt/tsconfig.json b/@commitlint/prompt/tsconfig.json index 2a6d93a0fa..76dd5e38cb 100644 --- a/@commitlint/prompt/tsconfig.json +++ b/@commitlint/prompt/tsconfig.json @@ -7,5 +7,5 @@ }, "include": ["./src"], "exclude": ["./src/**/*.test.ts", "./lib/**/*"], - "references": [{"path": "../cli"}] + "references": [{"path": "../types"}, {"path": "../load"}] } diff --git a/yarn.lock b/yarn.lock index f7c4ef8df9..b0437eda32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1398,6 +1398,18 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@commitlint/config-angular-type-enum@^13.2.0": + version "13.2.0" + resolved "https://registry.npmjs.org/@commitlint/config-angular-type-enum/-/config-angular-type-enum-13.2.0.tgz#e3f9b8a07118ed8e060b0b1d04a549f74957634d" + integrity sha512-HSP9lzCoHC9+bjJquvByiSUpo0GbAipbjcT6l3Jl6XOzkCjhnUkYcQ2b/O5nXv3mf8Vv/n5k2Sk4nbCYEVpSGQ== + +"@commitlint/config-angular@^13.2.0": + version "13.2.0" + resolved "https://registry.npmjs.org/@commitlint/config-angular/-/config-angular-13.2.0.tgz#78c62551279bdf7ed3a9bf993751f346c42b2944" + integrity sha512-mfytI8ZrPt7kuxjZo0ZfFw0bg1zEa2kI6/prVaYJ0FJgOE8EP1Co9Y4DJZEegohfYFeRcFK3radog7WOr2pzdw== + dependencies: + "@commitlint/config-angular-type-enum" "^13.2.0" + "@endemolshinegroup/cosmiconfig-typescript-loader@^3.0.2": version "3.0.2" resolved "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz#eea4635828dde372838b0909693ebd9aafeec22d" @@ -2623,6 +2635,14 @@ dependencies: "@types/node" "*" +"@types/inquirer@^6.5.0": + version "6.5.0" + resolved "https://registry.npmjs.org/@types/inquirer/-/inquirer-6.5.0.tgz#b83b0bf30b88b8be7246d40e51d32fe9d10e09be" + integrity sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw== + dependencies: + "@types/through" "*" + rxjs "^6.4.0" + "@types/inquirer@^8.0.0": version "8.1.0" resolved "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.1.0.tgz#99fab20fd6fb3ee2b0352042082fe8dbec76bf55" @@ -2956,11 +2976,6 @@ ansi-colors@^4.1.1: resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-escapes@^1.0.0, ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - integrity sha1-06ioOzGapneTZisT52HHkRQiMG4= - ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" @@ -3248,15 +3263,6 @@ babel-plugin-polyfill-regenerator@^0.2.3: dependencies: "@babel/helper-define-polyfill-provider" "^0.2.4" -babel-polyfill@^6.3.14: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" - integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM= - dependencies: - babel-runtime "^6.26.0" - core-js "^2.5.0" - regenerator-runtime "^0.10.5" - babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" @@ -3283,14 +3289,6 @@ babel-preset-jest@^27.2.0: babel-plugin-jest-hoist "^27.2.0" babel-preset-current-node-syntax "^1.0.0" -babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -3568,7 +3566,7 @@ caseless@~0.12.0: resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1: +chalk@^1.1.1: version "1.1.3" resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= @@ -3682,13 +3680,6 @@ cli-boxes@^2.2.0: resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== -cli-cursor@^1.0.1, cli-cursor@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc= - dependencies: - restore-cursor "^1.0.1" - cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -3711,11 +3702,6 @@ cli-truncate@2.1.0, cli-truncate@^2.1.0: slice-ansi "^3.0.0" string-width "^4.2.0" -cli-width@^1.0.1: - version "1.1.1" - resolved "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz#a4d293ef67ebb7b88d4a4d42c0ccf00c4d1e366d" - integrity sha1-pNKT72frt7iNSk1CwMzwDE0eNm0= - cli-width@^2.0.0: version "2.2.1" resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" @@ -3849,42 +3835,42 @@ commander@~2.20.3: resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commitizen@4.2.4, commitizen@^4.2.4: - version "4.2.4" - resolved "https://registry.npmjs.org/commitizen/-/commitizen-4.2.4.tgz#a3e5b36bd7575f6bf6e7aa19dbbf06b0d8f37165" - integrity sha512-LlZChbDzg3Ir3O2S7jSo/cgWp5/QwylQVr59K4xayVq8S4/RdKzSyJkghAiZZHfhh5t4pxunUoyeg0ml1q/7aw== +commitizen@^4.0.3: + version "4.1.2" + resolved "https://registry.npmjs.org/commitizen/-/commitizen-4.1.2.tgz#6095eb825fd3f0d3611df88e6803c69b23307e9a" + integrity sha512-LBxTQKHbVgroMz9ohpm86N+GfJobonGyvDc3zBGdZazbwCLz2tqLa48Rf2TnAdKx7/06W1i1R3SXUt5QW97qVQ== dependencies: cachedir "2.2.0" cz-conventional-changelog "3.2.0" dedent "0.7.0" detect-indent "6.0.0" - find-node-modules "^2.1.2" + find-node-modules "2.0.0" find-root "1.1.0" fs-extra "8.1.0" glob "7.1.4" - inquirer "6.5.2" + inquirer "6.5.0" is-utf8 "^0.2.1" - lodash "^4.17.20" + lodash "4.17.15" minimist "1.2.5" strip-bom "4.0.0" strip-json-comments "3.0.1" -commitizen@^4.0.3: - version "4.1.2" - resolved "https://registry.npmjs.org/commitizen/-/commitizen-4.1.2.tgz#6095eb825fd3f0d3611df88e6803c69b23307e9a" - integrity sha512-LBxTQKHbVgroMz9ohpm86N+GfJobonGyvDc3zBGdZazbwCLz2tqLa48Rf2TnAdKx7/06W1i1R3SXUt5QW97qVQ== +commitizen@^4.2.4: + version "4.2.4" + resolved "https://registry.npmjs.org/commitizen/-/commitizen-4.2.4.tgz#a3e5b36bd7575f6bf6e7aa19dbbf06b0d8f37165" + integrity sha512-LlZChbDzg3Ir3O2S7jSo/cgWp5/QwylQVr59K4xayVq8S4/RdKzSyJkghAiZZHfhh5t4pxunUoyeg0ml1q/7aw== dependencies: cachedir "2.2.0" cz-conventional-changelog "3.2.0" dedent "0.7.0" detect-indent "6.0.0" - find-node-modules "2.0.0" + find-node-modules "^2.1.2" find-root "1.1.0" fs-extra "8.1.0" glob "7.1.4" - inquirer "6.5.0" + inquirer "6.5.2" is-utf8 "^0.2.1" - lodash "4.17.15" + lodash "^4.17.20" minimist "1.2.5" strip-bom "4.0.0" strip-json-comments "3.0.1" @@ -4110,11 +4096,6 @@ core-js-compat@^3.18.0, core-js-compat@^3.19.0: browserslist "^4.17.5" semver "7.0.0" -core-js@^2.4.0, core-js@^2.5.0: - version "2.6.12" - resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" - integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== - core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -4933,11 +4914,6 @@ execa@^5.1.1: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g= - exit@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -5073,14 +5049,6 @@ figlet@^1.1.1: resolved "https://registry.npmjs.org/figlet/-/figlet-1.5.0.tgz#2db4d00a584e5155a96080632db919213c3e003c" integrity sha512-ZQJM4aifMpz6H19AW1VqvZ7l4pOE9p7i/3LyxgO2kp+PO/VcDYNqIHEMtkccqIhTXMKci4kjueJr/iCQEaT/Ww== -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - figures@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -5947,11 +5915,6 @@ imurmurhash@^0.1.4: resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -in-publish@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz#948b1a535c8030561cea522f73f78f4be357e00c" - integrity sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ== - indent-string@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" @@ -6011,24 +5974,6 @@ init-package-json@^2.0.2: validate-npm-package-license "^3.0.4" validate-npm-package-name "^3.0.0" -inquirer@0.11.0: - version "0.11.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-0.11.0.tgz#7448bfa924092af311d47173bbab990cae2bb027" - integrity sha1-dEi/qSQJKvMR1HFzu6uZDK4rsCc= - dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^1.0.1" - figures "^1.3.5" - lodash "^3.3.1" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - strip-ansi "^3.0.0" - through "^2.3.6" - inquirer@6.5.0: version "6.5.0" resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42" @@ -6048,7 +5993,7 @@ inquirer@6.5.0: strip-ansi "^5.1.0" through "^2.3.6" -inquirer@6.5.2: +inquirer@6.5.2, inquirer@^6.5.2: version "6.5.2" resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== @@ -7447,19 +7392,11 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" -lodash@4.17.15, lodash@^3.3.1, lodash@^4.17.12, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.5.1, lodash@^4.7.0: +lodash@4.17.15, lodash@^4.17.12, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-update@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1" - integrity sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE= - dependencies: - ansi-escapes "^1.0.0" - cli-cursor "^1.0.2" - log-update@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" @@ -7905,11 +7842,6 @@ multimatch@^5.0.0: arrify "^2.0.1" minimatch "^3.0.4" -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" - integrity sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA= - mute-stream@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -7995,11 +7927,6 @@ node-int64@^0.4.0: resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= -node-localstorage@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/node-localstorage/-/node-localstorage-0.6.0.tgz#45a0601c6932dfde6644a23361f1be173c75d3af" - integrity sha1-RaBgHGky395mRKIzYfG+Fzx1068= - node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" @@ -8265,11 +8192,6 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k= - onetime@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -9088,15 +9010,6 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - integrity sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - rechoir@^0.6.2: version "0.6.2" resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -9140,16 +9053,6 @@ regenerate@^1.4.2: resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@^0.10.5: - version "0.10.5" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" - integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg= - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - regenerator-runtime@^0.13.4: version "0.13.9" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" @@ -9366,14 +9269,6 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE= - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -9426,13 +9321,6 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" - integrity sha1-yK1KXhEGYeQCp9IbUw4AnyX444k= - dependencies: - once "^1.3.0" - run-async@^2.2.0, run-async@^2.4.0: version "2.4.1" resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -9445,11 +9333,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" - integrity sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI= - rxjs@^6.4.0: version "6.5.4" resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" @@ -10199,7 +10082,7 @@ text-table@^0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -throat@^6.0.0, throat@^6.0.1: +throat@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== @@ -10728,22 +10611,6 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vorpal@^1.12.0: - version "1.12.0" - resolved "https://registry.npmjs.org/vorpal/-/vorpal-1.12.0.tgz#4be7b2a4e48f8fcfc9cf3648c419d311c522159d" - integrity sha1-S+eypOSPj8/JzzZIxBnTEcUiFZ0= - dependencies: - babel-polyfill "^6.3.14" - chalk "^1.1.0" - in-publish "^2.0.0" - inquirer "0.11.0" - lodash "^4.5.1" - log-update "^1.0.2" - minimist "^1.2.0" - node-localstorage "^0.6.0" - strip-ansi "^3.0.0" - wrap-ansi "^2.0.0" - w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -10875,14 +10742,6 @@ wordwrap@^1.0.0: resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"