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