From f77fd5e02a2d432821c0b15ce9777420add7e79a Mon Sep 17 00:00:00 2001 From: Joey Perrott Date: Wed, 29 Jul 2020 14:19:15 -0700 Subject: [PATCH] feat(dev-infra): create a wizard for building commit messages (#38457) Creates a wizard to walk through creating a commit message in the correct template for commit messages in Angular repositories. PR Close #38457 --- dev-infra/commit-message/BUILD.bazel | 5 ++ dev-infra/commit-message/builder.spec.ts | 46 ++++++++++ dev-infra/commit-message/builder.ts | 70 +++++++++++++++ dev-infra/commit-message/cli.ts | 18 ++++ dev-infra/commit-message/config.ts | 20 +++++ dev-infra/commit-message/wizard.ts | 43 ++++++++++ dev-infra/utils/BUILD.bazel | 1 + dev-infra/utils/console.ts | 49 ++++++++++- .../utils/inquirer-autocomplete-typings.d.ts | 17 ++++ package.json | 7 +- yarn.lock | 85 ++++++++++++++++--- 11 files changed, 344 insertions(+), 17 deletions(-) create mode 100644 dev-infra/commit-message/builder.spec.ts create mode 100644 dev-infra/commit-message/builder.ts create mode 100644 dev-infra/commit-message/wizard.ts create mode 100644 dev-infra/utils/inquirer-autocomplete-typings.d.ts diff --git a/dev-infra/commit-message/BUILD.bazel b/dev-infra/commit-message/BUILD.bazel index c8e7898a4b..18ad90463a 100644 --- a/dev-infra/commit-message/BUILD.bazel +++ b/dev-infra/commit-message/BUILD.bazel @@ -4,6 +4,7 @@ load("@npm_bazel_typescript//:index.bzl", "ts_library") ts_library( name = "commit-message", srcs = [ + "builder.ts", "cli.ts", "commit-message-draft.ts", "config.ts", @@ -12,14 +13,17 @@ ts_library( "validate.ts", "validate-file.ts", "validate-range.ts", + "wizard.ts", ], module_name = "@angular/dev-infra-private/commit-message", visibility = ["//dev-infra:__subpackages__"], deps = [ "//dev-infra/utils", + "@npm//@types/inquirer", "@npm//@types/node", "@npm//@types/shelljs", "@npm//@types/yargs", + "@npm//inquirer", "@npm//shelljs", "@npm//yargs", ], @@ -29,6 +33,7 @@ ts_library( name = "test_lib", testonly = True, srcs = [ + "builder.spec.ts", "parse.spec.ts", "validate.spec.ts", ], diff --git a/dev-infra/commit-message/builder.spec.ts b/dev-infra/commit-message/builder.spec.ts new file mode 100644 index 0000000000..5b45ac4140 --- /dev/null +++ b/dev-infra/commit-message/builder.spec.ts @@ -0,0 +1,46 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as config from '../utils/config'; +import * as console from '../utils/console'; + +import {buildCommitMessage} from './builder'; + + +describe('commit message building:', () => { + beforeEach(() => { + // stub logging calls to prevent noise in test log + spyOn(console, 'info').and.stub(); + // provide a configuration for DevInfra when loaded + spyOn(config, 'getConfig').and.returnValue({ + commitMessage: { + scopes: ['core'], + } + } as any); + }); + + it('creates a commit message with a scope', async () => { + buildPromptResponseSpies('fix', 'core', 'This is a summary'); + + expect(await buildCommitMessage()).toMatch(/^fix\(core\): This is a summary/); + }); + + it('creates a commit message without a scope', async () => { + buildPromptResponseSpies('build', false, 'This is a summary'); + + expect(await buildCommitMessage()).toMatch(/^build: This is a summary/); + }); +}); + + +/** Create spies to return the mocked selections from prompts. */ +function buildPromptResponseSpies(type: string, scope: string|false, summary: string) { + spyOn(console, 'promptAutocomplete') + .and.returnValues(Promise.resolve(type), Promise.resolve(scope)); + spyOn(console, 'promptInput').and.returnValue(Promise.resolve(summary)); +} diff --git a/dev-infra/commit-message/builder.ts b/dev-infra/commit-message/builder.ts new file mode 100644 index 0000000000..f663f3619d --- /dev/null +++ b/dev-infra/commit-message/builder.ts @@ -0,0 +1,70 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {ListChoiceOptions} from 'inquirer'; + +import {info, promptAutocomplete, promptInput} from '../utils/console'; + +import {COMMIT_TYPES, CommitType, getCommitMessageConfig, ScopeRequirement} from './config'; + +/** Validate commit message at the provided file path. */ +export async function buildCommitMessage() { + // TODO(josephperrott): Add support for skipping wizard with local untracked config file + // TODO(josephperrott): Add default commit message information/commenting into generated messages + info('Just a few questions to start building the commit message!'); + + /** The commit message type. */ + const type = await promptForCommitMessageType(); + /** The commit message scope. */ + const scope = await promptForCommitMessageScopeForType(type); + /** The commit message summary. */ + const summary = await promptForCommitMessageSummary(); + + return `${type.name}${scope ? '(' + scope + ')' : ''}: ${summary}\n\n`; +} + +/** Prompts in the terminal for the commit message's type. */ +async function promptForCommitMessageType(): Promise { + info('The type of change in the commit. Allows a reader to know the effect of the change,'); + info('whether it brings a new feature, adds additional testing, documents the `project, etc.'); + + /** List of commit type options for the autocomplete prompt. */ + const typeOptions: ListChoiceOptions[] = + Object.values(COMMIT_TYPES).map(({description, name}) => { + return { + name: `${name} - ${description}`, + value: name, + short: name, + }; + }); + /** The key of a commit message type, selected by the user via prompt. */ + const typeName = await promptAutocomplete('Select a type for the commit:', typeOptions); + + return COMMIT_TYPES[typeName]; +} + +/** Prompts in the terminal for the commit message's scope. */ +async function promptForCommitMessageScopeForType(type: CommitType): Promise { + // If the commit type's scope requirement is forbidden, return early. + if (type.scope === ScopeRequirement.Forbidden) { + info(`Skipping scope selection as the '${type.name}' type does not allow scopes`); + return false; + } + /** Commit message configuration */ + const config = getCommitMessageConfig(); + + info('The area of the repository the changes in this commit most affects.'); + return await promptAutocomplete( + 'Select a scope for the commit:', config.commitMessage.scopes, + type.scope === ScopeRequirement.Optional ? '' : ''); +} + +/** Prompts in the terminal for the commit message's summary. */ +async function promptForCommitMessageSummary(): Promise { + info('Provide a short summary of what the changes in the commit do'); + return await promptInput('Provide a short summary of the commit'); +} diff --git a/dev-infra/commit-message/cli.ts b/dev-infra/commit-message/cli.ts index 90143ccee2..e6e97e3a52 100644 --- a/dev-infra/commit-message/cli.ts +++ b/dev-infra/commit-message/cli.ts @@ -12,6 +12,7 @@ import {info} from '../utils/console'; import {restoreCommitMessage} from './restore-commit-message'; import {validateFile} from './validate-file'; import {validateCommitRange} from './validate-range'; +import {runWizard} from './wizard'; /** Build the parser for the commit-message commands. */ export function buildCommitMessageParser(localYargs: yargs.Argv) { @@ -41,6 +42,23 @@ export function buildCommitMessageParser(localYargs: yargs.Argv) { args => { restoreCommitMessage(args['file-env-variable'][0], args['file-env-variable'][1] as any); }) + .command( + 'wizard [source] [commitSha]', '', ((args: any) => { + return args + .positional( + 'filePath', + {description: 'The file path to write the generated commit message into'}) + .positional('source', { + choices: ['message', 'template', 'merge', 'squash', 'commit'], + description: 'The source of the commit message as described here: ' + + 'https://git-scm.com/docs/githooks#_prepare_commit_msg' + }) + .positional( + 'commitSha', {description: 'The commit sha if source is set to `commit`'}); + }), + async (args: any) => { + await runWizard(args); + }) .command( 'pre-commit-validate', 'Validate the most recent commit message', { 'file': { diff --git a/dev-infra/commit-message/config.ts b/dev-infra/commit-message/config.ts index 9183e0c9ba..599f51aafb 100644 --- a/dev-infra/commit-message/config.ts +++ b/dev-infra/commit-message/config.ts @@ -39,36 +39,56 @@ export enum ScopeRequirement { /** A commit type */ export interface CommitType { + description: string; + name: string; scope: ScopeRequirement; } /** The valid commit types for Angular commit messages. */ export const COMMIT_TYPES: {[key: string]: CommitType} = { build: { + name: 'build', + description: 'Changes to local repository build system and tooling', scope: ScopeRequirement.Forbidden, }, ci: { + name: 'ci', + description: 'Changes to CI configuration and CI specific tooling', scope: ScopeRequirement.Forbidden, }, docs: { + name: 'docs', + description: 'Changes which exclusively affects documentation.', scope: ScopeRequirement.Optional, }, feat: { + name: 'feat', + description: 'Creates a new feature', scope: ScopeRequirement.Required, }, fix: { + name: 'fix', + description: 'Fixes a previously discovered failure/bug', scope: ScopeRequirement.Required, }, perf: { + name: 'perf', + description: 'Improves performance without any change in functionality or API', scope: ScopeRequirement.Required, }, refactor: { + name: 'refactor', + description: 'Refactor without any change in functionality or API (includes style changes)', scope: ScopeRequirement.Required, }, release: { + name: 'release', + description: 'A release point in the repository', scope: ScopeRequirement.Forbidden, }, test: { + name: 'test', + description: 'Improvements or corrections made to the project\'s test suite', scope: ScopeRequirement.Required, }, }; diff --git a/dev-infra/commit-message/wizard.ts b/dev-infra/commit-message/wizard.ts new file mode 100644 index 0000000000..fdf7d49496 --- /dev/null +++ b/dev-infra/commit-message/wizard.ts @@ -0,0 +1,43 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {writeFileSync} from 'fs'; + +import {info} from '../utils/console'; + +import {buildCommitMessage} from './builder'; + +/** + * The source triggering the git commit message creation. + * As described in: https://git-scm.com/docs/githooks#_prepare_commit_msg + */ +export type PrepareCommitMsgHookSource = 'message'|'template'|'merge'|'squash'|'commit'; + +/** The default commit message used if the wizard does not procude a commit message. */ +const defaultCommitMessage = `(): + +# \n\n`; + +export async function runWizard( + args: {filePath: string, source?: PrepareCommitMsgHookSource, commitSha?: string}) { + // TODO(josephperrott): Add support for skipping wizard with local untracked config file + + if (args.source !== undefined) { + info(`Skipping commit message wizard due because the commit was created via '${ + args.source}' source`); + process.exitCode = 0; + return; + } + + // Set the default commit message to be updated if the user cancels out of the wizard in progress + writeFileSync(args.filePath, defaultCommitMessage); + + /** The generated commit message. */ + const commitMessage = await buildCommitMessage(); + writeFileSync(args.filePath, commitMessage); +} diff --git a/dev-infra/utils/BUILD.bazel b/dev-infra/utils/BUILD.bazel index 248aaddacf..3881ac19b0 100644 --- a/dev-infra/utils/BUILD.bazel +++ b/dev-infra/utils/BUILD.bazel @@ -17,6 +17,7 @@ ts_library( "@npm//@types/shelljs", "@npm//chalk", "@npm//inquirer", + "@npm//inquirer-autocomplete-prompt", "@npm//shelljs", "@npm//tslib", "@npm//typed-graphqlify", diff --git a/dev-infra/utils/console.ts b/dev-infra/utils/console.ts index 63830a5e76..625cf9189a 100644 --- a/dev-infra/utils/console.ts +++ b/dev-infra/utils/console.ts @@ -7,7 +7,8 @@ */ import chalk from 'chalk'; -import {prompt} from 'inquirer'; +import {createPromptModule, ListChoiceOptions, prompt} from 'inquirer'; +import * as inquirerAutocomplete from 'inquirer-autocomplete-prompt'; /** Reexport of chalk colors for convenient access. */ @@ -26,6 +27,52 @@ export async function promptConfirm(message: string, defaultValue = false): Prom .result; } +/** Prompts the user to select an option from a filterable autocomplete list. */ +export async function promptAutocomplete( + message: string, choices: (string|ListChoiceOptions)[]): Promise; +/** + * Prompts the user to select an option from a filterable autocomplete list, with an option to + * choose no value. + */ +export async function promptAutocomplete( + message: string, choices: (string|ListChoiceOptions)[], + noChoiceText?: string): Promise; +export async function promptAutocomplete( + message: string, choices: (string|ListChoiceOptions)[], + noChoiceText?: string): Promise { + // Creates a local prompt module with an autocomplete prompt type. + const prompt = createPromptModule({}).registerPrompt('autocomplete', inquirerAutocomplete); + if (noChoiceText) { + choices = [noChoiceText, ...choices]; + } + // `prompt` must be cast as `any` as the autocomplete typings are not available. + const result = (await (prompt as any)({ + type: 'autocomplete', + name: 'result', + message, + source: (_: any, input: string) => { + if (!input) { + return Promise.resolve(choices); + } + return Promise.resolve(choices.filter(choice => { + if (typeof choice === 'string') { + return choice.includes(input); + } + return choice.name!.includes(input); + })); + } + })).result; + if (result === noChoiceText) { + return false; + } + return result; +} + +/** Prompts the user for one line of input. */ +export async function promptInput(message: string): Promise { + return (await prompt<{result: string}>({type: 'input', name: 'result', message})).result; +} + /** * Supported levels for logging functions. * diff --git a/dev-infra/utils/inquirer-autocomplete-typings.d.ts b/dev-infra/utils/inquirer-autocomplete-typings.d.ts new file mode 100644 index 0000000000..bddf9e2e1a --- /dev/null +++ b/dev-infra/utils/inquirer-autocomplete-typings.d.ts @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// inquirer-autocomplete-prompt doesn't provide types and no types are made available via +// DefinitelyTyped. +declare module "inquirer-autocomplete-prompt" { + + import {registerPrompt} from 'inquirer'; + + let AutocompletePrompt: Parameters[1]; + export = AutocompletePrompt; +} diff --git a/package.json b/package.json index 2fcd6424bc..d702e27d4e 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "@types/diff": "^3.5.1", "@types/fs-extra": "4.0.2", "@types/hammerjs": "2.0.35", - "@types/inquirer": "^6.5.0", + "@types/inquirer": "^7.3.0", "@types/jasmine": "3.5.10", "@types/jasmine-ajax": "^3.3.1", "@types/jasminewd2": "^2.0.8", @@ -179,8 +179,9 @@ "glob": "7.1.2", "gulp": "3.9.1", "gulp-conventional-changelog": "^2.0.3", - "husky": "^4.2.3", - "inquirer": "^7.1.0", + "husky": "^4.2.5", + "inquirer": "^7.3.3", + "inquirer-autocomplete-prompt": "^1.0.2", "jpm": "1.3.1", "karma-browserstack-launcher": "^1.3.0", "karma-sauce-launcher": "^2.0.2", diff --git a/yarn.lock b/yarn.lock index 54131051c6..62934308c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2198,10 +2198,10 @@ resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.35.tgz#7b7c950c7d54593e23bffc8d2b4feba9866a7277" integrity sha512-4mUIMSZ2U4UOWq1b+iV7XUTE4w+Kr3x+Zb/Qz5ROO6BTZLw2c8/ftjq0aRgluguLs4KRuBnrOy/s389HVn1/zA== -"@types/inquirer@^6.5.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-6.5.0.tgz#b83b0bf30b88b8be7246d40e51d32fe9d10e09be" - integrity sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw== +"@types/inquirer@^7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-7.3.0.tgz#a1233632ea6249f14eb481dae91138e747b85664" + integrity sha512-wcPs5jTrZYQBzzPlvUEzBcptzO4We2sijSvkBq8oAKRMJoH8PvrmP6QQnxLB5RScNUmRfujxA+ngxD4gk4xe7Q== dependencies: "@types/through" "*" rxjs "^6.4.0" @@ -2761,7 +2761,7 @@ ansi-colors@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== -ansi-escapes@^3.1.0, ansi-escapes@^3.2.0: +ansi-escapes@^3.0.0, ansi-escapes@^3.1.0, ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== @@ -4027,6 +4027,14 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + char-spinner@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/char-spinner/-/char-spinner-1.0.1.tgz#e6ea67bd247e107112983b7ab0479ed362800081" @@ -4271,6 +4279,11 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + cliui@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" @@ -4477,7 +4490,7 @@ compare-semver@^1.0.0: dependencies: semver "^5.0.1" -compare-versions@^3.5.1: +compare-versions@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== @@ -8061,14 +8074,14 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -husky@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.3.tgz#3b18d2ee5febe99e27f2983500202daffbc3151e" - integrity sha512-VxTsSTRwYveKXN4SaH1/FefRJYCtx+wx04sSVcOpD7N2zjoHxa+cEJ07Qg5NmV3HAK+IRKOyNVpi2YBIVccIfQ== +husky@^4.2.5: + version "4.2.5" + resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.5.tgz#2b4f7622673a71579f901d9885ed448394b5fa36" + integrity sha512-SYZ95AjKcX7goYVZtVZF2i6XiZcHknw50iXvY7b0MiGoj5RwdgRQNEHdb+gPDPCXKlzwrybjFjkL6FOj8uRhZQ== dependencies: - chalk "^3.0.0" + chalk "^4.0.0" ci-info "^2.0.0" - compare-versions "^3.5.1" + compare-versions "^3.6.0" cosmiconfig "^6.0.0" find-versions "^3.2.0" opencollective-postinstall "^2.0.2" @@ -8248,7 +8261,17 @@ ini@1.3.5, ini@^1.3.2, ini@^1.3.4, ini@~1.3.0, ini@~1.3.3: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== -inquirer@7.1.0, inquirer@^7.1.0: +inquirer-autocomplete-prompt@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/inquirer-autocomplete-prompt/-/inquirer-autocomplete-prompt-1.0.2.tgz#3f2548f73dd12f0a541be055ea9c8c7aedeb42bf" + integrity sha512-vNmAhhrOQwPnUm4B9kz1UB7P98rVF1z8txnjp53r40N0PBCuqoRWqjg3Tl0yz0UkDg7rEUtZ2OZpNc7jnOU9Zw== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + figures "^2.0.0" + run-async "^2.3.0" + +inquirer@7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" integrity sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg== @@ -8267,6 +8290,25 @@ inquirer@7.1.0, inquirer@^7.1.0: strip-ansi "^6.0.0" through "^2.3.6" +inquirer@^7.3.3: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + inquirer@~6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.3.1.tgz#7a413b5e7950811013a3db491c61d1f3b776e8e7" @@ -9889,6 +9931,11 @@ lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +lodash@^4.17.19: + version "4.17.19" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" + integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== + lodash@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" @@ -13380,6 +13427,11 @@ run-async@^2.2.0, run-async@^2.4.0: dependencies: is-promise "^2.1.0" +run-async@^2.3.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" @@ -13401,6 +13453,13 @@ rxjs@6.5.5: dependencies: tslib "^1.9.0" +rxjs@^6.6.0: + version "6.6.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2" + integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg== + dependencies: + tslib "^1.9.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"