From 39c0e4ba766cdc6cc6c9aa38a94a327fa8352e66 Mon Sep 17 00:00:00 2001 From: ssube Date: Thu, 4 Jul 2019 09:44:54 -0500 Subject: [PATCH] feat: add command completion BREAKING CHANGE: the `--mode` option has been replaced by a positional command, but the options and defaults are unchanged. --- src/index.ts | 155 +++++++++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 67 deletions(-) diff --git a/src/index.ts b/src/index.ts index aaa4e20..88bbfb7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,72 +19,92 @@ const RULE_OPTION: Options = { type: 'array', }; -const MAIN_ARGS = usage(`Usage: salty-dog [-m mode] [options]`) - .option(CONFIG_ARGS_NAME, { - default: `.${VERSION_INFO.app.name}.yml`, - group: 'Config:', - type: 'string', - }) - .option(CONFIG_ARGS_PATH, { - default: [], - group: 'Config:', - type: 'array', - }) - .option('coerce', { - default: false, - type: 'boolean', - }) - .option('count', { - alias: ['c'], - default: false, - desc: 'Exit with error count', - type: 'boolean', - }) - .option('dest', { - alias: ['d'], - default: '-', - type: 'string', - }) - .option('format', { - alias: ['f'], - default: 'yaml', - type: 'string', - }) - .option('mode', { - alias: ['m'], - choices: MODES, - default: 'check', - type: 'string', - }) - .option('rules', { - alias: ['r'], - default: [], - desc: 'Rules file', - type: 'array', - }) - .option('source', { - alias: ['s'], - default: '-', - type: 'string', - }) - .option('exclude-level', RULE_OPTION) - .option('exclude-name', RULE_OPTION) - .option('exclude-tag', RULE_OPTION) - .option('include-level', RULE_OPTION) - .option('include-name', RULE_OPTION) - .option('include-tag', { - ...RULE_OPTION, - alias: ['t', 'tag'], - }) - .help() - .version(VERSION_INFO.app.version) - .alias('version', 'v'); - const STATUS_SUCCESS = 0; const STATUS_ERROR = 1; export async function main(argv: Array): Promise { - const args = MAIN_ARGS.argv; + let mode = 'check'; + + const args = usage(`Usage: salty-dog [options]`) + .command({ + command: ['check', '*'], + describe: 'validate the source documents', + handler: (argv) => { + mode = 'check'; + }, + }) + .command({ + command: ['fix'], + describe: 'validate the source document and insert defaults', + builder: (yargs: any) => { + return yargs.option('coerce', { + default: false, + type: 'boolean', + }); + }, + handler: (argv) => { + mode = 'fix'; + }, + }) + .command({ + command: ['list'], + describe: 'list active rules', + handler: (argv) => { + mode = 'list'; + }, + }) + .option(CONFIG_ARGS_NAME, { + default: `.${VERSION_INFO.app.name}.yml`, + group: 'Config:', + type: 'string', + }) + .option(CONFIG_ARGS_PATH, { + default: [], + group: 'Config:', + type: 'array', + }) + .option('count', { + alias: ['c'], + default: false, + desc: 'Exit with error count', + type: 'boolean', + }) + .option('dest', { + alias: ['d'], + default: '-', + type: 'string', + }) + .option('format', { + alias: ['f'], + default: 'yaml', + type: 'string', + }) + .option('rules', { + alias: ['r'], + default: [], + desc: 'Rules file', + type: 'array', + }) + .option('source', { + alias: ['s'], + default: '-', + type: 'string', + }) + .option('exclude-level', RULE_OPTION) + .option('exclude-name', RULE_OPTION) + .option('exclude-tag', RULE_OPTION) + .option('include-level', RULE_OPTION) + .option('include-name', RULE_OPTION) + .option('include-tag', { + ...RULE_OPTION, + alias: ['t', 'tag'], + }) + .completion('completion', 'generate command completion for bash or zsh') + .help() + .version(VERSION_INFO.app.version) + .alias('version', 'v') + .argv; + const config = await loadConfig(args[CONFIG_ARGS_NAME], ...args[CONFIG_ARGS_PATH]); const logger = createLogger(config.data.logger); @@ -92,8 +112,8 @@ export async function main(argv: Array): Promise { logger.info({ args }, 'main arguments'); // check mode - if (!MODES.includes(args.mode)) { - logger.error({ mode: args.mode }, 'unsupported mode'); + if (!MODES.includes(mode)) { + logger.error({ mode }, 'unsupported mode'); return STATUS_ERROR; } @@ -104,9 +124,10 @@ export async function main(argv: Array): Promise { return STATUS_ERROR; } + const coerce = Reflect.has(args, 'coerce') ? Reflect.get(args, 'coerce') : false; const ctx = new VisitorContext({ - coerce: args.coerce, - defaults: args.mode === 'fix', + coerce, + defaults: mode === 'fix', logger, }); @@ -117,7 +138,7 @@ export async function main(argv: Array): Promise { const rules = await loadRules(args.rules, ctx.ajv); const activeRules = await resolveRules(rules, args as any); - if (args.mode === 'list') { + if (mode === 'list') { logger.info({ rules: activeRules }, 'listing active rules'); return STATUS_SUCCESS; }