From 90c15275d84ce57c51c3f95e634d991af0822c53 Mon Sep 17 00:00:00 2001 From: Rafa Mel Date: Sat, 3 Apr 2021 14:07:16 +0200 Subject: [PATCH] feat: treat 'default' keys in Task.Record as the task to be run for its top level --- src/bin/lift.ts | 9 +++-- src/bin/list.ts | 60 ++++++++++++++++++++++++++++++++++ src/bin/main.ts | 21 ++++-------- src/constants.ts | 3 +- src/helpers/parse.ts | 42 +++++++++++++++++++----- src/tasks/aggregate/combine.ts | 6 +++- src/tasks/reflection/lift.ts | 12 +++++-- src/tasks/reflection/list.ts | 11 +++++-- 8 files changed, 131 insertions(+), 33 deletions(-) create mode 100644 src/bin/list.ts diff --git a/src/bin/lift.ts b/src/bin/lift.ts index 5960073..b4fc917 100644 --- a/src/bin/lift.ts +++ b/src/bin/lift.ts @@ -25,13 +25,15 @@ export default async function bin( $ ${opts.bin} :lift [options] Options: - --purge Purge all non-${opts.bin} scripts - --mode Lift mode of operation (default, confirm, dry, audit) - -h, --help Show help + --purge Purge all non-${opts.bin} scripts + --defaults Lift default tasks and subtasks by their own + --mode Lift mode of operation (default, confirm, dry, audit) + -h, --help Show help `; const types = { '--purge': Boolean, + '--defaults': Boolean, '--mode': String, '--help': Boolean }; @@ -65,6 +67,7 @@ export default async function bin( print(), lift(params.record, { purge: cmd['--purge'], + defaults: cmd['--defaults'], mode: cmd['--mode'] as any, bin: opts.bin }) diff --git a/src/bin/list.ts b/src/bin/list.ts new file mode 100644 index 0000000..2338ef9 --- /dev/null +++ b/src/bin/list.ts @@ -0,0 +1,60 @@ +import { Task } from '../definitions'; +import { list, series, raises, print, log } from '../tasks'; +import { stripIndent as indent } from 'common-tags'; +import { flags, safePairs } from 'cli-belt'; +import chalk from 'chalk'; +import arg from 'arg'; + +interface Params { + argv: string[]; + record: Task.Record; +} + +interface Options { + bin: string; +} + +export default async function bin( + params: Params, + opts: Options +): Promise { + const help = indent` + ${chalk.bold(`Lists ${opts.bin} tasks`)} + + Usage: + $ ${opts.bin} :list [options] + + Options: + --defaults List default tasks and subtasks by their own + -h, --help Show help + `; + + const types = { + '--defaults': Boolean, + '--help': Boolean + }; + + const { options, aliases } = flags(help); + safePairs(types, options, { fail: true, bidirectional: true }); + Object.assign(types, aliases); + const cmd = arg(types, { + argv: params.argv, + permissive: false, + stopAtPositional: true + }); + + if (cmd['--help']) return print(help + '\n'); + if (cmd._.length) { + return series( + print(help + '\n'), + raises(Error(`Unknown subcommand: ${cmd._[0]}`)) + ); + } + + return series( + log('debug', 'Working directory:', process.cwd()), + log('info', chalk.bold(opts.bin), chalk.bold.blue(':list')), + print(), + list(params.record, { defaults: cmd['--defaults'], bin: opts.bin }) + ); +} diff --git a/src/bin/main.ts b/src/bin/main.ts index 9481852..16a7b7f 100644 --- a/src/bin/main.ts +++ b/src/bin/main.ts @@ -1,7 +1,8 @@ import { LogLevel, Task, PrefixPolicy } from '../definitions'; -import { print, log, list, raises, series, context, combine } from '../tasks'; +import { print, log, raises, series, context, combine } from '../tasks'; import { fetch } from '../utils'; import watch from './watch'; +import list from './list'; import lift from './lift'; import { Members } from 'type-core'; import { flags, safePairs, splitBy } from 'cli-belt'; @@ -153,20 +154,10 @@ export default async function main( ); } case ':list': { - return cmd._.length - ? series( - print(help + '\n'), - raises(Error(`Unknown subcommand: ${cmd._[0]}`)) - ) - : into( - series( - log('debug', 'Working directory:', process.cwd()), - log('info', chalk.bold(opts.bin), chalk.bold.blue(':list')), - print(), - list(record, { bin: opts.bin }) - ), - withContext - ); + return into( + await list({ argv: cmd._, record: record }, { bin: opts.bin }), + withContext + ); } case ':lift': { return into( diff --git a/src/constants.ts b/src/constants.ts index ba8bd98..843c939 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -4,5 +4,6 @@ export const constants = { bin: 'kpo', file: 'kpo.tasks.js', description: pkg.description || '', - version: pkg.version || 'Unknown' + version: pkg.version || 'Unknown', + record: { default: 'default' } }; diff --git a/src/helpers/parse.ts b/src/helpers/parse.ts index 9616e76..1eb98ed 100644 --- a/src/helpers/parse.ts +++ b/src/helpers/parse.ts @@ -1,7 +1,8 @@ import { Task } from '../definitions'; +import { constants } from '../constants'; import { series } from '../tasks/aggregate/series'; import { stringifyRoute } from './stringify-route'; -import { Members } from 'type-core'; +import { Members, TypeGuard } from 'type-core'; interface Item { name: string; @@ -9,17 +10,21 @@ interface Item { task: Task; } -interface Options { +interface ParseToArrayOptions { + defaults: boolean; +} + +interface ParseToRecordOptions extends ParseToArrayOptions { include: string[] | null; exclude: string[] | null; } export function parseToRecord( - options: Options, + options: ParseToRecordOptions, record: Task.Record ): Members { const { include, exclude } = options; - const arr = parseToArray(record); + const arr = parseToArray({ defaults: options.defaults }, record); const members: Members = {}; for (const item of arr) { @@ -39,7 +44,10 @@ export function parseToRecord( return members; } -export function parseToArray(record: Task.Record): Item[] { +export function parseToArray( + options: ParseToArrayOptions, + record: Task.Record +): Item[] { const names: string[] = []; return parseHelper(record) @@ -56,24 +64,40 @@ export function parseToArray(record: Task.Record): Item[] { names.push(name); return { name, route, task }; }) - .filter((item): item is Item => Boolean(item.task)); + .filter((item) => { + return options.defaults + ? Boolean(item.task) + : Boolean( + item.route.indexOf(constants.record.default) === -1 && item.task + ); + }); } function parseHelper(record: Task.Record): Array<[string[], Task]> { const arr: Array<[string[], Task]> = []; for (const [name, tasks] of Object.entries(record)) { - if (typeof tasks === 'function') { + if (TypeGuard.isFunction(tasks)) { arr.push([[name], tasks]); } else { const all: Task[] = []; + const defaults: Task[] = []; const every: Array<[string[], Task]> = []; for (const [route, task] of parseHelper(tasks)) { every.push([[name, ...route], task]); - if (route.length <= 1) all.push(task); + if (route.length <= 1) { + route[0] === constants.record.default + ? defaults.push(task) + : all.push(task); + } + } + + if (defaults.length) { + arr.push([[name], series(...defaults)]); + } else if (all.length) { + arr.push([[name], series(...all)]); } - if (all.length) arr.push([[name], series(...all)]); if (every.length) arr.push(...every); } } diff --git a/src/tasks/aggregate/combine.ts b/src/tasks/aggregate/combine.ts index eb5f61f..821e7b1 100644 --- a/src/tasks/aggregate/combine.ts +++ b/src/tasks/aggregate/combine.ts @@ -32,7 +32,11 @@ export function combine( task ); }), - parseToRecord.bind(null, { include: keys, exclude: null }), + parseToRecord.bind(null, { + include: keys, + exclude: null, + defaults: true + }), (record) => keys.map((key) => record[key]), (arr) => series(...arr), (task) => run(task, ctx) diff --git a/src/tasks/reflection/lift.ts b/src/tasks/reflection/lift.ts index 83a715a..0ffe5ac 100644 --- a/src/tasks/reflection/lift.ts +++ b/src/tasks/reflection/lift.ts @@ -27,6 +27,10 @@ export interface LiftOptions { * * `'audit'`: prints the expected changes and fails if there are pending changes. */ mode?: 'default' | 'confirm' | 'dry' | 'audit'; + /** + * Lift default tasks and subtasks by their own + */ + defaults?: boolean; /** * Name of kpo's executable */ @@ -47,7 +51,7 @@ export function lift( ): Task.Async { return async (ctx: Context): Promise => { const opts = shallow( - { purge: false, mode: 'default', bin: constants.bin }, + { purge: false, mode: 'default', defaults: false, bin: constants.bin }, options || undefined ); @@ -63,7 +67,11 @@ export function lift( const taskScripts = into( source, - parseToRecord.bind(null, { include: null, exclude: null }), + parseToRecord.bind(null, { + include: null, + exclude: null, + defaults: opts.defaults + }), (record) => Object.keys(record), (keys) => { return keys.reduce( diff --git a/src/tasks/reflection/list.ts b/src/tasks/reflection/list.ts index 5be493d..7a97b95 100644 --- a/src/tasks/reflection/list.ts +++ b/src/tasks/reflection/list.ts @@ -10,6 +10,10 @@ import table from 'as-table'; import chalk from 'chalk'; export interface ListOptions { + /** + * List default tasks and subtasks by their own + */ + defaults?: boolean; /** * Name of kpo's executable. */ @@ -27,10 +31,13 @@ export function list( map?: (name: string, route: string[]) => string[] ): Task.Async { return async (ctx: Context): Promise => { - const opts = shallow({ bin: constants.bin }, options || undefined); + const opts = shallow( + { defaults: false, bin: constants.bin }, + options || undefined + ); const source = await getTaskRecord(tasks); - const items = parseToArray(source); + const items = parseToArray({ defaults: opts.defaults }, source); const maxRouteLength = items.reduce( (acc, item) => (acc > item.route.length ? acc : item.route.length), 0