@kosdev-code/kos-ui-cli 2.0.31 → 2.0.33
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kosdev-code/kos-ui-cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.33",
|
|
4
4
|
"bin": {
|
|
5
5
|
"kosui": "./src/lib/cli.mjs"
|
|
6
6
|
},
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"main": "./src/index.js",
|
|
21
21
|
"kos": {
|
|
22
22
|
"build": {
|
|
23
|
-
"gitHash": "
|
|
23
|
+
"gitHash": "f20219f379424dadeb9920b5996c2acdb8840dfa"
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"publishConfig": {
|
package/src/lib/cli.mjs
CHANGED
|
@@ -28,14 +28,13 @@ const showBanner =
|
|
|
28
28
|
command !== "help" && process.env.DISABLE_CLI_BANNER !== "true";
|
|
29
29
|
|
|
30
30
|
async function launch() {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
clearCache();
|
|
35
|
-
return "[ok] CLI cache cleared successfully.";
|
|
36
|
-
});
|
|
37
|
-
|
|
31
|
+
// Check for help modes before initializing plop to avoid expensive model parsing
|
|
32
|
+
const shouldShowHelp = parsedArgs.help;
|
|
33
|
+
|
|
38
34
|
if (!command || command === "help") {
|
|
35
|
+
// For general help, we still need plop to list generators
|
|
36
|
+
const plop = await nodePlop(configPath);
|
|
37
|
+
|
|
39
38
|
console.warn("--- KOS CLI Help ---");
|
|
40
39
|
console.log("\nAvailable Generators:");
|
|
41
40
|
plop.getGeneratorList().forEach((g) => {
|
|
@@ -56,139 +55,297 @@ async function launch() {
|
|
|
56
55
|
return;
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
console.error(`[kos-cli] Generator "${command}" not found.`);
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const meta = await getGeneratorMetadata(command);
|
|
67
|
-
|
|
68
|
-
// Show generator-specific help if requested
|
|
69
|
-
if (parsedArgs.help) {
|
|
70
|
-
console.log(`--- ${meta?.name || command} Help ---`);
|
|
71
|
-
console.log(generator.description || "No description available");
|
|
72
|
-
|
|
73
|
-
if (meta?.namedArguments) {
|
|
74
|
-
console.log("\nNamed Arguments:");
|
|
75
|
-
Object.entries(meta.namedArguments).forEach(([cliArg, promptName]) => {
|
|
76
|
-
console.log(` --${cliArg} Maps to prompt: ${promptName}`);
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
console.log("\nExamples:");
|
|
58
|
+
// For generator-specific help, check if we can show help without full plop initialization
|
|
59
|
+
if (shouldShowHelp) {
|
|
60
|
+
const earlyMeta = await getGeneratorMetadata(command);
|
|
81
61
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
case 'modelName':
|
|
93
|
-
return 'my-model';
|
|
94
|
-
case 'workspaceName':
|
|
95
|
-
return 'my-workspace';
|
|
96
|
-
case 'project':
|
|
97
|
-
case 'componentProject':
|
|
98
|
-
case 'modelProject':
|
|
99
|
-
return 'my-ui-lib';
|
|
100
|
-
case 'registrationProject':
|
|
101
|
-
return 'my-lib';
|
|
102
|
-
case 'companionParent':
|
|
103
|
-
return 'parent-model';
|
|
104
|
-
case 'extensionPoint':
|
|
105
|
-
return 'utility';
|
|
106
|
-
case 'group':
|
|
107
|
-
return 'appearance';
|
|
108
|
-
case 'locale':
|
|
109
|
-
return 'en';
|
|
110
|
-
case 'container':
|
|
111
|
-
case 'singleton':
|
|
112
|
-
case 'parentAware':
|
|
113
|
-
case 'dataServices':
|
|
114
|
-
return true;
|
|
115
|
-
case 'dryRun':
|
|
116
|
-
return true;
|
|
117
|
-
default:
|
|
118
|
-
return `my-${argName}`;
|
|
62
|
+
if (earlyMeta && Object.keys(earlyMeta).length > 0) {
|
|
63
|
+
// Show help immediately for --help flag
|
|
64
|
+
console.log(`--- ${earlyMeta?.name || command} Help ---`);
|
|
65
|
+
console.log(earlyMeta.description || "No description available");
|
|
66
|
+
|
|
67
|
+
if (earlyMeta?.namedArguments) {
|
|
68
|
+
console.log("\nNamed Arguments:");
|
|
69
|
+
Object.entries(earlyMeta.namedArguments).forEach(([cliArg, promptName]) => {
|
|
70
|
+
console.log(` --${cliArg} Maps to prompt: ${promptName}`);
|
|
71
|
+
});
|
|
119
72
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// Create basic example with most important arguments
|
|
123
|
-
const basicArgs = [];
|
|
124
|
-
const booleanArgs = ['container', 'singleton', 'parentAware', 'dataServices', 'dryRun'];
|
|
125
|
-
|
|
126
|
-
// Pick the most relevant arguments for each generator type
|
|
127
|
-
const getRelevantArgs = (args, command) => {
|
|
128
|
-
const relevantArgs = [];
|
|
73
|
+
|
|
74
|
+
console.log("\nExamples:");
|
|
129
75
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
relevantArgs.push(nameArgs[0]); // Take the first name argument
|
|
134
|
-
}
|
|
76
|
+
// Generate examples dynamically from the generator's named arguments
|
|
77
|
+
if (earlyMeta?.namedArguments) {
|
|
78
|
+
const args = Object.keys(earlyMeta.namedArguments);
|
|
135
79
|
|
|
136
|
-
//
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
80
|
+
// Generate example values based on argument names
|
|
81
|
+
const generateExampleValue = (argName) => {
|
|
82
|
+
switch (argName) {
|
|
83
|
+
case 'name':
|
|
84
|
+
case 'componentName':
|
|
85
|
+
return command.includes('plugin') ? 'MyPlugin' : 'MyComponent';
|
|
86
|
+
case 'modelName':
|
|
87
|
+
return 'my-model';
|
|
88
|
+
case 'workspaceName':
|
|
89
|
+
return 'my-workspace';
|
|
90
|
+
case 'project':
|
|
91
|
+
case 'componentProject':
|
|
92
|
+
case 'modelProject':
|
|
93
|
+
return 'my-ui-lib';
|
|
94
|
+
case 'registrationProject':
|
|
95
|
+
return 'my-lib';
|
|
96
|
+
case 'companionParent':
|
|
97
|
+
return 'parent-model';
|
|
98
|
+
case 'extensionPoint':
|
|
99
|
+
return 'utility';
|
|
100
|
+
case 'group':
|
|
101
|
+
return 'appearance';
|
|
102
|
+
case 'locale':
|
|
103
|
+
return 'en';
|
|
104
|
+
case 'container':
|
|
105
|
+
case 'singleton':
|
|
106
|
+
case 'parentAware':
|
|
107
|
+
case 'dataServices':
|
|
108
|
+
return true;
|
|
109
|
+
case 'dryRun':
|
|
110
|
+
return true;
|
|
111
|
+
default:
|
|
112
|
+
return `my-${argName}`;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
141
115
|
|
|
142
|
-
//
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
!projectArgs.includes(arg) &&
|
|
146
|
-
!booleanArgs.includes(arg) &&
|
|
147
|
-
arg !== 'interactive'
|
|
148
|
-
);
|
|
116
|
+
// Create basic example with most important arguments
|
|
117
|
+
const basicArgs = [];
|
|
118
|
+
const booleanArgs = ['container', 'singleton', 'parentAware', 'dataServices', 'dryRun'];
|
|
149
119
|
|
|
150
|
-
//
|
|
151
|
-
|
|
120
|
+
// Pick the most relevant arguments for each generator type
|
|
121
|
+
const getRelevantArgs = (args, command) => {
|
|
122
|
+
const relevantArgs = [];
|
|
123
|
+
|
|
124
|
+
// Always prefer name-type arguments first
|
|
125
|
+
const nameArgs = ['name', 'componentName', 'modelName', 'workspaceName'].filter(arg => args.includes(arg));
|
|
126
|
+
if (nameArgs.length > 0) {
|
|
127
|
+
relevantArgs.push(nameArgs[0]); // Take the first name argument
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Then add project-type arguments
|
|
131
|
+
const projectArgs = ['project', 'componentProject', 'modelProject', 'registrationProject'].filter(arg => args.includes(arg));
|
|
132
|
+
if (projectArgs.length > 0) {
|
|
133
|
+
relevantArgs.push(projectArgs[0]); // Take the first project argument
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Add other specific arguments
|
|
137
|
+
const otherArgs = args.filter(arg =>
|
|
138
|
+
!nameArgs.includes(arg) &&
|
|
139
|
+
!projectArgs.includes(arg) &&
|
|
140
|
+
!booleanArgs.includes(arg) &&
|
|
141
|
+
arg !== 'interactive'
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
// Add up to 2 more relevant arguments
|
|
145
|
+
relevantArgs.push(...otherArgs.slice(0, 2));
|
|
146
|
+
|
|
147
|
+
return relevantArgs;
|
|
148
|
+
};
|
|
152
149
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
150
|
+
const relevantArgs = getRelevantArgs(args, command);
|
|
151
|
+
|
|
152
|
+
relevantArgs.forEach(argName => {
|
|
153
|
+
const value = generateExampleValue(argName);
|
|
154
|
+
basicArgs.push(`--${argName} ${value}`);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Create advanced example with boolean flags
|
|
158
|
+
const advancedBooleanArgs = [];
|
|
159
|
+
booleanArgs.forEach(argName => {
|
|
160
|
+
if (args.includes(argName)) {
|
|
161
|
+
advancedBooleanArgs.push(`--${argName}`);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Show basic example
|
|
166
|
+
if (basicArgs.length > 0) {
|
|
167
|
+
console.log(` kosui ${command} ${basicArgs.join(' ')}`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Show advanced example with boolean flags if any exist
|
|
171
|
+
if (basicArgs.length > 0 && advancedBooleanArgs.length > 0) {
|
|
172
|
+
console.log(` kosui ${command} ${basicArgs.slice(0, 2).join(' ')} ${advancedBooleanArgs.join(' ')}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// If no basic args, show a minimal example
|
|
176
|
+
if (basicArgs.length === 0) {
|
|
177
|
+
console.log(` kosui ${command} [options]`);
|
|
168
178
|
}
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// Show basic example
|
|
172
|
-
if (basicArgs.length > 0) {
|
|
173
|
-
console.log(` kosui ${command} ${basicArgs.join(' ')}`);
|
|
174
179
|
}
|
|
175
180
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
console.log(` kosui ${command} --interactive # Force interactive mode`);
|
|
182
|
+
console.log(` kosui ${command} -i # Force interactive mode (short form)`);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Also check for no-arguments case (when only global flags like --no-cache are present)
|
|
188
|
+
const earlyMeta = await getGeneratorMetadata(command);
|
|
189
|
+
if (earlyMeta?.namedArguments) {
|
|
190
|
+
const namedArgumentsMap = earlyMeta.namedArguments;
|
|
191
|
+
const providedAnswers = {};
|
|
192
|
+
Object.entries(namedArgumentsMap).forEach(([cliArg, promptName]) => {
|
|
193
|
+
if (cliArg === "interactive") return;
|
|
194
|
+
if (parsedArgs[cliArg] !== undefined) {
|
|
195
|
+
let value = parsedArgs[cliArg];
|
|
196
|
+
if (value === "true" || value === "y" || value === "yes") {
|
|
197
|
+
value = true;
|
|
198
|
+
} else if (value === "false" || value === "n" || value === "no") {
|
|
199
|
+
value = false;
|
|
200
|
+
}
|
|
201
|
+
providedAnswers[promptName] = value;
|
|
179
202
|
}
|
|
203
|
+
});
|
|
204
|
+
const hasAnyAnswers = Object.keys(providedAnswers).length > 0;
|
|
205
|
+
const forceInteractive = parsedArgs.interactive || parsedArgs.i;
|
|
206
|
+
|
|
207
|
+
// Show help for no-arguments case
|
|
208
|
+
if (!hasAnyAnswers && !forceInteractive) {
|
|
209
|
+
console.log(`--- ${earlyMeta?.name || command} Help ---`);
|
|
210
|
+
console.log(earlyMeta.description || "No description available");
|
|
211
|
+
|
|
212
|
+
if (earlyMeta?.namedArguments) {
|
|
213
|
+
console.log("\nNamed Arguments:");
|
|
214
|
+
Object.entries(earlyMeta.namedArguments).forEach(([cliArg, promptName]) => {
|
|
215
|
+
console.log(` --${cliArg} Maps to prompt: ${promptName}`);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.log("\nExamples:");
|
|
180
220
|
|
|
181
|
-
//
|
|
182
|
-
if (
|
|
183
|
-
|
|
221
|
+
// Generate examples dynamically from the generator's named arguments
|
|
222
|
+
if (earlyMeta?.namedArguments) {
|
|
223
|
+
const args = Object.keys(earlyMeta.namedArguments);
|
|
224
|
+
|
|
225
|
+
// Generate example values based on argument names
|
|
226
|
+
const generateExampleValue = (argName) => {
|
|
227
|
+
switch (argName) {
|
|
228
|
+
case 'name':
|
|
229
|
+
case 'componentName':
|
|
230
|
+
return command.includes('plugin') ? 'MyPlugin' : 'MyComponent';
|
|
231
|
+
case 'modelName':
|
|
232
|
+
return 'my-model';
|
|
233
|
+
case 'workspaceName':
|
|
234
|
+
return 'my-workspace';
|
|
235
|
+
case 'project':
|
|
236
|
+
case 'componentProject':
|
|
237
|
+
case 'modelProject':
|
|
238
|
+
return 'my-ui-lib';
|
|
239
|
+
case 'registrationProject':
|
|
240
|
+
return 'my-lib';
|
|
241
|
+
case 'companionParent':
|
|
242
|
+
return 'parent-model';
|
|
243
|
+
case 'extensionPoint':
|
|
244
|
+
return 'utility';
|
|
245
|
+
case 'group':
|
|
246
|
+
return 'appearance';
|
|
247
|
+
case 'locale':
|
|
248
|
+
return 'en';
|
|
249
|
+
case 'container':
|
|
250
|
+
case 'singleton':
|
|
251
|
+
case 'parentAware':
|
|
252
|
+
case 'dataServices':
|
|
253
|
+
return true;
|
|
254
|
+
case 'dryRun':
|
|
255
|
+
return true;
|
|
256
|
+
default:
|
|
257
|
+
return `my-${argName}`;
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
// Create basic example with most important arguments
|
|
262
|
+
const basicArgs = [];
|
|
263
|
+
const booleanArgs = ['container', 'singleton', 'parentAware', 'dataServices', 'dryRun'];
|
|
264
|
+
|
|
265
|
+
// Pick the most relevant arguments for each generator type
|
|
266
|
+
const getRelevantArgs = (args, command) => {
|
|
267
|
+
const relevantArgs = [];
|
|
268
|
+
|
|
269
|
+
// Always prefer name-type arguments first
|
|
270
|
+
const nameArgs = ['name', 'componentName', 'modelName', 'workspaceName'].filter(arg => args.includes(arg));
|
|
271
|
+
if (nameArgs.length > 0) {
|
|
272
|
+
relevantArgs.push(nameArgs[0]); // Take the first name argument
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Then add project-type arguments
|
|
276
|
+
const projectArgs = ['project', 'componentProject', 'modelProject', 'registrationProject'].filter(arg => args.includes(arg));
|
|
277
|
+
if (projectArgs.length > 0) {
|
|
278
|
+
relevantArgs.push(projectArgs[0]); // Take the first project argument
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Add other specific arguments
|
|
282
|
+
const otherArgs = args.filter(arg =>
|
|
283
|
+
!nameArgs.includes(arg) &&
|
|
284
|
+
!projectArgs.includes(arg) &&
|
|
285
|
+
!booleanArgs.includes(arg) &&
|
|
286
|
+
arg !== 'interactive'
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
// Add up to 2 more relevant arguments
|
|
290
|
+
relevantArgs.push(...otherArgs.slice(0, 2));
|
|
291
|
+
|
|
292
|
+
return relevantArgs;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const relevantArgs = getRelevantArgs(args, command);
|
|
296
|
+
|
|
297
|
+
relevantArgs.forEach(argName => {
|
|
298
|
+
const value = generateExampleValue(argName);
|
|
299
|
+
basicArgs.push(`--${argName} ${value}`);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Create advanced example with boolean flags
|
|
303
|
+
const advancedBooleanArgs = [];
|
|
304
|
+
booleanArgs.forEach(argName => {
|
|
305
|
+
if (args.includes(argName)) {
|
|
306
|
+
advancedBooleanArgs.push(`--${argName}`);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Show basic example
|
|
311
|
+
if (basicArgs.length > 0) {
|
|
312
|
+
console.log(` kosui ${command} ${basicArgs.join(' ')}`);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Show advanced example with boolean flags if any exist
|
|
316
|
+
if (basicArgs.length > 0 && advancedBooleanArgs.length > 0) {
|
|
317
|
+
console.log(` kosui ${command} ${basicArgs.slice(0, 2).join(' ')} ${advancedBooleanArgs.join(' ')}`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// If no basic args, show a minimal example
|
|
321
|
+
if (basicArgs.length === 0) {
|
|
322
|
+
console.log(` kosui ${command} [options]`);
|
|
323
|
+
}
|
|
184
324
|
}
|
|
325
|
+
|
|
326
|
+
console.log(` kosui ${command} --interactive # Force interactive mode`);
|
|
327
|
+
console.log(` kosui ${command} -i # Force interactive mode (short form)`);
|
|
328
|
+
return;
|
|
185
329
|
}
|
|
186
|
-
|
|
187
|
-
console.log(` kosui ${command} --interactive # Force interactive mode`);
|
|
188
|
-
console.log(` kosui ${command} -i # Force interactive mode (short form)`);
|
|
189
|
-
return;
|
|
190
330
|
}
|
|
191
331
|
|
|
332
|
+
const plop = await nodePlop(configPath);
|
|
333
|
+
|
|
334
|
+
plop.setActionType("clearCache", (answers, config, plop) => {
|
|
335
|
+
clearCache();
|
|
336
|
+
return "[ok] CLI cache cleared successfully.";
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
const generator = plop.getGenerator(command);
|
|
340
|
+
|
|
341
|
+
if (!generator) {
|
|
342
|
+
console.error(`[kos-cli] Generator "${command}" not found.`);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const meta = await getGeneratorMetadata(command);
|
|
347
|
+
|
|
348
|
+
|
|
192
349
|
if (showBanner) {
|
|
193
350
|
console.log(`--- Running KOS Generator: ${meta?.name || command} ---`);
|
|
194
351
|
}
|
|
@@ -251,6 +408,130 @@ async function launch() {
|
|
|
251
408
|
// Check if user wants to force interactive mode
|
|
252
409
|
const forceInteractive = parsedArgs.interactive || parsedArgs.i;
|
|
253
410
|
|
|
411
|
+
// If no arguments provided and no interactive flag, show help
|
|
412
|
+
if (!hasAnyAnswers && !forceInteractive) {
|
|
413
|
+
console.log(`--- ${meta?.name || command} Help ---`);
|
|
414
|
+
console.log(generator.description || "No description available");
|
|
415
|
+
|
|
416
|
+
if (meta?.namedArguments) {
|
|
417
|
+
console.log("\nNamed Arguments:");
|
|
418
|
+
Object.entries(meta.namedArguments).forEach(([cliArg, promptName]) => {
|
|
419
|
+
console.log(` --${cliArg} Maps to prompt: ${promptName}`);
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
console.log("\nExamples:");
|
|
424
|
+
|
|
425
|
+
// Generate examples dynamically from the generator's named arguments
|
|
426
|
+
if (meta?.namedArguments) {
|
|
427
|
+
const args = Object.keys(meta.namedArguments);
|
|
428
|
+
|
|
429
|
+
// Generate example values based on argument names
|
|
430
|
+
const generateExampleValue = (argName) => {
|
|
431
|
+
switch (argName) {
|
|
432
|
+
case 'name':
|
|
433
|
+
case 'componentName':
|
|
434
|
+
return command.includes('plugin') ? 'MyPlugin' : 'MyComponent';
|
|
435
|
+
case 'modelName':
|
|
436
|
+
return 'my-model';
|
|
437
|
+
case 'workspaceName':
|
|
438
|
+
return 'my-workspace';
|
|
439
|
+
case 'project':
|
|
440
|
+
case 'componentProject':
|
|
441
|
+
case 'modelProject':
|
|
442
|
+
return 'my-ui-lib';
|
|
443
|
+
case 'registrationProject':
|
|
444
|
+
return 'my-lib';
|
|
445
|
+
case 'companionParent':
|
|
446
|
+
return 'parent-model';
|
|
447
|
+
case 'extensionPoint':
|
|
448
|
+
return 'utility';
|
|
449
|
+
case 'group':
|
|
450
|
+
return 'appearance';
|
|
451
|
+
case 'locale':
|
|
452
|
+
return 'en';
|
|
453
|
+
case 'container':
|
|
454
|
+
case 'singleton':
|
|
455
|
+
case 'parentAware':
|
|
456
|
+
case 'dataServices':
|
|
457
|
+
return true;
|
|
458
|
+
case 'dryRun':
|
|
459
|
+
return true;
|
|
460
|
+
default:
|
|
461
|
+
return `my-${argName}`;
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
// Create basic example with most important arguments
|
|
466
|
+
const basicArgs = [];
|
|
467
|
+
const booleanArgs = ['container', 'singleton', 'parentAware', 'dataServices', 'dryRun'];
|
|
468
|
+
|
|
469
|
+
// Pick the most relevant arguments for each generator type
|
|
470
|
+
const getRelevantArgs = (args, command) => {
|
|
471
|
+
const relevantArgs = [];
|
|
472
|
+
|
|
473
|
+
// Always prefer name-type arguments first
|
|
474
|
+
const nameArgs = ['name', 'componentName', 'modelName', 'workspaceName'].filter(arg => args.includes(arg));
|
|
475
|
+
if (nameArgs.length > 0) {
|
|
476
|
+
relevantArgs.push(nameArgs[0]); // Take the first name argument
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Then add project-type arguments
|
|
480
|
+
const projectArgs = ['project', 'componentProject', 'modelProject', 'registrationProject'].filter(arg => args.includes(arg));
|
|
481
|
+
if (projectArgs.length > 0) {
|
|
482
|
+
relevantArgs.push(projectArgs[0]); // Take the first project argument
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Add other specific arguments
|
|
486
|
+
const otherArgs = args.filter(arg =>
|
|
487
|
+
!nameArgs.includes(arg) &&
|
|
488
|
+
!projectArgs.includes(arg) &&
|
|
489
|
+
!booleanArgs.includes(arg) &&
|
|
490
|
+
arg !== 'interactive'
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
// Add up to 2 more relevant arguments
|
|
494
|
+
relevantArgs.push(...otherArgs.slice(0, 2));
|
|
495
|
+
|
|
496
|
+
return relevantArgs;
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
const relevantArgs = getRelevantArgs(args, command);
|
|
500
|
+
|
|
501
|
+
relevantArgs.forEach(argName => {
|
|
502
|
+
const value = generateExampleValue(argName);
|
|
503
|
+
basicArgs.push(`--${argName} ${value}`);
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// Create advanced example with boolean flags
|
|
507
|
+
const advancedBooleanArgs = [];
|
|
508
|
+
booleanArgs.forEach(argName => {
|
|
509
|
+
if (args.includes(argName)) {
|
|
510
|
+
advancedBooleanArgs.push(`--${argName}`);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
// Show basic example
|
|
515
|
+
if (basicArgs.length > 0) {
|
|
516
|
+
console.log(` kosui ${command} ${basicArgs.join(' ')}`);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Show advanced example with boolean flags if any exist
|
|
520
|
+
if (basicArgs.length > 0 && advancedBooleanArgs.length > 0) {
|
|
521
|
+
console.log(` kosui ${command} ${basicArgs.slice(0, 2).join(' ')} ${advancedBooleanArgs.join(' ')}`);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// If no basic args, show a minimal example
|
|
525
|
+
if (basicArgs.length === 0) {
|
|
526
|
+
console.log(` kosui ${command} [options]`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
console.log(` kosui ${command} --interactive # Force interactive mode`);
|
|
531
|
+
console.log(` kosui ${command} -i # Force interactive mode (short form)`);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
|
|
254
535
|
if (hasAnyAnswers && !forceInteractive) {
|
|
255
536
|
// Create bypass array for all prompts
|
|
256
537
|
const bypassArgs = [];
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// generators/model/add-future.mjs
|
|
2
|
+
import { actionFactory } from "../../utils/action-factory.mjs";
|
|
3
|
+
import { execute } from "../../utils/exec.mjs";
|
|
4
|
+
import { getAllModels } from "../../utils/nx-context.mjs";
|
|
5
|
+
import { DEFAULT_PROMPTS } from "../../utils/prompts.mjs";
|
|
6
|
+
|
|
7
|
+
export const metadata = {
|
|
8
|
+
key: "add-future",
|
|
9
|
+
name: "Add Future Support to Model",
|
|
10
|
+
invalidateCache: true,
|
|
11
|
+
namedArguments: {
|
|
12
|
+
modelName: "modelName",
|
|
13
|
+
project: "modelProject",
|
|
14
|
+
modelProject: "modelProject",
|
|
15
|
+
futureType: "futureType",
|
|
16
|
+
updateServices: "updateServices",
|
|
17
|
+
dryRun: "dryRun",
|
|
18
|
+
interactive: "interactive",
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default async function (plop) {
|
|
23
|
+
const allModels = await getAllModels();
|
|
24
|
+
const modelChoices = allModels.map((m) => ({
|
|
25
|
+
name: `${m.model} (${m.project})`,
|
|
26
|
+
value: m.model,
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
plop.setActionType("addFutureToModel", async function (answers) {
|
|
30
|
+
const modelProject = allModels.find(
|
|
31
|
+
(m) => m.model === answers.modelName
|
|
32
|
+
)?.project;
|
|
33
|
+
|
|
34
|
+
const command = `npx nx generate @kosdev-code/kos-nx-plugin:kos-add-future-to-model \\
|
|
35
|
+
--modelName=${answers.modelName} \\
|
|
36
|
+
--modelProject=${modelProject} \\
|
|
37
|
+
--futureType=${answers.futureType} \\
|
|
38
|
+
--updateServices=${!!answers.updateServices} \\
|
|
39
|
+
--no-interactive ${answers.dryRun ? "--dryRun" : ""} --verbose`;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
await execute(command);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
throw new Error(error);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return `Future support (${answers.futureType}) added to model ${answers.modelName} in ${modelProject}`;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
plop.setGenerator("add-future", {
|
|
51
|
+
description: "Add Future support to an existing KOS Model",
|
|
52
|
+
prompts: [
|
|
53
|
+
...DEFAULT_PROMPTS,
|
|
54
|
+
{
|
|
55
|
+
type: "list",
|
|
56
|
+
name: "modelName",
|
|
57
|
+
message: "Which model do you want to add Future support to?",
|
|
58
|
+
choices: modelChoices,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: "list",
|
|
62
|
+
name: "futureType",
|
|
63
|
+
message: "What type of Future support?",
|
|
64
|
+
choices: [
|
|
65
|
+
{ name: "Minimal (external access only)", value: "minimal" },
|
|
66
|
+
{ name: "Complete (internal + external access)", value: "complete" },
|
|
67
|
+
],
|
|
68
|
+
default: "minimal",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: "confirm",
|
|
72
|
+
name: "updateServices",
|
|
73
|
+
message: "Update/create services file with Future operations?",
|
|
74
|
+
default: true,
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
|
|
78
|
+
actions: actionFactory("addFutureToModel", metadata),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
@@ -6,7 +6,11 @@ import {
|
|
|
6
6
|
getLibraryProjects,
|
|
7
7
|
getProjectDetails,
|
|
8
8
|
} from "../../utils/nx-context.mjs";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
COMPANION_PROMPTS,
|
|
11
|
+
DEFAULT_PROMPTS,
|
|
12
|
+
MODEL_PROMPTS,
|
|
13
|
+
} from "../../utils/prompts.mjs";
|
|
10
14
|
import { required } from "../../utils/validators.mjs";
|
|
11
15
|
|
|
12
16
|
export const metadata = {
|
|
@@ -18,13 +22,14 @@ export const metadata = {
|
|
|
18
22
|
project: "modelProject",
|
|
19
23
|
modelProject: "modelProject",
|
|
20
24
|
companionParent: "companionParent",
|
|
25
|
+
companionPattern: "companionPattern",
|
|
21
26
|
container: "container",
|
|
22
27
|
parentAware: "parentAware",
|
|
23
28
|
singleton: "singleton",
|
|
24
29
|
dataServices: "dataServices",
|
|
25
30
|
dryRun: "dryRun",
|
|
26
|
-
interactive: "interactive"
|
|
27
|
-
}
|
|
31
|
+
interactive: "interactive",
|
|
32
|
+
},
|
|
28
33
|
};
|
|
29
34
|
|
|
30
35
|
export default async function (plop) {
|
|
@@ -52,6 +57,7 @@ export default async function (plop) {
|
|
|
52
57
|
--companion=true \
|
|
53
58
|
--companionModel=${answers.companionParent} \
|
|
54
59
|
--companionModelProject=${companionProject} \
|
|
60
|
+
--companionPattern=${answers.companionPattern} \
|
|
55
61
|
--no-interactive ${answers.dryRun ? "--dryRun" : ""} --verbose`;
|
|
56
62
|
|
|
57
63
|
try {
|
|
@@ -84,6 +90,7 @@ export default async function (plop) {
|
|
|
84
90
|
message: "Select the companion parent model",
|
|
85
91
|
choices: modelChoices,
|
|
86
92
|
},
|
|
93
|
+
...COMPANION_PROMPTS,
|
|
87
94
|
...MODEL_PROMPTS,
|
|
88
95
|
],
|
|
89
96
|
actions: actionFactory("createCompanionModel", metadata),
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { actionFactory } from "../../utils/action-factory.mjs";
|
|
3
3
|
import { execute } from "../../utils/exec.mjs";
|
|
4
4
|
import {
|
|
5
|
-
getAllProjects,
|
|
6
5
|
getLibraryProjects,
|
|
7
6
|
getProjectDetails,
|
|
8
7
|
} from "../../utils/nx-context.mjs";
|
|
@@ -22,13 +21,13 @@ export const metadata = {
|
|
|
22
21
|
parentAware: "parentAware",
|
|
23
22
|
singleton: "singleton",
|
|
24
23
|
dataServices: "dataServices",
|
|
24
|
+
futureAware: "futureAware",
|
|
25
25
|
dryRun: "dryRun",
|
|
26
26
|
interactive: "interactive"
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
export default async function (plop) {
|
|
31
|
-
const allProjects = await getAllProjects();
|
|
32
31
|
const libraryProjects = await getLibraryProjects();
|
|
33
32
|
|
|
34
33
|
plop.setActionType("createModel", async function (answers) {
|
|
@@ -41,6 +40,7 @@ export default async function (plop) {
|
|
|
41
40
|
--dataServices=${!!answers.dataServices} \
|
|
42
41
|
--singleton=${!!answers.singleton} \
|
|
43
42
|
--parentAware=${!!answers.parentAware} \
|
|
43
|
+
--futureAware=${answers.futureAware || 'none'} \
|
|
44
44
|
--no-interactive ${answers.dryRun ? "--dryRun" : ""} --verbose`;
|
|
45
45
|
|
|
46
46
|
try {
|
package/src/lib/plopfile.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { detectWorkspace } from "./utils/nx-context.mjs";
|
|
3
3
|
|
|
4
4
|
// Generator registration
|
|
5
|
+
import registerAddFuture from "./generators/model/add-future.mjs";
|
|
5
6
|
import registerCompanion from "./generators/model/companion.mjs";
|
|
6
7
|
import registerContainer from "./generators/model/container.mjs";
|
|
7
8
|
import registerContext from "./generators/model/context.mjs";
|
|
@@ -40,6 +41,7 @@ export default async function (plop) {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
await registerKosModel(plop);
|
|
44
|
+
await registerAddFuture(plop);
|
|
43
45
|
await registerHook(plop);
|
|
44
46
|
await registerCompanion(plop);
|
|
45
47
|
await registerContainer(plop);
|
|
@@ -42,4 +42,34 @@ export const MODEL_PROMPTS = [
|
|
|
42
42
|
message: "Create data services?",
|
|
43
43
|
default: true,
|
|
44
44
|
},
|
|
45
|
+
{
|
|
46
|
+
type: "list",
|
|
47
|
+
name: "futureAware",
|
|
48
|
+
message: "Include Future-aware capabilities?",
|
|
49
|
+
choices: [
|
|
50
|
+
{ name: "No Future support", value: "none" },
|
|
51
|
+
{ name: "Minimal (external access only)", value: "minimal" },
|
|
52
|
+
{ name: "Complete (internal + external access)", value: "complete" },
|
|
53
|
+
],
|
|
54
|
+
default: "none",
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
export const COMPANION_PROMPTS = [
|
|
59
|
+
{
|
|
60
|
+
type: "list",
|
|
61
|
+
name: "companionPattern",
|
|
62
|
+
message: "Which companion pattern to use?",
|
|
63
|
+
choices: [
|
|
64
|
+
{
|
|
65
|
+
name: "Composition (recommended) - explicit parent access via this.parent",
|
|
66
|
+
value: "composition",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "Decorator - transparent parent access, drop-in replacement",
|
|
70
|
+
value: "decorator",
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
default: "composition",
|
|
74
|
+
},
|
|
45
75
|
];
|