@node-initializr/generator 0.1.0 → 0.1.2

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.
@@ -0,0 +1,4 @@
1
+ import { type ProjectConfig } from '@node-initializr/shared';
2
+ import type { GeneratedFile } from './template-engine.js';
3
+ export declare function buildAiGuidelines(config: ProjectConfig): string;
4
+ export declare function renderAiConfigFiles(config: ProjectConfig): GeneratedFile[];
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildAiGuidelines = buildAiGuidelines;
4
+ exports.renderAiConfigFiles = renderAiConfigFiles;
5
+ const shared_1 = require("@node-initializr/shared");
6
+ function labelFor(options, value) {
7
+ return options.find((o) => o.value === value)?.label ?? value;
8
+ }
9
+ function pmRun(config, script) {
10
+ if (config.packageManager === 'pnpm')
11
+ return `pnpm run ${script}`;
12
+ if (config.packageManager === 'yarn')
13
+ return `yarn ${script}`;
14
+ return `npm run ${script}`;
15
+ }
16
+ function pmExec(config, script) {
17
+ if (config.packageManager === 'pnpm')
18
+ return `pnpm ${script}`;
19
+ if (config.packageManager === 'yarn')
20
+ return `yarn ${script}`;
21
+ return `npm run ${script}`;
22
+ }
23
+ function architectureGuidelines(config) {
24
+ if (config.architecture === 'clean') {
25
+ return `## Arquitetura — Clean Architecture
26
+
27
+ - **domain/** — entidades e interfaces de repositório (sem dependências externas)
28
+ - **application/** — casos de uso que orquestram a lógica de negócio
29
+ - **infrastructure/** — implementações concretas (HTTP, persistência, mensageria)
30
+ - **shared/** — erros e utilitários compartilhados
31
+
32
+ Regras:
33
+ - Domínio não importa de infrastructure nem de frameworks HTTP
34
+ - Casos de uso dependem de interfaces do domínio, não de implementações
35
+ - Controllers/rotas apenas adaptam HTTP → casos de uso`;
36
+ }
37
+ if (config.architecture === 'mvc') {
38
+ return `## Arquitetura — MVC
39
+
40
+ - **controllers/** — entrada HTTP, validação de request/response
41
+ - **services/** — regras de negócio e orquestração
42
+ - **models/** — estruturas de dados e entidades
43
+
44
+ Regras:
45
+ - Controllers devem ser finos — delegam lógica para services
46
+ - Services não conhecem detalhes HTTP (req/res)
47
+ - Models representam dados, não lógica de transporte`;
48
+ }
49
+ return `## Arquitetura — Modular Monolith
50
+
51
+ - **modules/** — um módulo por domínio (ex: users, health)
52
+ - Cada módulo contém controller, service e module (NestJS) ou routes equivalentes
53
+ - **shared/** ou **infra/** — código transversal (DB, auth, config)
54
+
55
+ Regras:
56
+ - Módulos não importam implementações internas de outros módulos diretamente
57
+ - Comunicação entre módulos via interfaces públicas ou eventos
58
+ - Mantenha boundaries claros para facilitar extração futura em microserviços`;
59
+ }
60
+ function frameworkGuidelines(config) {
61
+ if (config.framework === 'nestjs') {
62
+ return `## Framework — NestJS
63
+
64
+ - Use módulos (\`@Module\`), injeção de dependência e providers
65
+ - Controllers com decorators (\`@Controller\`, \`@Get\`, etc.)
66
+ - Services como \`@Injectable()\`
67
+ - Prefira DTOs com class-validator para entrada
68
+ - Entry point: \`src/main.ts\``;
69
+ }
70
+ if (config.framework === 'express') {
71
+ return `## Framework — Express
72
+
73
+ - Rotas organizadas em módulos/arquivos separados
74
+ - Middleware para auth, parsing e erros
75
+ - Services puros importados pelos controllers/rotas
76
+ - Entry point: \`src/index.${config.language === 'typescript' ? 'ts' : 'js'}\``;
77
+ }
78
+ return `## Framework — Fastify
79
+
80
+ - Use plugins e \`register()\` para modularizar
81
+ - Schemas JSON para validação de request/response quando aplicável
82
+ - Hooks para auth e lifecycle
83
+ - Entry point: \`src/index.${config.language === 'typescript' ? 'ts' : 'js'}\``;
84
+ }
85
+ function stackSection(config) {
86
+ const lines = [
87
+ `- **Projeto:** ${config.name}`,
88
+ `- **Framework:** ${labelFor(shared_1.FRAMEWORK_OPTIONS, config.framework)}`,
89
+ `- **Linguagem:** ${labelFor(shared_1.LANGUAGE_OPTIONS, config.language)}`,
90
+ `- **Node.js:** ${config.nodeVersion}`,
91
+ `- **Package manager:** ${labelFor(shared_1.PACKAGE_MANAGER_OPTIONS, config.packageManager)}`,
92
+ `- **Arquitetura:** ${labelFor(shared_1.ARCHITECTURE_OPTIONS, config.architecture)}`,
93
+ `- **Banco:** ${labelFor(shared_1.DATABASE_OPTIONS, config.database)}`,
94
+ `- **ORM:** ${labelFor(shared_1.ORM_OPTIONS, config.orm)}`,
95
+ `- **Auth:** ${labelFor(shared_1.AUTH_OPTIONS, config.auth)}`,
96
+ `- **Mensageria:** ${labelFor(shared_1.MESSAGE_BROKER_OPTIONS, config.messageBroker)}`,
97
+ `- **Redis:** ${config.redis ? 'sim' : 'não'}`,
98
+ `- **Swagger:** ${config.swagger ? 'sim' : 'não'}`,
99
+ `- **Testes:** ${config.jest ? (config.framework === 'nestjs' ? 'Jest' : 'node:test') : 'não'}`,
100
+ `- **Docker:** ${config.docker ? 'sim' : 'não'}`,
101
+ `- **GitHub Actions:** ${config.githubActions ? 'sim' : 'não'}`,
102
+ ];
103
+ if (config.description) {
104
+ lines.unshift(`- **Descrição:** ${config.description}`);
105
+ }
106
+ return lines.join('\n');
107
+ }
108
+ function dataLayerGuidelines(config) {
109
+ if (config.database === 'none' || config.orm === 'none') {
110
+ return `## Camada de dados
111
+
112
+ Este projeto não inclui banco de dados configurado. Não adicione ORM ou migrations sem alinhar com o time.`;
113
+ }
114
+ const ormNotes = {
115
+ prisma: '- Schema em `prisma/schema.prisma`\n- Use `PrismaClient` via service injetável\n- Migrations: `npx prisma migrate dev`',
116
+ typeorm: '- Entidades com decorators em `entities/`\n- DataSource configurado em `infra/typeorm/`\n- Use repositories ou EntityManager conforme o padrão do projeto',
117
+ drizzle: '- Schema em `infra/drizzle/schema`\n- Client tipado via Drizzle\n- Migrations com drizzle-kit',
118
+ sequelize: '- Models Sequelize em `infra/sequelize/models/`\n- Inicialização em `infra/sequelize/sequelize`\n- Use migrations do Sequelize para alterações de schema',
119
+ };
120
+ return `## Camada de dados
121
+
122
+ - Banco: **${labelFor(shared_1.DATABASE_OPTIONS, config.database)}**
123
+ - ORM: **${labelFor(shared_1.ORM_OPTIONS, config.orm)}**
124
+
125
+ ${ormNotes[config.orm] ?? ''}`;
126
+ }
127
+ function buildAiGuidelines(config) {
128
+ const testCmd = config.framework === 'nestjs'
129
+ ? pmRun(config, 'test')
130
+ : pmExec(config, 'test');
131
+ const devCmd = config.framework === 'nestjs'
132
+ ? pmRun(config, 'start:dev')
133
+ : pmRun(config, 'dev');
134
+ return `# ${config.name} — instruções para assistentes de IA
135
+
136
+ Este arquivo foi gerado pelo [Node Initializr](https://github.com/pietro-sdev/node-initializr).
137
+ Siga estas diretrizes ao implementar funcionalidades neste projeto.
138
+
139
+ ## Stack do projeto
140
+
141
+ ${stackSection(config)}
142
+
143
+ ${frameworkGuidelines(config)}
144
+
145
+ ${architectureGuidelines(config)}
146
+
147
+ ${dataLayerGuidelines(config)}
148
+
149
+ ## Convenções gerais
150
+
151
+ - Linguagem: **${config.language === 'typescript' ? 'TypeScript estrito — evite `any`' : 'JavaScript (ESM)'}**
152
+ - Nomes de arquivos: kebab-case para pastas; siga o padrão já usado no módulo
153
+ - Novos endpoints: inclua health check compatível se alterar rotas globais
154
+ - Erros HTTP: respostas consistentes com o padrão existente no projeto
155
+ - Variáveis de ambiente: documente novas vars em \`.env.example\`
156
+ - Não reestruture a arquitetura escolhida sem solicitação explícita
157
+
158
+ ## Comandos úteis
159
+
160
+ \`\`\`bash
161
+ ${config.packageManager === 'pnpm' ? 'pnpm install' : config.packageManager === 'yarn' ? 'yarn install' : 'npm install'}
162
+ ${devCmd}
163
+ ${pmRun(config, 'build')}
164
+ ${testCmd}
165
+ \`\`\`
166
+
167
+ ## Ao adicionar features
168
+
169
+ 1. Identifique o módulo/camada correto conforme a arquitetura **${labelFor(shared_1.ARCHITECTURE_OPTIONS, config.architecture)}**
170
+ 2. Reutilize services, repositories e clients existentes
171
+ 3. Mantenha compatibilidade com ${labelFor(shared_1.PACKAGE_MANAGER_OPTIONS, config.packageManager)} e Node ${config.nodeVersion}
172
+ 4. Adicione ou atualize testes (${config.framework === 'nestjs' ? 'Jest' : 'node:test'}) quando alterar comportamento
173
+ ${config.swagger ? '5. Documente endpoints novos no Swagger/OpenAPI' : ''}
174
+ `;
175
+ }
176
+ const AI_TOOL_FILES = {
177
+ agents: {
178
+ path: 'AGENTS.md',
179
+ wrap: (body) => body,
180
+ },
181
+ cursor: {
182
+ path: '.cursor/rules/node-initializr.mdc',
183
+ wrap: (body) => `---\ncontext: true\npriority: high\nscope: project\n---\n\n${body}`,
184
+ },
185
+ claude: {
186
+ path: '.claude/CLAUDE.md',
187
+ wrap: (body) => body,
188
+ },
189
+ copilot: {
190
+ path: '.github/copilot-instructions.md',
191
+ wrap: (body) => body,
192
+ },
193
+ gemini: {
194
+ path: '.gemini/GEMINI.md',
195
+ wrap: (body) => body,
196
+ },
197
+ jetbrains: {
198
+ path: '.junie/guidelines.md',
199
+ wrap: (body) => body,
200
+ },
201
+ windsurf: {
202
+ path: '.windsurf/rules/guidelines.md',
203
+ wrap: (body) => body,
204
+ },
205
+ };
206
+ function renderAiConfigFiles(config) {
207
+ if (!config.aiTools?.length)
208
+ return [];
209
+ const body = buildAiGuidelines(config);
210
+ return config.aiTools.map((tool) => {
211
+ const target = AI_TOOL_FILES[tool];
212
+ return {
213
+ path: target.path,
214
+ content: target.wrap(body),
215
+ };
216
+ });
217
+ }
package/dist/generate.js CHANGED
@@ -40,6 +40,7 @@ exports.writeProject = writeProject;
40
40
  const shared_1 = require("@node-initializr/shared");
41
41
  const fs = __importStar(require("fs"));
42
42
  const path = __importStar(require("path"));
43
+ const ai_config_js_1 = require("./ai-config.js");
43
44
  const template_engine_js_1 = require("./template-engine.js");
44
45
  const validate_js_1 = require("./validate.js");
45
46
  const zip_js_1 = require("./zip.js");
@@ -56,7 +57,9 @@ function renderProject(config) {
56
57
  if (errors.length > 0) {
57
58
  throw new Error(errors.join('; '));
58
59
  }
59
- return engine.renderProject(config);
60
+ const projectFiles = engine.renderProject(config);
61
+ const aiFiles = (0, ai_config_js_1.renderAiConfigFiles)(config);
62
+ return [...projectFiles, ...aiFiles];
60
63
  }
61
64
  async function generateProject(config) {
62
65
  const files = renderProject(config);
package/dist/validate.js CHANGED
@@ -37,5 +37,11 @@ function validateProjectConfig(config) {
37
37
  if (config.framework === 'nestjs' && config.language === 'javascript') {
38
38
  errors.push('NestJS requer TypeScript.');
39
39
  }
40
+ if (config.aiTools?.length) {
41
+ const invalid = config.aiTools.filter((tool) => !shared_1.AI_TOOL_VALUES.includes(tool));
42
+ if (invalid.length > 0) {
43
+ errors.push(`Ferramentas de IA inválidas: ${invalid.join(', ')}`);
44
+ }
45
+ }
40
46
  return errors;
41
47
  }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@node-initializr/generator",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Engine de geração de projetos Node.js para o Node Initializr",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/pietro-sdev/node-initializr.git",
8
+ "url": "git+https://github.com/pietro-sdev/node-initializr.git",
9
9
  "directory": "packages/generator"
10
10
  },
11
11
  "publishConfig": {
@@ -22,7 +22,7 @@
22
22
  "prepack": "npm run build"
23
23
  },
24
24
  "dependencies": {
25
- "@node-initializr/shared": "*",
25
+ "@node-initializr/shared": "^0.1.2",
26
26
  "archiver": "^7.0.1",
27
27
  "handlebars": "^4.7.8"
28
28
  },