@moamc/rn-cli 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.
- package/LICENSE +21 -0
- package/README.md +154 -0
- package/generators/api.js +155 -0
- package/generators/feature.js +155 -0
- package/generators/hook.js +115 -0
- package/generators/screen.js +351 -0
- package/index.js +100 -0
- package/package.json +43 -0
- package/templates/apiTemplate.js +217 -0
- package/templates/constantsTemplate.js +33 -0
- package/templates/constantsTemplate.js.backup +18 -0
- package/templates/fieldGeneratorTemplate.js +165 -0
- package/templates/helpersTemplate.js +10 -0
- package/templates/hookTemplate.js +132 -0
- package/templates/hookTemplate.js.backup +113 -0
- package/templates/queryTemplate.js +23 -0
- package/templates/screenTemplate.js +165 -0
- package/templates/screenTemplate.js.backup +147 -0
- package/templates/stylesTemplate.js +52 -0
- package/templates/stylesTemplate.js.backup +88 -0
- package/templates/validationTemplate.js +122 -0
- package/templates/validationTemplate.js.backup +37 -0
- package/utils/fileUtils.js +116 -0
- package/utils/navigationUtils.js +74 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const {
|
|
6
|
+
getProjectPath,
|
|
7
|
+
writeFile,
|
|
8
|
+
logSuccess,
|
|
9
|
+
logInfo,
|
|
10
|
+
toPascalCase,
|
|
11
|
+
confirmOverwrite,
|
|
12
|
+
fileExists,
|
|
13
|
+
} = require('../utils/fileUtils');
|
|
14
|
+
const { addScreenToNavigation, addScreenToIndexExport } = require('../utils/navigationUtils');
|
|
15
|
+
const { generateScreenTemplate } = require('../templates/screenTemplate');
|
|
16
|
+
const { generateHookTemplate } = require('../templates/hookTemplate');
|
|
17
|
+
const { generateValidationTemplate } = require('../templates/validationTemplate');
|
|
18
|
+
const { generateStylesTemplate } = require('../templates/stylesTemplate');
|
|
19
|
+
const { generateConstantsTemplate } = require('../templates/constantsTemplate');
|
|
20
|
+
const { generateHelpersTemplate } = require('../templates/helpersTemplate');
|
|
21
|
+
const {
|
|
22
|
+
generateApiServiceTemplate,
|
|
23
|
+
generateQueryOptionsTemplate,
|
|
24
|
+
generateApiIntegratedHookTemplate
|
|
25
|
+
} = require('../templates/apiTemplate');
|
|
26
|
+
|
|
27
|
+
const generateScreen = async () => {
|
|
28
|
+
console.log(chalk.cyan.bold('\n╭────────────────────────────────────────────────────────────╮'));
|
|
29
|
+
console.log(chalk.cyan.bold('│') + chalk.white.bold(' 📱 SCREEN CREATION WIZARD ') + chalk.cyan.bold(' │'));
|
|
30
|
+
console.log(chalk.cyan.bold('╰────────────────────────────────────────────────────────────╯'));
|
|
31
|
+
console.log(chalk.gray(' Add a new screen to an existing feature module\n'));
|
|
32
|
+
|
|
33
|
+
const screensPath = getProjectPath('screens');
|
|
34
|
+
const features = fs.readdirSync(screensPath).filter(file => {
|
|
35
|
+
const fullPath = path.join(screensPath, file);
|
|
36
|
+
return fs.statSync(fullPath).isDirectory();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const answers = await inquirer.prompt([
|
|
40
|
+
{
|
|
41
|
+
type: 'list',
|
|
42
|
+
name: 'featureName',
|
|
43
|
+
message: chalk.yellow('❓ Select the target feature:'),
|
|
44
|
+
choices: features,
|
|
45
|
+
prefix: chalk.green('✓'),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: 'input',
|
|
49
|
+
name: 'screenName',
|
|
50
|
+
message: chalk.yellow('❓ Enter screen name') + chalk.gray(' (e.g., EditProfile, ViewDetails):'),
|
|
51
|
+
validate: (input) => input.trim() !== '' || chalk.red('⚠️ Screen name is required'),
|
|
52
|
+
prefix: chalk.green('✓'),
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: 'confirm',
|
|
56
|
+
name: 'hasForm',
|
|
57
|
+
message: chalk.yellow('❓ Does this screen include a form?'),
|
|
58
|
+
default: false,
|
|
59
|
+
prefix: chalk.green('✓'),
|
|
60
|
+
},
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
let formFields = [];
|
|
64
|
+
let eventName = null;
|
|
65
|
+
const featureName = answers.featureName;
|
|
66
|
+
const screenName = toPascalCase(answers.screenName);
|
|
67
|
+
|
|
68
|
+
if (answers.hasForm) {
|
|
69
|
+
console.log(chalk.cyan('\n╭────────────────────────────────────────────────────────────╮'));
|
|
70
|
+
console.log(chalk.cyan('│') + chalk.white.bold(' 🔌 API INTEGRATION ') + chalk.cyan('│'));
|
|
71
|
+
console.log(chalk.cyan('╰────────────────────────────────────────────────────────────╯'));
|
|
72
|
+
|
|
73
|
+
const apiAnswers = await inquirer.prompt([
|
|
74
|
+
{
|
|
75
|
+
type: 'confirm',
|
|
76
|
+
name: 'hasApi',
|
|
77
|
+
message: chalk.yellow('❓ Does this screen need API integration?'),
|
|
78
|
+
default: true,
|
|
79
|
+
prefix: chalk.green('✓'),
|
|
80
|
+
},
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
if (apiAnswers.hasApi) {
|
|
84
|
+
const apiDetails = await inquirer.prompt([
|
|
85
|
+
{
|
|
86
|
+
type: 'input',
|
|
87
|
+
name: 'apiEndpoint',
|
|
88
|
+
message: chalk.yellow('❓ Enter API endpoint') + chalk.gray(' (e.g., /api/bank/details):'),
|
|
89
|
+
validate: (input) => input.trim() !== '' || chalk.red('⚠️ API endpoint is required'),
|
|
90
|
+
prefix: chalk.green('✓'),
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
type: 'list',
|
|
94
|
+
name: 'apiMethod',
|
|
95
|
+
message: chalk.yellow('❓ Select HTTP method:'),
|
|
96
|
+
choices: [
|
|
97
|
+
{ name: chalk.blue('GET') + chalk.gray(' - Fetch data'), value: 'GET' },
|
|
98
|
+
{ name: chalk.blue('POST') + chalk.gray(' - Create/Update data'), value: 'POST' },
|
|
99
|
+
],
|
|
100
|
+
prefix: chalk.green('✓'),
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
type: 'input',
|
|
104
|
+
name: 'queryKey',
|
|
105
|
+
message: chalk.yellow('❓ Enter React Query key') + chalk.gray(' (e.g., bankDetails):'),
|
|
106
|
+
default: (answers) => screenName.toLowerCase(),
|
|
107
|
+
prefix: chalk.green('✓'),
|
|
108
|
+
},
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
const methods = [{
|
|
112
|
+
name: apiDetails.apiMethod === 'GET' ? `get${screenName}` : `submit${screenName}`,
|
|
113
|
+
endpoint: apiDetails.apiEndpoint,
|
|
114
|
+
type: apiDetails.apiMethod,
|
|
115
|
+
queryKey: apiDetails.queryKey,
|
|
116
|
+
hasAuth: true,
|
|
117
|
+
}];
|
|
118
|
+
|
|
119
|
+
// If GET was selected, ask if they want to add POST
|
|
120
|
+
if (apiDetails.apiMethod === 'GET') {
|
|
121
|
+
const postApiAnswer = await inquirer.prompt([
|
|
122
|
+
{
|
|
123
|
+
type: 'confirm',
|
|
124
|
+
name: 'addPostApi',
|
|
125
|
+
message: chalk.yellow('❓ Do you want to add a POST API for form submission?'),
|
|
126
|
+
default: true,
|
|
127
|
+
prefix: chalk.green('✓'),
|
|
128
|
+
},
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
if (postApiAnswer.addPostApi) {
|
|
132
|
+
const postApiDetails = await inquirer.prompt([
|
|
133
|
+
{
|
|
134
|
+
type: 'input',
|
|
135
|
+
name: 'postEndpoint',
|
|
136
|
+
message: chalk.yellow('❓ Enter POST API endpoint') + chalk.gray(' (e.g., /api/bank/submit):'),
|
|
137
|
+
validate: (input) => input.trim() !== '' || chalk.red('⚠️ POST endpoint is required'),
|
|
138
|
+
prefix: chalk.green('✓'),
|
|
139
|
+
},
|
|
140
|
+
]);
|
|
141
|
+
|
|
142
|
+
methods.push({
|
|
143
|
+
name: `submit${screenName}`,
|
|
144
|
+
endpoint: postApiDetails.postEndpoint,
|
|
145
|
+
type: 'POST',
|
|
146
|
+
queryKey: `${apiDetails.queryKey}-submit`,
|
|
147
|
+
hasAuth: true,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
answers.apiConfig = {
|
|
153
|
+
serviceName: featureName.toLowerCase(),
|
|
154
|
+
methods,
|
|
155
|
+
primaryMethod: methods[0].name,
|
|
156
|
+
hasPostMethod: methods.some(m => m.type === 'POST'),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
console.log(chalk.cyan('\n╭────────────────────────────────────────────────────────────╮'));
|
|
161
|
+
console.log(chalk.cyan('│') + chalk.white.bold(' 📋 FORM FIELD BUILDER ') + chalk.cyan('│'));
|
|
162
|
+
console.log(chalk.cyan('╰────────────────────────────────────────────────────────────╯'));
|
|
163
|
+
let addMore = true;
|
|
164
|
+
let fieldCount = 0;
|
|
165
|
+
while (addMore) {
|
|
166
|
+
fieldCount++;
|
|
167
|
+
console.log(chalk.gray(`\n Configuring Field #${fieldCount}\n`));
|
|
168
|
+
const fieldAnswers = await inquirer.prompt([
|
|
169
|
+
{
|
|
170
|
+
type: 'input',
|
|
171
|
+
name: 'fieldName',
|
|
172
|
+
message: chalk.yellow('❓ Enter field name') + chalk.gray(' (e.g., accountNumber, email):'),
|
|
173
|
+
validate: (input) => input.trim() !== '' || chalk.red('⚠️ Field name is required'),
|
|
174
|
+
prefix: chalk.green('✓'),
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
type: 'list',
|
|
178
|
+
name: 'fieldType',
|
|
179
|
+
message: chalk.yellow('❓ Select field type:'),
|
|
180
|
+
choices: [
|
|
181
|
+
{ name: chalk.blue('🔤 Text') + chalk.gray(' - Standard text input'), value: 'text' },
|
|
182
|
+
{ name: chalk.blue('🔢 Number') + chalk.gray(' - Numeric input'), value: 'number' },
|
|
183
|
+
{ name: chalk.blue('✉️ Email') + chalk.gray(' - Email address'), value: 'email' },
|
|
184
|
+
{ name: chalk.blue('📅 Date') + chalk.gray(' - Date picker'), value: 'date' },
|
|
185
|
+
{ name: chalk.blue('📝 Dropdown') + chalk.gray(' - Select from options'), value: 'dropdown' },
|
|
186
|
+
{ name: chalk.blue('◉ Radio') + chalk.gray(' - Single choice'), value: 'radio' },
|
|
187
|
+
{ name: chalk.blue('☑️ Checkbox') + chalk.gray(' - Multiple choices'), value: 'checkbox' },
|
|
188
|
+
{ name: chalk.blue('📄 File') + chalk.gray(' - File upload'), value: 'file' },
|
|
189
|
+
],
|
|
190
|
+
prefix: chalk.green('✓'),
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
type: 'input',
|
|
194
|
+
name: 'fieldLabel',
|
|
195
|
+
message: chalk.yellow('❓ Enter field label') + chalk.gray(' (e.g., Account Number, Email Address):'),
|
|
196
|
+
validate: (input) => input.trim() !== '' || chalk.red('⚠️ Field label is required'),
|
|
197
|
+
prefix: chalk.green('✓'),
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
type: 'confirm',
|
|
201
|
+
name: 'isRequired',
|
|
202
|
+
message: chalk.yellow('❓ Is this field required?'),
|
|
203
|
+
default: true,
|
|
204
|
+
prefix: chalk.green('✓'),
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
type: 'list',
|
|
208
|
+
name: 'fieldWidth',
|
|
209
|
+
message: chalk.yellow('❓ Select field width:'),
|
|
210
|
+
choices: [
|
|
211
|
+
{ name: chalk.green('⬜ Full width (100%)'), value: 'full' },
|
|
212
|
+
{ name: chalk.green('▦️ Half width (48% - side by side)'), value: 'half' },
|
|
213
|
+
],
|
|
214
|
+
default: 'full',
|
|
215
|
+
when: (answers) => answers.fieldType !== 'checkbox',
|
|
216
|
+
prefix: chalk.green('✓'),
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
type: 'input',
|
|
220
|
+
name: 'dropdownOptions',
|
|
221
|
+
message: chalk.yellow('❓ Enter dropdown options') + chalk.gray(' (comma-separated, e.g., Option1,Option2):'),
|
|
222
|
+
when: (answers) => answers.fieldType === 'dropdown' || answers.fieldType === 'radio',
|
|
223
|
+
prefix: chalk.green('✓'),
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
type: 'confirm',
|
|
227
|
+
name: 'addMore',
|
|
228
|
+
message: chalk.yellow('❓ Add another field?'),
|
|
229
|
+
default: true,
|
|
230
|
+
prefix: chalk.green('✓'),
|
|
231
|
+
},
|
|
232
|
+
]);
|
|
233
|
+
|
|
234
|
+
formFields.push({
|
|
235
|
+
name: fieldAnswers.fieldName,
|
|
236
|
+
type: fieldAnswers.fieldType,
|
|
237
|
+
label: fieldAnswers.fieldLabel,
|
|
238
|
+
required: fieldAnswers.isRequired,
|
|
239
|
+
width: fieldAnswers.fieldWidth || 'full',
|
|
240
|
+
options: fieldAnswers.dropdownOptions?.split(',').map(o => o.trim()),
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
addMore = fieldAnswers.addMore;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Ask about submit/continue button and event name
|
|
247
|
+
const buttonAnswer = await inquirer.prompt([
|
|
248
|
+
{
|
|
249
|
+
type: 'confirm',
|
|
250
|
+
name: 'hasSubmitButton',
|
|
251
|
+
message: chalk.yellow('❓ Does this screen have a submit/continue button?'),
|
|
252
|
+
default: true,
|
|
253
|
+
prefix: chalk.green('✓'),
|
|
254
|
+
},
|
|
255
|
+
]);
|
|
256
|
+
|
|
257
|
+
if (buttonAnswer.hasSubmitButton) {
|
|
258
|
+
const eventAnswer = await inquirer.prompt([
|
|
259
|
+
{
|
|
260
|
+
type: 'input',
|
|
261
|
+
name: 'eventName',
|
|
262
|
+
message: chalk.yellow('❓ Please enter the notify visitor\'s event name:'),
|
|
263
|
+
validate: (input) => input.trim() !== '' || chalk.red('⚠️ Event name is required'),
|
|
264
|
+
prefix: chalk.green('✓'),
|
|
265
|
+
},
|
|
266
|
+
]);
|
|
267
|
+
eventName = eventAnswer.eventName;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const screenPath = getProjectPath('screens', featureName, screenName);
|
|
272
|
+
const hooksPath = path.join(screenPath, 'hooks');
|
|
273
|
+
const componentsPath = path.join(screenPath, 'components');
|
|
274
|
+
|
|
275
|
+
const screenFile = path.join(screenPath, `${screenName}.js`);
|
|
276
|
+
const hookFile = path.join(hooksPath, `use${screenName}.js`);
|
|
277
|
+
const stylesFile = path.join(componentsPath, 'styles.js');
|
|
278
|
+
const constantsFile = path.join(screenPath, 'constants.js');
|
|
279
|
+
const helpersFile = path.join(screenPath, 'helpers.js');
|
|
280
|
+
|
|
281
|
+
const files = [
|
|
282
|
+
{ path: screenFile, content: generateScreenTemplate(screenName, featureName, answers.hasForm, formFields) },
|
|
283
|
+
{ path: hookFile, content: answers.apiConfig
|
|
284
|
+
? generateApiIntegratedHookTemplate(screenName, answers.apiConfig, formFields)
|
|
285
|
+
: generateHookTemplate(screenName, answers.hasForm, formFields, eventName) },
|
|
286
|
+
{ path: stylesFile, content: generateStylesTemplate() },
|
|
287
|
+
{ path: constantsFile, content: generateConstantsTemplate(formFields) },
|
|
288
|
+
{ path: helpersFile, content: generateHelpersTemplate() },
|
|
289
|
+
];
|
|
290
|
+
|
|
291
|
+
// Add API service and query files if API integration is enabled
|
|
292
|
+
if (answers.apiConfig) {
|
|
293
|
+
const serviceDir = getProjectPath('services', featureName.toLowerCase());
|
|
294
|
+
const queryFile = getProjectPath('queries', `${featureName.toLowerCase()}Query.js`);
|
|
295
|
+
const serviceFile = path.join(serviceDir, `${featureName.toLowerCase()}.js`);
|
|
296
|
+
|
|
297
|
+
files.push(
|
|
298
|
+
{ path: serviceFile, content: generateApiServiceTemplate(answers.apiConfig) },
|
|
299
|
+
{ path: queryFile, content: generateQueryOptionsTemplate(answers.apiConfig) }
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (answers.hasForm) {
|
|
304
|
+
const validationFile = path.join(screenPath, 'validation.js');
|
|
305
|
+
files.push({ path: validationFile, content: generateValidationTemplate(formFields, screenName) });
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
for (const file of files) {
|
|
309
|
+
if (fileExists(file.path)) {
|
|
310
|
+
const shouldOverwrite = await confirmOverwrite(inquirer, file.path);
|
|
311
|
+
if (!shouldOverwrite) {
|
|
312
|
+
logInfo(`Skipped: ${path.basename(file.path)}`);
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
writeFile(file.path, file.content);
|
|
317
|
+
logSuccess(`Created: ${path.relative(getProjectPath(), file.path)}`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Add screen to screens/index.js
|
|
321
|
+
const screensIndexPath = getProjectPath('screens', 'index.js');
|
|
322
|
+
if (fileExists(screensIndexPath)) {
|
|
323
|
+
addScreenToIndexExport(screenName, featureName, screensIndexPath);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Add screen to Navigation.js
|
|
327
|
+
const navigationPath = getProjectPath('navigations', 'Navigation.js');
|
|
328
|
+
if (fileExists(navigationPath)) {
|
|
329
|
+
addScreenToNavigation(screenName, featureName, navigationPath);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
logSuccess(`\n✨ Screen "${screenName}" added to "${featureName}" successfully!`);
|
|
333
|
+
|
|
334
|
+
if (answers.apiConfig) {
|
|
335
|
+
console.log(chalk.cyan('\n╭────────────────────────────────────────────────────────────╮'));
|
|
336
|
+
console.log(chalk.cyan('│') + chalk.white.bold(' 🚀 API INTEGRATION COMPLETE ') + chalk.cyan('│'));
|
|
337
|
+
console.log(chalk.cyan('╰────────────────────────────────────────────────────────────╯'));
|
|
338
|
+
console.log(chalk.white(' • ') + chalk.green('✓') + chalk.gray(' API Service: ') + chalk.blue(`services/${featureName.toLowerCase()}/${featureName.toLowerCase()}.js`));
|
|
339
|
+
console.log(chalk.white(' • ') + chalk.green('✓') + chalk.gray(' Query Options: ') + chalk.blue(`queries/${featureName.toLowerCase()}Query.js`));
|
|
340
|
+
console.log(chalk.white(' • ') + chalk.green('✓') + chalk.gray(' React Query Hook: ') + chalk.blue(`Integrated in use${screenName}.js`));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
console.log(chalk.cyan('\n╭────────────────────────────────────────────────────────────╮'));
|
|
344
|
+
console.log(chalk.cyan('│') + chalk.white.bold(' 📝 NEXT STEPS ') + chalk.cyan('│'));
|
|
345
|
+
console.log(chalk.cyan('╰────────────────────────────────────────────────────────────╯'));
|
|
346
|
+
console.log(chalk.white(' 1. ') + chalk.green('✓') + chalk.gray(' Implement the screen logic in the hook'));
|
|
347
|
+
console.log(chalk.white(' 2. ') + chalk.green('✓') + chalk.gray(' Test the navigation to the new screen'));
|
|
348
|
+
console.log(chalk.cyan('\n' + '─'.repeat(65) + '\n'));
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
module.exports = { generateScreen };
|
package/index.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const packageJson = require('./package.json');
|
|
6
|
+
const { generateFeature } = require('./generators/feature');
|
|
7
|
+
const { generateScreen } = require('./generators/screen');
|
|
8
|
+
const { generateAPI } = require('./generators/api');
|
|
9
|
+
const { generateHook } = require('./generators/hook');
|
|
10
|
+
|
|
11
|
+
// Display professional banner
|
|
12
|
+
const displayBanner = () => {
|
|
13
|
+
console.clear();
|
|
14
|
+
console.log('');
|
|
15
|
+
console.log(chalk.cyan.bold(' ███╗ ███╗ ██████╗ █████╗ ███╗ ███╗ ██████╗ ██████╗██╗ ██╗'));
|
|
16
|
+
console.log(chalk.cyan.bold(' ████╗ ████║██╔═══██╗██╔══██╗████╗ ████║██╔════╝ ██╔════╝██║ ██║'));
|
|
17
|
+
console.log(chalk.cyan.bold(' ██╔████╔██║██║ ██║███████║██╔████╔██║██║ ██║ ██║ ██║'));
|
|
18
|
+
console.log(chalk.cyan.bold(' ██║╚██╔╝██║██║ ██║██╔══██║██║╚██╔╝██║██║ ██║ ██║ ██║'));
|
|
19
|
+
console.log(chalk.cyan.bold(' ██║ ╚═╝ ██║╚██████╔╝██║ ██║██║ ╚═╝ ██║╚██████╗ ╚██████╗███████╗██║'));
|
|
20
|
+
console.log(chalk.cyan.bold(' ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚══════╝╚═╝'));
|
|
21
|
+
console.log('');
|
|
22
|
+
console.log(chalk.gray(' Professional Code Generation Tool for Investor Applications'));
|
|
23
|
+
console.log(chalk.gray(' Version: ') + chalk.yellow(packageJson.version) + chalk.gray(' | Powered by MOAMC Engineering Team'));
|
|
24
|
+
console.log('');
|
|
25
|
+
console.log(chalk.cyan(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
26
|
+
console.log(chalk.white.bold('\n 📋 Available Commands:\n'));
|
|
27
|
+
console.log(chalk.green(' • generate:feature') + chalk.gray(' (g:f)') + ' - Create a complete feature module');
|
|
28
|
+
console.log(chalk.green(' • generate:screen') + chalk.gray(' (g:s)') + ' - Add a new screen to existing feature');
|
|
29
|
+
console.log(chalk.green(' • generate:api') + chalk.gray(' (g:a)') + ' - Generate API service methods');
|
|
30
|
+
console.log(chalk.green(' • generate:hook') + chalk.gray(' (g:h)') + ' - Create data-fetching hooks');
|
|
31
|
+
console.log('');
|
|
32
|
+
console.log(chalk.cyan(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
33
|
+
console.log('');
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Show banner before any command
|
|
37
|
+
displayBanner();
|
|
38
|
+
|
|
39
|
+
program
|
|
40
|
+
.name('moamc-cli')
|
|
41
|
+
.description('Enterprise-grade code generator for MOAMC Investor Applications')
|
|
42
|
+
.version(packageJson.version);
|
|
43
|
+
|
|
44
|
+
program
|
|
45
|
+
.command('generate:feature')
|
|
46
|
+
.alias('g:f')
|
|
47
|
+
.description('🎯 Generate a new feature with screen, API, and hook')
|
|
48
|
+
.action(async () => {
|
|
49
|
+
try {
|
|
50
|
+
console.log(chalk.cyan('\n🚀 Initiating Feature Generation Module...\n'));
|
|
51
|
+
await generateFeature();
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error(chalk.red.bold('\n❌ Error generating feature:'), error.message);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
program
|
|
59
|
+
.command('generate:screen')
|
|
60
|
+
.alias('g:s')
|
|
61
|
+
.description('📱 Add a new screen to an existing feature')
|
|
62
|
+
.action(async () => {
|
|
63
|
+
try {
|
|
64
|
+
console.log(chalk.cyan('\n🚀 Initiating Screen Generation Module...\n'));
|
|
65
|
+
await generateScreen();
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(chalk.red.bold('\n❌ Error generating screen:'), error.message);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
program
|
|
73
|
+
.command('generate:api')
|
|
74
|
+
.alias('g:a')
|
|
75
|
+
.description('🔌 Add a new API method')
|
|
76
|
+
.action(async () => {
|
|
77
|
+
try {
|
|
78
|
+
console.log(chalk.cyan('\n🚀 Initiating API Generation Module...\n'));
|
|
79
|
+
await generateAPI();
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(chalk.red.bold('\n❌ Error generating API:'), error.message);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
program
|
|
87
|
+
.command('generate:hook')
|
|
88
|
+
.alias('g:h')
|
|
89
|
+
.description('🪝 Generate a data-fetching hook')
|
|
90
|
+
.action(async () => {
|
|
91
|
+
try {
|
|
92
|
+
console.log(chalk.cyan('\n🚀 Initiating Hook Generation Module...\n'));
|
|
93
|
+
await generateHook();
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.error(chalk.red.bold('\n❌ Error generating hook:'), error.message);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@moamc/rn-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Enterprise-grade Code Generation CLI for React Native Applications",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"rn-cli": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node index.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"cli",
|
|
14
|
+
"generator",
|
|
15
|
+
"react-native",
|
|
16
|
+
"code-generation",
|
|
17
|
+
"scaffolding",
|
|
18
|
+
"boilerplate"
|
|
19
|
+
],
|
|
20
|
+
"author": "MOAMC Engineering Team",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/moamc/rn-cli.git"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=14.0.0"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"commander": "^11.1.0",
|
|
31
|
+
"inquirer": "^8.2.5",
|
|
32
|
+
"chalk": "^4.1.2",
|
|
33
|
+
"fs-extra": "^11.2.0"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"index.js",
|
|
37
|
+
"generators/",
|
|
38
|
+
"templates/",
|
|
39
|
+
"utils/",
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE"
|
|
42
|
+
]
|
|
43
|
+
}
|