@igniter-js/cli 0.1.4 → 0.1.6
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.
- package/dist/index.js +373 -191
- package/dist/index.js.map +1 -0
- package/dist/templates/express.server.hbs +33 -0
- package/dist/templates/feature.controller.hbs +14 -4
- package/dist/templates/feature.interface.hbs +27 -5
- package/dist/templates/feature.procedure.hbs +12 -7
- package/dist/templates/globals.hbs +7 -82
- package/dist/templates/igniter.context.hbs +1 -1
- package/dist/templates/layout.hbs +6 -14
- package/dist/templates/page.hbs +4 -37
- package/dist/templates/readme.hbs +25 -42
- package/dist/utils/analyze.js +8 -10
- package/dist/utils/analyze.js.map +1 -0
- package/dist/utils/cli-style.d.ts +55 -0
- package/dist/utils/cli-style.js +171 -0
- package/dist/utils/cli-style.js.map +1 -0
- package/dist/utils/consts.d.ts +4 -9
- package/dist/utils/consts.js +5 -13
- package/dist/utils/consts.js.map +1 -0
- package/dist/utils/handlebars-helpers.js +18 -5
- package/dist/utils/handlebars-helpers.js.map +1 -0
- package/dist/utils/helpers.d.ts +2 -1
- package/dist/utils/helpers.js +44 -17
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/platform-utils.d.ts +46 -0
- package/dist/utils/platform-utils.js +95 -0
- package/dist/utils/platform-utils.js.map +1 -0
- package/dist/utils/prisma-schema-parser.js +11 -16
- package/dist/utils/prisma-schema-parser.js.map +1 -0
- package/dist/utils/project-utils.d.ts +32 -0
- package/dist/utils/project-utils.js +123 -0
- package/dist/utils/project-utils.js.map +1 -0
- package/dist/utils/template-handler.js +4 -5
- package/dist/utils/template-handler.js.map +1 -0
- package/package.json +3 -1
- package/readme.md +23 -1
package/dist/index.js
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
-
};
|
|
6
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
|
|
6
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
7
|
+
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
11
8
|
const commander_1 = require("commander");
|
|
12
|
-
const helpers_1 = require("./utils/helpers");
|
|
13
9
|
const consts_1 = require("./utils/consts");
|
|
10
|
+
const helpers_1 = require("./utils/helpers");
|
|
14
11
|
const template_handler_1 = require("./utils/template-handler");
|
|
15
12
|
const handlebars_helpers_1 = require("./utils/handlebars-helpers");
|
|
16
13
|
const prisma_schema_parser_1 = require("./utils/prisma-schema-parser");
|
|
17
14
|
const analyze_1 = require("./utils/analyze");
|
|
15
|
+
const cli_style_1 = require("./utils/cli-style");
|
|
16
|
+
const project_utils_1 = require("./utils/project-utils");
|
|
17
|
+
const platform_utils_1 = require("./utils/platform-utils");
|
|
18
18
|
class IgniterCLI extends helpers_1.CLIHelper {
|
|
19
19
|
constructor() {
|
|
20
20
|
super();
|
|
21
21
|
this.program = new commander_1.Command();
|
|
22
|
-
this.spinner = (0, ora_1.default)();
|
|
23
22
|
this.schemaParser = new prisma_schema_parser_1.PrismaSchemaParser();
|
|
24
23
|
this.analyze = new analyze_1.AnalyzeCommand();
|
|
25
24
|
this.setupCLI();
|
|
@@ -33,9 +32,10 @@ class IgniterCLI extends helpers_1.CLIHelper {
|
|
|
33
32
|
.version('1.0.0');
|
|
34
33
|
this.program
|
|
35
34
|
.command('init')
|
|
36
|
-
.description('Initialize a new Next.js project with Igniter
|
|
37
|
-
.
|
|
38
|
-
|
|
35
|
+
.description('Initialize a new Next.js project with Igniter.js')
|
|
36
|
+
.option('-d, --dir <directory>', 'Directory to initialize the project in')
|
|
37
|
+
.action(async (options) => {
|
|
38
|
+
await this.init(options.dir);
|
|
39
39
|
});
|
|
40
40
|
this.program
|
|
41
41
|
.command('analyze')
|
|
@@ -47,50 +47,180 @@ class IgniterCLI extends helpers_1.CLIHelper {
|
|
|
47
47
|
.command('generate feature')
|
|
48
48
|
.alias('g')
|
|
49
49
|
.description('Generate a new feature')
|
|
50
|
-
.option('-n, --name
|
|
50
|
+
.option('-n, --name <name>', 'Feature name')
|
|
51
51
|
.option('-f, --fields <fields...>', 'Fields for the feature (format: name:type)')
|
|
52
|
-
.
|
|
53
|
-
|
|
52
|
+
.option('-y, --yes', 'Automatically confirm creation if model is not found')
|
|
53
|
+
.action(async (options, params) => {
|
|
54
|
+
console.log(options, params);
|
|
55
|
+
if (!params.name) {
|
|
54
56
|
await this.generateAllFeatures();
|
|
55
57
|
return;
|
|
56
58
|
}
|
|
57
|
-
await this.generateFeature(name,
|
|
59
|
+
await this.generateFeature(params.name, params.fields || [], params.yes);
|
|
58
60
|
});
|
|
59
61
|
this.program.parse();
|
|
60
62
|
}
|
|
61
|
-
async init() {
|
|
63
|
+
async init(targetDir) {
|
|
62
64
|
console.clear();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
cli_style_1.CLIStyle.startSequence('Welcome to Igniter.js CLI');
|
|
66
|
+
cli_style_1.CLIStyle.logInfo('Let\'s configure your new project together. I\'ll guide you through each step.');
|
|
65
67
|
try {
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
+
// Se um diretório foi especificado, criar e navegar até ele
|
|
69
|
+
if (targetDir) {
|
|
70
|
+
cli_style_1.CLIStyle.logInfo(`Creating project in directory: ${targetDir}`);
|
|
71
|
+
// Normalizar o caminho do diretório
|
|
72
|
+
const normalizedPath = (0, platform_utils_1.normalizePath)(targetDir);
|
|
73
|
+
// Criar diretório se não existir
|
|
74
|
+
if (!fs_1.default.existsSync(normalizedPath)) {
|
|
75
|
+
fs_1.default.mkdirSync(normalizedPath, { recursive: true });
|
|
76
|
+
cli_style_1.CLIStyle.logSuccess(`Directory created: ${normalizedPath}`);
|
|
77
|
+
}
|
|
78
|
+
// Navegar para o diretório
|
|
79
|
+
process.chdir(normalizedPath);
|
|
80
|
+
cli_style_1.CLIStyle.logSuccess(`Changed to directory: ${process.cwd()}`);
|
|
81
|
+
}
|
|
82
|
+
const spinner = cli_style_1.CLIStyle.createSpinner('Checking required dependencies...');
|
|
83
|
+
spinner.start();
|
|
68
84
|
this.checkDependencies(consts_1.DEPENDENCIES.required);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
await this.setupProject();
|
|
85
|
+
spinner.succeed('All required dependencies are installed');
|
|
86
|
+
const preferences = await this.gatherUserPreferences();
|
|
87
|
+
await this.setupProject(preferences);
|
|
72
88
|
}
|
|
73
89
|
catch (error) {
|
|
74
|
-
|
|
75
|
-
console.error('\n' + chalk_1.default.red('Error details:'));
|
|
76
|
-
console.error(chalk_1.default.red(error));
|
|
90
|
+
cli_style_1.CLIStyle.logError('Project initialization failed', error);
|
|
77
91
|
process.exit(1);
|
|
78
92
|
}
|
|
79
93
|
}
|
|
80
|
-
async
|
|
94
|
+
async gatherUserPreferences() {
|
|
95
|
+
cli_style_1.CLIStyle.startSequence('Project Configuration');
|
|
96
|
+
const isNextProject = (0, project_utils_1.isNextJSProject)();
|
|
97
|
+
const packageManager = await inquirer_1.default.prompt({
|
|
98
|
+
type: 'list',
|
|
99
|
+
name: 'value',
|
|
100
|
+
message: 'Which package manager do you prefer?',
|
|
101
|
+
choices: [
|
|
102
|
+
{ name: 'bun', value: 'bun' },
|
|
103
|
+
{ name: 'npm', value: 'npm' },
|
|
104
|
+
{ name: 'yarn', value: 'yarn' },
|
|
105
|
+
{ name: 'pnpm', value: 'pnpm' }
|
|
106
|
+
],
|
|
107
|
+
default: 'npm'
|
|
108
|
+
});
|
|
109
|
+
let projectType = { value: 'nextjs' };
|
|
110
|
+
if (!isNextProject) {
|
|
111
|
+
projectType = await inquirer_1.default.prompt({
|
|
112
|
+
type: 'list',
|
|
113
|
+
name: 'value',
|
|
114
|
+
message: 'What type of project are you creating?',
|
|
115
|
+
choices: [
|
|
116
|
+
{
|
|
117
|
+
name: 'Fullstack (Igniter.js, Next.js, Zod and Prisma)',
|
|
118
|
+
value: 'nextjs',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'Rest API (Igniter.js, Express, Zod and Prisma)',
|
|
122
|
+
value: 'express',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'Only setup Igniter.js',
|
|
126
|
+
value: 'igniter',
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const database = await inquirer_1.default.prompt({
|
|
132
|
+
type: 'list',
|
|
133
|
+
name: 'value',
|
|
134
|
+
message: 'Would you like to set up Prisma ORM?',
|
|
135
|
+
choices: [
|
|
136
|
+
{
|
|
137
|
+
name: 'Yes, set up Prisma',
|
|
138
|
+
value: 'prisma',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: 'No, skip database setup',
|
|
142
|
+
value: 'none',
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
default: 'prisma'
|
|
146
|
+
});
|
|
147
|
+
// Display confirmation of selections
|
|
148
|
+
console.log('\n');
|
|
149
|
+
cli_style_1.CLIStyle.logInfo('Configuration summary:');
|
|
150
|
+
cli_style_1.CLIStyle.logInfo(`Package Manager: ${packageManager.value}`);
|
|
151
|
+
if (!isNextProject)
|
|
152
|
+
cli_style_1.CLIStyle.logInfo(`Project Type: ${projectType.value}`);
|
|
153
|
+
cli_style_1.CLIStyle.logInfo(`Database: ${database.value === 'prisma' ? 'Prisma ORM' : 'None'}`);
|
|
154
|
+
if (database.value === 'prisma') {
|
|
155
|
+
console.log('\n');
|
|
156
|
+
cli_style_1.CLIStyle.logInfo(`Note: With Prisma enabled, you can use the igniter generate feature command to automatically create features based on your Prisma schema models.`);
|
|
157
|
+
}
|
|
158
|
+
const confirm = await inquirer_1.default.prompt({
|
|
159
|
+
type: 'confirm',
|
|
160
|
+
name: 'value',
|
|
161
|
+
message: 'Ready to proceed with the installation?',
|
|
162
|
+
default: true
|
|
163
|
+
});
|
|
164
|
+
if (!confirm.value) {
|
|
165
|
+
cli_style_1.CLIStyle.logWarning('Installation cancelled by the user');
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
cli_style_1.CLIStyle.endSequence();
|
|
169
|
+
return {
|
|
170
|
+
'package-manager': packageManager.value,
|
|
171
|
+
'project-type': projectType.value,
|
|
172
|
+
'database': database.value,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
async generateFeature(name, fields = [], autoConfirm = false) {
|
|
81
176
|
console.clear();
|
|
82
|
-
|
|
177
|
+
cli_style_1.CLIStyle.startSequence(`Generating Feature: ${name}`);
|
|
83
178
|
try {
|
|
179
|
+
// Check if model exists in Prisma
|
|
180
|
+
const spinner = cli_style_1.CLIStyle.createSpinner('Parsing Prisma schema...');
|
|
181
|
+
spinner.start();
|
|
182
|
+
const modelExists = this.schemaParser.hasModel(name);
|
|
183
|
+
if (!modelExists) {
|
|
184
|
+
spinner.warn(`Model "${name}" not found in Prisma schema`);
|
|
185
|
+
// Ask user if they want to create a feature without a model
|
|
186
|
+
let createFeature = autoConfirm;
|
|
187
|
+
if (!autoConfirm) {
|
|
188
|
+
cli_style_1.CLIStyle.logInfo("The model doesn't exist in your Prisma schema");
|
|
189
|
+
console.log(cli_style_1.CLIStyle.getVerticalLine());
|
|
190
|
+
const answer = await inquirer_1.default.prompt({
|
|
191
|
+
type: 'confirm',
|
|
192
|
+
name: 'createFeature',
|
|
193
|
+
message: cli_style_1.CLIStyle.logPrompt(`Would you like to create a basic feature for "${name}" anyway?`),
|
|
194
|
+
default: true
|
|
195
|
+
});
|
|
196
|
+
createFeature = answer.createFeature;
|
|
197
|
+
}
|
|
198
|
+
if (!createFeature) {
|
|
199
|
+
cli_style_1.CLIStyle.logWarning('Feature generation cancelled');
|
|
200
|
+
cli_style_1.CLIStyle.endSequence();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
cli_style_1.CLIStyle.logInfo(`Creating basic feature for "${name}" without database model`);
|
|
204
|
+
}
|
|
84
205
|
// Parse fields from Prisma schema
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
206
|
+
let parsedFields = [];
|
|
207
|
+
if (modelExists) {
|
|
208
|
+
parsedFields = this.schemaParser.getModelFields(name);
|
|
209
|
+
// Transform parsed fields to include relationship info
|
|
210
|
+
parsedFields = parsedFields.map(field => ({
|
|
211
|
+
...field,
|
|
212
|
+
isRelation: !!field.relations,
|
|
213
|
+
isList: field.isList || (field.relations?.type === 'one-to-many' || field.relations?.type === 'many-to-many'),
|
|
214
|
+
isOptional: field.hasDefault || field.isOptional
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
else if (fields.length > 0) {
|
|
218
|
+
// Use provided fields as fallback
|
|
89
219
|
parsedFields = fields.map(field => {
|
|
90
220
|
const [name, type] = field.split(':');
|
|
91
221
|
return {
|
|
92
222
|
name,
|
|
93
|
-
type,
|
|
223
|
+
type: type || 'String',
|
|
94
224
|
zodType: 'z.string()',
|
|
95
225
|
description: `${name} field`,
|
|
96
226
|
isOptional: false,
|
|
@@ -101,21 +231,9 @@ class IgniterCLI extends helpers_1.CLIHelper {
|
|
|
101
231
|
};
|
|
102
232
|
});
|
|
103
233
|
}
|
|
104
|
-
|
|
105
|
-
// Transform parsed fields to include relationship info
|
|
106
|
-
parsedFields = parsedFields.map(field => {
|
|
107
|
-
var _a, _b;
|
|
108
|
-
return ({
|
|
109
|
-
...field,
|
|
110
|
-
isRelation: !!field.relations,
|
|
111
|
-
isList: field.isList || (((_a = field.relations) === null || _a === void 0 ? void 0 : _a.type) === 'one-to-many' || ((_b = field.relations) === null || _b === void 0 ? void 0 : _b.type) === 'many-to-many'),
|
|
112
|
-
isOptional: field.hasDefault || field.isOptional
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
this.spinner.succeed();
|
|
234
|
+
spinner.succeed('Schema analysis completed');
|
|
117
235
|
// Create feature directory
|
|
118
|
-
|
|
236
|
+
cli_style_1.CLIStyle.startStep('Creating directory structure');
|
|
119
237
|
const featurePath = path_1.default.join('src/features', name.toLowerCase());
|
|
120
238
|
this.createDir(featurePath);
|
|
121
239
|
// Create presentation directory and its subdirectories
|
|
@@ -140,13 +258,15 @@ class IgniterCLI extends helpers_1.CLIHelper {
|
|
|
140
258
|
for (const dir of featureDirs) {
|
|
141
259
|
this.createDir(path_1.default.join(featurePath, dir));
|
|
142
260
|
}
|
|
143
|
-
|
|
261
|
+
cli_style_1.CLIStyle.endStep();
|
|
144
262
|
// Generate files from templates
|
|
263
|
+
cli_style_1.CLIStyle.startStep('Generating feature files');
|
|
145
264
|
const templateData = {
|
|
146
265
|
name,
|
|
147
|
-
fields: parsedFields
|
|
266
|
+
fields: parsedFields,
|
|
267
|
+
hasFields: parsedFields.length > 0,
|
|
268
|
+
noModel: !modelExists
|
|
148
269
|
};
|
|
149
|
-
this.spinner.start('Generating feature files...');
|
|
150
270
|
const templates = {
|
|
151
271
|
'feature.index': 'index.ts',
|
|
152
272
|
'feature.interface': `${name.toLowerCase()}.interface.ts`,
|
|
@@ -157,19 +277,31 @@ class IgniterCLI extends helpers_1.CLIHelper {
|
|
|
157
277
|
const content = template_handler_1.TemplateHandler.render(template, templateData);
|
|
158
278
|
this.createFile(path_1.default.join(featurePath, filePath), content);
|
|
159
279
|
}
|
|
160
|
-
|
|
161
|
-
|
|
280
|
+
cli_style_1.CLIStyle.endStep();
|
|
281
|
+
cli_style_1.CLIStyle.endSequence();
|
|
282
|
+
cli_style_1.CLIStyle.logSuccess(`Feature ${name} generated successfully!`);
|
|
283
|
+
if (modelExists && parsedFields.length > 0) {
|
|
284
|
+
cli_style_1.CLIStyle.logInfo(`Created ${Object.keys(templates).length} files with ${parsedFields.length} fields from Prisma model`);
|
|
285
|
+
}
|
|
286
|
+
else if (!modelExists && parsedFields.length > 0) {
|
|
287
|
+
cli_style_1.CLIStyle.logInfo(`Created ${Object.keys(templates).length} files with ${parsedFields.length} custom fields`);
|
|
288
|
+
}
|
|
289
|
+
else if (!modelExists) {
|
|
290
|
+
cli_style_1.CLIStyle.logInfo(`Created basic feature template without fields`);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
cli_style_1.CLIStyle.logWarning(`No fields were found in the Prisma schema for model ${name}`);
|
|
294
|
+
}
|
|
295
|
+
console.log('\n');
|
|
162
296
|
}
|
|
163
297
|
catch (error) {
|
|
164
|
-
|
|
165
|
-
console.error('\n' + chalk_1.default.red('Error details:'));
|
|
166
|
-
console.error(chalk_1.default.red(error));
|
|
298
|
+
cli_style_1.CLIStyle.logError('Feature generation failed', error);
|
|
167
299
|
process.exit(1);
|
|
168
300
|
}
|
|
169
301
|
}
|
|
170
302
|
async generateAllFeatures() {
|
|
171
303
|
console.clear();
|
|
172
|
-
|
|
304
|
+
cli_style_1.CLIStyle.startSequence('Batch Feature Generation');
|
|
173
305
|
try {
|
|
174
306
|
// Get all models from schema
|
|
175
307
|
const schemaContent = this.schemaParser.getSchemaContent();
|
|
@@ -180,15 +312,16 @@ class IgniterCLI extends helpers_1.CLIHelper {
|
|
|
180
312
|
models.push(match[1]);
|
|
181
313
|
}
|
|
182
314
|
if (models.length === 0) {
|
|
183
|
-
|
|
184
|
-
|
|
315
|
+
cli_style_1.CLIStyle.logWarning('No models found in your Prisma schema');
|
|
316
|
+
cli_style_1.CLIStyle.logInfo('Tip: Add some models to your schema.prisma file first');
|
|
317
|
+
cli_style_1.CLIStyle.endSequence();
|
|
185
318
|
return;
|
|
186
319
|
}
|
|
187
320
|
// Let user select models
|
|
188
321
|
const { selectedModels } = await inquirer_1.default.prompt([{
|
|
189
322
|
type: 'checkbox',
|
|
190
323
|
name: 'selectedModels',
|
|
191
|
-
message:
|
|
324
|
+
message: cli_style_1.CLIStyle.logPrompt('Select which models to generate features for:'),
|
|
192
325
|
choices: models.map(model => ({
|
|
193
326
|
name: model,
|
|
194
327
|
value: model,
|
|
@@ -196,171 +329,220 @@ class IgniterCLI extends helpers_1.CLIHelper {
|
|
|
196
329
|
}))
|
|
197
330
|
}]);
|
|
198
331
|
if (selectedModels.length === 0) {
|
|
199
|
-
|
|
332
|
+
cli_style_1.CLIStyle.logWarning('No models selected. Operation cancelled.');
|
|
333
|
+
cli_style_1.CLIStyle.endSequence();
|
|
200
334
|
return;
|
|
201
335
|
}
|
|
336
|
+
cli_style_1.CLIStyle.startStep(`Generating ${selectedModels.length} features`);
|
|
202
337
|
// Track progress
|
|
203
338
|
let completed = 0;
|
|
204
339
|
const total = selectedModels.length;
|
|
205
340
|
const failed = [];
|
|
206
341
|
for (const model of selectedModels) {
|
|
207
|
-
|
|
342
|
+
const spinner = cli_style_1.CLIStyle.createSpinner(`Processing model ${model} [${completed + 1}/${total}]`);
|
|
343
|
+
spinner.start();
|
|
208
344
|
try {
|
|
209
|
-
|
|
345
|
+
// Create a feature without displaying all the normal output
|
|
346
|
+
const featurePath = path_1.default.join('src/features', model.toLowerCase());
|
|
347
|
+
this.createDir(featurePath);
|
|
348
|
+
// Create subdirectories
|
|
349
|
+
const presentationPath = path_1.default.join(featurePath, 'presentation');
|
|
350
|
+
this.createDir(presentationPath);
|
|
351
|
+
for (const dir of ['components', 'hooks', 'contexts', 'utils']) {
|
|
352
|
+
const dirPath = path_1.default.join(presentationPath, dir);
|
|
353
|
+
this.createDir(dirPath);
|
|
354
|
+
this.createFile(path_1.default.join(dirPath, '.gitkeep'), '');
|
|
355
|
+
}
|
|
356
|
+
for (const dir of ['controllers', 'procedures']) {
|
|
357
|
+
this.createDir(path_1.default.join(featurePath, dir));
|
|
358
|
+
}
|
|
359
|
+
// Parse fields and generate templates
|
|
360
|
+
let parsedFields = this.schemaParser.getModelFields(model);
|
|
361
|
+
parsedFields = parsedFields.map(field => ({
|
|
362
|
+
...field,
|
|
363
|
+
isRelation: !!field.relations,
|
|
364
|
+
isList: field.isList || (field.relations?.type === 'one-to-many' || field.relations?.type === 'many-to-many'),
|
|
365
|
+
isOptional: field.hasDefault || field.isOptional
|
|
366
|
+
}));
|
|
367
|
+
const templateData = { name: model, fields: parsedFields };
|
|
368
|
+
const templates = {
|
|
369
|
+
'feature.index': 'index.ts',
|
|
370
|
+
'feature.interface': `${model.toLowerCase()}.interface.ts`,
|
|
371
|
+
'feature.controller': `controllers/${model.toLowerCase()}.controller.ts`,
|
|
372
|
+
'feature.procedure': `procedures/${model.toLowerCase()}.procedure.ts`
|
|
373
|
+
};
|
|
374
|
+
for (const [template, filePath] of Object.entries(templates)) {
|
|
375
|
+
const content = template_handler_1.TemplateHandler.render(template, templateData);
|
|
376
|
+
this.createFile(path_1.default.join(featurePath, filePath), content);
|
|
377
|
+
}
|
|
210
378
|
completed++;
|
|
211
|
-
|
|
379
|
+
spinner.succeed(`Generated feature for ${model}`);
|
|
212
380
|
}
|
|
213
381
|
catch (error) {
|
|
214
382
|
failed.push(model);
|
|
215
|
-
|
|
216
|
-
|
|
383
|
+
spinner.fail(`Failed to generate feature for ${model}`);
|
|
384
|
+
cli_style_1.CLIStyle.logInfo(`Error: ${error}`);
|
|
217
385
|
}
|
|
218
|
-
// Show progress
|
|
386
|
+
// Show progress
|
|
219
387
|
const progress = completed / total * 100;
|
|
220
|
-
|
|
221
|
-
console.log('');
|
|
388
|
+
cli_style_1.CLIStyle.logInfo(`Progress: ${Math.round(progress)}% [${'='.repeat(Math.floor(progress / 5))}${' '.repeat(20 - Math.floor(progress / 5))}]`);
|
|
222
389
|
}
|
|
390
|
+
cli_style_1.CLIStyle.endStep();
|
|
391
|
+
cli_style_1.CLIStyle.endSequence();
|
|
223
392
|
// Final summary
|
|
224
|
-
|
|
225
|
-
|
|
393
|
+
cli_style_1.CLIStyle.logInfo(`Generation summary:`);
|
|
394
|
+
cli_style_1.CLIStyle.logSuccess(`Successfully generated: ${completed}/${total} features`);
|
|
226
395
|
if (failed.length > 0) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
failed.forEach(model =>
|
|
230
|
-
}
|
|
231
|
-
if (completed === total) {
|
|
232
|
-
console.log('\n' + chalk_1.default.bold.green('✨ All features generated successfully! ✨'));
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
console.log('\n' + chalk_1.default.yellow('⚠️ Some features could not be generated.'));
|
|
236
|
-
console.log(chalk_1.default.gray(' Check the errors above and try again.'));
|
|
396
|
+
cli_style_1.CLIStyle.logWarning(`Failed to generate: ${failed.length} features`);
|
|
397
|
+
cli_style_1.CLIStyle.logInfo('Failed models:');
|
|
398
|
+
failed.forEach(model => cli_style_1.CLIStyle.logInfo(`- ${model}`));
|
|
237
399
|
}
|
|
238
|
-
console.log('');
|
|
239
400
|
}
|
|
240
401
|
catch (error) {
|
|
241
|
-
|
|
242
|
-
console.error('\n' + chalk_1.default.red('Error details:'));
|
|
243
|
-
console.error(chalk_1.default.gray(error));
|
|
402
|
+
cli_style_1.CLIStyle.logError('Failed to generate features', error);
|
|
244
403
|
process.exit(1);
|
|
245
404
|
}
|
|
246
405
|
}
|
|
247
|
-
async setupProject() {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
this.spinner.start('Creating Next.js application...');
|
|
251
|
-
await this.delay(1000); // Pequena pausa para melhor visualização
|
|
252
|
-
this.execCommand('npx create-next-app@canary --ts --turbopack --import-alias "@/*" --src-dir --tailwind --eslint --typescript --app .');
|
|
253
|
-
this.spinner.succeed('Next.js application created successfully');
|
|
406
|
+
async setupProject(preferences) {
|
|
407
|
+
cli_style_1.CLIStyle.startSequence('Project Setup');
|
|
408
|
+
cli_style_1.CLIStyle.logInfo('Setting up your Igniter project. This might take a few minutes...');
|
|
254
409
|
// Project structure
|
|
255
|
-
|
|
256
|
-
|
|
410
|
+
cli_style_1.CLIStyle.startStep('Setting up project structure');
|
|
411
|
+
const spinner2 = cli_style_1.CLIStyle.createSpinner('Creating directories...');
|
|
412
|
+
spinner2.start();
|
|
413
|
+
const packageManager = preferences['package-manager'];
|
|
414
|
+
const isNextProject = (0, project_utils_1.isNextJSProject)();
|
|
415
|
+
if (isNextProject) {
|
|
416
|
+
this.createDir('src/app/api/[[...all]]');
|
|
417
|
+
this.createFile('src/app/api/[[...all]]/route.ts', template_handler_1.TemplateHandler.render('route.hbs', {}));
|
|
418
|
+
this.createFile('src/hooks/use-form-with-zod.ts', template_handler_1.TemplateHandler.render('use-form-with-zod', {}));
|
|
419
|
+
}
|
|
420
|
+
if (!isNextProject) {
|
|
421
|
+
if (preferences['project-type'] === 'express') {
|
|
422
|
+
this.execCommand(`${packageManager} init -y`);
|
|
423
|
+
this.execCommand(`${packageManager} install express`);
|
|
424
|
+
this.execCommand(`${packageManager} install --save-dev typescript ts-node @types/node @types/express`);
|
|
425
|
+
const packageJson = this.loadJSON('package.json');
|
|
426
|
+
packageJson.name = path_1.default.basename(process.cwd());
|
|
427
|
+
packageJson.version = '1.0.0';
|
|
428
|
+
packageJson.legacyPeerDeps = true;
|
|
429
|
+
packageJson.scripts = {};
|
|
430
|
+
packageJson.scripts['build'] = 'tsc';
|
|
431
|
+
packageJson.scripts['start'] = 'node dist/server.js';
|
|
432
|
+
packageJson.scripts['dev'] = 'ts-node src/server.ts';
|
|
433
|
+
this.saveJSON('package.json', packageJson);
|
|
434
|
+
this.createFile('src/server.ts', template_handler_1.TemplateHandler.render('express.server.hbs', {}));
|
|
435
|
+
this.createFile('README.md', template_handler_1.TemplateHandler.render('readme.hbs', {}));
|
|
436
|
+
this.createFile('eslintrc.json', template_handler_1.TemplateHandler.render('eslintrc.hbs', {}));
|
|
437
|
+
this.createFile('docker-compose.yml', template_handler_1.TemplateHandler.render('docker-compose.hbs', {}));
|
|
438
|
+
}
|
|
439
|
+
if (preferences['project-type'] === 'nextjs') {
|
|
440
|
+
this.execCommand(`npx create-next-app@latest --ts --tailwind --eslint --app --src-dir --turbopack --import-alias="@/*" --use-${packageManager} .`);
|
|
441
|
+
const packageJson = this.loadJSON('package.json');
|
|
442
|
+
packageJson.name = path_1.default.basename(process.cwd());
|
|
443
|
+
packageJson.version = '1.0.0';
|
|
444
|
+
packageJson.legacyPeerDeps = true;
|
|
445
|
+
this.saveJSON('package.json', packageJson);
|
|
446
|
+
this.createFile('.github/copilot.next.instructions.md', template_handler_1.TemplateHandler.render('copilot.next.instructions.hbs', {}));
|
|
447
|
+
this.createFile('.github/copilot.form.instructions.md', template_handler_1.TemplateHandler.render('copilot.form.instructions.hbs', {}));
|
|
448
|
+
this.createFile('src/app/page.tsx', template_handler_1.TemplateHandler.render('page.hbs', {}));
|
|
449
|
+
this.createFile('src/app/layout.tsx', template_handler_1.TemplateHandler.render('layout.hbs', {}));
|
|
450
|
+
this.createFile('src/app/globals.css', template_handler_1.TemplateHandler.render('globals.hbs', {}));
|
|
451
|
+
this.createDir('src/app/api/[[...all]]');
|
|
452
|
+
this.createFile('src/app/api/[[...all]]/route.ts', template_handler_1.TemplateHandler.render('route.hbs', {}));
|
|
453
|
+
this.createFile('src/hooks/use-form-with-zod.ts', template_handler_1.TemplateHandler.render('use-form-with-zod', {}));
|
|
454
|
+
this.createFile('README.md', template_handler_1.TemplateHandler.render('readme.hbs', {}));
|
|
455
|
+
this.createFile('eslintrc.json', template_handler_1.TemplateHandler.render('eslintrc.hbs', {}));
|
|
456
|
+
this.createFile('docker-compose.yml', template_handler_1.TemplateHandler.render('docker-compose.hbs', {}));
|
|
457
|
+
const runner = (0, project_utils_1.getPackageManagerRunner)(packageManager);
|
|
458
|
+
if (!runner) {
|
|
459
|
+
cli_style_1.CLIStyle.logError('Unsupported package manager. Please use npm, yarn, pnpm or bun.');
|
|
460
|
+
process.exit(1);
|
|
461
|
+
}
|
|
462
|
+
console.log(runner);
|
|
463
|
+
this.execCommand(`${runner} shadcn@latest init -y -f --src-dir --css-variables --base-color zinc`);
|
|
464
|
+
this.execCommand(`${runner} shadcn@latest add -y -a`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
257
467
|
this.createDirectoryStructure(consts_1.PROJECT_STRUCTURE);
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
468
|
+
spinner2.succeed('Directory structure created');
|
|
469
|
+
cli_style_1.CLIStyle.endStep();
|
|
470
|
+
// Prisma setup (conditional)
|
|
471
|
+
if (preferences.database === 'prisma') {
|
|
472
|
+
cli_style_1.CLIStyle.startStep('Setting up Prisma ORM');
|
|
473
|
+
const spinner3 = cli_style_1.CLIStyle.createSpinner('Initializing Prisma...');
|
|
474
|
+
spinner3.start();
|
|
475
|
+
this.execCommand('npx prisma init');
|
|
476
|
+
this.execCommand('rm ./.env');
|
|
477
|
+
const prismaFile = template_handler_1.TemplateHandler.render('prisma', {});
|
|
478
|
+
this.createFile('src/providers/prisma.ts', prismaFile);
|
|
479
|
+
spinner3.succeed('Prisma initialized');
|
|
480
|
+
cli_style_1.CLIStyle.endStep();
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
cli_style_1.CLIStyle.logInfo('Skipping Prisma setup as per your preference');
|
|
484
|
+
}
|
|
274
485
|
// Core dependencies
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
this.execCommand(
|
|
279
|
-
this.
|
|
280
|
-
// Shadcn/UI setup
|
|
281
|
-
await this.delay(1000);
|
|
282
|
-
this.spinner.start('Setting up Shadcn/UI...');
|
|
283
|
-
this.execCommand('npm config set legacy-peer-deps true');
|
|
284
|
-
this.execCommand('npx shadcn@canary init -d -y');
|
|
285
|
-
const content = template_handler_1.TemplateHandler.render('components.json', {});
|
|
286
|
-
this.updateFile('components.json', content);
|
|
287
|
-
this.execCommand('npx shadcn@canary add --all');
|
|
288
|
-
this.spinner.succeed('Shadcn/UI setup completed');
|
|
289
|
-
// Environment files
|
|
290
|
-
await this.delay(1000);
|
|
291
|
-
this.spinner.start('Creating environment files...');
|
|
486
|
+
cli_style_1.CLIStyle.startStep('Installing Igniter.js and updating environment files');
|
|
487
|
+
const spinner5 = cli_style_1.CLIStyle.createSpinner('Installing packages...');
|
|
488
|
+
spinner5.start();
|
|
489
|
+
this.execCommand(`${packageManager} install @igniter-js/eslint-config`);
|
|
490
|
+
this.execCommand(`${packageManager} install @igniter-js/core`);
|
|
292
491
|
const envContent = template_handler_1.TemplateHandler.render('env.hbs', {});
|
|
293
492
|
this.createFile('.env', envContent);
|
|
294
|
-
this.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
this.
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const pageContent = template_handler_1.TemplateHandler.render('page.hbs', {});
|
|
301
|
-
this.updateFile('src/app/page.tsx', pageContent);
|
|
302
|
-
const layoutContent = template_handler_1.TemplateHandler.render('layout.hbs', {});
|
|
303
|
-
this.updateFile('src/app/layout.tsx', layoutContent);
|
|
304
|
-
const globalsContent = template_handler_1.TemplateHandler.render('globals.hbs', {});
|
|
305
|
-
this.updateFile('src/app/globals.css', globalsContent);
|
|
306
|
-
this.spinner.succeed('Project files configured successfully');
|
|
307
|
-
// Package configuration
|
|
308
|
-
await this.delay(1000);
|
|
309
|
-
this.spinner.start('Updating package configuration...');
|
|
310
|
-
const packageJson = this.loadJSON('package.json');
|
|
311
|
-
for (const config of consts_1.CONFIG_FILES) {
|
|
312
|
-
const content = template_handler_1.TemplateHandler.render(config.template, {});
|
|
313
|
-
this.createFile(config.name, content);
|
|
314
|
-
}
|
|
315
|
-
this.spinner.succeed('Package configuration updated successfully');
|
|
493
|
+
this.createFile('src/igniter.client.ts', template_handler_1.TemplateHandler.render('igniter.client', {}));
|
|
494
|
+
this.createFile('src/igniter.context.ts', template_handler_1.TemplateHandler.render('igniter.context', {}));
|
|
495
|
+
this.createFile('src/igniter.router.ts', template_handler_1.TemplateHandler.render('igniter.router', {}));
|
|
496
|
+
this.createFile('src/igniter.ts', template_handler_1.TemplateHandler.render('igniter', {}));
|
|
497
|
+
spinner5.succeed('Igniter.js installed and environment files updated');
|
|
498
|
+
cli_style_1.CLIStyle.endStep();
|
|
316
499
|
// Lia files
|
|
317
|
-
|
|
318
|
-
|
|
500
|
+
cli_style_1.CLIStyle.startStep('Creating Lia assistant files for GitHub Copilot');
|
|
501
|
+
const spinner10 = cli_style_1.CLIStyle.createSpinner('Setting up Lia...');
|
|
502
|
+
spinner10.start();
|
|
319
503
|
for (const file of consts_1.LIA_FILES) {
|
|
320
504
|
const content = template_handler_1.TemplateHandler.render(file.template, {});
|
|
321
505
|
this.createFile(file.name, content);
|
|
322
506
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
console.log(
|
|
345
|
-
console.log(
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
${chalk_1.default.cyan('💡')} Need help? ${chalk_1.default.blue('https://github.com/felipebarcelospro/igniter-js/issues')}
|
|
361
|
-
`);
|
|
362
|
-
console.log(chalk_1.default.bold.green('\n✨ Happy coding! ✨\n'));
|
|
507
|
+
spinner10.succeed('Lia assistant configured');
|
|
508
|
+
cli_style_1.CLIStyle.endStep();
|
|
509
|
+
cli_style_1.CLIStyle.endSequence();
|
|
510
|
+
cli_style_1.CLIStyle.logSuccess('Your Igniter project is ready!');
|
|
511
|
+
console.log('\n' + '🎯 Next Steps:\n');
|
|
512
|
+
console.log(` 1. Start development server:`);
|
|
513
|
+
console.log(` $ npm run dev`);
|
|
514
|
+
console.log('');
|
|
515
|
+
if (preferences.database === 'prisma') {
|
|
516
|
+
console.log(` 2. Start Docker services for database:`);
|
|
517
|
+
console.log(` $ docker compose up -d`);
|
|
518
|
+
console.log('');
|
|
519
|
+
console.log(` 3. Run Prisma migrations:`);
|
|
520
|
+
console.log(` $ npx prisma migrate dev`);
|
|
521
|
+
console.log('');
|
|
522
|
+
console.log(` 4. Generate features from your database models:`);
|
|
523
|
+
console.log(` $ npx @igniter-js/cli generate feature`);
|
|
524
|
+
console.log('');
|
|
525
|
+
}
|
|
526
|
+
console.log('\n' + '🎯 Next Steps:\n');
|
|
527
|
+
console.log(` 1. Start development server:`);
|
|
528
|
+
console.log(` $ npm run dev`);
|
|
529
|
+
console.log('');
|
|
530
|
+
if (preferences.database === 'prisma') {
|
|
531
|
+
console.log(` 2. Start Docker services for database:`);
|
|
532
|
+
console.log(` $ docker compose up -d`);
|
|
533
|
+
console.log('');
|
|
534
|
+
console.log(` 3. Run Prisma migrations:`);
|
|
535
|
+
console.log(` $ npx prisma migrate dev`);
|
|
536
|
+
console.log('');
|
|
537
|
+
console.log(` 4. Generate features from your database models:`);
|
|
538
|
+
console.log(` $ npx @igniter-js/cli generate feature`);
|
|
539
|
+
console.log('');
|
|
540
|
+
}
|
|
541
|
+
console.log(` 📚 Documentation: https://github.com/felipebarcelospro/igniter-js`);
|
|
542
|
+
console.log(` 💡 Need help? https://github.com/felipebarcelospro/igniter-js/issues`);
|
|
543
|
+
console.log('\n' + '✨ Happy coding with Igniter! ✨\n');
|
|
363
544
|
}
|
|
364
545
|
}
|
|
365
546
|
// Start CLI
|
|
366
547
|
new IgniterCLI();
|
|
548
|
+
//# sourceMappingURL=index.js.map
|