From 7754698cf82bfd54918dec3cd2bff52e0deda7f5 Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 7 Mar 2019 13:12:04 -0800 Subject: [PATCH 1/4] [dev/run] typescriptify the dev/run helper --- src/dev/run/{fail.js => fail.ts} | 19 ++++++++++------ src/dev/run/{flags.js => flags.ts} | 35 +++++++++++++++++++++++------- src/dev/run/index.d.ts | 25 --------------------- src/dev/run/{index.js => index.ts} | 0 src/dev/run/{run.js => run.ts} | 8 +++---- 5 files changed, 43 insertions(+), 44 deletions(-) rename src/dev/run/{fail.js => fail.ts} (78%) rename src/dev/run/{flags.js => flags.ts} (73%) delete mode 100644 src/dev/run/index.d.ts rename src/dev/run/{index.js => index.ts} (100%) rename src/dev/run/{run.js => run.ts} (84%) diff --git a/src/dev/run/fail.js b/src/dev/run/fail.ts similarity index 78% rename from src/dev/run/fail.js rename to src/dev/run/fail.ts index af0197fd47fd4..aa8386eaeecaa 100644 --- a/src/dev/run/fail.js +++ b/src/dev/run/fail.ts @@ -21,18 +21,23 @@ import { inspect } from 'util'; const FAIL_TAG = Symbol('fail error'); -export function createFailError(reason, exitCode = 1) { - const error = new Error(reason); - error.exitCode = exitCode; - error[FAIL_TAG] = true; - return error; +interface FailError extends Error { + exitCode: number; + [FAIL_TAG]: true; } -export function isFailError(error) { +export function createFailError(reason: string, exitCode = 1): FailError { + return Object.assign(new Error(reason), { + exitCode, + [FAIL_TAG]: true as true, + }); +} + +export function isFailError(error: any): error is FailError { return Boolean(error && error[FAIL_TAG]); } -export function combineErrors(errors) { +export function combineErrors(errors: Array) { if (errors.length === 1) { return errors[0]; } diff --git a/src/dev/run/flags.js b/src/dev/run/flags.ts similarity index 73% rename from src/dev/run/flags.js rename to src/dev/run/flags.ts index ef98e9532b2c9..5c677771ad760 100644 --- a/src/dev/run/flags.js +++ b/src/dev/run/flags.ts @@ -21,8 +21,19 @@ import { relative } from 'path'; import getopts from 'getopts'; -export function getFlags(argv) { - return getopts(argv, { +export interface Flags { + verbose: boolean; + quiet: boolean; + silent: boolean; + debug: boolean; + help: boolean; + _: string[]; + + [key: string]: boolean | string | string[]; +} + +export function getFlags(argv: string[]): Flags { + const { verbose, quiet, silent, debug, help, _, ...others } = getopts(argv, { alias: { v: 'verbose', }, @@ -32,14 +43,23 @@ export function getFlags(argv) { silent: false, debug: false, help: false, - } + }, }); + + return { + verbose, + quiet, + silent, + debug, + help, + _, + ...others, + }; } export function getHelp() { - return ( - ` - node ${relative(process.cwd(), process.argv[1], '.js')} + return ` + node ${relative(process.cwd(), process.argv[1])} Runs a dev task @@ -50,6 +70,5 @@ export function getHelp() { --silent Don't log anything --help Show this message -` - ); +`; } diff --git a/src/dev/run/index.d.ts b/src/dev/run/index.d.ts deleted file mode 100644 index 8f49f5a84f3fd..0000000000000 --- a/src/dev/run/index.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { ToolingLog } from '@kbn/dev-utils'; - -export function createFailError(msg: string, exitCode?: number): Error; -export function run( - body: (args: { flags: Record; log: ToolingLog }) => void -): Promise; diff --git a/src/dev/run/index.js b/src/dev/run/index.ts similarity index 100% rename from src/dev/run/index.js rename to src/dev/run/index.ts diff --git a/src/dev/run/run.js b/src/dev/run/run.ts similarity index 84% rename from src/dev/run/run.js rename to src/dev/run/run.ts index d7d0b4ec30c72..0cdf2fe37df98 100644 --- a/src/dev/run/run.js +++ b/src/dev/run/run.ts @@ -17,11 +17,11 @@ * under the License. */ -import { ToolingLog, pickLevelFromFlags } from '@kbn/dev-utils'; +import { pickLevelFromFlags, ToolingLog } from '@kbn/dev-utils'; import { isFailError } from './fail'; -import { getFlags, getHelp } from './flags'; +import { Flags, getFlags, getHelp } from './flags'; -export async function run(body) { +export async function run(body: (args: { log: ToolingLog; flags: Flags }) => Promise | void) { const flags = getFlags(process.argv.slice(2)); if (flags.help) { @@ -31,7 +31,7 @@ export async function run(body) { const log = new ToolingLog({ level: pickLevelFromFlags(flags), - writeTo: process.stdout + writeTo: process.stdout, }); try { From d89023f6e1506499b8ed2c246f8d07f7a5a8157f Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 7 Mar 2019 13:15:44 -0800 Subject: [PATCH 2/4] unknown flags are potentially undefined --- src/dev/run/flags.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dev/run/flags.ts b/src/dev/run/flags.ts index 5c677771ad760..8adbf24567b35 100644 --- a/src/dev/run/flags.ts +++ b/src/dev/run/flags.ts @@ -29,7 +29,7 @@ export interface Flags { help: boolean; _: string[]; - [key: string]: boolean | string | string[]; + [key: string]: undefined | boolean | string | string[]; } export function getFlags(argv: string[]): Flags { From 7f50f567dba1caf8b5a3fc7b5257e51071e4052a Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 7 Mar 2019 13:25:07 -0800 Subject: [PATCH 3/4] properly validate arg types in i18n clis --- src/dev/run_i18n_check.ts | 10 ++++++++++ src/dev/run_i18n_extract.ts | 6 ++++++ src/dev/run_i18n_integrate.ts | 23 +++++++++++++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/dev/run_i18n_check.ts b/src/dev/run_i18n_check.ts index 28d518f008cfb..91180b2bfa5ea 100644 --- a/src/dev/run_i18n_check.ts +++ b/src/dev/run_i18n_check.ts @@ -49,6 +49,16 @@ run( ); } + if (typeof path === 'boolean' || typeof includeConfig === 'boolean') { + throw createFailError( + `${chalk.white.bgRed(' I18N ERROR ')} --path and --include-config require a value` + ); + } + + if (typeof fix !== 'boolean') { + throw createFailError(`${chalk.white.bgRed(' I18N ERROR ')} --fix can't have a value`); + } + const config = await mergeConfigs(includeConfig); const defaultMessages = await extractDefaultMessages({ path, config }); diff --git a/src/dev/run_i18n_extract.ts b/src/dev/run_i18n_extract.ts index 0610674a70e1c..c2584e2527389 100644 --- a/src/dev/run_i18n_extract.ts +++ b/src/dev/run_i18n_extract.ts @@ -39,6 +39,12 @@ run( ); } + if (typeof path === 'boolean' || typeof includeConfig === 'boolean') { + throw createFailError( + `${chalk.white.bgRed(' I18N ERROR ')} --path and --include-config require a value` + ); + } + const config = await mergeConfigs(includeConfig); const defaultMessages = await extractDefaultMessages({ path, config }); diff --git a/src/dev/run_i18n_integrate.ts b/src/dev/run_i18n_integrate.ts index 3e5877bfa924a..efbb459652e46 100644 --- a/src/dev/run_i18n_integrate.ts +++ b/src/dev/run_i18n_integrate.ts @@ -47,9 +47,28 @@ run( ); } - if (Array.isArray(target)) { + if (typeof target === 'boolean' || Array.isArray(target)) { throw createFailError( - `${chalk.white.bgRed(' I18N ERROR ')} --target should be specified only once.` + `${chalk.white.bgRed( + ' I18N ERROR ' + )} --target should be specified only once and must have a value.` + ); + } + + if (typeof path === 'boolean' || typeof includeConfig === 'boolean') { + throw createFailError( + `${chalk.white.bgRed(' I18N ERROR ')} --path and --include-config require a value` + ); + } + + if ( + typeof ignoreIncompatible !== 'boolean' || + typeof ignoreUnused !== 'boolean' || + typeof ignoreMissing !== 'boolean' || + typeof dryRun !== 'boolean' + ) { + throw createFailError( + `${chalk.white.bgRed(' I18N ERROR ')} --ignore-incompatible can't have a value` ); } From 115e47ee869cfb1033b28a110a18706c4f56c71e Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 7 Mar 2019 13:26:47 -0800 Subject: [PATCH 4/4] fix error message --- src/dev/run_i18n_integrate.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dev/run_i18n_integrate.ts b/src/dev/run_i18n_integrate.ts index efbb459652e46..d0ee997efa08a 100644 --- a/src/dev/run_i18n_integrate.ts +++ b/src/dev/run_i18n_integrate.ts @@ -68,7 +68,9 @@ run( typeof dryRun !== 'boolean' ) { throw createFailError( - `${chalk.white.bgRed(' I18N ERROR ')} --ignore-incompatible can't have a value` + `${chalk.white.bgRed( + ' I18N ERROR ' + )} --ignore-incompatible, --ignore-unused, --ignore-missing, and --dry-run can't have values` ); }