diff --git a/src/cli/bin/execute.ts b/src/cli/bin/execute.ts index 9f9f9ec..7a4f1c8 100644 --- a/src/cli/bin/execute.ts +++ b/src/cli/bin/execute.ts @@ -10,7 +10,7 @@ export async function execute(task: NullaryFn): Promise { const cancellation = new Promise((resolve) => cbs.push(resolve)); const exits = await import('exits'); - const promise = run(create(task), { cancellation }); + const promise = run({ cancellation }, create(task)); exits.attach(); exits.options({ @@ -28,7 +28,7 @@ export async function execute(task: NullaryFn): Promise { await promise; } catch (err) { - await run(log('error', stringifyError(err))); + await run(null, log('error', stringifyError(err))); return process.exit(1); } } diff --git a/src/cli/bin/main.ts b/src/cli/bin/main.ts index b3155e5..8d0770b 100644 --- a/src/cli/bin/main.ts +++ b/src/cli/bin/main.ts @@ -180,9 +180,9 @@ export function main( (task) => { return async (ctx: Context): Promise => { try { - await run(task, ctx); + await run(ctx, task); } catch (err) { - await run(log('trace', err), ctx); + await run(ctx, log('trace', err)); throw err; } }; diff --git a/src/cli/commands/lift.ts b/src/cli/commands/lift.ts index aaaf6a9..b38041f 100644 --- a/src/cli/commands/lift.ts +++ b/src/cli/commands/lift.ts @@ -57,12 +57,15 @@ export async function lift(params: CLI.Extension.Params): Promise { return series( print(), - _lift(tasks, { - purge: cmd['--purge'], - defaults: cmd['--defaults'], - mode: cmd['--mode'] as any, - bin: params.options.bin, - multitask: params.options.multitask - }) + _lift( + { + purge: cmd['--purge'], + defaults: cmd['--defaults'], + mode: cmd['--mode'] as any, + bin: params.options.bin, + multitask: params.options.multitask + }, + tasks + ) ); } diff --git a/src/cli/commands/list.ts b/src/cli/commands/list.ts index b1009fc..de322a7 100644 --- a/src/cli/commands/list.ts +++ b/src/cli/commands/list.ts @@ -47,9 +47,12 @@ export async function list(params: CLI.Extension.Params): Promise { return series( print(), - _list(tasks, { - defaults: cmd['--defaults'], - bin: params.options.bin - }) + _list( + { + defaults: cmd['--defaults'], + bin: params.options.bin + }, + tasks + ) ); } diff --git a/src/cli/commands/run.ts b/src/cli/commands/run.ts index 9d9b584..9c12458 100644 --- a/src/cli/commands/run.ts +++ b/src/cli/commands/run.ts @@ -18,5 +18,5 @@ export async function run(params: CLI.Extension.Params): Promise { directory: params.options.directory }); - return context({ args }, combine(tasks, { include: names })); + return context({ args }, combine({ include: names }, tasks)); } diff --git a/src/cli/commands/watch.ts b/src/cli/commands/watch.ts index 8fa4db3..96b59c3 100644 --- a/src/cli/commands/watch.ts +++ b/src/cli/commands/watch.ts @@ -112,7 +112,7 @@ export async function watch(params: CLI.Extension.Params): Promise { stringifyArgvCommands(params.argv) ); }), - combine(tasks, { include: names }) + combine({ include: names }, tasks) ) ) ); diff --git a/src/helpers/paths.ts b/src/helpers/paths.ts index 7e3c543..1e7a856 100644 --- a/src/helpers/paths.ts +++ b/src/helpers/paths.ts @@ -37,7 +37,7 @@ export async function useSource( if (options.strict) { throw Error(`Source path doesn't exist: ${src}`); } - await run(log('debug', 'Ignore source:', src), context); + await run(context, log('debug', 'Ignore source:', src)); } export async function useDestination( @@ -55,7 +55,7 @@ export async function useDestination( if (!exists) return cb(dest); if (options.exists === 'ignore') { - await run(log('debug', 'Ignore destination:', dest), context); + await run(context, log('debug', 'Ignore destination:', dest)); } else { throw Error(`Destination exists: ${dest}`); } diff --git a/src/tasks/aggregate/combine.ts b/src/tasks/aggregate/combine.ts index ea927d5..4cb0ac7 100644 --- a/src/tasks/aggregate/combine.ts +++ b/src/tasks/aggregate/combine.ts @@ -1,12 +1,12 @@ +import { Empty, NullaryFn } from 'type-core'; +import { shallow } from 'merge-strategies'; +import { into } from 'pipettes'; import { Task } from '../../definitions'; import { parseToRecord } from '../../helpers/parse'; import { recreate } from '../../utils/recreate'; import { context } from '../creation/context'; import { create } from '../creation/create'; import { series } from './series'; -import { NullaryFn } from 'type-core'; -import { shallow } from 'merge-strategies'; -import { into } from 'pipettes'; export interface CombineOptions { /** @@ -32,8 +32,8 @@ export interface CombineOptions { * @returns Task */ export function combine( - tasks: Task.Record | NullaryFn, - options?: CombineOptions + options: CombineOptions | Empty, + tasks: Task.Record | NullaryFn ): Task.Async { return create(() => { const opts: Required = shallow( @@ -42,12 +42,12 @@ export function combine( ); return into( - recreate(tasks, (task, route) => { + recreate((task, route) => { return context( (ctx) => ({ ...ctx, route: ctx.route.concat(route) }), task ); - }), + }, tasks), parseToRecord.bind(null, { include: opts.include, exclude: opts.exclude, diff --git a/src/tasks/aggregate/parallel.ts b/src/tasks/aggregate/parallel.ts index 7ce20bd..4fde92c 100644 --- a/src/tasks/aggregate/parallel.ts +++ b/src/tasks/aggregate/parallel.ts @@ -33,13 +33,16 @@ export function parallel( try { await Promise.all( items.map((task) => { - return run(task, { - ...ctx, - stdio: [null, ctx.stdio[1], ctx.stdio[2]], - cancellation: new Promise((resolve) => { - cbs.push(resolve); - }) - }); + return run( + { + ...ctx, + stdio: [null, ctx.stdio[1], ctx.stdio[2]], + cancellation: new Promise((resolve) => { + cbs.push(resolve); + }) + }, + task + ); }) ); } catch (err) { diff --git a/src/tasks/aggregate/series.ts b/src/tasks/aggregate/series.ts index 996b0fd..e133fa8 100644 --- a/src/tasks/aggregate/series.ts +++ b/src/tasks/aggregate/series.ts @@ -22,7 +22,7 @@ export function series( return async (ctx: Context): Promise => { for (const task of items) { if (await isCancelled(ctx)) break; - await run(task, ctx); + await run(ctx, task); } }; } diff --git a/src/tasks/creation/context.ts b/src/tasks/creation/context.ts index 9c9a0b8..491be22 100644 --- a/src/tasks/creation/context.ts +++ b/src/tasks/creation/context.ts @@ -1,7 +1,7 @@ -import { Task, Context } from '../../definitions'; -import { run } from '../../utils/run'; import { UnaryFn, Empty } from 'type-core'; import { shallow } from 'merge-strategies'; +import { Task, Context } from '../../definitions'; +import { run } from '../../utils/run'; /** * Modifies a task's context with a given `context`. @@ -20,6 +20,6 @@ export function context( ): Task.Async { const fn = typeof context === 'function' ? context : () => context; return async (context: Context): Promise => { - await run(task, shallow(context, fn(context) || undefined)); + await run(shallow(context, fn(context) || undefined), task); }; } diff --git a/src/tasks/creation/create.ts b/src/tasks/creation/create.ts index 6300813..0970b4c 100644 --- a/src/tasks/creation/create.ts +++ b/src/tasks/creation/create.ts @@ -21,7 +21,7 @@ function pipe(...fns: Array>>): Task.Async { if (await isCancelled(ctx)) break; value = await fn(value); } - if (value) await run(value, ctx); + if (value) await run(ctx, value); }; } diff --git a/src/tasks/exception/catches.ts b/src/tasks/exception/catches.ts index 4a0af12..4f28a38 100644 --- a/src/tasks/exception/catches.ts +++ b/src/tasks/exception/catches.ts @@ -1,10 +1,11 @@ +import { Empty } from 'type-core'; +import { shallow } from 'merge-strategies'; +import { into } from 'pipettes'; import { Task, Context, LogLevel } from '../../definitions'; import { stringifyError } from '../../helpers/stringify'; import { run } from '../../utils/run'; import { series } from '../aggregate/series'; import { log } from '../stdio/log'; -import { shallow } from 'merge-strategies'; -import { into } from 'pipettes'; export interface CatchesOptions { /** Logs the error message with a given level. Default: `'warn'` */ @@ -22,15 +23,15 @@ export interface CatchesOptions { * @returns Task */ export function catches( + options: CatchesOptions | Empty, task: Task, - alternate?: Task | null, - options?: CatchesOptions + alternate?: Task | null ): Task.Async { return async (ctx: Context): Promise => { const opts = shallow({ level: 'warn' }, options || undefined); try { - await run(task, ctx); + await run(ctx, task); } catch (err) { await into( series( @@ -38,7 +39,7 @@ export function catches( log(opts.level, stringifyError(err)), alternate ), - (task) => run(task, ctx) + (task) => run(ctx, task) ); } }; diff --git a/src/tasks/exception/finalize.ts b/src/tasks/exception/finalize.ts index 64236e8..c17d5c1 100644 --- a/src/tasks/exception/finalize.ts +++ b/src/tasks/exception/finalize.ts @@ -16,7 +16,7 @@ export function finalize(task: Task, final?: Task | null): Task.Async { const errors: Error[] = []; try { - await run(task, ctx); + await run(ctx, task); } catch (err) { errors.push(err); } @@ -24,7 +24,7 @@ export function finalize(task: Task, final?: Task | null): Task.Async { if (await isCancelled(ctx)) return; try { - if (final) await run(final, ctx); + if (final) await run(ctx, final); } catch (err) { errors.push(err); } @@ -36,7 +36,7 @@ export function finalize(task: Task, final?: Task | null): Task.Async { errors, (arr) => arr.map((err) => log('trace', err)), (tasks) => series(...tasks), - (task) => run(task, ctx) + (task) => run(ctx, task) ); throw err; }; diff --git a/src/tasks/filesystem/watch.ts b/src/tasks/filesystem/watch.ts index d1795fd..d86bb63 100644 --- a/src/tasks/filesystem/watch.ts +++ b/src/tasks/filesystem/watch.ts @@ -99,23 +99,25 @@ export function watch(options: WatchOptions | Empty, task: Task): Task.Async { current = after .then(() => { i += 1; - return run(series(i > 0 && opts.clear ? clear() : null, task), { - ...ctx, - route: opts.parallel ? ctx.route.concat(String(i)) : ctx.route, - cancellation: new Promise((resolve) => { - cbs.push(resolve); - }) - }); + return run( + { + ...ctx, + route: opts.parallel + ? ctx.route.concat(String(i)) + : ctx.route, + cancellation: new Promise((resolve) => { + cbs.push(resolve); + }) + }, + series(i > 0 && opts.clear ? clear() : null, task) + ); }) .catch((err) => { return opts.fail ? onError(err) : run( - series( - log('trace', err), - log('error', stringifyError(err)) - ), - ctx + ctx, + series(log('trace', err), log('error', stringifyError(err))) ); }); }, @@ -127,14 +129,14 @@ export function watch(options: WatchOptions | Empty, task: Task): Task.Async { if (opts.prime) { watcher.on('ready', () => { promises.push( - run(log('debug', 'Watch event:', 'prime'), ctx).catch(reject) + run(ctx, log('debug', 'Watch event:', 'prime')).catch(reject) ); onEvent(reject); }); } watcher.on('all', (event) => { promises.push( - run(log('debug', 'Watch event:', event), ctx).catch(reject) + run(ctx, log('debug', 'Watch event:', event)).catch(reject) ); onEvent(reject); }); diff --git a/src/tasks/process/exec.ts b/src/tasks/process/exec.ts index 93a3972..aefbe4f 100644 --- a/src/tasks/process/exec.ts +++ b/src/tasks/process/exec.ts @@ -94,7 +94,7 @@ export function exec( ? '' : `: ${cmd}`; - await run(log('trace', err), ctx); + await run(ctx, log('trace', err)); throw Error(message); }); } diff --git a/src/tasks/reflection/lift.ts b/src/tasks/reflection/lift.ts index 995b21b..533ac81 100644 --- a/src/tasks/reflection/lift.ts +++ b/src/tasks/reflection/lift.ts @@ -1,4 +1,4 @@ -import { Members, NullaryFn, TypeGuard } from 'type-core'; +import { Empty, Members, NullaryFn, TypeGuard } from 'type-core'; import { shallow } from 'merge-strategies'; import { into } from 'pipettes'; import fs from 'fs-extra'; @@ -50,8 +50,8 @@ export interface LiftOptions { * @returns Task */ export function lift( - tasks: Task.Record | NullaryFn, - options?: LiftOptions + options: LiftOptions | Empty, + tasks: Task.Record | NullaryFn ): Task.Async { return create(async (ctx) => { const opts = shallow( @@ -188,7 +188,7 @@ async function evaluateChanges( strArr.push(style('No pending scripts changes', { bold: true })); } - await run(print(strArr.join('\n')), context); + await run(context, print(strArr.join('\n'))); return areChangesPending; } diff --git a/src/tasks/reflection/list.ts b/src/tasks/reflection/list.ts index 7891f28..b5c874e 100644 --- a/src/tasks/reflection/list.ts +++ b/src/tasks/reflection/list.ts @@ -1,4 +1,4 @@ -import { NullaryFn, TypeGuard } from 'type-core'; +import { Empty, NullaryFn, TypeGuard } from 'type-core'; import { shallow } from 'merge-strategies'; import table from 'as-table'; import { Task } from '../../definitions'; @@ -25,8 +25,8 @@ export interface ListOptions { * @returns Task */ export function list( - tasks: Task.Record | NullaryFn, - options?: ListOptions + options: ListOptions | Empty, + tasks: Task.Record | NullaryFn ): Task.Async { return create(async () => { const opts = shallow( diff --git a/src/tasks/schedule/repeat.ts b/src/tasks/schedule/repeat.ts index 97d2425..eba5824 100644 --- a/src/tasks/schedule/repeat.ts +++ b/src/tasks/schedule/repeat.ts @@ -19,7 +19,7 @@ export function repeat(times: number | null, task: Task): Task.Async { while (!isDone()) { i++; if (await isCancelled(ctx)) break; - await run(series(log('debug', 'Repeat task:', i), task), ctx); + await run(ctx, series(log('debug', 'Repeat task:', i), task)); } } ); diff --git a/src/tasks/schedule/timeout.ts b/src/tasks/schedule/timeout.ts index 89961e7..39031ca 100644 --- a/src/tasks/schedule/timeout.ts +++ b/src/tasks/schedule/timeout.ts @@ -26,18 +26,21 @@ export function timeout( let didTimeout = false; let timeout: NodeJS.Timeout | null = null; - await run(task, { - ...ctx, - cancellation: Promise.race([ - new Promise((resolve) => { - timeout = setTimeout( - () => (didTimeout = true) && resolve(), - ms - ); - }), - ctx.cancellation.finally(() => timeout && clearTimeout(timeout)) - ]) - }); + await run( + { + ...ctx, + cancellation: Promise.race([ + new Promise((resolve) => { + timeout = setTimeout( + () => (didTimeout = true) && resolve(), + ms + ); + }), + ctx.cancellation.finally(() => timeout && clearTimeout(timeout)) + ]) + }, + task + ); if (timeout) clearTimeout(timeout); if (didTimeout) { diff --git a/src/tasks/stdio/announce.ts b/src/tasks/stdio/announce.ts index 6478940..642cdfc 100644 --- a/src/tasks/stdio/announce.ts +++ b/src/tasks/stdio/announce.ts @@ -1,4 +1,4 @@ -import { TypeGuard } from 'type-core'; +import { Empty, TypeGuard } from 'type-core'; import { shallow } from 'merge-strategies'; import { Task } from '../../definitions'; import { stringifyPrintRoute } from '../../helpers/stringify'; @@ -20,7 +20,10 @@ export interface AnnounceOptions { * Prints tasks route before execution and upon success. * @returns Task */ -export function announce(task: Task, options?: AnnounceOptions): Task.Async { +export function announce( + options: AnnounceOptions | Empty, + task: Task +): Task.Async { return create((ctx) => { const opts = shallow({ info: true, success: false }, options || undefined); diff --git a/src/tasks/stdio/confirm.ts b/src/tasks/stdio/confirm.ts index afec24e..7869ce5 100644 --- a/src/tasks/stdio/confirm.ts +++ b/src/tasks/stdio/confirm.ts @@ -66,7 +66,7 @@ export function confirm( const response = (ctx.args[0] || '').toLowerCase(); const task = response[0] === 'y' ? yes : no; if (!task) return; - await run(task, { ...ctx, args: ctx.args.slice(1) }); + await run({ ...ctx, args: ctx.args.slice(1) }, task); } ); }); diff --git a/src/tasks/stdio/progress.ts b/src/tasks/stdio/progress.ts index 5277050..7fa087a 100644 --- a/src/tasks/stdio/progress.ts +++ b/src/tasks/stdio/progress.ts @@ -40,7 +40,7 @@ export function progress( : style('task ', { bold: true }) + stringifyPrintRoute(ctx.route); if (!isInteractive(ctx) || isLogLevelActive('debug', ctx)) { - return announce(silent, { message, info: true, success: true }); + return announce({ message, info: true, success: true }, silent); } const spinner = ora({ @@ -63,7 +63,7 @@ export function progress( let wasCancelled = false; ctx.cancellation.finally(() => (wasCancelled = true) && spinner.stop()); try { - await run(silent, ctx); + await run(ctx, silent); } catch (err) { spinner.stopAndPersist({ text: message, diff --git a/src/tasks/stdio/prompt.ts b/src/tasks/stdio/prompt.ts index 1686d71..7de9912 100644 --- a/src/tasks/stdio/prompt.ts +++ b/src/tasks/stdio/prompt.ts @@ -115,6 +115,7 @@ export function prompt(options: PromptOptions | Empty, task: Task): Task.Async { } else { response = null; await run( + ctx, series( error ? log('trace', error[0]) : null, log( @@ -123,8 +124,7 @@ export function prompt(options: PromptOptions | Empty, task: Task): Task.Async { ? style(stringifyError(error[0]), { bold: true }) : style('Invalid response', { bold: true }) ) - ), - ctx + ) ); } } @@ -136,8 +136,8 @@ export function prompt(options: PromptOptions | Empty, task: Task): Task.Async { if (response === null) { if (TypeGuard.isString(opts.default) && opts.validate(opts.default)) { await run( - log('info', 'Timeout default:', style(opts.default, { bold: true })), - ctx + ctx, + log('info', 'Timeout default:', style(opts.default, { bold: true })) ); response = opts.default; } else { diff --git a/src/tasks/stdio/select.ts b/src/tasks/stdio/select.ts index a1572b3..9a58774 100644 --- a/src/tasks/stdio/select.ts +++ b/src/tasks/stdio/select.ts @@ -58,7 +58,7 @@ export function select( : -1; const message = getBadge('prompt') + ` ${opts.message}`; - await run(print(message), ctx); + await run(ctx, print(message)); if (await isCancelled(ctx)) return; if (!isInteractive(ctx)) { diff --git a/src/utils/recreate.ts b/src/utils/recreate.ts index 66dc855..fcb217e 100644 --- a/src/utils/recreate.ts +++ b/src/utils/recreate.ts @@ -1,9 +1,9 @@ -import { Task } from '../definitions'; -import { context } from '../tasks/creation/context'; -import { announce } from '../tasks/stdio/announce'; import { Empty, NullaryFn, TypeGuard } from 'type-core'; import { shallow } from 'merge-strategies'; import { into } from 'pipettes'; +import { Task } from '../definitions'; +import { context } from '../tasks/creation/context'; +import { announce } from '../tasks/stdio/announce'; export interface RecreateOptions { /** @@ -25,8 +25,8 @@ export interface RecreateMap { * Maps all tasks in a `Task.Record`. */ export function recreate( - tasks: Task.Record | NullaryFn, - options?: RecreateOptions | RecreateMap + options: RecreateOptions | RecreateMap | Empty, + tasks: Task.Record | NullaryFn ): Task.Record { const record = TypeGuard.isFunction(tasks) ? tasks() : tasks; @@ -42,7 +42,7 @@ export function recreate( return recreateHelper([], record, (task, route) => { return into( task, - (task) => (opts.announce ? announce(task) : task), + (task) => (opts.announce ? announce(null, task) : task), (task) => (opts.fix ? context({ route }, task) : task) ); }); diff --git a/src/utils/run.ts b/src/utils/run.ts index 782b4b3..d23f55d 100644 --- a/src/utils/run.ts +++ b/src/utils/run.ts @@ -1,7 +1,7 @@ +import { Empty, TypeGuard } from 'type-core'; import { Task, Context } from '../definitions'; import { createContext } from '../helpers/create-context'; import { isCancelled } from './is-cancelled'; -import { TypeGuard } from 'type-core'; const noop = (): void => undefined; @@ -9,10 +9,10 @@ const noop = (): void => undefined; * Safely runs a task with an optional given context. */ export async function run( - task: Task, - context?: Partial + context: Partial | Empty, + task: Task ): Promise { - const unsafe = createContext(context); + const unsafe = createContext(context || undefined); const ctx = { ...unsafe, cancellation: unsafe.cancellation.catch(noop) }; if (await isCancelled(ctx)) return;