diff --git a/package-lock.json b/package-lock.json index 42bcef3..2d7c645 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,18 +15,18 @@ "columnify": "^1.6.0", "commander": "^9.5.0", "figlet": "^1.7.0", - "inquirer": "^9.2.13", + "inquirer": "^9.2.14", "log-update": "^5.0.1", "ora": "^6.3.1" }, "devDependencies": { - "@athenna/common": "^4.34.0", - "@athenna/config": "^4.16.0", - "@athenna/ioc": "^4.16.0", - "@athenna/logger": "^4.17.0", + "@athenna/common": "^4.35.0", + "@athenna/config": "^4.18.0", + "@athenna/ioc": "^4.18.0", + "@athenna/logger": "^4.18.0", "@athenna/test": "^4.22.0", "@athenna/tsconfig": "^4.12.0", - "@athenna/view": "^4.18.0", + "@athenna/view": "^4.20.0", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "commitizen": "^4.2.6", @@ -101,9 +101,9 @@ "dev": true }, "node_modules/@athenna/common": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@athenna/common/-/common-4.34.0.tgz", - "integrity": "sha512-2rIUEB4M7AsUXC8wNotTrVmuFj2PpJao41otaM3yMa7A8rc7c+aRIMHgX/IMk4wfOy3ajdF5v9cEkn6W/6skUw==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@athenna/common/-/common-4.35.0.tgz", + "integrity": "sha512-f5JRdrjdozbtHjG0YgqVLXv6fjmss7PKAQWeyqGLg4dpGmheZ19xXYONZYf3ng6d0k2+YQ7IjLzGmfwSsrO+wA==", "dev": true, "dependencies": { "@fastify/formbody": "^7.4.0", @@ -114,7 +114,7 @@ "collect.js": "^4.36.1", "csv-parser": "^3.0.0", "execa": "^8.0.1", - "fastify": "^4.26.0", + "fastify": "^4.26.1", "got": "^12.6.1", "http-status-codes": "^2.2.0", "is-wsl": "^2.2.0", @@ -156,12 +156,12 @@ } }, "node_modules/@athenna/config": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@athenna/config/-/config-4.16.0.tgz", - "integrity": "sha512-uR0hyTApbaOp1YK143BkeczeygbU8SmLHnJLwRAweplauDydRW8TZw9pETO1w1TwMnK6iDobjl/GX2NWoid6rw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@athenna/config/-/config-4.18.0.tgz", + "integrity": "sha512-nAxoFSJoNF63gJY582J42sFFN0NMsk4jL4rtZKfTKb6URICoO/1rv6DqNc6hBSeiJoLDLZTO72QUzyty+iDfKw==", "dev": true, "dependencies": { - "dotenv": "^16.4.0", + "dotenv": "^16.4.1", "magicast": "^0.3.3", "syntax-error": "^1.4.0" }, @@ -170,9 +170,9 @@ } }, "node_modules/@athenna/ioc": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@athenna/ioc/-/ioc-4.16.0.tgz", - "integrity": "sha512-oq6PP26VMOmdyMqTbv/iaGrP1ACK7mVVsyAyTc+z8xrpLyAeQ++r53bAK7obZz+LIPDNNPd/cgmk6WH0zq6paA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@athenna/ioc/-/ioc-4.18.0.tgz", + "integrity": "sha512-Ocz7Miaj5dvtnp66brol9Bf6vU97XaBfeXP+RfQtzSyyQs70nSIvCmIXK4oAya15OqHFpqJtR6JXikkQuOVIXw==", "dev": true, "dependencies": { "awilix": "^7.0.3" @@ -182,9 +182,9 @@ } }, "node_modules/@athenna/logger": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@athenna/logger/-/logger-4.17.0.tgz", - "integrity": "sha512-Xlaz56JVyyy4BrsaqGlHyR2WahDN7aW4r+WdkYDU40EluOFeisSBg/dR8PBZzIohMUFZEJHye+G+d7DoNEGNDg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@athenna/logger/-/logger-4.18.0.tgz", + "integrity": "sha512-mUGqj5Guh6ZdYflijGAdnn6Zrse2I7SG9fj5jMxSdrQ3hFMCGIgpWIk/ctXCGhPnsHlrVfAmEJeqnCxbtaytZQ==", "dev": true, "dependencies": { "@aws-lambda-powertools/logger": "^1.18.0", @@ -227,9 +227,9 @@ } }, "node_modules/@athenna/view": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@athenna/view/-/view-4.18.0.tgz", - "integrity": "sha512-PnBShkzzXeGtI2kfYOfN7JmE/Y+vpDRx7QDGyHhpH9vzyDG8tMABq34kkLjyiY2EgNtm25ZmYERQV8N3IFL/jQ==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@athenna/view/-/view-4.20.0.tgz", + "integrity": "sha512-eAoCPn53GM5zGU9lY0rTNnv8PTSmYNMauy1w9/8BE0OAuedN0a0qVt2W1E1m9IJDsYd29dmV/K63xL6fOR8Ydw==", "dev": true, "dependencies": { "edge.js": "^6.0.1" @@ -6610,9 +6610,9 @@ "dev": true }, "node_modules/inquirer": { - "version": "9.2.13", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.13.tgz", - "integrity": "sha512-mUlJNemjYioZgaZXqEFlQ0z9GD8/o+pavIF3JyhzWLX4Xa9M1wioGMCxQEFmps70un9lrah2WaBl3kSRVcoV3g==", + "version": "9.2.15", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz", + "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==", "dependencies": { "@ljharb/through": "^2.3.12", "ansi-escapes": "^4.3.2", @@ -6631,7 +6631,7 @@ "wrap-ansi": "^6.2.0" }, "engines": { - "node": ">=14.18.0" + "node": ">=18" } }, "node_modules/inquirer/node_modules/ansi-styles": { diff --git a/package.json b/package.json index a9aa9f6..c65e09d 100644 --- a/package.json +++ b/package.json @@ -71,18 +71,18 @@ "columnify": "^1.6.0", "commander": "^9.5.0", "figlet": "^1.7.0", - "inquirer": "^9.2.13", + "inquirer": "^9.2.14", "log-update": "^5.0.1", "ora": "^6.3.1" }, "devDependencies": { - "@athenna/common": "^4.34.0", - "@athenna/config": "^4.16.0", - "@athenna/ioc": "^4.16.0", - "@athenna/logger": "^4.17.0", + "@athenna/common": "^4.35.0", + "@athenna/config": "^4.18.0", + "@athenna/ioc": "^4.18.0", + "@athenna/logger": "^4.18.0", "@athenna/test": "^4.22.0", "@athenna/tsconfig": "^4.12.0", - "@athenna/view": "^4.18.0", + "@athenna/view": "^4.20.0", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "commitizen": "^4.2.6", diff --git a/src/artisan/BaseCommand.ts b/src/artisan/BaseCommand.ts index ffc94ba..26ca0e2 100644 --- a/src/artisan/BaseCommand.ts +++ b/src/artisan/BaseCommand.ts @@ -9,6 +9,7 @@ import { Rc } from '@athenna/config' import { Color } from '@athenna/common' +import { Npm } from '#src/helpers/command/Npm' import { Prompt } from '#src/helpers/command/Prompt' import { Logger } from '#src/helpers/command/Logger' import { Annotation } from '#src/helpers/Annotation' @@ -73,12 +74,21 @@ export abstract class BaseCommand { /** * The generator used to make files. The generator uses the - * athenna/view package to generate files from templates. A + * `@athenna/view` package to generate files from templates. A * briefly knowledge about how to setup templates inside - * athenna/view is very good to use this helper. + * `@athenna/view` is very good to use this helper. */ public generator = new Generator() + /** + * Use the npm helper to perform operations inside child + * processes for linking and installing dependencies using + * any kind of registry. The npm registry will always be the + * default registry, but you can change it setting the registry + * in options. + */ + public npm = new Npm() + /** * Execute the command setting args and options in the class */ diff --git a/src/artisan/BaseConfigurer.ts b/src/artisan/BaseConfigurer.ts index 9e239b0..23e0fe5 100644 --- a/src/artisan/BaseConfigurer.ts +++ b/src/artisan/BaseConfigurer.ts @@ -10,6 +10,7 @@ import { Rc } from '@athenna/config' import { Color } from '@athenna/common' import { parse, resolve } from 'node:path' +import { Npm } from '#src/helpers/command/Npm' import { Prompt } from '#src/helpers/command/Prompt' import { Logger } from '#src/helpers/command/Logger' import { Generator } from '#src/helpers/command/Generator' @@ -60,12 +61,21 @@ export abstract class BaseConfigurer { /** * The generator used to make files. The generator uses the - * athenna/view package to generate files from templates. A + * `@athenna/view` package to generate files from templates. A * briefly knowledge about how to setup templates inside - * athenna/view is very good to use this helper. + * `@athenna/view` is very good to use this helper. */ public generator = new Generator() + /** + * Use the npm helper to perform operations inside child + * processes for linking and installing dependencies using + * any kind of registry. The npm registry will always be the + * default registry, but you can change it setting the registry + * in options. + */ + public npm = new Npm() + /** * Set the path of the configurer. */ diff --git a/src/commands/ConfigureCommand.ts b/src/commands/ConfigureCommand.ts index 11d08c6..d707d32 100644 --- a/src/commands/ConfigureCommand.ts +++ b/src/commands/ConfigureCommand.ts @@ -9,7 +9,7 @@ import { extname, resolve } from 'node:path' import { Argument, BaseCommand } from '#src' -import { File, Module } from '@athenna/common' +import { Path, File, Module } from '@athenna/common' import { NotFoundLibraryException } from '#src/exceptions/NotFoundLibraryException' import { NotFoundConfigurerException } from '#src/exceptions/NotFoundConfigurerException' diff --git a/src/commands/TemplateCustomizeCommand.ts b/src/commands/TemplateCustomizeCommand.ts index 68f4f69..db3250c 100644 --- a/src/commands/TemplateCustomizeCommand.ts +++ b/src/commands/TemplateCustomizeCommand.ts @@ -8,7 +8,7 @@ */ import { BaseCommand } from '#src' -import { Exec, File } from '@athenna/common' +import { Path, Exec, File } from '@athenna/common' import { resolve, relative, isAbsolute } from 'node:path' export class TemplateCustomizeCommand extends BaseCommand { diff --git a/src/helpers/command/Generator.ts b/src/helpers/command/Generator.ts index 9592789..541f55d 100644 --- a/src/helpers/command/Generator.ts +++ b/src/helpers/command/Generator.ts @@ -8,7 +8,7 @@ */ import { View } from '@athenna/view' -import { File, String } from '@athenna/common' +import { Path, File, String } from '@athenna/common' import { sep, resolve, isAbsolute } from 'node:path' import { AlreadyExistFileException } from '#src/exceptions/AlreadyExistFileException' diff --git a/src/helpers/command/Npm.ts b/src/helpers/command/Npm.ts new file mode 100644 index 0000000..cb942d0 --- /dev/null +++ b/src/helpers/command/Npm.ts @@ -0,0 +1,46 @@ +/** + * @athenna/artisan + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { + Exec, + type LinkPackageOptions, + type InstallPackageOptions +} from '@athenna/common' + +export class Npm { + /** + * Run `npm link` command inside a child process. + * + * @example + * ```ts + * await this.npm.link('@athenna/common') + * ``` + * + * By default the registry used will be `npm`, but you + * can change it by adding your registry in options: + * + * @example + * ```ts + * await this.npm.link('@athenna/common', { registry: 'yarn' }) + * ``` + */ + public async link( + libraries: string | string[], + options?: LinkPackageOptions + ) { + return Exec.link(libraries, options) + } + + public async install( + libraries: string | string[], + options?: InstallPackageOptions + ) { + return Exec.install(libraries, options) + } +} diff --git a/src/kernels/ConsoleKernel.ts b/src/kernels/ConsoleKernel.ts index bca4a5f..05763ea 100644 --- a/src/kernels/ConsoleKernel.ts +++ b/src/kernels/ConsoleKernel.ts @@ -8,7 +8,7 @@ */ import { sep, isAbsolute, resolve } from 'node:path' -import { Exec, File, Is, Module } from '@athenna/common' +import { Path, Exec, File, Is, Module } from '@athenna/common' import { Artisan, CommanderHandler, ConsoleExceptionHandler } from '#src' export class ConsoleKernel { diff --git a/src/testing/plugins/command/TestCommand.ts b/src/testing/plugins/command/TestCommand.ts index ff976df..6d88a89 100644 --- a/src/testing/plugins/command/TestCommand.ts +++ b/src/testing/plugins/command/TestCommand.ts @@ -9,7 +9,7 @@ import { Artisan } from '#src' import { Assert } from '@japa/assert' -import type { CommandOutput } from '@athenna/common' +import { Path, type CommandOutput } from '@athenna/common' import { TestOutput } from '#src/testing/plugins/command/TestOutput' import type { CallInChildOptions } from '#src/types/CallInChildOptions' @@ -17,7 +17,7 @@ export class TestCommand { /** * The Artisan file path that will be used to run commands. * - * @default 'Path.bootstrap(`console.${Path.ext()}`)' + * @default Path.bootstrap(`console.${Path.ext()}`) */ public static artisanPath = Path.bootstrap(`console.${Path.ext()}`) diff --git a/tests/fixtures/consoles/base-command.ts b/tests/fixtures/consoles/base-command.ts index 44da5ae..17acabb 100644 --- a/tests/fixtures/consoles/base-command.ts +++ b/tests/fixtures/consoles/base-command.ts @@ -7,6 +7,7 @@ * file that was distributed with this source code. */ +import { Path } from '@athenna/common' import { Config, Rc } from '@athenna/config' import { ViewProvider } from '@athenna/view' import { Artisan, ArtisanProvider } from '#src' diff --git a/tests/fixtures/consoles/console-mock-dest-import.ts b/tests/fixtures/consoles/console-mock-dest-import.ts index e60a50c..939213d 100644 --- a/tests/fixtures/consoles/console-mock-dest-import.ts +++ b/tests/fixtures/consoles/console-mock-dest-import.ts @@ -7,10 +7,10 @@ * file that was distributed with this source code. */ -import { Artisan, ArtisanProvider } from '#src' - -import { Config, Rc } from '@athenna/config' +import { Path } from '@athenna/common' import { ViewProvider } from '@athenna/view' +import { Config, Rc } from '@athenna/config' +import { Artisan, ArtisanProvider } from '#src' import { ListCommand } from '#src/commands/ListCommand' import { ConfigureCommand } from '#src/commands/ConfigureCommand' import { MakeCommandCommand } from '#src/commands/MakeCommandCommand' diff --git a/tests/fixtures/consoles/console-mock-library.ts b/tests/fixtures/consoles/console-mock-library.ts index 065f4fe..9ed8257 100644 --- a/tests/fixtures/consoles/console-mock-library.ts +++ b/tests/fixtures/consoles/console-mock-library.ts @@ -8,12 +8,11 @@ */ import { Mock } from '@athenna/test' -import { BaseConfigurer, Artisan, ArtisanProvider } from '#src' -import { File, Module } from '@athenna/common' - import { Config, Rc } from '@athenna/config' import { ViewProvider } from '@athenna/view' +import { Path, File, Module } from '@athenna/common' import { ListCommand } from '#src/commands/ListCommand' +import { BaseConfigurer, Artisan, ArtisanProvider } from '#src' import { ConfigureCommand } from '#src/commands/ConfigureCommand' import { MakeCommandCommand } from '#src/commands/MakeCommandCommand' import { TemplateCustomizeCommand } from '#src/commands/TemplateCustomizeCommand' diff --git a/tests/fixtures/consoles/console-mock-test-template.ts b/tests/fixtures/consoles/console-mock-test-template.ts index 8b10818..95c1ce9 100644 --- a/tests/fixtures/consoles/console-mock-test-template.ts +++ b/tests/fixtures/consoles/console-mock-test-template.ts @@ -1,8 +1,16 @@ -import { File, Path } from '@athenna/common' -import { Artisan, ArtisanProvider } from '#src' +/** + * @athenna/artisan + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ import { Config, Rc } from '@athenna/config' +import { File, Path } from '@athenna/common' import { ViewProvider } from '@athenna/view' +import { Artisan, ArtisanProvider } from '#src' import { ListCommand } from '#src/commands/ListCommand' import { ConfigureCommand } from '#src/commands/ConfigureCommand' import { MakeCommandCommand } from '#src/commands/MakeCommandCommand' diff --git a/tests/fixtures/routes/console.ts b/tests/fixtures/routes/console.ts index 24f59da..bc9fde9 100644 --- a/tests/fixtures/routes/console.ts +++ b/tests/fixtures/routes/console.ts @@ -1,3 +1,12 @@ +/** + * @athenna/artisan + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Artisan } from '#src' Artisan.route('test:one', async function () {}) diff --git a/tests/unit/artisan/ArtisanTest.ts b/tests/unit/artisan/ArtisanTest.ts index fd9bc41..f22b376 100644 --- a/tests/unit/artisan/ArtisanTest.ts +++ b/tests/unit/artisan/ArtisanTest.ts @@ -7,6 +7,7 @@ * file that was distributed with this source code. */ +import { Path } from '@athenna/common' import { BaseTest } from '#tests/helpers/BaseTest' import { Test, type Context, Mock } from '@athenna/test' import { Annotation, Artisan, CommanderHandler } from '#src' diff --git a/tests/unit/commands/ConfigureCommandTest.ts b/tests/unit/commands/ConfigureCommandTest.ts index e8bafe1..8a20b8b 100644 --- a/tests/unit/commands/ConfigureCommandTest.ts +++ b/tests/unit/commands/ConfigureCommandTest.ts @@ -7,6 +7,7 @@ * file that was distributed with this source code. */ +import { Path } from '@athenna/common' import { BaseTest } from '#tests/helpers/BaseTest' import { Test, type Context } from '@athenna/test' diff --git a/tests/unit/commands/TemplateCustomizeCommandTest.ts b/tests/unit/commands/TemplateCustomizeCommandTest.ts index 48e165d..dfebf26 100644 --- a/tests/unit/commands/TemplateCustomizeCommandTest.ts +++ b/tests/unit/commands/TemplateCustomizeCommandTest.ts @@ -7,9 +7,9 @@ * file that was distributed with this source code. */ -import { File, Folder } from '@athenna/common' import { BaseTest } from '#tests/helpers/BaseTest' import { Test, type Context } from '@athenna/test' +import { Path, File, Folder } from '@athenna/common' export default class TemplateCustomizeCommandTest extends BaseTest { @Test() @@ -37,6 +37,8 @@ export default class TemplateCustomizeCommandTest extends BaseTest { path: Path.fixtures('consoles/console-mock-test-template.ts') }) + console.log(output.output.stderr) + const { athenna } = await new File(Path.pwd('package.json')).getContentAsJson() output.assertSucceeded() diff --git a/tests/unit/helpers/TaskTest.ts b/tests/unit/helpers/TaskTest.ts index 99a4b92..1d472be 100644 --- a/tests/unit/helpers/TaskTest.ts +++ b/tests/unit/helpers/TaskTest.ts @@ -8,9 +8,9 @@ */ import { Task } from '#src/helpers/Task' +import { Path, Exec } from '@athenna/common' import { Test, BeforeEach, type Context } from '@athenna/test' import { RunningTaskException } from '#src/exceptions/RunningTaskException' -import { Exec } from '@athenna/common' export default class TaskTest { @BeforeEach() diff --git a/tests/unit/helpers/command/NpmTest.ts b/tests/unit/helpers/command/NpmTest.ts new file mode 100644 index 0000000..f8a16aa --- /dev/null +++ b/tests/unit/helpers/command/NpmTest.ts @@ -0,0 +1,44 @@ +/** + * @athenna/artisan + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Exec } from '@athenna/common' +import { Npm } from '#src/helpers/command/Npm' +import { Test, BeforeEach, type Context, Mock, AfterEach } from '@athenna/test' + +export default class NpmTest { + private npm = new Npm() + + @BeforeEach() + public async beforeEach() { + this.npm = new Npm() + } + + @AfterEach() + public async afterEach() { + Mock.restoreAll() + } + + @Test() + public async shouldBeAbleToRunNpmLinkCommand({ assert }: Context) { + Mock.when(Exec, 'link').resolve(undefined) + + await this.npm.link('@athenna/common') + + assert.calledOnceWith(Exec.link, '@athenna/common') + } + + @Test() + public async shouldBeAbleToRunNpmInstallCommand({ assert }: Context) { + Mock.when(Exec, 'install').resolve(undefined) + + await this.npm.install('@athenna/common') + + assert.calledOnceWith(Exec.install, '@athenna/common') + } +} diff --git a/tests/unit/kernels/ConsoleKernelTest.ts b/tests/unit/kernels/ConsoleKernelTest.ts index 6bb13f2..640b634 100644 --- a/tests/unit/kernels/ConsoleKernelTest.ts +++ b/tests/unit/kernels/ConsoleKernelTest.ts @@ -7,6 +7,7 @@ * file that was distributed with this source code. */ +import { Path } from '@athenna/common' import { ArtisanProvider, CommanderHandler, ConsoleKernel } from '#src' import { Test, BeforeEach, AfterEach, type Context } from '@athenna/test' diff --git a/tests/unit/testing/plugins/CommandPluginTest.ts b/tests/unit/testing/plugins/CommandPluginTest.ts index 796c323..3980163 100644 --- a/tests/unit/testing/plugins/CommandPluginTest.ts +++ b/tests/unit/testing/plugins/CommandPluginTest.ts @@ -7,6 +7,7 @@ * file that was distributed with this source code. */ +import { Path } from '@athenna/common' import { ArtisanProvider } from '#src/index' import { TestCommand } from '#src/testing/plugins/index' import { Test, type Context, BeforeEach, AfterEach, Fails } from '@athenna/test'