jarvis-arch-hexagonal-gen 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/.create-resource.json +6 -0
  2. package/README.md +74 -0
  3. package/bin/create-resource.js +10 -0
  4. package/dist/.create-resource.json +6 -0
  5. package/dist/cli/commands/generate.js +33 -0
  6. package/dist/cli/commands/init.js +112 -0
  7. package/dist/cli/commands/list.js +51 -0
  8. package/dist/cli/index.js +27 -0
  9. package/dist/core/generator.js +121 -0
  10. package/dist/core/hook-runner.js +14 -0
  11. package/dist/core/parser.js +19 -0
  12. package/dist/core/plugin-manager.js +64 -0
  13. package/dist/plugins/bundles/crud/hooks.js +1 -0
  14. package/dist/plugins/bundles/crud/manifest.json +6 -0
  15. package/dist/plugins/bundles/resource/hooks.js +1 -0
  16. package/dist/plugins/bundles/resource/manifest.json +6 -0
  17. package/dist/plugins/controller/hooks.js +20 -0
  18. package/dist/plugins/controller/manifest.json +14 -0
  19. package/dist/plugins/controller/templates/controller.ejs +66 -0
  20. package/dist/plugins/dto/hooks.js +11 -0
  21. package/dist/plugins/dto/manifest.json +19 -0
  22. package/dist/plugins/dto/templates/create.ejs +11 -0
  23. package/dist/plugins/dto/templates/update.ejs +11 -0
  24. package/dist/plugins/repository/hooks.js +1 -0
  25. package/dist/plugins/repository/manifest.json +15 -0
  26. package/dist/plugins/repository/templates/interface.ejs +9 -0
  27. package/dist/plugins/repository/templates/repository.ejs +38 -0
  28. package/dist/plugins/routes/hooks.js +1 -0
  29. package/dist/plugins/routes/manifest.json +11 -0
  30. package/dist/plugins/routes/templates/routes.ejs +34 -0
  31. package/dist/plugins/swagger/hooks.js +1 -0
  32. package/dist/plugins/swagger/manifest.json +11 -0
  33. package/dist/plugins/swagger/templates/swagger.ejs +123 -0
  34. package/dist/plugins/usecases/hooks.js +1 -0
  35. package/dist/plugins/usecases/manifest.json +27 -0
  36. package/dist/plugins/usecases/templates/create.ejs +11 -0
  37. package/dist/plugins/usecases/templates/delete.ejs +11 -0
  38. package/dist/plugins/usecases/templates/find-all.ejs +10 -0
  39. package/dist/plugins/usecases/templates/find-by-id.ejs +12 -0
  40. package/dist/plugins/usecases/templates/update.ejs +12 -0
  41. package/dist/utils/config.js +15 -0
  42. package/dist/utils/file-system.js +1 -0
  43. package/dist/utils/logger.js +7 -0
  44. package/package.json +45 -0
  45. package/scripts/copy-plugins.js +40 -0
@@ -0,0 +1,6 @@
1
+ {
2
+ "pluginsDir": "src/plugins",
3
+ "templatesDir": "templates",
4
+ "outputDir": "src/modules",
5
+ "defaultPlugin": "resource"
6
+ }
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ folder/
2
+ ├── package.json
3
+ ├── tsconfig.json
4
+ ├── README.md
5
+ ├── bin/
6
+ │ └── create-resource.js # Ponto de entrada da CLI
7
+ ├── src/
8
+ │ ├── core/
9
+ │ │ ├── Generator.ts # Motor principal (renderiza templates + executa hooks)
10
+ │ │ ├── PluginManager.ts # Carrega plugins e resolve dependências
11
+ │ │ ├── Parser.ts # Converte "Product" → metadados enriquecidos
12
+ │ │ └── HookRunner.ts # Executa hooks (pré/pós geração)
13
+ │ ├── cli/
14
+ │ │ ├── index.ts # Comandos da CLI (generate, init, list)
15
+ │ │ └── commands/
16
+ │ │ ├── generate.ts
17
+ │ │ ├── init.ts
18
+ │ │ └── list.ts
19
+ │ ├── plugins/ # Plugins nativos (cada um com manifesto + templates + hooks)
20
+ │ │ ├── dto/
21
+ │ │ │ ├── manifest.json
22
+ │ │ │ ├── templates/
23
+ │ │ │ │ ├── create.ejs
24
+ │ │ │ │ └── update.ejs
25
+ │ │ │ └── hooks.ts
26
+ │ │ ├── controller/
27
+ │ │ │ ├── manifest.json
28
+ │ │ │ ├── templates/
29
+ │ │ │ │ └── controller.ejs
30
+ │ │ │ └── hooks.ts
31
+ │ │ ├── repository/
32
+ │ │ │ ├── manifest.json
33
+ │ │ │ ├── templates/
34
+ │ │ │ │ ├── interface.ejs
35
+ │ │ │ │ └── repository.ejs
36
+ │ │ │ └── hooks.ts
37
+ │ │ ├── usecases/
38
+ │ │ │ ├── manifest.json
39
+ │ │ │ ├── templates/
40
+ │ │ │ │ ├── create.ejs
41
+ │ │ │ │ ├── update.ejs
42
+ │ │ │ │ ├── delete.ejs
43
+ │ │ │ │ ├── find-by-id.ejs
44
+ │ │ │ │ └── find-all.ejs
45
+ │ │ │ └── hooks.ts
46
+ │ │ ├── routes/
47
+ │ │ │ ├── manifest.json
48
+ │ │ │ ├── templates/
49
+ │ │ │ │ └── routes.ejs
50
+ │ │ │ └── hooks.ts
51
+ │ │ ├── tests/
52
+ │ │ │ ├── manifest.json
53
+ │ │ │ ├── templates/
54
+ │ │ │ │ ├── usecase.spec.ejs
55
+ │ │ │ │ └── integration.ejs
56
+ │ │ │ └── hooks.ts
57
+ │ │ ├── swagger/
58
+ │ │ │ ├── manifest.json
59
+ │ │ │ ├── templates/
60
+ │ │ │ │ └── swagger.ejs
61
+ │ │ │ └── hooks.ts
62
+ │ │ └── bundles/ # Combinações de plugins (ex: resource, crud)
63
+ │ │ ├── resource/
64
+ │ │ │ ├── manifest.json # extends: [dto, controller, repository, routes, tests]
65
+ │ │ │ └── hooks.ts
66
+ │ │ └── crud/
67
+ │ │ ├── manifest.json # extends: [resource, swagger]
68
+ │ │ └── hooks.ts
69
+ │ └── utils/
70
+ │ ├── file-system.ts
71
+ │ └── logger.ts
72
+ └── templates/ # Templates globais (opcionais, podem ser usados por vários plugins)
73
+ └── shared/
74
+ └── header.ejs
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Carrega o módulo principal
4
+ const { main } = require('../dist/cli');
5
+
6
+ // Executa a CLI com os argumentos da linha de comando
7
+ main().catch((error) => {
8
+ console.error('❌ Erro fatal:', error.message);
9
+ process.exit(1);
10
+ });
@@ -0,0 +1,6 @@
1
+ {
2
+ "pluginsDir": "dist/plugins",
3
+ "templatesDir": "templates",
4
+ "outputDir": "src/",
5
+ "defaultPlugin": "resource"
6
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateCommand = generateCommand;
7
+ // src/cli/commands/generate.ts
8
+ const generator_1 = require("../../core/generator");
9
+ const parser_1 = require("../../core/parser");
10
+ const path_1 = __importDefault(require("path"));
11
+ const config_1 = require("../../utils/config");
12
+ async function generateCommand(plugin, entity, options) {
13
+ let columns = [];
14
+ if (options.fields) {
15
+ columns = options.fields.split(',').map((field) => {
16
+ const [name, type] = field.split(':');
17
+ return { name, type: type || 'string' };
18
+ });
19
+ }
20
+ const metadata = (0, parser_1.parseEntity)(entity, { columns });
21
+ // Lê configuração
22
+ const config = (0, config_1.loadConfig)();
23
+ const pluginsDir = config.pluginsDir || 'src/plugins';
24
+ const generator = new generator_1.Generator(path_1.default.join(process.cwd(), pluginsDir));
25
+ try {
26
+ await generator.generate(plugin, metadata, options);
27
+ console.log('✨ Geração concluída!');
28
+ }
29
+ catch (error) {
30
+ console.error('❌ Erro:', error.message);
31
+ process.exit(1);
32
+ }
33
+ }
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.initCommand = initCommand;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const child_process_1 = require("child_process");
11
+ /**
12
+ * Inicializa um novo projeto com a estrutura mínima necessária para usar o gerador.
13
+ * Cria pastas, arquivos de exemplo e instala dependências recomendadas.
14
+ */
15
+ async function initCommand() {
16
+ const cwd = process.cwd();
17
+ const folders = [
18
+ 'src/modules',
19
+ 'src/shared',
20
+ 'tests/unit',
21
+ 'tests/integration',
22
+ 'plugins',
23
+ ];
24
+ console.log(chalk_1.default.bold.blue('\n🚀 Inicializando projeto com create-api...\n'));
25
+ // 1. Cria estrutura de pastas
26
+ for (const folder of folders) {
27
+ const fullPath = path_1.default.join(cwd, folder);
28
+ if (!fs_extra_1.default.existsSync(fullPath)) {
29
+ fs_extra_1.default.ensureDirSync(fullPath);
30
+ console.log(chalk_1.default.green(`✅ Criado: ${folder}`));
31
+ }
32
+ else {
33
+ console.log(chalk_1.default.gray(`ℹ️ Já existe: ${folder}`));
34
+ }
35
+ }
36
+ // 2. Cria um arquivo de configuração .create-api.json
37
+ const configPath = path_1.default.join(cwd, '.create-api.json');
38
+ if (!fs_extra_1.default.existsSync(configPath)) {
39
+ const defaultConfig = {
40
+ pluginsDir: 'plugins',
41
+ templatesDir: 'templates',
42
+ outputDir: 'src/modules',
43
+ defaultPlugin: 'resource',
44
+ };
45
+ fs_extra_1.default.writeJsonSync(configPath, defaultConfig, { spaces: 2 });
46
+ console.log(chalk_1.default.green('✅ Criado: .create-api.json'));
47
+ }
48
+ else {
49
+ console.log(chalk_1.default.gray('ℹ️ .create-api.json já existe.'));
50
+ }
51
+ // 3. Cria um exemplo de plugin (opcional, mas didático)
52
+ const examplePluginDir = path_1.default.join(cwd, 'plugins', 'example');
53
+ if (!fs_extra_1.default.existsSync(examplePluginDir)) {
54
+ fs_extra_1.default.ensureDirSync(examplePluginDir);
55
+ fs_extra_1.default.ensureDirSync(path_1.default.join(examplePluginDir, 'templates'));
56
+ // Manifesto exemplo
57
+ const manifestExample = {
58
+ name: 'example',
59
+ description: 'Exemplo de plugin para demonstrar a estrutura',
60
+ dependencies: [],
61
+ files: [
62
+ {
63
+ template: 'hello.ejs',
64
+ output: 'src/modules/<%= route %>/hello.txt',
65
+ },
66
+ ],
67
+ };
68
+ fs_extra_1.default.writeJsonSync(path_1.default.join(examplePluginDir, 'manifest.json'), manifestExample, { spaces: 2 });
69
+ // Template exemplo
70
+ const templateContent = 'Olá, <%= entity %>! Este é um template de exemplo.';
71
+ fs_extra_1.default.writeFileSync(path_1.default.join(examplePluginDir, 'templates', 'hello.ejs'), templateContent);
72
+ console.log(chalk_1.default.green('✅ Criado plugin de exemplo: plugins/example'));
73
+ }
74
+ else {
75
+ console.log(chalk_1.default.gray('ℹ️ Plugin de exemplo já existe.'));
76
+ }
77
+ // 4. (Opcional) Instala dependências básicas
78
+ console.log(chalk_1.default.yellow('\n📦 Instalando dependências recomendadas...'));
79
+ try {
80
+ (0, child_process_1.execSync)('npm install -D typescript @types/node ts-node ejs fs-extra chalk text-table commander', {
81
+ stdio: 'inherit',
82
+ cwd,
83
+ });
84
+ console.log(chalk_1.default.green('✅ Dependências instaladas.'));
85
+ }
86
+ catch (error) {
87
+ console.warn(chalk_1.default.yellow('⚠️ Falha ao instalar dependências. Faça manualmente:'));
88
+ console.warn(' npm install -D typescript @types/node ts-node ejs fs-extra chalk text-table commander');
89
+ }
90
+ // 5. Cria um script de exemplo no package.json
91
+ const pkgPath = path_1.default.join(cwd, 'package.json');
92
+ if (fs_extra_1.default.existsSync(pkgPath)) {
93
+ const pkg = fs_extra_1.default.readJsonSync(pkgPath);
94
+ if (!pkg.scripts)
95
+ pkg.scripts = {};
96
+ if (!pkg.scripts['generate']) {
97
+ pkg.scripts['generate'] = 'create-api generate';
98
+ fs_extra_1.default.writeJsonSync(pkgPath, pkg, { spaces: 2 });
99
+ console.log(chalk_1.default.green('✅ Adicionado script "generate" ao package.json'));
100
+ }
101
+ }
102
+ else {
103
+ console.warn(chalk_1.default.yellow('⚠️ package.json não encontrado. Crie um com "npm init -y".'));
104
+ }
105
+ console.log(chalk_1.default.bold.green('\n✨ Projeto inicializado com sucesso!\n'));
106
+ console.log(chalk_1.default.cyan('Próximos passos:'));
107
+ console.log(' 1. Crie seus próprios plugins em plugins/');
108
+ console.log(' 2. Gere artefatos com:');
109
+ console.log(` ${chalk_1.default.white('create-api generate resource Product')}`);
110
+ console.log(' 3. Ou use:');
111
+ console.log(` ${chalk_1.default.white('npm run generate resource Product')}\n`);
112
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.listCommand = listCommand;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const text_table_1 = __importDefault(require("text-table"));
11
+ /**
12
+ * Lista todos os plugins disponíveis, exibindo nome, descrição e dependências.
13
+ */
14
+ async function listCommand() {
15
+ const pluginsDir = path_1.default.join(__dirname, '../../../plugins');
16
+ if (!fs_extra_1.default.existsSync(pluginsDir)) {
17
+ console.error(chalk_1.default.red('❌ Diretório de plugins não encontrado.'));
18
+ console.error(chalk_1.default.yellow('Execute `create-api init` para criar a estrutura.'));
19
+ process.exit(1);
20
+ }
21
+ const pluginFolders = fs_extra_1.default.readdirSync(pluginsDir).filter((item) => {
22
+ const stat = fs_extra_1.default.statSync(path_1.default.join(pluginsDir, item));
23
+ return stat.isDirectory() && !item.startsWith('.');
24
+ });
25
+ if (pluginFolders.length === 0) {
26
+ console.log(chalk_1.default.yellow('⚠️ Nenhum plugin encontrado.'));
27
+ return;
28
+ }
29
+ console.log(chalk_1.default.bold.blue('\n📦 Plugins disponíveis:\n'));
30
+ const rows = [
31
+ [chalk_1.default.bold('Nome'), chalk_1.default.bold('Descrição'), chalk_1.default.bold('Dependências')],
32
+ ];
33
+ for (const folder of pluginFolders) {
34
+ const manifestPath = path_1.default.join(pluginsDir, folder, 'manifest.json');
35
+ if (!fs_extra_1.default.existsSync(manifestPath)) {
36
+ continue;
37
+ }
38
+ try {
39
+ const manifest = fs_extra_1.default.readJsonSync(manifestPath);
40
+ const name = chalk_1.default.green(folder);
41
+ const description = manifest.description || '';
42
+ const deps = (manifest.dependencies || []).join(', ') || '—';
43
+ rows.push([name, description, deps]);
44
+ }
45
+ catch (error) {
46
+ // Ignora manifestos inválidos
47
+ }
48
+ }
49
+ console.log((0, text_table_1.default)(rows, { align: ['l', 'l', 'l'] }));
50
+ console.log(`\n💡 Use: ${chalk_1.default.cyan('create-api generate <plugin> <Entity>')}`);
51
+ }
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const generate_1 = require("./commands/generate");
6
+ const init_1 = require("./commands/init");
7
+ const list_1 = require("./commands/list");
8
+ const program = new commander_1.Command();
9
+ program
10
+ .name('create-api')
11
+ .description('Gerador de código baseado em plugins')
12
+ .version('1.0.0');
13
+ program
14
+ .command('generate <plugin> <entity>')
15
+ .description('Gera artefatos usando um plugin')
16
+ .option('--swagger', 'Inclui documentação Swagger')
17
+ .option('--fields <fields>', 'Define campos (ex: name:string age:number)')
18
+ .action(generate_1.generateCommand);
19
+ program
20
+ .command('init')
21
+ .description('Inicializa um projeto com exemplos')
22
+ .action(init_1.initCommand);
23
+ program
24
+ .command('list')
25
+ .description('Lista todos os plugins disponíveis')
26
+ .action(list_1.listCommand);
27
+ program.parse(process.argv);
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Generator = void 0;
7
+ // src/core/Generator.ts
8
+ const ejs_1 = __importDefault(require("ejs"));
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const plugin_manager_1 = require("./plugin-manager");
12
+ const hook_runner_1 = require("./hook-runner");
13
+ class Generator {
14
+ constructor(pluginsDir) {
15
+ const defaultPluginsDir = path_1.default.join(process.cwd(), 'src', 'plugins');
16
+ this.pluginManager = new plugin_manager_1.PluginManager(pluginsDir || defaultPluginsDir);
17
+ this.hookRunner = new hook_runner_1.HookRunner();
18
+ }
19
+ async generate(pluginName, metadata, options = {}) {
20
+ const plugin = this.pluginManager.load(pluginName);
21
+ if (!plugin)
22
+ throw new Error(`Plugin "${pluginName}" não encontrado`);
23
+ // Executa dependências primeiro (se houver)
24
+ if (plugin.dependencies && plugin.dependencies.length > 0) {
25
+ for (const dep of plugin.dependencies) {
26
+ await this.generate(dep, metadata, options);
27
+ }
28
+ }
29
+ // Executa hooks pré (do plugin atual)
30
+ if (plugin.hooks?.pre) {
31
+ await this.hookRunner.run(plugin.hooks.pre, metadata, options);
32
+ }
33
+ // Processa os arquivos do plugin
34
+ for (const file of plugin.files || []) {
35
+ if (file.condition && !this.evaluateCondition(file.condition, options)) {
36
+ continue;
37
+ }
38
+ const outputPath = ejs_1.default.render(file.output, { ...metadata, ...options });
39
+ const fullOutputPath = path_1.default.join(process.cwd(), outputPath);
40
+ const templatePath = path_1.default.join(plugin.templatesDir, file.template);
41
+ if (!fs_extra_1.default.existsSync(templatePath)) {
42
+ console.warn(`⚠️ Template não encontrado: ${templatePath}`);
43
+ continue;
44
+ }
45
+ const templateContent = await fs_extra_1.default.readFile(templatePath, 'utf-8');
46
+ const rendered = ejs_1.default.render(templateContent, { ...metadata, ...options });
47
+ await fs_extra_1.default.ensureDir(path_1.default.dirname(fullOutputPath));
48
+ await fs_extra_1.default.writeFile(fullOutputPath, rendered);
49
+ console.log(`✅ Gerado: ${outputPath}`);
50
+ }
51
+ // Executa hooks pós
52
+ if (plugin.hooks?.post) {
53
+ await this.hookRunner.run(plugin.hooks.post, metadata, options);
54
+ }
55
+ }
56
+ /**
57
+ * Avalia se um arquivo deve ser gerado com base na condição definida
58
+ * no manifesto e nas opções fornecidas pelo usuário.
59
+ *
60
+ * Atualmente são suportados os seguintes operadores:
61
+ *
62
+ * - equals:
63
+ * Compara o valor de uma opção com um valor esperado.
64
+ *
65
+ * Exemplo:
66
+ * {
67
+ * option: "swagger",
68
+ * equals: true
69
+ * }
70
+ *
71
+ * options:
72
+ * {
73
+ * swagger: true
74
+ * }
75
+ *
76
+ * Resultado: true
77
+ *
78
+ * ------------------------------------------------------------
79
+ *
80
+ * - in:
81
+ * Verifica se o valor da opção pertence a uma lista de valores.
82
+ *
83
+ * Exemplo:
84
+ * {
85
+ * option: "orm",
86
+ * in: ["typeorm", "prisma"]
87
+ * }
88
+ *
89
+ * options:
90
+ * {
91
+ * orm: "typeorm"
92
+ * }
93
+ *
94
+ * Resultado: true
95
+ *
96
+ * ------------------------------------------------------------
97
+ *
98
+ * O retorno possui a seguinte semântica:
99
+ *
100
+ * true -> A condição foi satisfeita e o arquivo será gerado.
101
+ * false -> A condição não foi satisfeita e o arquivo será ignorado.
102
+ *
103
+ * Recomenda-se lançar uma exceção quando a condição possuir um formato
104
+ * desconhecido, evitando que manifestos inválidos passem despercebidos.
105
+ *
106
+ * @param condition Condição declarada no manifesto.
107
+ * @param options Opções informadas pelo usuário durante a execução da CLI.
108
+ * @returns `true` quando o arquivo deve ser gerado; caso contrário, `false`.
109
+ * @throws Error Quando o formato da condição não é suportado.
110
+ */
111
+ evaluateCondition(condition, options) {
112
+ if ("equals" in condition) {
113
+ return options[condition.option] === condition.equals;
114
+ }
115
+ if ("in" in condition) {
116
+ return condition.in.includes(options[condition.option]);
117
+ }
118
+ throw new Error(`Unsupported condition: ${JSON.stringify(condition)}`);
119
+ }
120
+ }
121
+ exports.Generator = Generator;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HookRunner = void 0;
4
+ class HookRunner {
5
+ async run(hookFunction, metadata, options) {
6
+ // O hookFunction pode ser o nome da função exportada no hooks.ts
7
+ // ou um caminho para um script.
8
+ // Para simplificar, assumimos que está no mesmo plugin.
9
+ // Implementação real pode usar require dinâmico.
10
+ console.log(`⏳ Executando hook: ${hookFunction}`);
11
+ // ...
12
+ }
13
+ }
14
+ exports.HookRunner = HookRunner;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseEntity = parseEntity;
4
+ function parseEntity(entityName, options = {}) {
5
+ const entity = entityName.charAt(0).toUpperCase() + entityName.slice(1);
6
+ const entityLower = entity.toLowerCase();
7
+ const plural = entity + 's';
8
+ const pluralLower = plural.toLowerCase();
9
+ const route = pluralLower;
10
+ const table = `tb_${pluralLower}`;
11
+ // Colunas podem vir das opções ou de um schema
12
+ const columns = options.columns || [
13
+ { name: 'id', type: 'number', primary: true },
14
+ { name: 'name', type: 'string' },
15
+ { name: 'createdAt', type: 'Date' },
16
+ { name: 'updatedAt', type: 'Date' },
17
+ ];
18
+ return { entity, entityName: entity, entityLower, plural, pluralLower, route, table, columns };
19
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PluginManager = void 0;
7
+ // src/core/PluginManager.ts
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ class PluginManager {
11
+ constructor(pluginsDir) {
12
+ this.cache = new Map();
13
+ this.pluginsDir = pluginsDir;
14
+ }
15
+ load(pluginName) {
16
+ if (this.cache.has(pluginName))
17
+ return this.cache.get(pluginName);
18
+ const foundPath = this.findPluginPath(pluginName);
19
+ if (!foundPath) {
20
+ throw new Error(`Manifest não encontrado para o plugin "${pluginName}"`);
21
+ }
22
+ const manifestPath = path_1.default.join(foundPath, 'manifest.json');
23
+ const manifest = fs_extra_1.default.readJsonSync(manifestPath);
24
+ const templatesDir = path_1.default.join(foundPath, 'templates');
25
+ let hooks = null;
26
+ const hooksPath = path_1.default.join(foundPath, 'hooks.ts');
27
+ if (fs_extra_1.default.existsSync(hooksPath)) {
28
+ try {
29
+ hooks = require(hooksPath);
30
+ }
31
+ catch {
32
+ // ignora
33
+ }
34
+ }
35
+ const plugin = {
36
+ ...manifest,
37
+ templatesDir,
38
+ hooks,
39
+ path: foundPath,
40
+ };
41
+ this.cache.set(pluginName, plugin);
42
+ return plugin;
43
+ }
44
+ findPluginPath(pluginName) {
45
+ const search = (dir) => {
46
+ const items = fs_extra_1.default.readdirSync(dir);
47
+ for (const item of items) {
48
+ const fullPath = path_1.default.join(dir, item);
49
+ const stat = fs_extra_1.default.statSync(fullPath);
50
+ if (stat.isDirectory()) {
51
+ if (item === pluginName && fs_extra_1.default.existsSync(path_1.default.join(fullPath, 'manifest.json'))) {
52
+ return fullPath;
53
+ }
54
+ const found = search(fullPath);
55
+ if (found)
56
+ return found;
57
+ }
58
+ }
59
+ return null;
60
+ };
61
+ return search(this.pluginsDir);
62
+ }
63
+ }
64
+ exports.PluginManager = PluginManager;
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "crud",
3
+ "description": "Gera CRUD com Swagger",
4
+ "dependencies": ["resource", "swagger"],
5
+ "files": []
6
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "resource",
3
+ "description": "Gera um CRUD completo",
4
+ "dependencies": ["dto", "controller", "repository", "usecases", "routes", "tests"],
5
+ "files": []
6
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerRoutes = registerRoutes;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ async function registerRoutes(metadata, options) {
10
+ const routesFile = path_1.default.join(process.cwd(), 'src/routes/index.ts');
11
+ if (await fs_extra_1.default.pathExists(routesFile)) {
12
+ const content = await fs_extra_1.default.readFile(routesFile, 'utf-8');
13
+ const newImport = `import { ${metadata.entity}Controller } from '../modules/${metadata.route}/${metadata.entity}Controller';\n`;
14
+ const newRoute = `router.use('/${metadata.route}', ${metadata.entity}Controller);\n`;
15
+ if (!content.includes(newImport)) {
16
+ await fs_extra_1.default.appendFile(routesFile, `\n${newImport}${newRoute}`);
17
+ console.log(`📝 Registrada rota em routes/index.ts`);
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "controller",
3
+ "description": "Gera um controller CRUD",
4
+ "dependencies": ["dto"],
5
+ "files": [
6
+ {
7
+ "template": "controller.ejs",
8
+ "output": "src/adapters/inbound/controllers/<%= entity %>Controller.ts"
9
+ }
10
+ ],
11
+ "hooks": {
12
+ "post": "registerRoutes"
13
+ }
14
+ }
@@ -0,0 +1,66 @@
1
+ import { Request, Response } from 'express';
2
+ import { Create<%= entity %>UseCase } from '../usecases/create-<%= entityLower %>.usecase';
3
+ import { Update<%= entity %>UseCase } from '../usecases/update-<%= entityLower %>.usecase';
4
+ import { Delete<%= entity %>UseCase } from '../usecases/delete-<%= entityLower %>.usecase';
5
+ import { Find<%= entity %>ByIdUseCase } from '../usecases/find-<%= entityLower %>-by-id.usecase';
6
+ import { FindAll<%= plural %>UseCase } from '../usecases/find-all-<%= pluralLower %>.usecase';
7
+
8
+ export class <%= entity %>Controller {
9
+ constructor(
10
+ private readonly createUseCase: Create<%= entity %>UseCase,
11
+ private readonly updateUseCase: Update<%= entity %>UseCase,
12
+ private readonly deleteUseCase: Delete<%= entity %>UseCase,
13
+ private readonly findByIdUseCase: Find<%= entity %>ByIdUseCase,
14
+ private readonly findAllUseCase: FindAll<%= plural %>UseCase
15
+ ) {}
16
+
17
+ async create(req: Request, res: Response): Promise<Response> {
18
+ try {
19
+ const data = req.body;
20
+ const result = await this.createUseCase.execute(data);
21
+ return res.status(201).json(result);
22
+ } catch (error: any) {
23
+ return res.status(400).json({ error: error.message });
24
+ }
25
+ }
26
+
27
+ async update(req: Request, res: Response): Promise<Response> {
28
+ try {
29
+ const id = Number(req.params.id);
30
+ const data = req.body;
31
+ const result = await this.updateUseCase.execute(id, data);
32
+ return res.json(result);
33
+ } catch (error: any) {
34
+ return res.status(400).json({ error: error.message });
35
+ }
36
+ }
37
+
38
+ async delete(req: Request, res: Response): Promise<Response> {
39
+ try {
40
+ const id = Number(req.params.id);
41
+ await this.deleteUseCase.execute(id);
42
+ return res.status(204).send();
43
+ } catch (error: any) {
44
+ return res.status(400).json({ error: error.message });
45
+ }
46
+ }
47
+
48
+ async findById(req: Request, res: Response): Promise<Response> {
49
+ try {
50
+ const id = Number(req.params.id);
51
+ const result = await this.findByIdUseCase.execute(id);
52
+ return res.json(result);
53
+ } catch (error: any) {
54
+ return res.status(404).json({ error: error.message });
55
+ }
56
+ }
57
+
58
+ async findAll(req: Request, res: Response): Promise<Response> {
59
+ try {
60
+ const result = await this.findAllUseCase.execute();
61
+ return res.json(result);
62
+ } catch (error: any) {
63
+ return res.status(500).json({ error: error.message });
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.preGenerate = preGenerate;
4
+ exports.postGenerate = postGenerate;
5
+ function preGenerate(metadata, options) {
6
+ console.log(`📦 Preparando DTOs para ${metadata.entity}`);
7
+ }
8
+ function postGenerate(metadata, options) {
9
+ // Pode atualizar um arquivo central de exportação
10
+ // ou instalar dependências, etc.
11
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "dto",
3
+ "description": "Gera DTOs de criação e atualização",
4
+ "dependencies": [],
5
+ "files": [
6
+ {
7
+ "template": "create.ejs",
8
+ "output": "src/core/dtos/create-<%= route %>.dto.ts"
9
+ },
10
+ {
11
+ "template": "update.ejs",
12
+ "output": "src/core/dtos/update-<%= route %>.dto.ts"
13
+ }
14
+ ],
15
+ "hooks": {
16
+ "pre": "preGenerate",
17
+ "post": "postGenerate"
18
+ }
19
+ }
@@ -0,0 +1,11 @@
1
+ export class Create<%= entityName %>Dto {
2
+
3
+ <% columns
4
+ .filter(c => !c.generated)
5
+ .forEach(column => { %>
6
+
7
+ <%= column.name %>: <%= column.type %>;
8
+
9
+ <% }) %>
10
+
11
+ }
@@ -0,0 +1,11 @@
1
+ export class Update<%= entityName %>Dto {
2
+
3
+ <% columns
4
+ .filter(c => !c.generated)
5
+ .forEach(column => { %>
6
+
7
+ <%= column.name %>?: <%= column.type %>;
8
+
9
+ <% }) %>
10
+
11
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "repository",
3
+ "description": "Gera interface e implementação do repositório para uma entidade",
4
+ "dependencies": [],
5
+ "files": [
6
+ {
7
+ "template": "interface.ejs",
8
+ "output": "src/core/ports/outbound/repositories/I<%= entity %>Repository.ts"
9
+ },
10
+ {
11
+ "template": "repository.ejs",
12
+ "output": "src/adapters/outbound/persistence/typeorm/repositories/<%= entity %>Repository.ts"
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,9 @@
1
+ import { <%= entity %> } from '../entities/<%= entityLower %>.entity';
2
+
3
+ export interface I<%= entity %>Repository {
4
+ create(data: Omit<<%= entity %>, 'id'>): Promise<<%= entity %>>;
5
+ update(id: number, data: Partial<<%= entity %>>): Promise<<%= entity %>>;
6
+ delete(id: number): Promise<void>;
7
+ findById(id: number): Promise<<%= entity %> | null>;
8
+ findAll(): Promise<<%= entity %>[]>;
9
+ }
@@ -0,0 +1,38 @@
1
+ import { <%= entity %> } from '../entities/<%= entityLower %>.entity';
2
+ import { I<%= entity %>Repository } from './I<%= entity %>Repository';
3
+
4
+ export class <%= entity %>Repository implements I<%= entity %>Repository {
5
+ private items: <%= entity %>[] = [];
6
+ private currentId = 1;
7
+
8
+ async create(data: Omit<<%= entity %>, 'id'>): Promise<<%= entity %>> {
9
+ const newItem: <%= entity %> = {
10
+ id: this.currentId++,
11
+ ...data,
12
+ } as <%= entity %>;
13
+ this.items.push(newItem);
14
+ return newItem;
15
+ }
16
+
17
+ async update(id: number, data: Partial<<%= entity %>>): Promise<<%= entity %>> {
18
+ const index = this.items.findIndex(item => item.id === id);
19
+ if (index === -1) throw new Error('<%= entity %> not found');
20
+ const updated = { ...this.items[index], ...data };
21
+ this.items[index] = updated;
22
+ return updated;
23
+ }
24
+
25
+ async delete(id: number): Promise<void> {
26
+ const index = this.items.findIndex(item => item.id === id);
27
+ if (index === -1) throw new Error('<%= entity %> not found');
28
+ this.items.splice(index, 1);
29
+ }
30
+
31
+ async findById(id: number): Promise<<%= entity %> | null> {
32
+ return this.items.find(item => item.id === id) || null;
33
+ }
34
+
35
+ async findAll(): Promise<<%= entity %>[]> {
36
+ return this.items;
37
+ }
38
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "routes",
3
+ "description": "Gera rotas Express para a entidade, com injeção de dependências",
4
+ "dependencies": ["controller"],
5
+ "files": [
6
+ {
7
+ "template": "routes.ejs",
8
+ "output": "src/adapters/inbound/routes/<%= route %>/<%= route %>.routes.ts"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,34 @@
1
+ import { Router } from 'express';
2
+ import { <%= entity %>Controller } from './<%= entityLower %>.controller';
3
+ import { <%= entity %>Repository } from './repositories/<%= entityLower %>.repository';
4
+ import { Create<%= entity %>UseCase } from './usecases/create-<%= entityLower %>.usecase';
5
+ import { Update<%= entity %>UseCase } from './usecases/update-<%= entityLower %>.usecase';
6
+ import { Delete<%= entity %>UseCase } from './usecases/delete-<%= entityLower %>.usecase';
7
+ import { Find<%= entity %>ByIdUseCase } from './usecases/find-<%= entityLower %>-by-id.usecase';
8
+ import { FindAll<%= plural %>UseCase } from './usecases/find-all-<%= pluralLower %>.usecase';
9
+
10
+ const router = Router();
11
+
12
+ // Instâncias
13
+ const repository = new <%= entity %>Repository();
14
+ const createUseCase = new Create<%= entity %>UseCase(repository);
15
+ const updateUseCase = new Update<%= entity %>UseCase(repository);
16
+ const deleteUseCase = new Delete<%= entity %>UseCase(repository);
17
+ const findByIdUseCase = new Find<%= entity %>ByIdUseCase(repository);
18
+ const findAllUseCase = new FindAll<%= plural %>UseCase(repository);
19
+
20
+ const controller = new <%= entity %>Controller(
21
+ createUseCase,
22
+ updateUseCase,
23
+ deleteUseCase,
24
+ findByIdUseCase,
25
+ findAllUseCase
26
+ );
27
+
28
+ router.post('/', (req, res) => controller.create(req, res));
29
+ router.put('/:id', (req, res) => controller.update(req, res));
30
+ router.delete('/:id', (req, res) => controller.delete(req, res));
31
+ router.get('/:id', (req, res) => controller.findById(req, res));
32
+ router.get('/', (req, res) => controller.findAll(req, res));
33
+
34
+ export default router;
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "swagger",
3
+ "description": "Gera documentação Swagger/OpenAPI em YAML para a entidade",
4
+ "dependencies": [],
5
+ "files": [
6
+ {
7
+ "template": "swagger.ejs",
8
+ "output": "src/swagger.yaml"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,123 @@
1
+ openapi: 3.0.0
2
+ info:
3
+ title: API - <%= plural %>
4
+ version: 1.0.0
5
+ description: Documentação da API para gerenciamento de <%= pluralLower %>
6
+
7
+ paths:
8
+ /api/<%= route %>:
9
+ post:
10
+ summary: Cria um novo <%= entityLower %>
11
+ tags:
12
+ - <%= plural %>
13
+ requestBody:
14
+ required: true
15
+ content:
16
+ application/json:
17
+ schema:
18
+ $ref: '#/components/schemas/<%= entity %>Input'
19
+ responses:
20
+ '201':
21
+ description: Criado com sucesso
22
+ content:
23
+ application/json:
24
+ schema:
25
+ $ref: '#/components/schemas/<%= entity %>'
26
+ '400':
27
+ description: Dados inválidos
28
+ get:
29
+ summary: Lista todos os <%= pluralLower %>
30
+ tags:
31
+ - <%= plural %>
32
+ responses:
33
+ '200':
34
+ description: Lista de <%= pluralLower %>
35
+ content:
36
+ application/json:
37
+ schema:
38
+ type: array
39
+ items:
40
+ $ref: '#/components/schemas/<%= entity %>'
41
+
42
+ /api/<%= route %>/{id}:
43
+ get:
44
+ summary: Busca um <%= entityLower %> por ID
45
+ tags:
46
+ - <%= plural %>
47
+ parameters:
48
+ - name: id
49
+ in: path
50
+ required: true
51
+ schema:
52
+ type: integer
53
+ responses:
54
+ '200':
55
+ description: <%= entity %> encontrado
56
+ content:
57
+ application/json:
58
+ schema:
59
+ $ref: '#/components/schemas/<%= entity %>'
60
+ '404':
61
+ description: <%= entity %> não encontrado
62
+ put:
63
+ summary: Atualiza um <%= entityLower %>
64
+ tags:
65
+ - <%= plural %>
66
+ parameters:
67
+ - name: id
68
+ in: path
69
+ required: true
70
+ schema:
71
+ type: integer
72
+ requestBody:
73
+ required: true
74
+ content:
75
+ application/json:
76
+ schema:
77
+ $ref: '#/components/schemas/<%= entity %>Input'
78
+ responses:
79
+ '200':
80
+ description: Atualizado com sucesso
81
+ content:
82
+ application/json:
83
+ schema:
84
+ $ref: '#/components/schemas/<%= entity %>'
85
+ '404':
86
+ description: <%= entity %> não encontrado
87
+ '400':
88
+ description: Dados inválidos
89
+ delete:
90
+ summary: Deleta um <%= entityLower %>
91
+ tags:
92
+ - <%= plural %>
93
+ parameters:
94
+ - name: id
95
+ in: path
96
+ required: true
97
+ schema:
98
+ type: integer
99
+ responses:
100
+ '204':
101
+ description: Deletado com sucesso
102
+ '404':
103
+ description: <%= entity %> não encontrado
104
+
105
+ components:
106
+ schemas:
107
+ <%= entity %>:
108
+ type: object
109
+ properties:
110
+ <% columns.forEach(c => { %> <%= c.name %>:
111
+ type: <%= c.type === 'number' ? 'number' : 'string' %>
112
+ <% if (c.primary) { %> readOnly: true
113
+ <% } %><% }) %> required:
114
+ <% columns.filter(c => !c.primary).forEach(c => { %> - <%= c.name %>
115
+ <% }) %>
116
+ <%= entity %>Input:
117
+ type: object
118
+ properties:
119
+ <% columns.filter(c => !c.primary).forEach(c => { %> <%= c.name %>:
120
+ type: <%= c.type === 'number' ? 'number' : 'string' %>
121
+ <% }) %> required:
122
+ <% columns.filter(c => !c.primary).forEach(c => { %> - <%= c.name %>
123
+ <% }) %>
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "usecases",
3
+ "description": "Gera todos os use cases para a entidade (CRUD)",
4
+ "dependencies": ["repository"],
5
+ "files": [
6
+ {
7
+ "template": "create.ejs",
8
+ "output": "src/core/usecases/<%= route %>/create-<%= entityLower %>.usecase.ts"
9
+ },
10
+ {
11
+ "template": "update.ejs",
12
+ "output": "src/core/usecases/<%= route %>/update-<%= entityLower %>.usecase.ts"
13
+ },
14
+ {
15
+ "template": "delete.ejs",
16
+ "output": "src/core/usecases/<%= route %>/delete-<%= entityLower %>.usecase.ts"
17
+ },
18
+ {
19
+ "template": "find-by-id.ejs",
20
+ "output": "src/core/usecases/<%= route %>/find-<%= entityLower %>-by-id.usecase.ts"
21
+ },
22
+ {
23
+ "template": "find-all.ejs",
24
+ "output": "src/core/usecases/<%= route %>/find-all-<%= pluralLower %>.usecase.ts"
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,11 @@
1
+ import { <%= entity %> } from '../entities/<%= entityLower %>.entity';
2
+ import { I<%= entity %>Repository } from '../repositories/I<%= entity %>Repository';
3
+
4
+ export class Create<%= entity %>UseCase {
5
+ constructor(private readonly repository: I<%= entity %>Repository) {}
6
+
7
+ async execute(data: Omit<<%= entity %>, 'id'>): Promise<<%= entity %>> {
8
+ // Aqui pode adicionar validações, regras de negócio, etc.
9
+ return this.repository.create(data);
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ import { I<%= entity %>Repository } from '../repositories/I<%= entity %>Repository';
2
+
3
+ export class Delete<%= entity %>UseCase {
4
+ constructor(private readonly repository: I<%= entity %>Repository) {}
5
+
6
+ async execute(id: number): Promise<void> {
7
+ const existing = await this.repository.findById(id);
8
+ if (!existing) throw new Error('<%= entity %> not found');
9
+ await this.repository.delete(id);
10
+ }
11
+ }
@@ -0,0 +1,10 @@
1
+ import { <%= entity %> } from '../entities/<%= entityLower %>.entity';
2
+ import { I<%= entity %>Repository } from '../repositories/I<%= entity %>Repository';
3
+
4
+ export class FindAll<%= plural %>UseCase {
5
+ constructor(private readonly repository: I<%= entity %>Repository) {}
6
+
7
+ async execute(): Promise<<%= entity %>[]> {
8
+ return this.repository.findAll();
9
+ }
10
+ }
@@ -0,0 +1,12 @@
1
+ import { <%= entity %> } from '../entities/<%= entityLower %>.entity';
2
+ import { I<%= entity %>Repository } from '../repositories/I<%= entity %>Repository';
3
+
4
+ export class Find<%= entity %>ByIdUseCase {
5
+ constructor(private readonly repository: I<%= entity %>Repository) {}
6
+
7
+ async execute(id: number): Promise<<%= entity %>> {
8
+ const result = await this.repository.findById(id);
9
+ if (!result) throw new Error('<%= entity %> not found');
10
+ return result;
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { <%= entity %> } from '../entities/<%= entityLower %>.entity';
2
+ import { I<%= entity %>Repository } from '../repositories/I<%= entity %>Repository';
3
+
4
+ export class Update<%= entity %>UseCase {
5
+ constructor(private readonly repository: I<%= entity %>Repository) {}
6
+
7
+ async execute(id: number, data: Partial<<%= entity %>>): Promise<<%= entity %>> {
8
+ const existing = await this.repository.findById(id);
9
+ if (!existing) throw new Error('<%= entity %> not found');
10
+ return this.repository.update(id, data);
11
+ }
12
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadConfig = loadConfig;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ function loadConfig() {
10
+ const configPath = path_1.default.join(process.cwd(), '.create-resource.json');
11
+ if (fs_extra_1.default.existsSync(configPath)) {
12
+ return fs_extra_1.default.readJsonSync(configPath);
13
+ }
14
+ return {};
15
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loggerFormated = void 0;
4
+ const loggerFormated = (data) => {
5
+ return console.log(JSON.stringify(data, null, 2));
6
+ };
7
+ exports.loggerFormated = loggerFormated;
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "jarvis-arch-hexagonal-gen",
3
+ "version": "1.0.0",
4
+ "description": "Gerador de recursos para projetos Node.js com TypeScript",
5
+ "keywords": [
6
+ "Arquitetura Hexagonal",
7
+ "Gerador de Códigos"
8
+ ],
9
+ "author": "Anderson Paiva",
10
+ "license": "ISC",
11
+ "main": "./dist/cli/index.js",
12
+ "type": "commonjs",
13
+ "bin": {
14
+ "create-resource": "./dist/cli/index.js"
15
+ },
16
+ "scripts": {
17
+ "prepublishOnly": "npm run build",
18
+ "generate": "ts-node src/cli/index.ts generate",
19
+ "build": "tsc && npm run copy-plugins",
20
+ "copy-plugins": "node scripts/copy-plugins.js"
21
+ },
22
+ "dependencies": {
23
+ "chalk": "^5.6.2",
24
+ "commander": "^15.0.0",
25
+ "ejs": "^6.0.1",
26
+ "text-table": "^0.2.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/chalk": "^0.4.31",
30
+ "@types/ejs": "^3.1.5",
31
+ "@types/fs-extra": "^11.0.4",
32
+ "@types/jest": "^30.0.0",
33
+ "@types/node": "^26.0.1",
34
+ "@types/supertest": "^7.2.0",
35
+ "@types/text-table": "^0.2.5",
36
+ "copyfiles": "^2.4.1",
37
+ "cpx": "^1.5.0",
38
+ "fs-extra": "^11.3.5",
39
+ "jest": "^30.4.2",
40
+ "supertest": "^7.2.2",
41
+ "ts-jest": "^29.4.11",
42
+ "ts-node": "^10.9.2",
43
+ "typescript": "^6.0.3"
44
+ }
45
+ }
@@ -0,0 +1,40 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ // Ajuste o caminho de origem conforme sua estrutura:
5
+ // Se seus plugins estão em 'src/plugins', use:
6
+ const srcDir = path.join(__dirname, '..', 'src', 'plugins');
7
+ // Se estiverem na raiz ('plugins'), use:
8
+ // const srcDir = path.join(__dirname, '..', 'plugins');
9
+
10
+ const destDir = path.join(__dirname, '..', 'dist', 'plugins');
11
+
12
+ // Função recursiva para copiar apenas arquivos não-.ts
13
+ function copyNonTsFiles(src, dest) {
14
+ // Cria o diretório de destino se não existir
15
+ fs.ensureDirSync(dest);
16
+
17
+ const items = fs.readdirSync(src);
18
+
19
+ for (const item of items) {
20
+ const srcPath = path.join(src, item);
21
+ const destPath = path.join(dest, item);
22
+ const stat = fs.statSync(srcPath);
23
+
24
+ if (stat.isDirectory()) {
25
+ // Recursivamente para subpastas
26
+ copyNonTsFiles(srcPath, destPath);
27
+ } else {
28
+ // Copia apenas se NÃO for .ts
29
+ if (!item.endsWith('.ts')) {
30
+ fs.copySync(srcPath, destPath);
31
+ // console.log(`Copiado: ${srcPath} -> ${destPath}`);
32
+ }
33
+ }
34
+ }
35
+ }
36
+
37
+ // Executa a cópia (sem remover nada)
38
+ copyNonTsFiles(srcDir, destDir);
39
+
40
+ console.log('✅ Arquivos não-.ts copiados de src/plugins para dist/plugins');