From 6f77e3edb3c03afd3d6415341359e0418956aac8 Mon Sep 17 00:00:00 2001 From: "Micael Levi L. Cavalcante" Date: Sun, 16 Jul 2023 17:38:28 -0400 Subject: [PATCH] refactor: replace command inputs by dictionary-like data abstraction --- actions/abstract.action.ts | 4 +- actions/add.action.ts | 14 +++--- actions/build.action.ts | 36 +++++---------- actions/generate.action.ts | 6 +-- actions/new.action.ts | 46 ++++++++----------- actions/start.action.ts | 25 +++------- commands/add.command.ts | 13 +++--- commands/build.command.ts | 22 ++++----- commands/command.input.ts | 40 +++++++++++++++- commands/generate.command.ts | 21 +++++---- commands/new.command.ts | 25 +++++----- commands/start.command.ts | 34 +++++++------- lib/compiler/helpers/get-builder.ts | 4 +- lib/compiler/helpers/get-tsc-config.path.ts | 4 +- lib/compiler/helpers/get-value-or-default.ts | 12 +++-- .../helpers/get-webpack-config-path.ts | 4 +- lib/compiler/webpack-compiler.ts | 4 +- lib/utils/project-utils.ts | 10 ++-- 18 files changed, 165 insertions(+), 159 deletions(-) diff --git a/actions/abstract.action.ts b/actions/abstract.action.ts index 70355adf8..ca8bd5825 100644 --- a/actions/abstract.action.ts +++ b/actions/abstract.action.ts @@ -1,9 +1,9 @@ -import { Input } from '../commands'; +import { Input, CommandInputsContainer } from '../commands'; export abstract class AbstractAction { public abstract handle( inputs?: Input[], - options?: Input[], + options?: CommandInputsContainer, extraFlags?: string[], ): Promise; } diff --git a/actions/add.action.ts b/actions/add.action.ts index 5c5d1d09e..08c7924e8 100644 --- a/actions/add.action.ts +++ b/actions/add.action.ts @@ -1,5 +1,5 @@ import * as chalk from 'chalk'; -import { Input } from '../commands'; +import { CommandInputsContainer, Input } from '../commands'; import { getValueOrDefault } from '../lib/compiler/helpers/get-value-or-default'; import { AbstractPackageManager, @@ -23,7 +23,7 @@ import { AbstractAction } from './abstract.action'; const schematicName = 'nest-add'; export class AddAction extends AbstractAction { - public async handle(inputs: Input[], options: Input[], extraFlags: string[]) { + public async handle(inputs: Input[], options: CommandInputsContainer, extraFlags: string[]) { const libraryName = this.getLibraryName(inputs); const packageName = this.getPackageName(libraryName); const collectionName = this.getCollectionName(libraryName, packageName); @@ -33,9 +33,11 @@ export class AddAction extends AbstractAction { skipInstall || (await this.installPackage(collectionName, tagName)); if (packageInstallSuccess) { const sourceRootOption: Input = await this.getSourceRoot( - inputs.concat(options), + inputs.concat(options.toArray()), ); - options.push(sourceRootOption); + if (sourceRootOption) { + options.addInput(sourceRootOption) + } await this.addLibrary(collectionName, options, extraFlags); } else { @@ -117,7 +119,7 @@ export class AddAction extends AbstractAction { private async addLibrary( collectionName: string, - options: Input[], + options: CommandInputsContainer, extraFlags: string[], ) { console.info(MESSAGES.LIBRARY_INSTALLATION_STARTS); @@ -125,7 +127,7 @@ export class AddAction extends AbstractAction { schematicOptions.push( new SchematicOption( 'sourceRoot', - options.find((option) => option.name === 'sourceRoot')!.value as string, + options.resolveInput('sourceRoot', true).value, ), ); const extraFlagsString = extraFlags ? extraFlags.join(' ') : undefined; diff --git a/actions/build.action.ts b/actions/build.action.ts index 7048aa086..e736569d5 100644 --- a/actions/build.action.ts +++ b/actions/build.action.ts @@ -1,7 +1,7 @@ import * as chalk from 'chalk'; import { join } from 'path'; import * as ts from 'typescript'; -import { Input } from '../commands'; +import { Input, CommandInputsContainer } from '../commands'; import { AssetsManager } from '../lib/compiler/assets-manager'; import { Compiler } from '../lib/compiler/compiler'; import { getBuilder } from '../lib/compiler/helpers/get-builder'; @@ -40,19 +40,10 @@ export class BuildAction extends AbstractAction { protected readonly assetsManager = new AssetsManager(); protected readonly workspaceUtils = new WorkspaceUtils(); - public async handle(commandInputs: Input[], commandOptions: Input[]) { + public async handle(commandInputs: Input[], commandOptions: CommandInputsContainer) { try { - const watchModeOption = commandOptions.find( - (option) => option.name === 'watch', - ); - const watchMode = !!(watchModeOption && watchModeOption.value); - - const watchAssetsModeOption = commandOptions.find( - (option) => option.name === 'watchAssets', - ); - const watchAssetsMode = !!( - watchAssetsModeOption && watchAssetsModeOption.value - ); + const watchMode = !!commandOptions.resolveInput('watch')?.value; + const watchAssetsMode = !!commandOptions.resolveInput('watchAssets')?.value; await this.runBuild( commandInputs, @@ -72,15 +63,13 @@ export class BuildAction extends AbstractAction { public async runBuild( commandInputs: Input[], - commandOptions: Input[], + commandOptions: CommandInputsContainer, watchMode: boolean, watchAssetsMode: boolean, isDebugEnabled = false, onSuccess?: () => void, ) { - const configFileName = commandOptions.find( - (option) => option.name === 'config', - )!.value as string; + const configFileName = commandOptions.resolveInput('config', true).value const configuration = await this.loader.load(configFileName); const appName = commandInputs.find((input) => input.name === 'app')! .value as string; @@ -155,7 +144,7 @@ export class BuildAction extends AbstractAction { appName: string, pathToTsconfig: string, watchMode: boolean, - options: Input[], + options: CommandInputsContainer, tsOptions: ts.CompilerOptions, onSuccess: (() => void) | undefined, ) { @@ -183,7 +172,7 @@ export class BuildAction extends AbstractAction { private runWebpack( configuration: Required, appName: string, - commandOptions: Input[], + commandOptions: CommandInputsContainer, pathToTsconfig: string, debug: boolean, watchMode: boolean, @@ -216,7 +205,7 @@ export class BuildAction extends AbstractAction { private runTsc( watchMode: boolean, - options: Input[], + options: CommandInputsContainer, configuration: Required, pathToTsconfig: string, appName: string, @@ -228,15 +217,12 @@ export class BuildAction extends AbstractAction { this.tsConfigProvider, this.tsLoader, ); - const isPreserveWatchOutputEnabled = options.find( - (option) => - option.name === 'preserveWatchOutput' && option.value === true, - ); + const isPreserveWatchOutputEnabled = options.resolveInput('preserveWatchOutput')?.value || false watchCompiler.run( configuration, pathToTsconfig, appName, - { preserveWatchOutput: !!isPreserveWatchOutputEnabled }, + { preserveWatchOutput: isPreserveWatchOutputEnabled }, onSuccess, ); } else { diff --git a/actions/generate.action.ts b/actions/generate.action.ts index 22c3ff012..c412737df 100644 --- a/actions/generate.action.ts +++ b/actions/generate.action.ts @@ -1,6 +1,6 @@ import * as chalk from 'chalk'; import { Answers } from 'inquirer'; -import { Input } from '../commands'; +import { Input, CommandInputsContainer } from '../commands'; import { getValueOrDefault } from '../lib/compiler/helpers/get-value-or-default'; import { AbstractCollection, @@ -21,8 +21,8 @@ import { import { AbstractAction } from './abstract.action'; export class GenerateAction extends AbstractAction { - public async handle(inputs: Input[], options: Input[]) { - await generateFiles(inputs.concat(options)); + public async handle(inputs: Input[], options: CommandInputsContainer) { + await generateFiles(inputs.concat(options.toArray())); } } diff --git a/actions/new.action.ts b/actions/new.action.ts index 99c3fef50..6e78fbbf9 100644 --- a/actions/new.action.ts +++ b/actions/new.action.ts @@ -4,7 +4,7 @@ import * as fs from 'fs'; import * as inquirer from 'inquirer'; import { Answers, Question } from 'inquirer'; import { join } from 'path'; -import { Input } from '../commands'; +import { CommandInputsContainer, Input } from '../commands'; import { defaultGitIgnore } from '../lib/configuration/defaults'; import { AbstractPackageManager, @@ -24,22 +24,16 @@ import { normalizeToKebabOrSnakeCase } from '../lib/utils/formatting'; import { AbstractAction } from './abstract.action'; export class NewAction extends AbstractAction { - public async handle(inputs: Input[], options: Input[]) { - const directoryOption = options.find( - (option) => option.name === 'directory', - ); - const dryRunOption = options.find((option) => option.name === 'dry-run'); - const isDryRunEnabled = dryRunOption && dryRunOption.value; + public async handle(inputs: Input[], options: CommandInputsContainer) { + const directoryOption = options.resolveInput('directory'); + const dryRunOption = options.resolveInput('dry-run'); + const isDryRunEnabled = !!dryRunOption?.value; await askForMissingInformation(inputs, options); await generateApplicationFiles(inputs, options).catch(exit); - const shouldSkipInstall = options.some( - (option) => option.name === 'skip-install' && option.value === true, - ); - const shouldSkipGit = options.some( - (option) => option.name === 'skip-git' && option.value === true, - ); + const shouldSkipInstall = options.resolveInput('skip-install')?.value + const shouldSkipGit = options.resolveInput('skip-git')?.value; const projectDirectory = getProjectDirectory( getApplicationNameInput(inputs)!, directoryOption, @@ -67,9 +61,6 @@ export class NewAction extends AbstractAction { const getApplicationNameInput = (inputs: Input[]) => inputs.find((input) => input.name === 'name'); -const getPackageManagerInput = (inputs: Input[]) => - inputs.find((options) => options.name === 'packageManager'); - const getProjectDirectory = ( applicationName: Input, directoryOption?: Input, @@ -80,7 +71,7 @@ const getProjectDirectory = ( ); }; -const askForMissingInformation = async (inputs: Input[], options: Input[]) => { +const askForMissingInformation = async (inputs: Input[], options: CommandInputsContainer) => { console.info(MESSAGES.PROJECT_INFORMATION_START); console.info(); @@ -94,17 +85,20 @@ const askForMissingInformation = async (inputs: Input[], options: Input[]) => { replaceInputMissingInformation(inputs, answers); } - const packageManagerInput = getPackageManagerInput(options); - if (!packageManagerInput!.value) { + const packageManagerInput = options.resolveInput('packageManager') + if (!packageManagerInput?.value) { const answers = await askForPackageManager(); replaceInputMissingInformation(options, answers); } }; const replaceInputMissingInformation = ( - inputs: Input[], + inputs: Input[] | CommandInputsContainer, answers: Answers, ): Input[] => { + if (!Array.isArray(inputs)) { + inputs = inputs.toArray() + } return inputs.map( (input) => (input.value = @@ -112,15 +106,13 @@ const replaceInputMissingInformation = ( ); }; -const generateApplicationFiles = async (args: Input[], options: Input[]) => { - const collectionName = options.find( - (option) => option.name === 'collection' && option.value != null, - )!.value; +const generateApplicationFiles = async (args: Input[], options: CommandInputsContainer) => { + const collectionName = options.resolveInput('collection', true)?.value const collection: AbstractCollection = CollectionFactory.create( (collectionName as Collection) || Collection.NESTJS, ); const schematicOptions: SchematicOption[] = mapSchematicOptions( - args.concat(options), + args.concat(options.toArray()), ); await collection.execute('application', schematicOptions); console.info(); @@ -139,11 +131,11 @@ const mapSchematicOptions = (options: Input[]): SchematicOption[] => { }; const installPackages = async ( - options: Input[], + options: CommandInputsContainer, dryRunMode: boolean, installDirectory: string, ) => { - const inputPackageManager = getPackageManagerInput(options)!.value as string; + const inputPackageManager = options.resolveInput('packageManager', true).value; let packageManager: AbstractPackageManager; if (dryRunMode) { diff --git a/actions/start.action.ts b/actions/start.action.ts index a87599a13..a56824385 100644 --- a/actions/start.action.ts +++ b/actions/start.action.ts @@ -3,7 +3,7 @@ import { spawn } from 'child_process'; import * as fs from 'fs'; import { join } from 'path'; import * as killProcess from 'tree-kill'; -import { Input } from '../commands'; +import { Input, CommandInputsContainer } from '../commands'; import { getTscConfigPath } from '../lib/compiler/helpers/get-tsc-config.path'; import { getValueOrDefault } from '../lib/compiler/helpers/get-value-or-default'; import { @@ -15,11 +15,9 @@ import { treeKillSync as killProcessSync } from '../lib/utils/tree-kill'; import { BuildAction } from './build.action'; export class StartAction extends BuildAction { - public async handle(commandInputs: Input[], commandOptions: Input[]) { + public async handle(commandInputs: Input[], commandOptions: CommandInputsContainer) { try { - const configFileName = commandOptions.find( - (option) => option.name === 'config', - )!.value as string; + const configFileName = commandOptions.resolveInput('config', true).value; const configuration = await this.loader.load(configFileName); const appName = commandInputs.find((input) => input.name === 'app')! .value as string; @@ -30,20 +28,9 @@ export class StartAction extends BuildAction { appName, ); - const debugModeOption = commandOptions.find( - (option) => option.name === 'debug', - ); - const watchModeOption = commandOptions.find( - (option) => option.name === 'watch', - ); - const isWatchEnabled = !!(watchModeOption && watchModeOption.value); - const watchAssetsModeOption = commandOptions.find( - (option) => option.name === 'watchAssets', - ); - const isWatchAssetsEnabled = !!( - watchAssetsModeOption && watchAssetsModeOption.value - ); - const debugFlag = debugModeOption && debugModeOption.value; + const isWatchEnabled = !!commandOptions.resolveInput('watch')?.value; + const isWatchAssetsEnabled = !!commandOptions.resolveInput('watchAssets')?.value; + const debugFlag = commandOptions.resolveInput('debug')?.value; const binaryToRun = getValueOrDefault( configuration, 'exec', diff --git a/commands/add.command.ts b/commands/add.command.ts index a2006dbef..792a3a52b 100644 --- a/commands/add.command.ts +++ b/commands/add.command.ts @@ -1,7 +1,7 @@ import { Command, CommanderStatic } from 'commander'; import { getRemainingFlags } from '../lib/utils/remaining-flags'; import { AbstractCommand } from './abstract.command'; -import { Input } from './command.input'; +import { Input, CommandInputsContainer } from './command.input'; export class AddCommand extends AbstractCommand { public load(program: CommanderStatic): void { @@ -17,10 +17,11 @@ export class AddCommand extends AbstractCommand { .option('-p, --project [project]', 'Project in which to generate files.') .usage(' [options] [library-specific-options]') .action(async (library: string, command: Command) => { - const options: Input[] = []; - options.push({ name: 'dry-run', value: !!command.dryRun }); - options.push({ name: 'skip-install', value: command.skipInstall }); - options.push({ + const commandOptions = new CommandInputsContainer(); + + commandOptions.addInput({ name: 'dry-run', value: !!command.dryRun }); + commandOptions.addInput({ name: 'skip-install', value: command.skipInstall }); + commandOptions.addInput({ name: 'project', value: command.project, }); @@ -30,7 +31,7 @@ export class AddCommand extends AbstractCommand { const flags = getRemainingFlags(program); try { - await this.action.handle(inputs, options, flags); + await this.action.handle(inputs, commandOptions, flags); } catch (err) { process.exit(1); } diff --git a/commands/build.command.ts b/commands/build.command.ts index cd40aab75..42bde0c0a 100644 --- a/commands/build.command.ts +++ b/commands/build.command.ts @@ -1,7 +1,7 @@ import { Command, CommanderStatic } from 'commander'; import { ERROR_PREFIX, INFO_PREFIX } from '../lib/ui'; import { AbstractCommand } from './abstract.command'; -import { Input } from './command.input'; +import { Input, CommandInputsContainer } from './command.input'; export class BuildCommand extends AbstractCommand { public load(program: CommanderStatic): void { @@ -21,22 +21,22 @@ export class BuildCommand extends AbstractCommand { .option('--tsc', 'Use tsc for compilation.') .description('Build Nest application.') .action(async (app: string, command: Command) => { - const options: Input[] = []; + const commandOptions = new CommandInputsContainer() - options.push({ + commandOptions.addInput({ name: 'config', value: command.config, }); const isWebpackEnabled = command.tsc ? false : command.webpack; - options.push({ name: 'webpack', value: isWebpackEnabled }); - options.push({ name: 'watch', value: !!command.watch }); - options.push({ name: 'watchAssets', value: !!command.watchAssets }); - options.push({ + commandOptions.addInput({ name: 'webpack', value: isWebpackEnabled }); + commandOptions.addInput({ name: 'watch', value: !!command.watch }); + commandOptions.addInput({ name: 'watchAssets', value: !!command.watchAssets }); + commandOptions.addInput({ name: 'path', value: command.path, }); - options.push({ + commandOptions.addInput({ name: 'webpackPath', value: command.webpackPath, }); @@ -51,7 +51,7 @@ export class BuildCommand extends AbstractCommand { ); return; } - options.push({ + commandOptions.addInput({ name: 'builder', value: command.builder, }); @@ -62,14 +62,14 @@ export class BuildCommand extends AbstractCommand { ` "typeCheck" will not have any effect when "builder" is not "swc".`, ); } - options.push({ + commandOptions.addInput({ name: 'typeCheck', value: command.typeCheck, }); const inputs: Input[] = []; inputs.push({ name: 'app', value: app }); - await this.action.handle(inputs, options); + await this.action.handle(inputs, commandOptions); }); } } diff --git a/commands/command.input.ts b/commands/command.input.ts index 3d490827f..79f82998f 100644 --- a/commands/command.input.ts +++ b/commands/command.input.ts @@ -1,5 +1,41 @@ -export interface Input { +export interface Input { name: string; - value: boolean | string; + value: TValue; options?: any; } + +export class CommandInputsContainer { + private readonly inputsByName = new Map(); + + toArray(): Input[] { + return Array.from(this.inputsByName.values()) + } + + addInput(input: Input) { + this.inputsByName.set(input.name, input); + } + + resolveInput( + inputName: Input['name'], + ): Input | undefined; + resolveInput( + inputName: Input['name'], + errorOnMissing: false, + ): Input | undefined; + resolveInput( + inputName: Input['name'], + errorOnMissing: true, + ): Input; + resolveInput( + inputName: Input['name'], + errorOnMissing = false + ): Input | undefined { + const input = this.inputsByName.get(inputName) as Input | undefined; + if (errorOnMissing) { + if (!input) { + throw new Error(`The input ${inputName} is missing!`); + } + } + return input + } +} diff --git a/commands/generate.command.ts b/commands/generate.command.ts index d6613afe5..a5e638462 100644 --- a/commands/generate.command.ts +++ b/commands/generate.command.ts @@ -5,7 +5,7 @@ import { AbstractCollection, CollectionFactory } from '../lib/schematics'; import { Schematic } from '../lib/schematics/nest.collection'; import { loadConfiguration } from '../lib/utils/load-configuration'; import { AbstractCommand } from './abstract.command'; -import { Input } from './command.input'; +import { Input, CommandInputsContainer } from './command.input'; export class GenerateCommand extends AbstractCommand { public async load(program: CommanderStatic): Promise { @@ -55,14 +55,15 @@ export class GenerateCommand extends AbstractCommand { path: string, command: Command, ) => { - const options: Input[] = []; - options.push({ name: 'dry-run', value: !!command.dryRun }); + const commandOptions = new CommandInputsContainer(); + + commandOptions.addInput({ name: 'dry-run', value: !!command.dryRun }); if (command.flat !== undefined) { - options.push({ name: 'flat', value: command.flat }); + commandOptions.addInput({ name: 'flat', value: command.flat }); } - options.push({ + commandOptions.addInput({ name: 'spec', value: typeof command.spec === 'boolean' @@ -75,20 +76,20 @@ export class GenerateCommand extends AbstractCommand { : command.spec.passedAsInput, }, }); - options.push({ + commandOptions.addInput({ name: 'specFileSuffix', value: command.specFileSuffix, }); - options.push({ + commandOptions.addInput({ name: 'collection', value: command.collection, }); - options.push({ + commandOptions.addInput({ name: 'project', value: command.project, }); - options.push({ + commandOptions.addInput({ name: 'skipImport', value: command.skipImport, }); @@ -98,7 +99,7 @@ export class GenerateCommand extends AbstractCommand { inputs.push({ name: 'name', value: name }); inputs.push({ name: 'path', value: path }); - await this.action.handle(inputs, options); + await this.action.handle(inputs, commandOptions); }, ); } diff --git a/commands/new.command.ts b/commands/new.command.ts index 28b595e1e..f549282a1 100644 --- a/commands/new.command.ts +++ b/commands/new.command.ts @@ -1,7 +1,7 @@ import { Command, CommanderStatic } from 'commander'; import { Collection } from '../lib/schematics'; import { AbstractCommand } from './abstract.command'; -import { Input } from './command.input'; +import { Input, CommandInputsContainer } from './command.input'; export class NewCommand extends AbstractCommand { public load(program: CommanderStatic) { @@ -33,19 +33,20 @@ export class NewCommand extends AbstractCommand { ) .option('--strict', 'Enables strict mode in TypeScript.', false) .action(async (name: string, command: Command) => { - const options: Input[] = []; - const availableLanguages = ['js', 'ts', 'javascript', 'typescript']; - options.push({ name: 'directory', value: command.directory }); - options.push({ name: 'dry-run', value: command.dryRun }); - options.push({ name: 'skip-git', value: command.skipGit }); - options.push({ name: 'skip-install', value: command.skipInstall }); - options.push({ name: 'strict', value: command.strict }); - options.push({ + const commandOptions = new CommandInputsContainer(); + + commandOptions.addInput({ name: 'directory', value: command.directory }); + commandOptions.addInput({ name: 'dry-run', value: command.dryRun }); + commandOptions.addInput({ name: 'skip-git', value: command.skipGit }); + commandOptions.addInput({ name: 'skip-install', value: command.skipInstall }); + commandOptions.addInput({ name: 'strict', value: command.strict }); + commandOptions.addInput({ name: 'packageManager', value: command.packageManager, }); - options.push({ name: 'collection', value: command.collection }); + commandOptions.addInput({ name: 'collection', value: command.collection }); + const availableLanguages = ['js', 'ts', 'javascript', 'typescript']; if (!!command.language) { const lowercasedLanguage = command.language.toLowerCase(); const langMatch = availableLanguages.includes(lowercasedLanguage); @@ -66,7 +67,7 @@ export class NewCommand extends AbstractCommand { break; } } - options.push({ + commandOptions.addInput({ name: 'language', value: command.language, }); @@ -74,7 +75,7 @@ export class NewCommand extends AbstractCommand { const inputs: Input[] = []; inputs.push({ name: 'name', value: name }); - await this.action.handle(inputs, options); + await this.action.handle(inputs, commandOptions); }); } } diff --git a/commands/start.command.ts b/commands/start.command.ts index 1d4f256b2..f95e9265d 100644 --- a/commands/start.command.ts +++ b/commands/start.command.ts @@ -2,7 +2,7 @@ import { Command, CommanderStatic } from 'commander'; import { ERROR_PREFIX, INFO_PREFIX } from '../lib/ui'; import { getRemainingFlags } from '../lib/utils/remaining-flags'; import { AbstractCommand } from './abstract.command'; -import { Input } from './command.input'; +import { Input, CommandInputsContainer } from './command.input'; import type { BuilderVariant } from '../lib/configuration'; export class StartCommand extends AbstractCommand { @@ -40,39 +40,39 @@ export class StartCommand extends AbstractCommand { ) .description('Run Nest application.') .action(async (app: string, command: Command) => { - const options: Input[] = []; + const commandOptions = new CommandInputsContainer(); - options.push({ + commandOptions.addInput({ name: 'config', value: command.config, - }); + }) const isWebpackEnabled = command.tsc ? false : command.webpack; - options.push({ name: 'webpack', value: isWebpackEnabled }); - options.push({ name: 'debug', value: command.debug }); - options.push({ name: 'watch', value: !!command.watch }); - options.push({ name: 'watchAssets', value: !!command.watchAssets }); - options.push({ + commandOptions.addInput({ name: 'webpack', value: isWebpackEnabled }); + commandOptions.addInput({ name: 'debug', value: command.debug }); + commandOptions.addInput({ name: 'watch', value: !!command.watch }); + commandOptions.addInput({ name: 'watchAssets', value: !!command.watchAssets }); + commandOptions.addInput({ name: 'path', value: command.path, }); - options.push({ + commandOptions.addInput({ name: 'webpackPath', value: command.webpackPath, }); - options.push({ + commandOptions.addInput({ name: 'exec', value: command.exec, }); - options.push({ + commandOptions.addInput({ name: 'sourceRoot', value: command.sourceRoot, }); - options.push({ + commandOptions.addInput({ name: 'entryFile', value: command.entryFile, }); - options.push({ + commandOptions.addInput({ name: 'preserveWatchOutput', value: !!command.preserveWatchOutput && @@ -90,7 +90,7 @@ export class StartCommand extends AbstractCommand { ); return; } - options.push({ + commandOptions.addInput({ name: 'builder', value: command.builder, }); @@ -101,7 +101,7 @@ export class StartCommand extends AbstractCommand { ` "typeCheck" will not have any effect when "builder" is not "swc".`, ); } - options.push({ + commandOptions.addInput({ name: 'typeCheck', value: command.typeCheck, }); @@ -111,7 +111,7 @@ export class StartCommand extends AbstractCommand { const flags = getRemainingFlags(program); try { - await this.action.handle(inputs, options, flags); + await this.action.handle(inputs, commandOptions, flags); } catch (err) { process.exit(1); } diff --git a/lib/compiler/helpers/get-builder.ts b/lib/compiler/helpers/get-builder.ts index 316513136..bd1250525 100644 --- a/lib/compiler/helpers/get-builder.ts +++ b/lib/compiler/helpers/get-builder.ts @@ -1,4 +1,4 @@ -import { Input } from '../../../commands'; +import { CommandInputsContainer } from '../../../commands'; import { Builder, Configuration } from '../../configuration'; import { getValueOrDefault } from './get-value-or-default'; @@ -11,7 +11,7 @@ import { getValueOrDefault } from './get-value-or-default'; */ export function getBuilder( configuration: Required, - cmdOptions: Input[], + cmdOptions: CommandInputsContainer, appName: string, ) { const builderValue = getValueOrDefault( diff --git a/lib/compiler/helpers/get-tsc-config.path.ts b/lib/compiler/helpers/get-tsc-config.path.ts index 04dee58f6..a31583713 100644 --- a/lib/compiler/helpers/get-tsc-config.path.ts +++ b/lib/compiler/helpers/get-tsc-config.path.ts @@ -1,4 +1,4 @@ -import { Input } from '../../../commands'; +import { CommandInputsContainer } from '../../../commands'; import { Builder, Configuration } from '../../configuration'; import { getDefaultTsconfigPath } from '../../utils/get-default-tsconfig-path'; import { getValueOrDefault } from './get-value-or-default'; @@ -12,7 +12,7 @@ import { getValueOrDefault } from './get-value-or-default'; */ export function getTscConfigPath( configuration: Required, - cmdOptions: Input[], + cmdOptions: CommandInputsContainer, appName: string, ) { let tsconfigPath = getValueOrDefault( diff --git a/lib/compiler/helpers/get-value-or-default.ts b/lib/compiler/helpers/get-value-or-default.ts index 9b0b71c14..157373f01 100644 --- a/lib/compiler/helpers/get-value-or-default.ts +++ b/lib/compiler/helpers/get-value-or-default.ts @@ -1,4 +1,4 @@ -import { Input } from '../../../commands'; +import { Input, CommandInputsContainer } from '../../../commands'; import { Configuration } from '../../configuration'; export function getValueOrDefault( @@ -14,13 +14,15 @@ export function getValueOrDefault( | 'exec' | 'builder' | 'typeCheck', - options: Input[] = [], + options: Input[] | CommandInputsContainer = [], defaultValue?: T, ): T { - const item = options.find((option) => option.name === key); - const origValue = item && (item.value as unknown as T); + const item = Array.isArray(options) + ? options.find((option) => option.name === key) + : key && options.resolveInput(key) + const origValue = item?.value as T | undefined; if (origValue !== undefined && origValue !== null) { - return origValue as T; + return origValue; } if (configuration.projects && configuration.projects[appName as string]) { // Wrap the application name in double-quotes to prevent splitting it diff --git a/lib/compiler/helpers/get-webpack-config-path.ts b/lib/compiler/helpers/get-webpack-config-path.ts index 08e8a58ca..bc4f3be90 100644 --- a/lib/compiler/helpers/get-webpack-config-path.ts +++ b/lib/compiler/helpers/get-webpack-config-path.ts @@ -1,4 +1,4 @@ -import { Input } from '../../../commands'; +import { CommandInputsContainer } from '../../../commands'; import { Builder, Configuration } from '../../configuration'; import { getValueOrDefault } from './get-value-or-default'; @@ -11,7 +11,7 @@ import { getValueOrDefault } from './get-value-or-default'; */ export function getWebpackConfigPath( configuration: Required, - cmdOptions: Input[], + cmdOptions: CommandInputsContainer, appName: string, ) { let webpackPath = getValueOrDefault( diff --git a/lib/compiler/webpack-compiler.ts b/lib/compiler/webpack-compiler.ts index db125e182..5072503ce 100644 --- a/lib/compiler/webpack-compiler.ts +++ b/lib/compiler/webpack-compiler.ts @@ -1,6 +1,6 @@ import { existsSync } from 'fs'; import { join } from 'path'; -import { Input } from '../../commands'; +import { CommandInputsContainer } from '../../commands'; import { Configuration } from '../configuration'; import { INFO_PREFIX } from '../ui'; import { AssetsManager } from './assets-manager'; @@ -20,7 +20,7 @@ type WebpackConfigFactoryOrConfig = | webpack.Configuration; type WebpackCompilerExtras = { - inputs: Input[]; + inputs: CommandInputsContainer; assetsManager: AssetsManager; webpackConfigFactoryOrConfig: | WebpackConfigFactoryOrConfig diff --git a/lib/utils/project-utils.ts b/lib/utils/project-utils.ts index 5c4c6fbf9..3a7807919 100644 --- a/lib/utils/project-utils.ts +++ b/lib/utils/project-utils.ts @@ -1,6 +1,6 @@ import * as inquirer from 'inquirer'; import { Answers, Question } from 'inquirer'; -import { Input } from '../../commands'; +import { CommandInputsContainer, Input } from '../../commands'; import { getValueOrDefault } from '../compiler/helpers/get-value-or-default'; import { Configuration, ProjectConfiguration } from '../configuration'; import { generateSelect } from '../questions/questions'; @@ -142,11 +142,9 @@ export function moveDefaultProjectToStart( export function hasValidOptionFlag( queriedOptionName: string, - options: Input[], + options: CommandInputsContainer, queriedValue: string | number | boolean = true, ): boolean { - return options.some( - (option: Input) => - option.name === queriedOptionName && option.value === queriedValue, - ); + const option = options.resolveInput(queriedOptionName); + return option?.value === queriedValue; }