From c5bd5840e568e73bc1e3960bb536f7d692587b99 Mon Sep 17 00:00:00 2001 From: Edie Lemoine Date: Thu, 7 Nov 2024 14:29:38 +0100 Subject: [PATCH] feat(app-builder): improve error handling --- .../src/__tests__/createTestContext.ts | 4 +- .../src/commands/increment/increment.types.ts | 6 +- .../src/commands/upgrade/upgrade.types.ts | 4 +- apps/app-builder/src/definitions.ts | 6 +- apps/app-builder/src/run.ts | 29 ++++---- .../src/types/bulkCommand.types.ts | 8 +-- apps/app-builder/src/types/command.types.ts | 66 +++++++++++-------- apps/app-builder/src/types/config.types.ts | 4 +- .../src/utils/addPlatformToContext.ts | 6 +- .../src/utils/command/createCommandContext.ts | 35 ++++++++++ .../src/utils/command/createDebugger.ts | 4 +- .../src/utils/command/createWithConfig.ts | 53 +++++---------- .../src/utils/command/createWithContext.ts | 6 +- .../{parseCommand.ts => parseCommandArgs.ts} | 15 +++-- .../src/utils/command/parseCommandInput.ts | 34 ++++++---- .../src/utils/command/registerCommand.ts | 13 ++-- .../app-builder/src/utils/command/runHooks.ts | 26 ++++++++ apps/app-builder/src/utils/defineCommand.ts | 10 ++- apps/app-builder/src/utils/executePromises.ts | 4 +- apps/app-builder/src/utils/resolveConfig.ts | 6 +- 20 files changed, 214 insertions(+), 125 deletions(-) create mode 100644 apps/app-builder/src/utils/command/createCommandContext.ts rename apps/app-builder/src/utils/command/{parseCommand.ts => parseCommandArgs.ts} (51%) create mode 100644 apps/app-builder/src/utils/command/runHooks.ts diff --git a/apps/app-builder/src/__tests__/createTestContext.ts b/apps/app-builder/src/__tests__/createTestContext.ts index 9799f6ba..3f4a878b 100644 --- a/apps/app-builder/src/__tests__/createTestContext.ts +++ b/apps/app-builder/src/__tests__/createTestContext.ts @@ -2,14 +2,14 @@ import {type RecursivePartial} from '@myparcel/ts-utils'; import {mergeDefaultConfig} from '../utils/mergeDefaultConfig'; import {createDebugger} from '../utils/command/createDebugger'; import {type PdkBuilderConfig} from '../types/config.types'; -import {type CommandArgs, type PdkBuilderContext} from '../types/command.types'; +import {type DefaultCommandArgs, type PdkBuilderContext} from '../types/command.types'; import {PdkPlatformName} from '../constants'; import {MOCK_ROOT_DIR} from './constants'; export const createTestContext = ( context?: RecursivePartial, ): Context => { - const args: CommandArgs = { + const args: DefaultCommandArgs = { arguments: [], dryRun: false, parallel: false, diff --git a/apps/app-builder/src/commands/increment/increment.types.ts b/apps/app-builder/src/commands/increment/increment.types.ts index 02a096b4..e5b21a4d 100644 --- a/apps/app-builder/src/commands/increment/increment.types.ts +++ b/apps/app-builder/src/commands/increment/increment.types.ts @@ -1,8 +1,8 @@ import {type Debugger} from 'debug'; import {type PdkBuilderConfig} from '../../types/config.types'; -import {type CommandArgs} from '../../types/command.types'; +import {type DefaultCommandArgs} from '../../types/command.types'; -export type IncrementCommandArgs = CommandArgs & { +export type IncrementCommandArgs = DefaultCommandArgs & { version?: string; }; @@ -42,7 +42,7 @@ export interface VersionReplacerInput { export interface VersionReplacerContext { config: PdkBuilderConfig; - args: CommandArgs; + args: DefaultCommandArgs; debug: Debugger; } diff --git a/apps/app-builder/src/commands/upgrade/upgrade.types.ts b/apps/app-builder/src/commands/upgrade/upgrade.types.ts index fd739816..eaa041e2 100644 --- a/apps/app-builder/src/commands/upgrade/upgrade.types.ts +++ b/apps/app-builder/src/commands/upgrade/upgrade.types.ts @@ -1,7 +1,7 @@ -import {type CommandArgs, type PdkBuilderContext} from '../../types/command.types'; +import {type DefaultCommandArgs, type PdkBuilderContext} from '../../types/command.types'; import {type UpgradeMode} from './enums'; -export type UpgradeCommandArgs = CommandArgs & { +export type UpgradeCommandArgs = DefaultCommandArgs & { check?: boolean; commit?: boolean; commitType?: string; diff --git a/apps/app-builder/src/definitions.ts b/apps/app-builder/src/definitions.ts index cf89fc05..702b1870 100644 --- a/apps/app-builder/src/definitions.ts +++ b/apps/app-builder/src/definitions.ts @@ -1,6 +1,6 @@ import {defineCommand} from './utils/defineCommand'; import {defineBulkCommand} from './utils/defineBulkCommand'; -import {type CommandDefinition} from './types/command.types'; +import {type AnyCommandDefinition} from './types/command.types'; import {type BulkCommandDefinition} from './types/bulkCommand.types'; import { COMMAND_BUILD_NAME, @@ -112,7 +112,7 @@ const CORE_COMMANDS = Object.freeze([ copyCommand, renameCommand, transformCommand, -] satisfies CommandDefinition[]); +] satisfies AnyCommandDefinition[]); export const buildBulkCommand = defineBulkCommand({ name: COMMAND_BUILD_NAME, @@ -168,7 +168,7 @@ export const releaseBulkCommand = defineBulkCommand({ commands: [cleanCommand, scopePhpCommand, incrementCommand, ...CORE_COMMANDS, zipCommand], }); -export const ALL_COMMANDS: readonly CommandDefinition[] = Object.freeze([ +export const ALL_COMMANDS: readonly AnyCommandDefinition[] = Object.freeze([ initCommand, cleanCommand, copyCommand, diff --git a/apps/app-builder/src/run.ts b/apps/app-builder/src/run.ts index 6bde53a9..15b047c0 100644 --- a/apps/app-builder/src/run.ts +++ b/apps/app-builder/src/run.ts @@ -6,14 +6,18 @@ import {getBulkCommandDescription} from './utils/getBulkCommandDescription'; import {registerCommand} from './utils/command/registerCommand'; import {createWithContext} from './utils/command/createWithContext'; import {createWithConfig} from './utils/command/createWithConfig'; -import {type CommandArgs, type CommandDefinition, type CommandDefinitionWithoutConfig} from './types/command.types'; +import { + type AnyCommandDefinition, + type CommandDefinitionWithoutConfig, + type DefaultCommandArgs, +} from './types/command.types'; import {ALL_BULK_COMMANDS, ALL_COMMANDS} from './definitions'; import {BULK_COMMAND_OPTIONS, CONFIG_OPTIONS, TITLE} from './constants'; // eslint-disable-next-line max-lines-per-function export const run = (env: LiftoffEnv, argv: string[]): void => { - const withContext = createWithContext(env, argv); - const withConfig = createWithConfig(env, argv); + const withContext = createWithContext(env); + const withConfig = createWithConfig(env); program.name(TITLE).description('Builds a plugin for MyParcel.'); @@ -29,7 +33,7 @@ export const run = (env: LiftoffEnv, argv: string[]): void => { ALL_BULK_COMMANDS.forEach(({name, description, commands}) => { const commandDefinitions = commands.map((definition) => { - return toArray(definition)[0] as CommandDefinition; + return toArray(definition)[0] as AnyCommandDefinition; }); const command = program.command(name).description(getBulkCommandDescription(commandDefinitions, description)); @@ -51,7 +55,7 @@ export const run = (env: LiftoffEnv, argv: string[]): void => { for (const command of commands) { const [resolvedCommand, commandOptions] = command; - const resolvedArgs: CommandArgs = {...args, ...commandOptions}; + const resolvedArgs: DefaultCommandArgs = {...args, ...commandOptions}; await withConfig(resolvedCommand)(resolvedArgs, originalCommand); } @@ -63,13 +67,14 @@ export const run = (env: LiftoffEnv, argv: string[]): void => { const config = await resolveConfig(env); config.additionalCommands?.forEach((definition) => { - const resolvedDefinition = { - ...definition, - options: [...CONFIG_OPTIONS, ...(definition.options ?? [])], - action: () => Promise.resolve({default: definition.action}), - }; - - return registerCommand(resolvedDefinition, withConfig); + return registerCommand( + { + ...definition, + options: [...CONFIG_OPTIONS, ...(definition.options ?? [])], + action: () => Promise.resolve({default: definition.action}), + }, + withConfig, + ); }); } diff --git a/apps/app-builder/src/types/bulkCommand.types.ts b/apps/app-builder/src/types/bulkCommand.types.ts index 01600adb..695903e6 100644 --- a/apps/app-builder/src/types/bulkCommand.types.ts +++ b/apps/app-builder/src/types/bulkCommand.types.ts @@ -1,11 +1,11 @@ -import {type CommandDefinition} from './command.types'; +import {type AnyCommandDefinition} from './command.types'; -type CommandArguments = Cd extends CommandDefinition ? Args : never; +type CommandArguments = Cd extends AnyCommandDefinition ? Args : never; -export type CommandWithArguments = +export type CommandWithArguments = | [Command, Partial>]; -export type CommandWithOrWithoutArguments = +export type CommandWithOrWithoutArguments = | Command | CommandWithArguments; diff --git a/apps/app-builder/src/types/command.types.ts b/apps/app-builder/src/types/command.types.ts index f363c788..9e623c32 100644 --- a/apps/app-builder/src/types/command.types.ts +++ b/apps/app-builder/src/types/command.types.ts @@ -4,35 +4,46 @@ import type Liftoff from 'liftoff'; import {type LiftoffEnv} from 'liftoff'; import {type Debugger} from 'debug'; import {type Command} from 'commander'; -import {type PromiseOr} from '@myparcel/ts-utils'; +import {type PromiseOr, type Replace} from '@myparcel/ts-utils'; import {type CommandName, type PdkPlatformName} from '../constants'; import {type ResolvedPdkBuilderConfig} from './config.types'; -export interface BaseCommandDefinition { +export interface BaseCommandDefinition { name: CommandName; - action: (args?: Args & AnyCommandArgs) => Promise; description: string; options?: any[]; args?: string[][]; + + action(): Promise<{default: PdkBuilderCommand}>; } -export interface CommandDefinitionWithoutConfig extends BaseCommandDefinition { +export interface CommandDefinitionWithoutConfig + extends BaseCommandDefinition { hasConfig?: false; } -export type CommandDefinition = BaseCommandDefinition | CommandDefinitionWithoutConfig; +export type AnyCommandDefinition = + | BaseCommandDefinition + | CommandDefinitionWithoutConfig; -export type PdkBuilderCommand = ( - context: PdkBuilderContext, -) => PromiseOr; +export type AdditionalCommandDefinition = Replace< + AnyCommandDefinition, + 'action', + PdkBuilderCommand +>; + +export type PdkBuilderCommand< + Args extends AnyCommandArgs = DefaultCommandArgs, + Context extends BasePdkBuilderContext = BasePdkBuilderContext, +> = (context: Context) => PromiseOr; -export type PdkBuilderCommandWithoutConfig = ( - context: PdkBuilderContextWithoutConfig, +export type PdkBuilderCommandWithoutConfig = ( + context: BasePdkBuilderContext, ) => PromiseOr; export type AnyCommandArgs = Record; -export type CommandArgs = { +export type DefaultCommandArgs = { arguments?: string[]; dryRun?: boolean; parallel?: boolean; @@ -40,47 +51,50 @@ export type CommandArgs = { verbose: number; }; -type PlatformArgs = { +export type PlatformCommandArgs = { platform: Platform; platformOutDir: string; }; -export type CommandArguments = (string | (CommandArgs & AnyCommandArgs) | Command)[]; +export type InputCommandArguments = ( + | string + | (DefaultCommandArgs & Args) + | Command +)[]; -export type ParsedCommand = Record> = CommandArgs & - A & { +export type ParsedCommandArguments = DefaultCommandArgs & + Args & { arguments?: string[]; command: Command; }; -export type CommandCb = (...args: CommandArguments) => void | Promise; +export type CommandCb = (...args: InputCommandArguments) => void | Promise; -export type CreateHook = ( +export type CreateHook = ( env: Liftoff.LiftoffEnv, - argv: string[], -) => (definition: CommandDefinition) => CommandCb; +) => (definition: Definition) => CommandCb; -export type BaseCommandContext = { +export type BaseCommandContext = { env: LiftoffEnv; args: Args; debug?: PdkDebugger; }; -export type PdkBuilderContextWithoutConfig = BaseCommandContext & { - args: ParsedCommand; +export type BasePdkBuilderContext = BaseCommandContext & { + args: ParsedCommandArguments; debug: PdkDebugger; }; -export type PdkBuilderContext = PdkBuilderContextWithoutConfig< - Args & Partial +export type PdkBuilderContext = BasePdkBuilderContext< + Args & Partial > & { config: ResolvedPdkBuilderConfig; }; export type PdkBuilderContextWithPlatformArgs< - Args extends AnyCommandArgs = CommandArgs, + Args extends AnyCommandArgs = DefaultCommandArgs, Platform extends PdkPlatformName = PdkPlatformName, -> = PdkBuilderContext & Args>; +> = PdkBuilderContext & Args>; export type PdkDebugger = Debugger & { logTimeTaken(): void; diff --git a/apps/app-builder/src/types/config.types.ts b/apps/app-builder/src/types/config.types.ts index c43b5b0b..dcc19551 100644 --- a/apps/app-builder/src/types/config.types.ts +++ b/apps/app-builder/src/types/config.types.ts @@ -4,7 +4,7 @@ import {type NodePackageManager} from '../commands/upgrade/enums'; import {type VersionSource} from '../commands/increment/increment.types'; import {type StringGenerator} from './common.types'; import { - type CommandDefinition, + type AdditionalCommandDefinition, type PdkBuilderCommand, type PdkBuilderCommandWithoutConfig, type PdkBuilderContext, @@ -208,7 +208,7 @@ export type PdkBuilderConfig = { /** * Define additional custom commands on the pdk builder. */ - additionalCommands?: CommandDefinition[]; + additionalCommands?: AdditionalCommandDefinition[]; /** * Hooks to execute before or after other commands. Works with custom commands added with `additionalCommands` as well. diff --git a/apps/app-builder/src/utils/addPlatformToContext.ts b/apps/app-builder/src/utils/addPlatformToContext.ts index 6d559d57..ded629cf 100644 --- a/apps/app-builder/src/utils/addPlatformToContext.ts +++ b/apps/app-builder/src/utils/addPlatformToContext.ts @@ -1,5 +1,6 @@ import { type AnyCommandArgs, + type DefaultCommandArgs, type PdkBuilderContext, type PdkBuilderContextWithPlatformArgs, } from '../types/command.types'; @@ -7,7 +8,10 @@ import {type PdkPlatformName} from '../constants'; import {resolvePath} from './resolvePath'; import {withArgs} from './command/withArgs'; -export const addPlatformToContext = ( +export const addPlatformToContext = < + Platform extends PdkPlatformName, + Args extends AnyCommandArgs = DefaultCommandArgs, +>( context: PdkBuilderContext, platform: Platform, ): PdkBuilderContextWithPlatformArgs => { diff --git a/apps/app-builder/src/utils/command/createCommandContext.ts b/apps/app-builder/src/utils/command/createCommandContext.ts new file mode 100644 index 00000000..19a6806e --- /dev/null +++ b/apps/app-builder/src/utils/command/createCommandContext.ts @@ -0,0 +1,35 @@ +import type Liftoff from 'liftoff'; +import {resolveConfig} from '../resolveConfig'; +import {mergeDefaultConfig} from '../mergeDefaultConfig'; +import { + type AnyCommandArgs, + type AnyCommandDefinition, + type DefaultCommandArgs, + type InputCommandArguments, + type PdkBuilderCommand, + type PdkBuilderContext, +} from '../../types/command.types'; +import {parseCommandInput} from './parseCommandInput'; + +type CommandContext = { + command: PdkBuilderCommand; + context: PdkBuilderContext; +}; + +export const createCommandContext = async ( + definition: AnyCommandDefinition, + args: InputCommandArguments, + env: Liftoff.LiftoffEnv, +): Promise> => { + const {command, context} = await parseCommandInput(definition, args, env); + + const config = await resolveConfig(env, context.args); + + return { + command, + context: { + ...context, + config: mergeDefaultConfig(config), + }, + }; +}; diff --git a/apps/app-builder/src/utils/command/createDebugger.ts b/apps/app-builder/src/utils/command/createDebugger.ts index 400f9d28..dc1d0c98 100644 --- a/apps/app-builder/src/utils/command/createDebugger.ts +++ b/apps/app-builder/src/utils/command/createDebugger.ts @@ -1,8 +1,8 @@ import debugFactory from 'debug'; import chalk from 'chalk'; -import {type CommandArgs, type PdkDebugger} from '../../types/command.types'; +import {type DefaultCommandArgs, type PdkDebugger} from '../../types/command.types'; -export const createDebugger = (name: string, args: CommandArgs): PdkDebugger => { +export const createDebugger = (name: string, args: DefaultCommandArgs): PdkDebugger => { const debug = debugFactory(`@myparcel-pdk/app-builder:${name}`) as PdkDebugger; const timeStart = Date.now(); diff --git a/apps/app-builder/src/utils/command/createWithConfig.ts b/apps/app-builder/src/utils/command/createWithConfig.ts index 00dda8e7..0304c987 100644 --- a/apps/app-builder/src/utils/command/createWithConfig.ts +++ b/apps/app-builder/src/utils/command/createWithConfig.ts @@ -1,49 +1,32 @@ +/* eslint-disable no-console */ import chalk from 'chalk'; -import {resolveConfig} from '../resolveConfig'; -import {mergeDefaultConfig} from '../mergeDefaultConfig'; -import {type PdkBuilderConfig} from '../../types/config.types'; -import {type CreateHook, type PdkBuilderContext} from '../../types/command.types'; -import {VerbosityLevel} from '../../constants'; -import {parseCommandInput} from './parseCommandInput'; +import {type AnyCommandDefinition, type CreateHook} from '../../types/command.types'; +import {runHooks} from './runHooks'; import {isDryRun} from './isDryRun'; +import {createCommandContext} from './createCommandContext'; -export const createWithConfig: CreateHook = (env) => { +export const createWithConfig = ((env) => { return (definition) => { return async (...args) => { - const {command, context} = await parseCommandInput(definition, args, env); + const {command, context} = await createCommandContext(definition, args, env); - const config = await resolveConfig(env, context.args); - - const commandName = definition.name; - - const mergedContext = {...context, config: mergeDefaultConfig(config)} satisfies PdkBuilderContext; - - if (isDryRun(mergedContext)) { - mergedContext.debug(chalk.redBright(`The command was run with --dry-run. No files will be modified`)); + if (isDryRun(context)) { + context.debug(chalk.redBright(`The command was run with --dry-run. No files will be modified`)); } - const capitalizedCommandName = commandName.charAt(0).toUpperCase() + commandName.slice(1); + try { + await runHooks('before', definition, context, command); + await command(context); + await runHooks('after', definition, context, command); + } catch (error) { + console.error(`An error occurred while running the command "${definition.name}".`); + console.error('Arguments:', args[0]); + console.error(error); - const beforeHook = `before${capitalizedCommandName}` as keyof PdkBuilderConfig['hooks']; - const afterHook = `after${capitalizedCommandName}` as keyof PdkBuilderConfig['hooks']; - - if (context.args.verbose >= VerbosityLevel.Verbose && (config.hooks?.[beforeHook] ?? null)) { - context.debug(`Running hook ${beforeHook}`); + process.exit(1); } - // @ts-expect-error todo - await config.hooks?.[beforeHook]?.({command, context: mergedContext}); - - await command(mergedContext); - - if (context.args.verbose >= VerbosityLevel.Verbose && (config.hooks?.[afterHook] ?? null)) { - context.debug(`Running hook ${afterHook}`); - } - - // @ts-expect-error todo - await config.hooks?.[afterHook]?.({command, context: mergedContext}); - context.debug.logTimeTaken(); }; }; -}; +}) satisfies CreateHook; diff --git a/apps/app-builder/src/utils/command/createWithContext.ts b/apps/app-builder/src/utils/command/createWithContext.ts index 12a8fb31..6b1ad876 100644 --- a/apps/app-builder/src/utils/command/createWithContext.ts +++ b/apps/app-builder/src/utils/command/createWithContext.ts @@ -1,7 +1,7 @@ -import {type CreateHook, type PdkBuilderContext} from '../../types/command.types'; +import {type CommandDefinitionWithoutConfig, type CreateHook} from '../../types/command.types'; import {parseCommandInput} from './parseCommandInput'; -export const createWithContext: CreateHook> = (env) => { +export const createWithContext = ((env) => { return (definition) => { return async (...args) => { const {command, context} = await parseCommandInput(definition, args, env); @@ -11,4 +11,4 @@ export const createWithContext: CreateHook> = context.debug.logTimeTaken(); }; }; -}; +}) satisfies CreateHook; diff --git a/apps/app-builder/src/utils/command/parseCommand.ts b/apps/app-builder/src/utils/command/parseCommandArgs.ts similarity index 51% rename from apps/app-builder/src/utils/command/parseCommand.ts rename to apps/app-builder/src/utils/command/parseCommandArgs.ts index 1a3bdbae..aa3a9712 100644 --- a/apps/app-builder/src/utils/command/parseCommand.ts +++ b/apps/app-builder/src/utils/command/parseCommandArgs.ts @@ -1,9 +1,16 @@ import {type Command} from 'commander'; import {isOfType} from '@myparcel/ts-utils'; -import {type CommandArguments, type ParsedCommand} from '../../types/command.types'; +import { + type AnyCommandArgs, + type DefaultCommandArgs, + type InputCommandArguments, + type ParsedCommandArguments, +} from '../../types/command.types'; -export const parseCommand = (args: CommandArguments): ParsedCommand => - args.reduce((acc: ParsedCommand, arg) => { +export const parseCommandArgs = ( + args: InputCommandArguments, +): ParsedCommandArguments => + args.reduce((acc: ParsedCommandArguments, arg) => { if (isOfType(arg, 'on')) { const command = arg; @@ -24,4 +31,4 @@ export const parseCommand = (args: CommandArguments): ParsedCommand => } return acc; - }, {} as ParsedCommand); + }, {} as ParsedCommandArguments); diff --git a/apps/app-builder/src/utils/command/parseCommandInput.ts b/apps/app-builder/src/utils/command/parseCommandInput.ts index 5f2d47f9..2fd98875 100644 --- a/apps/app-builder/src/utils/command/parseCommandInput.ts +++ b/apps/app-builder/src/utils/command/parseCommandInput.ts @@ -1,24 +1,30 @@ import type Liftoff from 'liftoff'; import { - type CommandArguments, - type CommandDefinition, - type PdkBuilderContextWithoutConfig, + type AnyCommandArgs, + type AnyCommandDefinition, + type BasePdkBuilderContext, + type DefaultCommandArgs, + type InputCommandArguments, + type PdkBuilderCommandWithoutConfig, } from '../../types/command.types'; -import {parseCommand} from './parseCommand'; +import {parseCommandArgs} from './parseCommandArgs'; import {createDebugger} from './createDebugger'; -export const parseCommandInput = async ( - definition: O, - args: CommandArguments, +type ParsedCommandInput = { + command: PdkBuilderCommandWithoutConfig; + context: BasePdkBuilderContext; +}; + +export const parseCommandInput = async < + Args extends AnyCommandArgs = DefaultCommandArgs, + Definition extends AnyCommandDefinition = AnyCommandDefinition, +>( + definition: Definition, + args: InputCommandArguments, env: Liftoff.LiftoffEnv, -): Promise<{ - command: O['action']; - // eslint-disable-next-line @typescript-eslint/no-magic-numbers - context: Parameters[0] & PdkBuilderContextWithoutConfig[0]['args']>; -}> => { +): Promise> => { const command = (await definition.action()).default; - - const parsedArgs = parseCommand(args); + const parsedArgs = parseCommandArgs(args); return { command, diff --git a/apps/app-builder/src/utils/command/registerCommand.ts b/apps/app-builder/src/utils/command/registerCommand.ts index fead3a59..79160545 100644 --- a/apps/app-builder/src/utils/command/registerCommand.ts +++ b/apps/app-builder/src/utils/command/registerCommand.ts @@ -1,9 +1,14 @@ import {program} from 'commander'; -import {type AnyCommandArgs, type CommandCb, type CommandDefinition} from '../../types/command.types'; +import { + type AnyCommandArgs, + type AnyCommandDefinition, + type CommandCb, + type DefaultCommandArgs, +} from '../../types/command.types'; -export const registerCommand = ( - definition: CommandDefinition, - callback: (definition: CommandDefinition) => CommandCb, +export const registerCommand = ( + definition: AnyCommandDefinition, + callback: (definition: AnyCommandDefinition) => CommandCb, ): void => { const command = program.command(definition.name).description(definition.description); diff --git a/apps/app-builder/src/utils/command/runHooks.ts b/apps/app-builder/src/utils/command/runHooks.ts new file mode 100644 index 00000000..dc4ca20c --- /dev/null +++ b/apps/app-builder/src/utils/command/runHooks.ts @@ -0,0 +1,26 @@ +import {type PdkBuilderConfig} from '../../types/config.types'; +import { + type AnyCommandDefinition, + type DefaultCommandArgs, + type PdkBuilderCommand, + type PdkBuilderContext, +} from '../../types/command.types'; +import {VerbosityLevel} from '../../constants'; + +export const runHooks = async ( + type: 'before' | 'after', + definition: AnyCommandDefinition, + context: PdkBuilderContext, + command: PdkBuilderCommand, +): Promise => { + const commandName = definition.name; + const capitalizedCommandName = commandName.charAt(0).toUpperCase() + commandName.slice(1); + const hookName = `${type}${capitalizedCommandName}` as keyof PdkBuilderConfig['hooks']; + + if (context.args.verbose >= VerbosityLevel.Verbose && (context.config.hooks?.[hookName] ?? null)) { + context.debug(`Running hook ${hookName}`); + } + + // @ts-expect-error todo + await context.config.hooks?.[hookName]?.({command, context}); +}; diff --git a/apps/app-builder/src/utils/defineCommand.ts b/apps/app-builder/src/utils/defineCommand.ts index c0b5c1e0..948a2a15 100644 --- a/apps/app-builder/src/utils/defineCommand.ts +++ b/apps/app-builder/src/utils/defineCommand.ts @@ -1,13 +1,17 @@ import {isOfType} from '@myparcel/ts-utils'; -import {type AnyCommandArgs, type CommandDefinition, type CommandDefinitionWithoutConfig} from '../types/command.types'; +import { + type AnyCommandArgs, + type AnyCommandDefinition, + type CommandDefinitionWithoutConfig, +} from '../types/command.types'; import {CONFIG_OPTIONS, OPTION_DRY_RUN, OPTION_QUIET, OPTION_VERBOSITY} from '../constants'; export const defineCommand = < Args = AnyCommandArgs, - Definition extends CommandDefinition = CommandDefinition, + Definition extends AnyCommandDefinition = AnyCommandDefinition, >( definition: Definition, -): CommandDefinition => { +): AnyCommandDefinition => { const resolvedDefinition = { ...definition, options: [OPTION_DRY_RUN, OPTION_QUIET, OPTION_VERBOSITY, ...(definition.options ?? [])], diff --git a/apps/app-builder/src/utils/executePromises.ts b/apps/app-builder/src/utils/executePromises.ts index cdc5a347..959ce60b 100644 --- a/apps/app-builder/src/utils/executePromises.ts +++ b/apps/app-builder/src/utils/executePromises.ts @@ -1,6 +1,6 @@ -import {type CommandArgs} from '../types/command.types'; +import {type DefaultCommandArgs} from '../types/command.types'; -export const executePromises = async (args: CommandArgs, promises: Promise[]): Promise => { +export const executePromises = async (args: DefaultCommandArgs, promises: Promise[]): Promise => { if (args.parallel) { await Promise.all(promises); diff --git a/apps/app-builder/src/utils/resolveConfig.ts b/apps/app-builder/src/utils/resolveConfig.ts index 2f26070d..0d09e543 100644 --- a/apps/app-builder/src/utils/resolveConfig.ts +++ b/apps/app-builder/src/utils/resolveConfig.ts @@ -1,12 +1,12 @@ import {type LiftoffEnv} from 'liftoff'; import {type PdkBuilderConfig, type ResolvedPdkBuilderConfig} from '../types/config.types'; -import {type AnyCommandArgs, type ParsedCommand} from '../types/command.types'; +import {type AnyCommandArgs, type ParsedCommandArguments} from '../types/command.types'; const configCache = new Map(); -export async function resolveConfig( +export async function resolveConfig( env: LiftoffEnv, - args?: ParsedCommand, + args?: ParsedCommandArguments, ): Promise { if (!env.configPath) { throw new Error('No config file found.');