diff --git a/package-lock.json b/package-lock.json index a8f6322..729b9a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "@athenna/artisan", - "version": "1.2.3", + "version": "1.2.8", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@athenna/artisan", - "version": "1.2.3", + "version": "1.2.8", "license": "MIT", "dependencies": { - "@athenna/ioc": "1.2.0", - "@athenna/logger": "1.2.5", - "@secjs/utils": "1.9.4", + "@athenna/ioc": "1.2.2", + "@athenna/logger": "1.2.7", + "@secjs/utils": "1.9.7", "chalk-rainbow": "1.0.0", "cli-table": "0.3.11", "columnify": "1.6.0", @@ -73,21 +73,21 @@ "dev": true }, "node_modules/@athenna/ioc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@athenna/ioc/-/ioc-1.2.0.tgz", - "integrity": "sha512-R5NLoNo7c/lgHRr5zj97d5TW1r4MLTysBlARhD99LykitqNJqBLYexOBAEP8dVEqYC/0+iAW3rUuSRi4emKoNA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@athenna/ioc/-/ioc-1.2.2.tgz", + "integrity": "sha512-J8O/iz2lCKPixI69ZFk/o5p/chxQVjqD/GkY4CZgvIdlvfqvBErpOqG/eelPrLS6FrMDnZZMNy9TH9NUNYKrAw==", "dependencies": { - "@secjs/utils": "1.9.4", + "@secjs/utils": "1.9.7", "awilix": "7.0.2" } }, "node_modules/@athenna/logger": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@athenna/logger/-/logger-1.2.5.tgz", - "integrity": "sha512-1SIOVb4Jaa/Qbp6ph8xVadPghNLQlq4Q70AyolbbGOPIjwef5+IeGMABvANsaL7U+4q3UD0/M0HLp2mmaS4sVA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@athenna/logger/-/logger-1.2.7.tgz", + "integrity": "sha512-2keZikNxtChRgToz48XJmv/3sRF5b5p0znwdxIzUTSVh/Ezk1dw7ie46RtjQmHnWERQvAJPtS8Ra+PIhTKF9Jw==", "dependencies": { - "@athenna/ioc": "1.2.0", - "@secjs/utils": "1.9.4", + "@athenna/ioc": "1.2.2", + "@secjs/utils": "1.9.7", "axios": "0.26.1", "chalk": "5.0.1", "debug": "4.3.4", @@ -768,9 +768,9 @@ "dev": true }, "node_modules/@secjs/utils": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@secjs/utils/-/utils-1.9.4.tgz", - "integrity": "sha512-3m0/y2TFsTGTY9b1beH5ykER7c/EP4IY1N88jF49PV93nDER77E0NBtO1C1v4lVWS714M+HzknMYRAxo+5cCyQ==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@secjs/utils/-/utils-1.9.7.tgz", + "integrity": "sha512-64N34fSbfFmsAkkaCvP6ax2xm6cZCI6nP41onrbQ8zcJfq5nKrGfdpugTRkwNraffbAo88hJBlAk3lS9iGBpXA==", "dependencies": { "bytes": "3.1.2", "callsite": "1.0.0", @@ -9144,21 +9144,21 @@ "dev": true }, "@athenna/ioc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@athenna/ioc/-/ioc-1.2.0.tgz", - "integrity": "sha512-R5NLoNo7c/lgHRr5zj97d5TW1r4MLTysBlARhD99LykitqNJqBLYexOBAEP8dVEqYC/0+iAW3rUuSRi4emKoNA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@athenna/ioc/-/ioc-1.2.2.tgz", + "integrity": "sha512-J8O/iz2lCKPixI69ZFk/o5p/chxQVjqD/GkY4CZgvIdlvfqvBErpOqG/eelPrLS6FrMDnZZMNy9TH9NUNYKrAw==", "requires": { - "@secjs/utils": "1.9.4", + "@secjs/utils": "1.9.7", "awilix": "7.0.2" } }, "@athenna/logger": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@athenna/logger/-/logger-1.2.5.tgz", - "integrity": "sha512-1SIOVb4Jaa/Qbp6ph8xVadPghNLQlq4Q70AyolbbGOPIjwef5+IeGMABvANsaL7U+4q3UD0/M0HLp2mmaS4sVA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@athenna/logger/-/logger-1.2.7.tgz", + "integrity": "sha512-2keZikNxtChRgToz48XJmv/3sRF5b5p0znwdxIzUTSVh/Ezk1dw7ie46RtjQmHnWERQvAJPtS8Ra+PIhTKF9Jw==", "requires": { - "@athenna/ioc": "1.2.0", - "@secjs/utils": "1.9.4", + "@athenna/ioc": "1.2.2", + "@secjs/utils": "1.9.7", "axios": "0.26.1", "chalk": "5.0.1", "debug": "4.3.4", @@ -9723,9 +9723,9 @@ "dev": true }, "@secjs/utils": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@secjs/utils/-/utils-1.9.4.tgz", - "integrity": "sha512-3m0/y2TFsTGTY9b1beH5ykER7c/EP4IY1N88jF49PV93nDER77E0NBtO1C1v4lVWS714M+HzknMYRAxo+5cCyQ==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@secjs/utils/-/utils-1.9.7.tgz", + "integrity": "sha512-64N34fSbfFmsAkkaCvP6ax2xm6cZCI6nP41onrbQ8zcJfq5nKrGfdpugTRkwNraffbAo88hJBlAk3lS9iGBpXA==", "requires": { "bytes": "3.1.2", "callsite": "1.0.0", diff --git a/package.json b/package.json index 779d65c..e8881ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@athenna/artisan", - "version": "1.2.7", + "version": "1.2.8", "description": "The Athenna CLI application. Built on top of commander.", "license": "MIT", "author": "João Lenon ", @@ -42,9 +42,9 @@ "#tests/*": "./tests/*.js" }, "dependencies": { - "@athenna/ioc": "1.2.0", - "@athenna/logger": "1.2.5", - "@secjs/utils": "1.9.4", + "@athenna/ioc": "1.2.2", + "@athenna/logger": "1.2.7", + "@secjs/utils": "1.9.7", "chalk-rainbow": "1.0.0", "cli-table": "0.3.11", "columnify": "1.6.0", diff --git a/src/Commands/Command.js b/src/Commands/Command.js index 0b5e4be..00c00bd 100644 --- a/src/Commands/Command.js +++ b/src/Commands/Command.js @@ -19,16 +19,20 @@ export class Command { /** * The name and signature of the console command. * - * @type {string} + * @return {string} */ - signature + get signature() { + throw new Error('Signature getter not implemented.') + } /** * The console command description. * - * @type {string} + * @return {string} */ - description + get description() { + return '' + } /** * Set additional flags in the commander instance. diff --git a/src/Commands/Eslint/Fix.js b/src/Commands/Eslint/Fix.js index b84f627..6cffec9 100644 --- a/src/Commands/Eslint/Fix.js +++ b/src/Commands/Eslint/Fix.js @@ -14,13 +14,21 @@ import { Command } from '#src/index' export class MakeFix extends Command { /** * The name and signature of the console command. + * + * @return {string} */ - signature = 'eslint:fix ' + get signature() { + return 'eslint:fix ' + } /** * The console command description. + * + * @return {string} */ - description = 'Lint one specific file using eslint.' + get description() { + return 'Lint one specific file using eslint.' + } /** * Set additional flags in the commander instance. diff --git a/src/Commands/List.js b/src/Commands/List.js index 7ef4f44..68313bb 100644 --- a/src/Commands/List.js +++ b/src/Commands/List.js @@ -12,13 +12,21 @@ import { Artisan, Command } from '#src/index' export class List extends Command { /** * The name and signature of the console command. + * + * @return {string} */ - signature = 'list ' + get signature() { + return 'list ' + } /** * The console command description. + * + * @return {string} */ - description = 'List all commands available of the alias.' + get description() { + return 'List all commands available of the alias.' + } /** * Set additional flags in the commander instance. diff --git a/src/Commands/Make/Command.js b/src/Commands/Make/Command.js index 43217a7..63a5f2e 100644 --- a/src/Commands/Make/Command.js +++ b/src/Commands/Make/Command.js @@ -14,13 +14,21 @@ import { Artisan, Command as AbstractCommand } from '#src/index' export class MakeCommand extends AbstractCommand { /** * The name and signature of the console command. + * + * @return {string} */ - signature = 'make:command ' + get signature() { + return 'make:command ' + } /** * The console command description. + * + * @return {string} */ - description = 'Make a new command file.' + get description() { + return 'Make a new command file.' + } /** * Set additional flags in the commander instance. @@ -66,9 +74,9 @@ export class MakeCommand extends AbstractCommand { } if (options.register) { - await TemplateHelper.replaceArrayProperty( + await TemplateHelper.replaceArrayGetter( Path.console('Kernel.js'), - 'commands =', + 'commands', `#app/Console/Commands/${file.name}`, ) } diff --git a/src/Commands/Make/Exception.js b/src/Commands/Make/Exception.js index b5bba25..8965c56 100644 --- a/src/Commands/Make/Exception.js +++ b/src/Commands/Make/Exception.js @@ -14,13 +14,21 @@ import { TemplateHelper } from '#src/Helpers/TemplateHelper' export class MakeException extends Command { /** * The name and signature of the console command. + * + * @return {string} */ - signature = 'make:exception ' + get signature() { + return 'make:exception ' + } /** * The console command description. + * + * @return {string} */ - description = 'Make a new exception file.' + get description() { + return 'Make a new exception file.' + } /** * Set additional flags in the commander instance. diff --git a/src/Commands/Make/Facade.js b/src/Commands/Make/Facade.js index 989e63a..ca58ade 100644 --- a/src/Commands/Make/Facade.js +++ b/src/Commands/Make/Facade.js @@ -14,13 +14,21 @@ import { TemplateHelper } from '#src/Helpers/TemplateHelper' export class MakeFacade extends Command { /** * The name and signature of the console command. + * + * @return {string} */ - signature = 'make:facade ' + get signature() { + return 'make:facade ' + } /** * The console command description. + * + * @return {string} */ - description = 'Make a new facade file.' + get description() { + return 'Make a new facade file.' + } /** * Set additional flags in the commander instance. diff --git a/src/Commands/Make/Provider.js b/src/Commands/Make/Provider.js index 81f92a6..f5762e9 100644 --- a/src/Commands/Make/Provider.js +++ b/src/Commands/Make/Provider.js @@ -14,13 +14,21 @@ import { TemplateHelper } from '#src/Helpers/TemplateHelper' export class MakeProvider extends Command { /** * The name and signature of the console command. + * + * @return {string} */ - signature = 'make:provider ' + get signature() { + return 'make:provider ' + } /** * The console command description. + * + * @return {string} */ - description = 'Make a new provider file.' + get description() { + return 'Make a new provider file.' + } /** * Set additional flags in the commander instance. diff --git a/src/Commands/Make/Service.js b/src/Commands/Make/Service.js index df87fcf..9264bf7 100644 --- a/src/Commands/Make/Service.js +++ b/src/Commands/Make/Service.js @@ -14,13 +14,21 @@ import { TemplateHelper } from '#src/Helpers/TemplateHelper' export class MakeService extends Command { /** * The name and signature of the console command. + * + * @return {string} */ - signature = 'make:service ' + get signature() { + return 'make:service ' + } /** * The console command description. + * + * @return {string} */ - description = 'Make a new service file.' + get description() { + return 'Make a new service file.' + } /** * Set additional flags in the commander instance. diff --git a/src/Commands/Make/Test.js b/src/Commands/Make/Test.js index 5fd6256..7dffea8 100644 --- a/src/Commands/Make/Test.js +++ b/src/Commands/Make/Test.js @@ -14,13 +14,21 @@ import { TemplateHelper } from '#src/Helpers/TemplateHelper' export class MakeTest extends Command { /** * The name and signature of the console command. + * + * @return {string} */ - signature = 'make:test ' + get signature() { + return 'make:test ' + } /** * The console command description. + * + * @return {string} */ - description = 'Make a new test file.' + get description() { + return 'Make a new test file.' + } /** * Set additional flags in the commander instance. diff --git a/src/Commands/Serve.js b/src/Commands/Serve.js index 9e1e208..ae4ea91 100644 --- a/src/Commands/Serve.js +++ b/src/Commands/Serve.js @@ -17,13 +17,21 @@ import { Command } from '#src/index' export class Serve extends Command { /** * The name and signature of the console command. + * + * @return {string} */ - signature = 'serve' + get signature() { + return 'serve' + } /** * The console command description. + * + * @return {string} */ - description = 'Serve the Athenna application.' + get description() { + return 'Serve the Athenna application.' + } /** * Set additional flags in the commander instance. diff --git a/src/Commands/Test.js b/src/Commands/Test.js index 68e2e2c..816ff9b 100644 --- a/src/Commands/Test.js +++ b/src/Commands/Test.js @@ -14,13 +14,21 @@ import { Command } from '#src/index' export class Test extends Command { /** * The name and signature of the console command. + * + * @return {string} */ - signature = 'test' + get signature() { + return 'test' + } /** * The console command description. + * + * @return {string} */ - description = 'Run the tests of Athenna application.' + get description() { + return 'Run the tests of Athenna application.' + } /** * Set additional flags in the commander instance. diff --git a/src/Helpers/TemplateHelper.js b/src/Helpers/TemplateHelper.js index 6a400f1..22ae6fc 100644 --- a/src/Helpers/TemplateHelper.js +++ b/src/Helpers/TemplateHelper.js @@ -9,45 +9,80 @@ import ejs from 'ejs' -import { fileURLToPath } from 'node:url' -import { dirname, join } from 'node:path' +import { join } from 'node:path' +import { File, Folder, Module, String } from '@secjs/utils' import { Artisan } from '#src/index' -import { File, Folder, String } from '@secjs/utils' import { AlreadyExistFileException } from '#src/Exceptions/AlreadyExistFileException' -const __dirname = dirname(fileURLToPath(import.meta.url)) - export class TemplateHelper { /** * The original templates' folder instance of artisan. */ static #originalTemplatesFolder = new Folder( - join(__dirname, '..', '..', 'templates'), + join(Module.createDirname(import.meta.url), '..', '..', 'templates'), ).loadSync() /** - * The templates' folder. Could be changed with setTemplatesFolder - * method. + * The custom templates' files. Use this property to set custom + * templates' files to use inside Artisan. + * + * @type {File[]} */ - static #templatesFolder = new Folder( - join(__dirname, '..', '..', 'templates'), - ).loadSync() + static #customTemplates = [] + + /** + * Set a custom template file. + * + * @param {File} file + * @return {void} + */ + static setTemplate(file) { + this.#customTemplates.push(file) + } /** - * Set the templates' folder. + * Set all .ejs files inside folder as templates. * * @param {Folder} folder + * @return {void} + */ + static setAllTemplates(folder) { + folder.getFilesByPattern('*/**/*.ejs').forEach(file => { + if (file.extension !== '.js.ejs') { + return + } + + this.setTemplate(file) + }) + } + + /** + * Remove the custom template file. + * + * @param {File} file + * @return {void} */ - static setTemplatesFolder(folder) { - this.#templatesFolder = folder + static removeTemplate(file) { + delete this.#customTemplates[ + this.#customTemplates.findIndex(f => f === file) + ] } /** - * Set the templates' folder same as the original. + * Remove all .ejs files inside folders from custom templates. + * + * @param {Folder} folder + * @return {void} */ - static setOriginalTemplatesFolder() { - this.#templatesFolder = this.#originalTemplatesFolder + static removeAllTemplates(folder) { + folder.getFilesByPattern('*/**/*.ejs').forEach(file => { + if (file.extension !== '.ejs') { + return + } + + this.removeTemplate(file) + }) } /** @@ -80,9 +115,11 @@ export class TemplateHelper { static getTemplate(templateName) { templateName = `${templateName}.js.ejs` + const predicate = file => file.base === templateName + return ( - this.#templatesFolder.files.find(f => f.base === templateName) || - this.#originalTemplatesFolder.files.find(f => f.base === templateName) + this.#customTemplates.find(file => predicate(file)) || + this.#originalTemplatesFolder.files.find(file => predicate(file)) ) } @@ -174,6 +211,63 @@ export class TemplateHelper { ) } + /** + * Replace the content of the array getter inside a file. + * + * @param {string} path + * @param {string} getter + * @param {string} importAlias + */ + static async replaceArrayGetter(path, getter, importAlias) { + const file = new File(path).loadSync() + let content = file.getContentSync().toString() + + const getMethod = `get\\s*${getter}\\(\\)\\s*\\{\\n\\s*return\\s*` + + const matches = content.match( + new RegExp(`(?:${getMethod})(?:\\[[^\\]]*\\])`), + ) + + if (!matches) { + return + } + + const match = matches[0] + + const arrayString = match + .replace(new RegExp(getMethod), '') + .replace(/ /g, '') + .replace(/\n/g, '') + .replace(/(\[|\])/g, '') + .split(',') + + /** + * In case "matcher" is an empty array. + * Example: "matcher" = [] + */ + if (arrayString.length) { + const last = () => arrayString.length - 1 + + if (arrayString[last()] === '') { + arrayString.pop() + } + } + + arrayString.push(`import('${importAlias}')`) + + content = content.replace( + match, + `get ${getter}() {\n return [${arrayString.join(',')}]`, + ) + + await file.remove() + await new File(file.path, Buffer.from(content)).load() + + await Artisan.call( + `eslint:fix ${file.path} --resource TemplateHelper --quiet`, + ) + } + /** * Replace the content of the object property inside a file. * @@ -229,6 +323,64 @@ export class TemplateHelper { ) } + /** + * Replace the content of the object getter inside a file. + * + * @param {string} path + * @param {string} getter + * @param {string} resource + * @param {string} importAlias + */ + static async replaceObjectGetter(path, getter, resource, importAlias) { + const file = new File(path).loadSync() + let content = file.getContentSync().toString() + + const getMethod = `get\\s*${getter}\\(\\)\\s*\\{\\n\\s*return\\s*` + + const matches = content.match(new RegExp(`(?:${getMethod})(?:\\{[^}]*\\})`)) + + if (!matches) { + return + } + + const match = matches[0] + + const arrayString = match + .replace(new RegExp(getMethod), '') + .replace(/ /g, '') + .replace(/\n/g, '') + .replace(/(\{|\})/g, '') + .split(',') + + /** + * In case "matcher" is an empty object. + * Example: "matcher" = {} + */ + if (arrayString.length) { + const last = () => arrayString.length - 1 + + if (arrayString[last()] === '') { + arrayString.pop() + } + } + + const name = String.toCamelCase(resource) + + arrayString.push(`${name}:import('${importAlias}')`) + + content = content.replace( + match, + `get ${getter}() {\n return {${arrayString.join(',')}}`, + ) + + await file.remove() + await new File(file.path, Buffer.from(content)).load() + + await Artisan.call( + `eslint:fix ${file.path} --resource TemplateHelper --quiet`, + ) + } + /** * Create a new file from resource. * diff --git a/src/Kernels/ConsoleKernel.js b/src/Kernels/ConsoleKernel.js index 99b8150..f3a4142 100644 --- a/src/Kernels/ConsoleKernel.js +++ b/src/Kernels/ConsoleKernel.js @@ -7,18 +7,28 @@ * file that was distributed with this source code. */ -import { pathToFileURL } from 'node:url' -import { Exec, Path } from '@secjs/utils' +import { Module, Path } from '@secjs/utils' -import { Artisan } from '#src/index' +import { Artisan, ArtisanLoader, TemplateHelper } from '#src/index' export class ConsoleKernel { /** * Register the commands for the application. * - * @type {import('#src/index').Command[] | Promise} + * @return {import('#src/index').Command[] | Promise} */ - commands + get commands() { + return [...ArtisanLoader.loadCommands()] + } + + /** + * Register custom templates files. + * + * @return {import('@secjs/utils').File[] | Promise} + */ + get templates() { + return [] + } /** * Register all the commands to the artisan. @@ -26,22 +36,23 @@ export class ConsoleKernel { * @return {Promise} */ async registerCommands() { - for (const module of this.commands) { - let Command = await Exec.getModule(module) + const commands = await Module.getAllWithAlias( + this.commands, + 'App/Console/Commands', + ) - const alias = `App/Console/Commands/${Command.name}` - - Command = ioc.bind(alias, Command).safeUse(alias) + /** + * Action runner catches all exceptions thrown by commands + * exceptions and sends to the Artisan exception handler. + * + * @param {any} fn + */ + const actionRunner = fn => { + return (...args) => fn(...args).catch(Artisan.getErrorHandler()) + } - /** - * Action runner catches all exceptions thrown by commands - * exceptions and sends to the Artisan exception handler. - * - * @param {any} fn - */ - const actionRunner = fn => { - return (...args) => fn(...args).catch(Artisan.getErrorHandler()) - } + commands.forEach(({ alias, module }) => { + const Command = ioc.bind(alias, module).safeUse(alias) Artisan.register(commander => { commander = commander @@ -53,20 +64,28 @@ export class ConsoleKernel { .showHelpAfterError() .createHelp() }) - } + }) } /** - * Register the default error handler + * Register the default error handler. * * @return {Promise} */ async registerErrorHandler() { - const path = Path.console('Exceptions/Handler.js') + const Handler = await Module.getFrom(Path.console('Exceptions/Handler.js')) - const Handler = await Exec.getModule(import(pathToFileURL(path).href)) const handler = new Handler() Artisan.setErrorHandler(handler.handle.bind(handler)) } + + /** + * Register the custom templates on template helper + * + * @return {Promise} + */ + async registerCustomTemplates() { + this.templates.forEach(file => TemplateHelper.setTemplate(file)) + } } diff --git a/src/index.d.ts b/src/index.d.ts index c23bc88..794f893 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -160,16 +160,36 @@ export class ArtisanLoader { export class TemplateHelper { /** - * Set the templates' folder. + * Set a custom template file. + * + * @param {File} file + * @return {void} + */ + static setTemplate(file: File): void + + /** + * Set all .ejs files inside folder as templates. * * @param {Folder} folder + * @return {void} + */ + static setAllTemplates(folder: Folder): void + + /** + * Remove the custom template file. + * + * @param {File} file + * @return {void} */ - static setTemplatesFolder(folder: Folder): void + static removeTemplate(file: Folder): void /** - * Set the templates' folder same as the original. + * Remove all .ejs files inside folders from custom templates. + * + * @param {Folder} folder + * @return {void} */ - static setOriginalTemplatesFolder(): void + static removeAllTemplates(folder: Folder): void /** * Normalize the resource name removing duplicated. diff --git a/tests/Stubs/app/Console/Exceptions/Handler.js b/tests/Stubs/app/Console/Exceptions/Handler.js index ee539a3..6f07b14 100644 --- a/tests/Stubs/app/Console/Exceptions/Handler.js +++ b/tests/Stubs/app/Console/Exceptions/Handler.js @@ -12,11 +12,6 @@ import { ConsoleExceptionHandler } from '#src/Handlers/ConsoleExceptionHandler' */ export class Handler extends ConsoleExceptionHandler { - /** - * Set if error logs will come with stack. - */ - addStack = false - /** * The global exception handler of all Artisan commands. * diff --git a/tests/Stubs/app/Console/Kernel.js b/tests/Stubs/app/Console/Kernel.js index 718ffd6..52960ef 100644 --- a/tests/Stubs/app/Console/Kernel.js +++ b/tests/Stubs/app/Console/Kernel.js @@ -7,12 +7,22 @@ * file that was distributed with this source code. */ +import { Folder, Path } from '@secjs/utils' + import { ConsoleKernel } from '#src/Kernels/ConsoleKernel' import { ArtisanLoader } from '#src/Helpers/ArtisanLoader' export class Kernel extends ConsoleKernel { /** * Register the commands for the application. + * + * @return {import('#src/index').Command[] | Promise} */ - commands = [...ArtisanLoader.loadCommands()] + get commands() { + return [...ArtisanLoader.loadCommands()] + } + + get templates() { + return [...new Folder(Path.stubs('templates')).loadSync().files] + } } diff --git a/tests/Stubs/app/Http/Kernel.js b/tests/Stubs/app/Http/Kernel.js index c0828ab..10283ff 100644 --- a/tests/Stubs/app/Http/Kernel.js +++ b/tests/Stubs/app/Http/Kernel.js @@ -4,14 +4,18 @@ export class Kernel { * * This middlewares are run during every request to your http server. */ - globalMiddlewares = [] + get globalMiddlewares() { + return [] + } /** * The application's named HTTP middlewares. * * Here you define all your named middlewares to use inside routes/http file. */ - namedMiddlewares = { - test: 'example', + get namedMiddlewares() { + return { + test: 'example', + } } } diff --git a/tests/Stubs/templates/__name__Command.js.ejs b/tests/Stubs/templates/__name__Command.js.ejs new file mode 100644 index 0000000..ad98b08 --- /dev/null +++ b/tests/Stubs/templates/__name__Command.js.ejs @@ -0,0 +1,15 @@ +import { Command } from '@athenna/artisan' + +// Custom template command! +export class <%= namePascal %>Command extends Command { + signature = 'your:command ' + description = 'Your command description.' + + addFlags(commander) { + return commander + } + + async handle(_argument, _options) { + // + } +} diff --git a/tests/Unit/ArtisanTest.js b/tests/Unit/ArtisanTest.js index 8972d43..00514ef 100644 --- a/tests/Unit/ArtisanTest.js +++ b/tests/Unit/ArtisanTest.js @@ -8,8 +8,9 @@ */ import { test } from '@japa/runner' -import { Artisan } from '#src/index' -import { Config, Exception, Folder, Path } from '@secjs/utils' +import { Config, Exception, File, Folder, Path } from '@secjs/utils' + +import { Artisan, TemplateHelper } from '#src/index' import { Kernel } from '#tests/Stubs/app/Console/Kernel' import { ArtisanProvider } from '#src/Providers/ArtisanProvider' import { LoggerProvider } from '@athenna/logger/providers/LoggerProvider' @@ -29,11 +30,13 @@ test.group('ArtisanTest', group => { await kernel.registerErrorHandler() await kernel.registerCommands() + await kernel.registerCustomTemplates() }) group.each.teardown(async () => { await Folder.safeRemove(Path.app()) await Folder.safeRemove(Path.config()) + TemplateHelper.removeAllTemplates(await new Folder(Path.stubs('templates')).load()) }) test('should be able to execute test:error command from routes/console', async ({ assert }) => { @@ -47,4 +50,12 @@ test.group('ArtisanTest', group => { await assert.rejects(useCaseTwo, Exception) }).timeout(60000) + + test('should be able to set custom templates on artisan template helper', async ({ assert }) => { + await Artisan.call('make:command CustomCommand') + + const file = await new File(Path.console('Commands/CustomCommand.js')).load({ withContent: true }) + + assert.isTrue(file.content.toString().includes('Custom template command!')) + }).timeout(60000) })