From 6312c0491c20c2cc1d8f0d610ac217a614a87c80 Mon Sep 17 00:00:00 2001 From: Patrick Sullivan Date: Sat, 9 Dec 2023 05:22:16 -0500 Subject: [PATCH] feat(cli): Added the `cli` package --- .../packages/file-system/api-report.md | 6 + .../file-system/documents-model.api.json | 45 +++++ package.json | 3 +- packages/cli/README.md | 185 ++++++++++++++++++ packages/cli/eslint.config.js | 31 +++ packages/cli/jest.config.ts | 3 + packages/cli/package.json | 22 +++ packages/cli/project.json | 53 +++++ packages/cli/src/index.ts | 13 ++ packages/cli/src/program/index.ts | 170 ++++++++++++++++ packages/cli/src/program/shutdown.ts | 65 ++++++ packages/cli/src/types.ts | 37 ++++ .../src/utilities}/create-cli-options.ts | 12 ++ .../src/cli => cli/src/utilities}/execute.ts | 18 ++ .../src/cli => cli/src/utilities}/index.ts | 0 packages/cli/tsconfig.json | 11 ++ packages/cli/tsconfig.spec.json | 13 ++ packages/file-system/src/index.ts | 2 +- .../src/package-management/package-fns.ts | 2 +- pnpm-lock.yaml | 107 +++++++++- tsconfig.base.json | 2 + 21 files changed, 796 insertions(+), 4 deletions(-) create mode 100644 packages/cli/README.md create mode 100644 packages/cli/eslint.config.js create mode 100644 packages/cli/jest.config.ts create mode 100644 packages/cli/package.json create mode 100644 packages/cli/project.json create mode 100644 packages/cli/src/index.ts create mode 100644 packages/cli/src/program/index.ts create mode 100644 packages/cli/src/program/shutdown.ts create mode 100644 packages/cli/src/types.ts rename packages/{file-system/src/cli => cli/src/utilities}/create-cli-options.ts (65%) rename packages/{file-system/src/cli => cli/src/utilities}/execute.ts (69%) rename packages/{file-system/src/cli => cli/src/utilities}/index.ts (100%) create mode 100644 packages/cli/tsconfig.json create mode 100644 packages/cli/tsconfig.spec.json diff --git a/docs/api-reports/packages/file-system/api-report.md b/docs/api-reports/packages/file-system/api-report.md index 1600a32e..bbb4d2ba 100644 --- a/docs/api-reports/packages/file-system/api-report.md +++ b/docs/api-reports/packages/file-system/api-report.md @@ -131,6 +131,12 @@ const FileSystemErrorCode: { export { FileSystemErrorCode }; export { FileSystemErrorCode as FileSystemErrorCode_alias_1 }; +// @public +function findFileExtension(filePath: string): string; +export { findFileExtension }; +export { findFileExtension as findFileExtension_alias_1 }; +export { findFileExtension as findFileExtension_alias_2 }; + // @public function findFileName(filePath: string): string; export { findFileName }; diff --git a/docs/api-reports/packages/file-system/documents-model.api.json b/docs/api-reports/packages/file-system/documents-model.api.json index d5df9048..a9308516 100644 --- a/docs/api-reports/packages/file-system/documents-model.api.json +++ b/docs/api-reports/packages/file-system/documents-model.api.json @@ -909,6 +909,51 @@ "endIndex": 46 } }, + { + "kind": "Function", + "canonicalReference": "@storm-stack/file-system!findFileExtension:function(1)", + "docComment": "/**\n * Find the file extension from a file path.\n *\n * @param filePath - The file path to process\n *\n * @returns The file extension\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function findFileExtension(filePath: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "packages/file-system/src/files/file-path-fns.ts", + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "filePath", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "name": "findFileExtension" + }, { "kind": "Function", "canonicalReference": "@storm-stack/file-system!findFileName:function(1)", diff --git a/package.json b/package.json index a6a10fe4..3c972ac4 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,8 @@ "@storm-stack/errors": "workspace:*", "@storm-stack/serialization": "workspace:*", "@storm-stack/logging": "workspace:*", - "@storm-stack/file-system": "workspace:*" + "@storm-stack/file-system": "workspace:*", + "@storm-stack/cli": "workspace:*" } }, "triggerEmptyDevReleaseByIncrementingThisNumber": 0 diff --git a/packages/cli/README.md b/packages/cli/README.md new file mode 100644 index 00000000..dbc362cf --- /dev/null +++ b/packages/cli/README.md @@ -0,0 +1,185 @@ + + + + + +
+ +
+
+Website | Contact | Repository | Documentation | Report a Bug | Request a Feature | Ask a Question +
+ +
+This package is part of the ⚑storm-stack monorepo. The storm-stack packages include CLI utility applications, tools, and various libraries used to create modern, scalable web applications. +
+ +

πŸ’» Visit stormsoftware.org to stay up to date with this developer


+ +[![Version](https://img.shields.io/badge/version-0.0.1-1fb2a6.svg?style=for-the-badge&color=1fb2a6)](https://prettier.io/)  +[![Nx](https://img.shields.io/badge/Nx-17.0.2-lightgrey?style=for-the-badge&logo=nx&logoWidth=20&&color=1fb2a6)](http://nx.dev/) [![NextJs](https://img.shields.io/badge/Next.js-14.0.2-lightgrey?style=for-the-badge&logo=nextdotjs&logoWidth=20&color=1fb2a6)](https://nextjs.org/) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=for-the-badge&logo=commitlint&color=1fb2a6)](http://commitizen.github.io/cz-cli/) ![Semantic-Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=for-the-badge&color=1fb2a6) [![documented with docusaurus](https://img.shields.io/badge/documented_with-docusaurus-success.svg?style=for-the-badge&logo=readthedocs&color=1fb2a6)](https://docusaurus.io/) ![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/storm-software/storm-ops/cr.yml?style=for-the-badge&logo=github-actions&color=1fb2a6) + +

⚠️ Attention ⚠️ This repository, and the apps, libraries, and tools contained within, is still in it's initial development phase. As a result, bugs and issues are expected with it's usage. When the main development phase completes, a proper release will be performed, the packages will be availible through NPM (and other distributions), and this message will be removed. However, in the meantime, please feel free to report any issues you may come across.


+ + + + + + + +# Command Line Utility Library + +A collection of CLI utilities to assist in creating command line applications + + + + +## Installing + +Using [pnpm](http://pnpm.io): + +```bash +pnpm add -D @storm-stack/cli +``` + +
+ Using npm + +```bash +npm install -D @storm-stack/cli +``` + +
+ +
+ Using yarn + +```bash +yarn add -D @storm-stack/cli +``` + +
+ +## Reduced Package Size + +This project uses [tsup](https://tsup.egoist.dev/) to package the source code due to its ability to remove unused code and ship smaller javascript files thanks to code splitting. This helps to greatly reduce the size of the package and to make it easier to use in other projects. + +## Development + +This project is built using [Nx](https://nx.dev). As a result, many of the usual commands are available to assist in development. + +### Building + +Run `nx build cli` to build the library. + +### Running unit tests + +Run `nx test cli` to execute the unit tests via [Jest](https://jestjs.io). + +### Linting + +Run `nx lint cli` to run [ESLint](https://eslint.org/) on the package. + + + + + + +## Storm Workspaces + +Storm workspaces are built using Nx, a set of extensible dev tools for monorepos, which helps you develop like Google, Facebook, and Microsoft. Building on top of Nx, the Open System provides a set of tools and patterns that help you scale your monorepo to many teams while keeping the codebase maintainable. + +## Roadmap + +See the [open issues](https://github.com/storm-software/storm-stack/issues) for a list of proposed features (and known issues). + +- [Top Feature Requests](https://github.com/storm-software/storm-stack/issues?q=label%3Aenhancement+is%3Aopen+sort%3Areactions-%2B1-desc) (Add your votes using the πŸ‘ reaction) +- [Top Bugs](https://github.com/storm-software/storm-stack/issues?q=is%3Aissue+is%3Aopen+label%3Abug+sort%3Areactions-%2B1-desc) (Add your votes using the πŸ‘ reaction) +- [Newest Bugs](https://github.com/storm-software/storm-stack/issues?q=is%3Aopen+is%3Aissue+label%3Abug) + +## Support + +Reach out to the maintainer at one of the following places: + +- [Contact](https://stormsoftware.org/contact) +- [GitHub discussions](https://github.com/storm-software/storm-stack/discussions) +- + +## License + +This project is licensed under the **Apache License 2.0**. Feel free to edit and distribute this template as you like. + +See [LICENSE](LICENSE) for more information. + +## Changelog + +This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Every release, along with the migration instructions, is documented in the [CHANGELOG](CHANGELOG.md) file + +## Contributing + +First off, thanks for taking the time to contribute! Contributions are what makes the open-source community such an amazing place to learn, inspire, and create. Any contributions you make will benefit everybody else and are **greatly appreciated**. + +Please try to create bug reports that are: + +- _Reproducible._ Include steps to reproduce the problem. +- _Specific._ Include as much detail as possible: which version, what environment, etc. +- _Unique._ Do not duplicate existing opened issues. +- _Scoped to a Single Bug._ One bug per report. + +Please adhere to this project's [code of conduct](.github/CODE_OF_CONDUCT.md). + +You can use [markdownlint-cli](https://github.com/storm-software/storm-stack/markdownlint-cli) to check for common markdown style inconsistency. + +## Contributors + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + + + + + + + +
Patrick Sullivan
Patrick Sullivan

🎨 πŸ’» πŸ”§ πŸ“– ⚠️
Tyler Benning
Tyler Benning

🎨
Stormie
Stormie

🚧
+ + Add your contributions + +
+ + + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! + +
+
+
+ +
+
+Website | Contact | LinkedIn | Medium | GitHub | OpenPGP Key +
+ +
+

Fingerprint: 1BD2 7192 7770 2549 F4C9 F238 E6AD C420 DA5C 4C2D

+
+ +Storm Software is an open source software development organization and creator of Acidic, StormStack and StormCloud. Our mission is to make software development more accessible. Our ideal future is one where anyone can create software without years of prior development experience serving as a barrier to entry. We hope to achieve this via LLMs, Generative AI, and intuitive, high-level data modeling/programming languagues. + +If this sounds interesting, and you would like to help us in creating the next generation of development tools, please reach out on our website! + +

πŸ’» Visit stormsoftware.org to stay up to date with this developer



+ + + + + + diff --git a/packages/cli/eslint.config.js b/packages/cli/eslint.config.js new file mode 100644 index 00000000..d75deb70 --- /dev/null +++ b/packages/cli/eslint.config.js @@ -0,0 +1,31 @@ +const { FlatCompat } = require("@eslint/eslintrc"); +const baseConfig = require("../../eslint.config.js"); +const js = require("@eslint/js"); + +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended +}); + +module.exports = [ + ...baseConfig, + { + files: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"], + rules: {} + }, + { + files: ["**/*.ts", "**/*.tsx"], + rules: {} + }, + { + files: ["**/*.js", "**/*.jsx"], + rules: {} + }, + ...compat.config({ parser: "jsonc-eslint-parser" }).map(config => ({ + ...config, + "files": ["packages/cli/**/*.json"], + "rules": { + "@nx/dependency-checks": "error" + } + })) +]; diff --git a/packages/cli/jest.config.ts b/packages/cli/jest.config.ts new file mode 100644 index 00000000..9cefcf86 --- /dev/null +++ b/packages/cli/jest.config.ts @@ -0,0 +1,3 @@ +import { getJestConfig } from "@storm-software/testing-tools"; + +export default getJestConfig("packages/cli", true, "cli"); diff --git a/packages/cli/package.json b/packages/cli/package.json new file mode 100644 index 00000000..ce18358b --- /dev/null +++ b/packages/cli/package.json @@ -0,0 +1,22 @@ +{ + "name": "@storm-stack/cli", + "version": "0.0.1", + "private": true, + "description": "A collection of CLI utilities to assist in creating command line applications.", + "repository": { + "type": "github", + "url": "https://github.com/storm-software/storm-stack.git", + "directory": "packages/cli" + }, + "type": "module", + "dependencies": { + "@storm-software/config-tools": "latest", + "chalk": "^5.3.0", + "commander": "^11.1.0", + "console-table-printer": "^2.11.2", + "ora": "^7.0.1" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/cli/project.json b/packages/cli/project.json new file mode 100644 index 00000000..7be2bd8f --- /dev/null +++ b/packages/cli/project.json @@ -0,0 +1,53 @@ +{ + "name": "cli", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "projectType": "library", + "sourceRoot": "packages/cli/src", + "targets": { + "build": { + "executor": "@storm-software/workspace-tools:tsup-node", + "outputs": ["{options.outputPath}"], + "options": { + "entry": "packages/cli/src/index.ts", + "outputPath": "dist/packages/cli", + "tsConfig": "packages/cli/tsconfig.json", + "project": "packages/cli/package.json", + "defaultConfiguration": "production", + "assets": [ + { + "input": "packages/cli", + "glob": "*.md", + "output": "/" + }, + { + "input": "", + "glob": "LICENSE", + "output": "/" + } + ], + "platform": "node" + }, + "configurations": { + "production": { + "debug": false, + "verbose": false + }, + "development": { + "debug": true, + "verbose": true + } + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": [ + "packages/cli/**/*.ts", + "{projectRoot}/package.json" + ] + } + }, + "test": {} + } +} diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts new file mode 100644 index 00000000..9340bbd5 --- /dev/null +++ b/packages/cli/src/index.ts @@ -0,0 +1,13 @@ +/** + * The cli library used by Storm Software for building TypeScript applications. + * + * @remarks + * A collection of CLI utilities to assist in creating command line applications + * + * @packageDocumentation + */ + +export * from "./program"; +export * from "./program/shutdown"; +export * from "./types"; +export * from "./utilities"; diff --git a/packages/cli/src/program/index.ts b/packages/cli/src/program/index.ts new file mode 100644 index 00000000..25769db9 --- /dev/null +++ b/packages/cli/src/program/index.ts @@ -0,0 +1,170 @@ +import { createStormConfig } from "@storm-software/config-tools"; +import { getCauseFromUnknown } from "@storm-stack/errors/storm-error"; +import { StormLog } from "@storm-stack/logging"; +import { EMPTY_STRING, NEWLINE_STRING } from "@storm-stack/utilities"; +import chalk from "chalk"; +import { AddHelpTextContext, Argument, Command, Option } from "commander"; +import { Table } from "console-table-printer"; +import { CLIArgument, CLICommand, CLIConfig, CLIOption } from "../types"; +import { registerShutdown } from "./shutdown"; + +const createCLICommand = (cliCommand: CLICommand): Command => { + const command = new Command(cliCommand.name); + command.description(cliCommand.description ?? EMPTY_STRING); + if (cliCommand.commands) { + cliCommand.commands.forEach(_cliCommand => + command.addCommand(createCLICommand(_cliCommand)) + ); + } + if (cliCommand.options) { + cliCommand.options.forEach(_cliOption => + command.addOption(createCLIOption(_cliOption)) + ); + } + if (cliCommand.argument) { + cliCommand.argument.forEach(_cliArgument => + command.addArgument(createCLIArgument(_cliArgument)) + ); + } + + command.action(cliCommand.action); + return command; +}; + +const createCLIArgument = (cliArgument: CLIArgument): Argument => { + const argument = new Argument( + cliArgument.flags, + cliArgument.description ?? EMPTY_STRING + ); + if (cliArgument.default) { + argument.default; + } + + return argument; +}; + +const createCLIOption = (cliOption: CLIOption): Option => { + const option = new Option( + cliOption.flags, + cliOption.description ?? EMPTY_STRING + ); + if (cliOption.choices) { + option.choices(cliOption.choices); + } + if (cliOption.default) { + option.default(cliOption.default.value, cliOption.default.description); + } + + return option; +}; + +export const createCLIProgram = async (cliConfig: CLIConfig): Promise => { + const config = createStormConfig(); + const logger = StormLog.create(config); + + try { + logger.info(`Starting ${cliConfig.name ?? "Storm CLI Application"}`); + logger.start(cliConfig.name ?? "Storm CLI Application"); + + const program = new Command(cliConfig.name ?? "Storm CLI Application"); + const shutdown = registerShutdown({ + logger, + onShutdown: () => { + logger.stopwatch("Storm CLI Application"); + program.exitOverride(); + + logger.info("Application is shutting down..."); + } + }); + + try { + program.hook("preAction", cliConfig.preAction); + program.hook("postAction", cliConfig.postAction); + + program.version("v1.0.0", "-v --version", "display CLI version"); + program + .description(`${chalk.bold.blue("⚑")} ${cliConfig.description}`) + .showHelpAfterError() + .showSuggestionAfterError(); + + createCLICommand(program); + + program + .addHelpCommand("help [cmd]", "display help for [cmd]") + .addHelpText("beforeAll", "Welcome to Storm CLI Application!") + .addHelpText( + "afterAll", + "For more information, please visit " + ) + .addHelpText("before", (context: AddHelpTextContext) => { + return cliConfig.commands + .map((command: CLICommand) => { + const table = new Table({ + style: { + headerTop: { + left: chalk.hex(config.colors.background)("β•”"), + mid: chalk.hex(config.colors.background)("╦"), + right: chalk.hex(config.colors.background)("β•—"), + other: chalk.hex(config.colors.background)("═") + }, + headerBottom: { + left: chalk.hex(config.colors.background)("β•Ÿ"), + mid: chalk.hex(config.colors.background)("╬"), + right: chalk.hex(config.colors.background)("β•’"), + other: chalk.hex(config.colors.background)("═") + }, + tableBottom: { + left: chalk.hex(config.colors.background)("β•š"), + mid: chalk.hex(config.colors.background)("β•©"), + right: chalk.hex(config.colors.background)("╝"), + other: chalk.hex(config.colors.background)("═") + }, + vertical: chalk.hex(config.colors.background)("β•‘") + }, + title: command.name, + columns: [ + { name: "flags", title: "Flags", alignment: "left" }, + { + name: "description", + title: "Description", + alignment: "left" + }, + { name: "options", title: "Options", alignment: "left" }, + { + name: "defaultValue", + title: "Default Value", + alignment: "left" + } + ] + }); + + // add rows with color + command.options?.forEach(option => { + table.addRow( + { + flags: option.flags, + description: option.description ?? EMPTY_STRING, + options: option.choices?.join(", ") ?? EMPTY_STRING, + defaultValue: option.default?.value ?? EMPTY_STRING + }, + { color: config.colors.primary } + ); + }); + + return table.render(); + }) + .join(NEWLINE_STRING + NEWLINE_STRING + NEWLINE_STRING); + }); + + await program.parseAsync(process.argv); + + shutdown(); + } catch (innerError) { + logger.fatal(innerError); + shutdown(getCauseFromUnknown(innerError).message); + } + } catch (error) { + logger.fatal(error); + process.exit(1); + } +}; diff --git a/packages/cli/src/program/shutdown.ts b/packages/cli/src/program/shutdown.ts new file mode 100644 index 00000000..3ab5de2a --- /dev/null +++ b/packages/cli/src/program/shutdown.ts @@ -0,0 +1,65 @@ +import { StormLog } from "@storm-stack/logging"; +import { MaybePromise } from "@storm-stack/utilities"; + +const errorTypes = ["unhandledRejection", "uncaughtException"]; +const signalTraps = ["SIGTERM", "SIGINT", "SIGUSR2"]; + +export function registerShutdown(config: { + logger: StormLog; + onShutdown(): void | MaybePromise; +}): (reason?: string) => Promise { + let exited = false; + + async function shutdown() { + if (exited) { + return; + } + config.logger.info("Shutting down..."); + exited = true; + await config.onShutdown(); + } + + errorTypes.map(type => { + process.on(type, async e => { + try { + config.logger.info(`process.on ${type}`); + config.logger.error(e); + await shutdown(); + config.logger.info(`shutdown process done, exiting with code 0`); + process.exit(0); + } catch (e) { + config.logger.warn(`shutdown process failed, exiting with code 1`); + config.logger.error(e); + process.exit(1); + } + }); + }); + + signalTraps.map(type => { + process.once(type, async () => { + try { + config.logger.info(`process.on ${type}`); + await shutdown(); + config.logger.info(`shutdown process done, exiting with code 0`); + process.exit(0); + } catch (e) { + config.logger.warn(`shutdown process failed, exiting with code 1`); + config.logger.error(e); + process.exit(1); + } + }); + }); + + return async (reason?: string) => { + try { + config.logger.info(`Manual shutdown ${reason ? `(${reason})` : ""}`); + await shutdown(); + config.logger.info(`shutdown process done, exiting with code 0`); + process.exit(0); + } catch (e) { + config.logger.warn(`shutdown process failed, exiting with code 1`); + config.logger.error(e); + process.exit(1); + } + }; +} diff --git a/packages/cli/src/types.ts b/packages/cli/src/types.ts new file mode 100644 index 00000000..3ed1dd16 --- /dev/null +++ b/packages/cli/src/types.ts @@ -0,0 +1,37 @@ +import { MaybePromise } from "@storm-stack/utilities"; +import { Command } from "commander"; + +export type CLIConfig = { + name: string; + description: string; + commands: CLICommand[]; + preAction: (command: Command) => MaybePromise; + postAction: (command: Command) => MaybePromise; +}; + +export type CLICommand = { + name: string; + description: string; + commands?: CLICommand[]; + options?: CLIOption[]; + argument?: CLIArgument[]; + action: (...args: any[]) => MaybePromise; +}; + +export type CLIArgument = { + flags: string; + description?: string; + default?: unknown | undefined; +}; + +export type CLIOption = { + flags: string; + description: string | undefined; + choices?: string[]; + default?: CLIOptionDefault; +}; + +export type CLIOptionDefault = { + value: unknown; + description?: string | undefined; +}; diff --git a/packages/file-system/src/cli/create-cli-options.ts b/packages/cli/src/utilities/create-cli-options.ts similarity index 65% rename from packages/file-system/src/cli/create-cli-options.ts rename to packages/cli/src/utilities/create-cli-options.ts index 30943c75..266fe0fa 100644 --- a/packages/file-system/src/cli/create-cli-options.ts +++ b/packages/cli/src/utilities/create-cli-options.ts @@ -1,3 +1,9 @@ +/** + * Create CLI options from an object. + * + * @param obj - The object to create CLI options from + * @returns The CLI options + */ export function createCliOptions( obj: Record ): string[] { @@ -13,6 +19,12 @@ export function createCliOptions( ); } +/** + * Create CLI options from an object and join them into a string. + * + * @param obj - The object to create CLI options from + * @returns The CLI options as a string + */ export function createCliOptionsString( obj: Record ): string { diff --git a/packages/file-system/src/cli/execute.ts b/packages/cli/src/utilities/execute.ts similarity index 69% rename from packages/file-system/src/cli/execute.ts rename to packages/cli/src/utilities/execute.ts index 53c08279..1978b1d1 100644 --- a/packages/file-system/src/cli/execute.ts +++ b/packages/cli/src/utilities/execute.ts @@ -10,6 +10,15 @@ import { import { Readable } from "node:stream"; import { promisify } from "node:util"; +/** + * Execute a command. + * + * @param command - The command to execute + * @param options - The options to use when executing the command + * @param env - The environment variables to use when executing the command + * @param stdio - The stdio options to use when executing the command + * @returns The result of the command + */ export const execute = ( command: string, options: ExecOptions = {}, @@ -42,6 +51,15 @@ export const execute = ( } }; +/** + * Execute a command asynchronously. + * + * @param command - The command to execute + * @param options - The options to use when executing the command + * @param env - The environment variables to use when executing the command + * @param stdio - The stdio options to use when executing the command + * @returns The result of the command + */ export const executeAsync = async ( command: string, options?: ExecOptions, diff --git a/packages/file-system/src/cli/index.ts b/packages/cli/src/utilities/index.ts similarity index 100% rename from packages/file-system/src/cli/index.ts rename to packages/cli/src/utilities/index.ts diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json new file mode 100644 index 00000000..d3928740 --- /dev/null +++ b/packages/cli/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "noEmit": true + }, + "files": [], + "include": ["src/**/*.ts", "src/**/*.js", "bin/**/*"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], + "composite": true +} diff --git a/packages/cli/tsconfig.spec.json b/packages/cli/tsconfig.spec.json new file mode 100644 index 00000000..d41aea47 --- /dev/null +++ b/packages/cli/tsconfig.spec.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/packages/file-system/src/index.ts b/packages/file-system/src/index.ts index 6488957c..280777fc 100644 --- a/packages/file-system/src/index.ts +++ b/packages/file-system/src/index.ts @@ -7,7 +7,7 @@ * @packageDocumentation */ -export * from "./cli"; +export * from "../../cli/src/utilities"; export * from "./errors"; export * from "./files"; export * from "./package-management"; diff --git a/packages/file-system/src/package-management/package-fns.ts b/packages/file-system/src/package-management/package-fns.ts index c1637e42..cce7e3cc 100644 --- a/packages/file-system/src/package-management/package-fns.ts +++ b/packages/file-system/src/package-management/package-fns.ts @@ -1,5 +1,5 @@ import { basename, resolve } from "path"; -import { execute } from "../cli/execute"; +import { execute } from "../../../cli/src/utilities/execute"; import { exists } from "../files/exists"; import { joinPaths } from "../files/join-paths"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 55688f81..6bf714ab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,6 +12,7 @@ overrides: "@storm-stack/serialization": workspace:* "@storm-stack/logging": workspace:* "@storm-stack/file-system": workspace:* + "@storm-stack/cli": workspace:* importers: .: @@ -152,6 +153,24 @@ importers: specifier: ^5.29.0 version: 5.29.0(typanion@3.14.0) + packages/cli: + dependencies: + "@storm-software/config-tools": + specifier: ^1.2.14 + version: 1.2.14(typescript@5.3.3) + chalk: + specifier: ^5.3.0 + version: 5.3.0 + commander: + specifier: ^11.1.0 + version: 11.1.0 + console-table-printer: + specifier: ^2.11.2 + version: 2.11.2 + ora: + specifier: ^7.0.1 + version: 7.0.1 + packages/date-time: dependencies: "@js-temporal/polyfill": @@ -4469,7 +4488,7 @@ packages: "@nrwl/esbuild": 17.0.3(@swc-node/register@1.6.8)(@swc/core@1.3.100)(@types/node@20.9.0)(esbuild@0.19.8)(nx@17.0.3)(typescript@5.3.3)(verdaccio@5.29.0) "@nx/devkit": 17.0.3(nx@17.0.3) "@nx/js": 17.0.3(@swc-node/register@1.6.8)(@swc/core@1.3.100)(@types/node@20.9.0)(nx@17.0.3)(typescript@5.3.3)(verdaccio@5.29.0) - chalk: 4.1.0 + chalk: 4.1.2 esbuild: 0.19.8 fast-glob: 3.2.7 fs-extra: 11.2.0 @@ -6187,6 +6206,18 @@ packages: - typescript dev: false + /@storm-software/config-tools@1.2.14(typescript@5.3.3): + resolution: + { + integrity: sha512-Pozk1IHYZCeVhXYP5uVgpzDmoduyJVZthShWY09jd4aAHvon9aUwT7scMuGcIClWVzWI9oCmE/R7zT+yHVS2xg== + } + dependencies: + cosmiconfig: 9.0.0(typescript@5.3.3) + zod: 3.22.4 + transitivePeerDependencies: + - typescript + dev: false + /@storm-software/git-tools@1.14.8(@swc-node/register@1.6.8)(@swc/core@1.3.100)(typescript@5.3.3): resolution: { @@ -8543,6 +8574,17 @@ packages: readable-stream: 3.6.2 dev: false + /bl@5.1.0: + resolution: + { + integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ== + } + dependencies: + buffer: 6.0.3 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + /blob@0.0.5: resolution: { @@ -9867,6 +9909,15 @@ packages: } dev: false + /console-table-printer@2.11.2: + resolution: + { + integrity: sha512-uuUHie0sfPP542TKGzPFal0W1wo1beuKAqIZdaavcONx8OoqdnJRKjkinbRTOta4FaCa1RcIL+7mMJWX3pQGVg== + } + dependencies: + simple-wcswidth: 1.0.1 + dev: false + /constants-browserify@1.0.0: resolution: { @@ -14597,6 +14648,14 @@ packages: engines: { node: ">=8" } dev: false + /is-interactive@2.0.0: + resolution: + { + integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ== + } + engines: { node: ">=12" } + dev: false + /is-nan@1.3.2: resolution: { @@ -16395,6 +16454,17 @@ packages: is-unicode-supported: 0.1.0 dev: false + /log-symbols@5.1.0: + resolution: + { + integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA== + } + engines: { node: ">=12" } + dependencies: + chalk: 5.3.0 + is-unicode-supported: 1.3.0 + dev: false + /log-update@6.0.0: resolution: { @@ -19799,6 +19869,24 @@ packages: wcwidth: 1.0.1 dev: false + /ora@7.0.1: + resolution: + { + integrity: sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw== + } + engines: { node: ">=16" } + dependencies: + chalk: 5.3.0 + cli-cursor: 4.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 1.3.0 + log-symbols: 5.1.0 + stdin-discarder: 0.1.0 + string-width: 6.1.0 + strip-ansi: 7.1.0 + dev: false + /os-browserify@0.3.0: resolution: { @@ -22739,6 +22827,13 @@ packages: - supports-color dev: false + /simple-wcswidth@1.0.1: + resolution: + { + integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg== + } + dev: false + /sirv@1.0.19: resolution: { @@ -23245,6 +23340,16 @@ packages: engines: { node: ">= 0.8" } dev: false + /stdin-discarder@0.1.0: + resolution: + { + integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ== + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + dependencies: + bl: 5.1.0 + dev: false + /steno@0.4.4: resolution: { diff --git a/tsconfig.base.json b/tsconfig.base.json index ff506955..468ca8a7 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -6,6 +6,8 @@ "rootDir": ".", "baseUrl": ".", "paths": { + "@storm-stack/cli": ["packages/cli/src/index.ts"], + "@storm-stack/cli/*": ["packages/cli/src/*"], "@storm-stack/date-time": ["packages/date-time/src/index.ts"], "@storm-stack/date-time/*": ["packages/date-time/src/*"], "@storm-stack/errors": ["packages/errors/src/index.ts"],