-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🏗 build(cli): extract args before running build cmd (#196)
* refactor: extract cli args before running cmd * feat: validate pckgs before building * chore: update delete cmd description * feat: support force option when building node pckgs * refactor(cli): convert CLI to class and use zod for validation * feat(cli): add clientId as build option * fix(cli): validate packages after they're provided * refactor(cli): move validation from util to Cli class this improves readability, because the class has access to the 'options', which means we don't have to keep passing that arg to the util functions * refactor(cli): extract parsing and validation into separate class this makes the division of responsibilities more clear: the Validator parses cli args and validates their inputs against our types. The CLI is then free to accept the parsed args and simply trigger the provided commands * build(deps): add zod to backend
- Loading branch information
1 parent
1423ed4
commit 67db6a0
Showing
6 changed files
with
301 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import { Command } from "commander"; | ||
|
||
import { ALL_PACKAGES } from "./common/cli.constants"; | ||
import { | ||
Options_Cli, | ||
Options_Cli_Build, | ||
Options_Cli_Delete, | ||
Schema_Options_Cli_Build, | ||
Schema_Options_Cli_Delete, | ||
Schema_Options_Cli_Root, | ||
} from "./common/cli.types"; | ||
import { getPckgsTo, log } from "./common/cli.utils"; | ||
|
||
export class CliValidator { | ||
private program: Command; | ||
|
||
constructor(program: Command) { | ||
this.program = program; | ||
} | ||
|
||
public exitHelpfully(cmd: "root" | "build" | "delete", msg?: string) { | ||
msg && log.error(msg); | ||
|
||
if (cmd === "root") { | ||
console.log(this.program.helpInformation()); | ||
} else { | ||
const command = this.program.commands.find( | ||
(c) => c.name() === cmd | ||
) as Command; | ||
console.log(command.helpInformation()); | ||
} | ||
|
||
process.exit(1); | ||
} | ||
|
||
public getCliOptions(): Options_Cli { | ||
const options = this._mergeOptions(); | ||
const validOptions = this._validateOptions(options); | ||
|
||
return validOptions; | ||
} | ||
|
||
public async validateBuild(options: Options_Cli) { | ||
if (!options.packages) { | ||
options.packages = await getPckgsTo("build"); | ||
} | ||
|
||
const unsupportedPackages = options.packages.filter( | ||
(pkg) => !ALL_PACKAGES.includes(pkg) | ||
); | ||
if (unsupportedPackages.length > 0) { | ||
this.exitHelpfully( | ||
"build", | ||
`One or more of these packages isn't supported: ${unsupportedPackages.toString()}` | ||
); | ||
} | ||
} | ||
|
||
public validateDelete(options: Options_Cli) { | ||
const { user } = options; | ||
if (!user || typeof user !== "string") { | ||
this.exitHelpfully("delete", "You must supply a user"); | ||
} | ||
} | ||
|
||
private _getBuildOptions() { | ||
const buildOpts: Options_Cli_Build = {}; | ||
|
||
const buildCmd = this.program.commands.find( | ||
(cmd) => cmd.name() === "build" | ||
); | ||
if (buildCmd) { | ||
const packages = this.program.args[1]?.split(","); | ||
if (packages) { | ||
buildOpts.packages = packages; | ||
} | ||
|
||
const environment = buildCmd?.opts()[ | ||
"environment" | ||
] as Options_Cli_Build["environment"]; | ||
if (environment) { | ||
buildOpts.environment = environment; | ||
} | ||
|
||
const clientId = buildCmd?.opts()[ | ||
"clientId" | ||
] as Options_Cli_Build["clientId"]; | ||
if (clientId) { | ||
buildOpts.clientId = clientId; | ||
} | ||
} | ||
return buildOpts; | ||
} | ||
|
||
private _getDeleteOptions() { | ||
const deleteOpts: Options_Cli_Delete = {}; | ||
|
||
const deleteCmd = this.program.commands.find( | ||
(cmd) => cmd.name() === "delete" | ||
); | ||
if (deleteCmd) { | ||
const user = deleteCmd?.opts()["user"] as Options_Cli["user"]; | ||
if (user) { | ||
deleteOpts.user = user; | ||
} | ||
} | ||
|
||
return deleteOpts; | ||
} | ||
|
||
private _mergeOptions = (): Options_Cli => { | ||
const _options = this.program.opts(); | ||
let options: Options_Cli = { | ||
..._options, | ||
force: _options["force"] === true, | ||
}; | ||
|
||
const buildOptions = this._getBuildOptions(); | ||
if (Object.keys(buildOptions).length > 0) { | ||
options = { | ||
...options, | ||
...buildOptions, | ||
}; | ||
} | ||
|
||
const deleteOptions = this._getDeleteOptions(); | ||
if (Object.keys(deleteOptions).length > 0) { | ||
options = { | ||
...options, | ||
...deleteOptions, | ||
}; | ||
} | ||
|
||
return options; | ||
}; | ||
|
||
private _validateOptions(options: Options_Cli) { | ||
const { data: rootData, error: rootError } = | ||
Schema_Options_Cli_Root.safeParse(options); | ||
if (rootError) { | ||
this.exitHelpfully( | ||
"root", | ||
`Invalid CLI options: ${rootError.toString()}` | ||
); | ||
} | ||
|
||
const { data: buildData, error: buildError } = | ||
Schema_Options_Cli_Build.safeParse(options); | ||
if (buildError) { | ||
this.exitHelpfully( | ||
"build", | ||
`Invalid build options: ${buildError.toString()}` | ||
); | ||
} | ||
|
||
const { data: deleteData, error: deleteError } = | ||
Schema_Options_Cli_Delete.safeParse(options); | ||
if (deleteError) { | ||
this.exitHelpfully( | ||
"delete", | ||
`Invalid delete options: ${deleteError.toString()}` | ||
); | ||
} | ||
|
||
const data: Options_Cli = { ...rootData, ...buildData, ...deleteData }; | ||
return data; | ||
} | ||
} |
Oops, something went wrong.