@kosdev-code/kos-ui-cli 2.1.23 → 2.1.26
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/README.md +346 -4
- package/package.json +4 -3
- package/src/lib/cli.mjs +48 -467
- package/src/lib/generators/api/generate.mjs +105 -0
- package/src/lib/generators/api/lib/generate-api.mjs +452 -0
- package/src/lib/plopfile.mjs +2 -0
- package/src/lib/utils/cli-help-display.mjs +84 -0
- package/src/lib/utils/cli-help-utils.mjs +261 -0
package/src/lib/cli.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { fileURLToPath } from "node:url";
|
|
|
8
8
|
import { clearCache } from "./utils/cache.mjs";
|
|
9
9
|
import { buildNonInteractiveCommand, isRunningInteractively } from "./utils/command-builder.mjs";
|
|
10
10
|
import { getGeneratorMetadata } from "./utils/generator-loader.mjs";
|
|
11
|
+
import { displayGeneralHelp, displayGeneratorHelp } from "./utils/cli-help-display.mjs";
|
|
11
12
|
|
|
12
13
|
const originalArgs = process.argv.slice(2);
|
|
13
14
|
const parsedArgs = minimist(originalArgs);
|
|
@@ -37,6 +38,47 @@ const configPath = path.join(__dirname, "plopfile.mjs");
|
|
|
37
38
|
const showBanner =
|
|
38
39
|
command !== "help" && process.env.DISABLE_CLI_BANNER !== "true";
|
|
39
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Parse CLI argument values, handling booleans, JSON, key=value pairs, and repeated arguments
|
|
43
|
+
* @param {*} value - The raw argument value from minimist
|
|
44
|
+
* @returns {*} - The parsed value (boolean, object, or original value)
|
|
45
|
+
*/
|
|
46
|
+
function parseArgumentValue(value) {
|
|
47
|
+
// Convert string boolean values to actual booleans
|
|
48
|
+
if (value === "true" || value === "y" || value === "yes") {
|
|
49
|
+
return true;
|
|
50
|
+
} else if (value === "false" || value === "n" || value === "no") {
|
|
51
|
+
return false;
|
|
52
|
+
} else if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
|
|
53
|
+
// Try to parse JSON for complex arguments like --app-version='{"ice-app":"v2"}'
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse(value);
|
|
56
|
+
} catch (e) {
|
|
57
|
+
// If JSON parsing fails, keep as string
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
} else if (Array.isArray(value)) {
|
|
61
|
+
// Handle repeated arguments like --app-version ice-app=v2 --app-version apc=v3
|
|
62
|
+
// Minimist stores repeated args as arrays
|
|
63
|
+
const parsedObject = {};
|
|
64
|
+
value.forEach(item => {
|
|
65
|
+
if (typeof item === 'string' && item.includes('=')) {
|
|
66
|
+
const [key, val] = item.split('=');
|
|
67
|
+
parsedObject[key.trim()] = val.trim();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return Object.keys(parsedObject).length > 0 ? parsedObject : value;
|
|
71
|
+
} else if (typeof value === "string" && value.includes("=")) {
|
|
72
|
+
// Handle single key=value format like --app-version ice-app=v2
|
|
73
|
+
const parsedObject = {};
|
|
74
|
+
const [key, val] = value.split('=');
|
|
75
|
+
parsedObject[key.trim()] = val.trim();
|
|
76
|
+
return parsedObject;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
|
|
40
82
|
async function launch() {
|
|
41
83
|
// Check for help modes before initializing plop to avoid expensive model parsing
|
|
42
84
|
const shouldShowHelp = parsedArgs.help;
|
|
@@ -44,25 +86,7 @@ async function launch() {
|
|
|
44
86
|
if (!command || command === "help") {
|
|
45
87
|
// For general help, we still need plop to list generators
|
|
46
88
|
const plop = await nodePlop(configPath);
|
|
47
|
-
|
|
48
|
-
console.warn("--- KOS CLI Help ---");
|
|
49
|
-
console.log("\nAvailable Generators:");
|
|
50
|
-
plop.getGeneratorList().forEach((g) => {
|
|
51
|
-
console.log(`- ${g.name}: ${g.description}`);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
console.log("\nUsage:");
|
|
55
|
-
console.log(" kosui <generator> [options]");
|
|
56
|
-
console.log(" kosui <generator> --help # Show generator-specific help");
|
|
57
|
-
console.log("\nGlobal Options:");
|
|
58
|
-
console.log(" --no-cache Disable cache");
|
|
59
|
-
console.log(" --refresh Clear cache and refresh");
|
|
60
|
-
console.log(" --quiet Suppress banner and debug output");
|
|
61
|
-
console.log(
|
|
62
|
-
" --interactive, -i Force interactive mode (ignore provided arguments)"
|
|
63
|
-
);
|
|
64
|
-
console.log(" --help Show this help");
|
|
65
|
-
|
|
89
|
+
displayGeneralHelp(plop);
|
|
66
90
|
return;
|
|
67
91
|
}
|
|
68
92
|
|
|
@@ -71,151 +95,7 @@ async function launch() {
|
|
|
71
95
|
const earlyMeta = await getGeneratorMetadata(command);
|
|
72
96
|
|
|
73
97
|
if (earlyMeta && Object.keys(earlyMeta).length > 0) {
|
|
74
|
-
|
|
75
|
-
console.log(`--- ${earlyMeta?.name || command} Help ---`);
|
|
76
|
-
console.log(earlyMeta.description || "No description available");
|
|
77
|
-
|
|
78
|
-
if (earlyMeta?.namedArguments) {
|
|
79
|
-
console.log("\nNamed Arguments:");
|
|
80
|
-
Object.entries(earlyMeta.namedArguments).forEach(
|
|
81
|
-
([cliArg, promptName]) => {
|
|
82
|
-
console.log(` --${cliArg} Maps to prompt: ${promptName}`);
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
console.log("\nExamples:");
|
|
88
|
-
|
|
89
|
-
// Generate examples dynamically from the generator's named arguments
|
|
90
|
-
if (earlyMeta?.namedArguments) {
|
|
91
|
-
const args = Object.keys(earlyMeta.namedArguments);
|
|
92
|
-
|
|
93
|
-
// Generate example values based on argument names
|
|
94
|
-
const generateExampleValue = (argName) => {
|
|
95
|
-
switch (argName) {
|
|
96
|
-
case "name":
|
|
97
|
-
case "componentName":
|
|
98
|
-
return command.includes("plugin") ? "MyPlugin" : "MyComponent";
|
|
99
|
-
case "modelName":
|
|
100
|
-
return "my-model";
|
|
101
|
-
case "workspaceName":
|
|
102
|
-
return "my-workspace";
|
|
103
|
-
case "project":
|
|
104
|
-
case "componentProject":
|
|
105
|
-
case "modelProject":
|
|
106
|
-
return "my-ui-lib";
|
|
107
|
-
case "registrationProject":
|
|
108
|
-
return "my-lib";
|
|
109
|
-
case "companionParent":
|
|
110
|
-
return "parent-model";
|
|
111
|
-
case "extensionPoint":
|
|
112
|
-
return "utility";
|
|
113
|
-
case "group":
|
|
114
|
-
return "appearance";
|
|
115
|
-
case "locale":
|
|
116
|
-
return "en";
|
|
117
|
-
case "container":
|
|
118
|
-
case "singleton":
|
|
119
|
-
case "parentAware":
|
|
120
|
-
case "dataServices":
|
|
121
|
-
return true;
|
|
122
|
-
case "dryRun":
|
|
123
|
-
return true;
|
|
124
|
-
default:
|
|
125
|
-
return `my-${argName}`;
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
// Create basic example with most important arguments
|
|
130
|
-
const basicArgs = [];
|
|
131
|
-
const booleanArgs = [
|
|
132
|
-
"container",
|
|
133
|
-
"singleton",
|
|
134
|
-
"parentAware",
|
|
135
|
-
"dataServices",
|
|
136
|
-
"dryRun",
|
|
137
|
-
];
|
|
138
|
-
|
|
139
|
-
// Pick the most relevant arguments for each generator type
|
|
140
|
-
const getRelevantArgs = (args, command) => {
|
|
141
|
-
const relevantArgs = [];
|
|
142
|
-
|
|
143
|
-
// Always prefer name-type arguments first
|
|
144
|
-
const nameArgs = [
|
|
145
|
-
"name",
|
|
146
|
-
"componentName",
|
|
147
|
-
"modelName",
|
|
148
|
-
"workspaceName",
|
|
149
|
-
].filter((arg) => args.includes(arg));
|
|
150
|
-
if (nameArgs.length > 0) {
|
|
151
|
-
relevantArgs.push(nameArgs[0]); // Take the first name argument
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Then add project-type arguments
|
|
155
|
-
const projectArgs = [
|
|
156
|
-
"project",
|
|
157
|
-
"componentProject",
|
|
158
|
-
"modelProject",
|
|
159
|
-
"registrationProject",
|
|
160
|
-
].filter((arg) => args.includes(arg));
|
|
161
|
-
if (projectArgs.length > 0) {
|
|
162
|
-
relevantArgs.push(projectArgs[0]); // Take the first project argument
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Add other specific arguments
|
|
166
|
-
const otherArgs = args.filter(
|
|
167
|
-
(arg) =>
|
|
168
|
-
!nameArgs.includes(arg) &&
|
|
169
|
-
!projectArgs.includes(arg) &&
|
|
170
|
-
!booleanArgs.includes(arg) &&
|
|
171
|
-
arg !== "interactive"
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
// Add up to 2 more relevant arguments
|
|
175
|
-
relevantArgs.push(...otherArgs.slice(0, 2));
|
|
176
|
-
|
|
177
|
-
return relevantArgs;
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const relevantArgs = getRelevantArgs(args, command);
|
|
181
|
-
|
|
182
|
-
relevantArgs.forEach((argName) => {
|
|
183
|
-
const value = generateExampleValue(argName);
|
|
184
|
-
basicArgs.push(`--${argName} ${value}`);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// Create advanced example with boolean flags
|
|
188
|
-
const advancedBooleanArgs = [];
|
|
189
|
-
booleanArgs.forEach((argName) => {
|
|
190
|
-
if (args.includes(argName)) {
|
|
191
|
-
advancedBooleanArgs.push(`--${argName}`);
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// Show basic example
|
|
196
|
-
if (basicArgs.length > 0) {
|
|
197
|
-
console.log(` kosui ${command} ${basicArgs.join(" ")}`);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Show advanced example with boolean flags if any exist
|
|
201
|
-
if (basicArgs.length > 0 && advancedBooleanArgs.length > 0) {
|
|
202
|
-
console.log(
|
|
203
|
-
` kosui ${command} ${basicArgs
|
|
204
|
-
.slice(0, 2)
|
|
205
|
-
.join(" ")} ${advancedBooleanArgs.join(" ")}`
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// If no basic args, show a minimal example
|
|
210
|
-
if (basicArgs.length === 0) {
|
|
211
|
-
console.log(` kosui ${command} [options]`);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
console.log(` kosui ${command} --interactive # Force interactive mode`);
|
|
216
|
-
console.log(
|
|
217
|
-
` kosui ${command} -i # Force interactive mode (short form)`
|
|
218
|
-
);
|
|
98
|
+
displayGeneratorHelp(command, earlyMeta);
|
|
219
99
|
return;
|
|
220
100
|
}
|
|
221
101
|
}
|
|
@@ -228,13 +108,7 @@ async function launch() {
|
|
|
228
108
|
Object.entries(namedArgumentsMap).forEach(([cliArg, promptName]) => {
|
|
229
109
|
if (cliArg === "interactive") return;
|
|
230
110
|
if (parsedArgs[cliArg] !== undefined) {
|
|
231
|
-
|
|
232
|
-
if (value === "true" || value === "y" || value === "yes") {
|
|
233
|
-
value = true;
|
|
234
|
-
} else if (value === "false" || value === "n" || value === "no") {
|
|
235
|
-
value = false;
|
|
236
|
-
}
|
|
237
|
-
providedAnswers[promptName] = value;
|
|
111
|
+
providedAnswers[promptName] = parseArgumentValue(parsedArgs[cliArg]);
|
|
238
112
|
}
|
|
239
113
|
});
|
|
240
114
|
const hasAnyAnswers = Object.keys(providedAnswers).length > 0;
|
|
@@ -242,150 +116,7 @@ async function launch() {
|
|
|
242
116
|
|
|
243
117
|
// Show help for no-arguments case
|
|
244
118
|
if (!hasAnyAnswers && !forceInteractive) {
|
|
245
|
-
|
|
246
|
-
console.log(earlyMeta.description || "No description available");
|
|
247
|
-
|
|
248
|
-
if (earlyMeta?.namedArguments) {
|
|
249
|
-
console.log("\nNamed Arguments:");
|
|
250
|
-
Object.entries(earlyMeta.namedArguments).forEach(
|
|
251
|
-
([cliArg, promptName]) => {
|
|
252
|
-
console.log(` --${cliArg} Maps to prompt: ${promptName}`);
|
|
253
|
-
}
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
console.log("\nExamples:");
|
|
258
|
-
|
|
259
|
-
// Generate examples dynamically from the generator's named arguments
|
|
260
|
-
if (earlyMeta?.namedArguments) {
|
|
261
|
-
const args = Object.keys(earlyMeta.namedArguments);
|
|
262
|
-
|
|
263
|
-
// Generate example values based on argument names
|
|
264
|
-
const generateExampleValue = (argName) => {
|
|
265
|
-
switch (argName) {
|
|
266
|
-
case "name":
|
|
267
|
-
case "componentName":
|
|
268
|
-
return command.includes("plugin") ? "MyPlugin" : "MyComponent";
|
|
269
|
-
case "modelName":
|
|
270
|
-
return "my-model";
|
|
271
|
-
case "workspaceName":
|
|
272
|
-
return "my-workspace";
|
|
273
|
-
case "project":
|
|
274
|
-
case "componentProject":
|
|
275
|
-
case "modelProject":
|
|
276
|
-
return "my-ui-lib";
|
|
277
|
-
case "registrationProject":
|
|
278
|
-
return "my-lib";
|
|
279
|
-
case "companionParent":
|
|
280
|
-
return "parent-model";
|
|
281
|
-
case "extensionPoint":
|
|
282
|
-
return "utility";
|
|
283
|
-
case "group":
|
|
284
|
-
return "appearance";
|
|
285
|
-
case "locale":
|
|
286
|
-
return "en";
|
|
287
|
-
case "container":
|
|
288
|
-
case "singleton":
|
|
289
|
-
case "parentAware":
|
|
290
|
-
case "dataServices":
|
|
291
|
-
return true;
|
|
292
|
-
case "dryRun":
|
|
293
|
-
return true;
|
|
294
|
-
default:
|
|
295
|
-
return `my-${argName}`;
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
// Create basic example with most important arguments
|
|
300
|
-
const basicArgs = [];
|
|
301
|
-
const booleanArgs = [
|
|
302
|
-
"container",
|
|
303
|
-
"singleton",
|
|
304
|
-
"parentAware",
|
|
305
|
-
"dataServices",
|
|
306
|
-
"dryRun",
|
|
307
|
-
];
|
|
308
|
-
|
|
309
|
-
// Pick the most relevant arguments for each generator type
|
|
310
|
-
const getRelevantArgs = (args, command) => {
|
|
311
|
-
const relevantArgs = [];
|
|
312
|
-
|
|
313
|
-
// Always prefer name-type arguments first
|
|
314
|
-
const nameArgs = [
|
|
315
|
-
"name",
|
|
316
|
-
"componentName",
|
|
317
|
-
"modelName",
|
|
318
|
-
"workspaceName",
|
|
319
|
-
].filter((arg) => args.includes(arg));
|
|
320
|
-
if (nameArgs.length > 0) {
|
|
321
|
-
relevantArgs.push(nameArgs[0]); // Take the first name argument
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Then add project-type arguments
|
|
325
|
-
const projectArgs = [
|
|
326
|
-
"project",
|
|
327
|
-
"componentProject",
|
|
328
|
-
"modelProject",
|
|
329
|
-
"registrationProject",
|
|
330
|
-
].filter((arg) => args.includes(arg));
|
|
331
|
-
if (projectArgs.length > 0) {
|
|
332
|
-
relevantArgs.push(projectArgs[0]); // Take the first project argument
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Add other specific arguments
|
|
336
|
-
const otherArgs = args.filter(
|
|
337
|
-
(arg) =>
|
|
338
|
-
!nameArgs.includes(arg) &&
|
|
339
|
-
!projectArgs.includes(arg) &&
|
|
340
|
-
!booleanArgs.includes(arg) &&
|
|
341
|
-
arg !== "interactive"
|
|
342
|
-
);
|
|
343
|
-
|
|
344
|
-
// Add up to 2 more relevant arguments
|
|
345
|
-
relevantArgs.push(...otherArgs.slice(0, 2));
|
|
346
|
-
|
|
347
|
-
return relevantArgs;
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
const relevantArgs = getRelevantArgs(args, command);
|
|
351
|
-
|
|
352
|
-
relevantArgs.forEach((argName) => {
|
|
353
|
-
const value = generateExampleValue(argName);
|
|
354
|
-
basicArgs.push(`--${argName} ${value}`);
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
// Create advanced example with boolean flags
|
|
358
|
-
const advancedBooleanArgs = [];
|
|
359
|
-
booleanArgs.forEach((argName) => {
|
|
360
|
-
if (args.includes(argName)) {
|
|
361
|
-
advancedBooleanArgs.push(`--${argName}`);
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
// Show basic example
|
|
366
|
-
if (basicArgs.length > 0) {
|
|
367
|
-
console.log(` kosui ${command} ${basicArgs.join(" ")}`);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// Show advanced example with boolean flags if any exist
|
|
371
|
-
if (basicArgs.length > 0 && advancedBooleanArgs.length > 0) {
|
|
372
|
-
console.log(
|
|
373
|
-
` kosui ${command} ${basicArgs
|
|
374
|
-
.slice(0, 2)
|
|
375
|
-
.join(" ")} ${advancedBooleanArgs.join(" ")}`
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// If no basic args, show a minimal example
|
|
380
|
-
if (basicArgs.length === 0) {
|
|
381
|
-
console.log(` kosui ${command} [options]`);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
console.log(` kosui ${command} --interactive # Force interactive mode`);
|
|
386
|
-
console.log(
|
|
387
|
-
` kosui ${command} -i # Force interactive mode (short form)`
|
|
388
|
-
);
|
|
119
|
+
displayGeneratorHelp(command, earlyMeta);
|
|
389
120
|
return;
|
|
390
121
|
}
|
|
391
122
|
}
|
|
@@ -434,16 +165,7 @@ async function launch() {
|
|
|
434
165
|
}
|
|
435
166
|
|
|
436
167
|
if (parsedArgs[cliArg] !== undefined) {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
// Convert string boolean values to actual booleans
|
|
440
|
-
if (value === "true" || value === "y" || value === "yes") {
|
|
441
|
-
value = true;
|
|
442
|
-
} else if (value === "false" || value === "n" || value === "no") {
|
|
443
|
-
value = false;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
providedAnswers[promptName] = value;
|
|
168
|
+
providedAnswers[promptName] = parseArgumentValue(parsedArgs[cliArg]);
|
|
447
169
|
}
|
|
448
170
|
});
|
|
449
171
|
|
|
@@ -478,148 +200,7 @@ async function launch() {
|
|
|
478
200
|
|
|
479
201
|
// If no arguments provided and no interactive flag, show help
|
|
480
202
|
if (!hasAnyAnswers && !forceInteractive) {
|
|
481
|
-
|
|
482
|
-
console.log(generator.description || "No description available");
|
|
483
|
-
|
|
484
|
-
if (meta?.namedArguments) {
|
|
485
|
-
console.log("\nNamed Arguments:");
|
|
486
|
-
Object.entries(meta.namedArguments).forEach(([cliArg, promptName]) => {
|
|
487
|
-
console.log(` --${cliArg} Maps to prompt: ${promptName}`);
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
console.log("\nExamples:");
|
|
492
|
-
|
|
493
|
-
// Generate examples dynamically from the generator's named arguments
|
|
494
|
-
if (meta?.namedArguments) {
|
|
495
|
-
const args = Object.keys(meta.namedArguments);
|
|
496
|
-
|
|
497
|
-
// Generate example values based on argument names
|
|
498
|
-
const generateExampleValue = (argName) => {
|
|
499
|
-
switch (argName) {
|
|
500
|
-
case "name":
|
|
501
|
-
case "componentName":
|
|
502
|
-
return command.includes("plugin") ? "MyPlugin" : "MyComponent";
|
|
503
|
-
case "modelName":
|
|
504
|
-
return "my-model";
|
|
505
|
-
case "workspaceName":
|
|
506
|
-
return "my-workspace";
|
|
507
|
-
case "project":
|
|
508
|
-
case "componentProject":
|
|
509
|
-
case "modelProject":
|
|
510
|
-
return "my-ui-lib";
|
|
511
|
-
case "registrationProject":
|
|
512
|
-
return "my-lib";
|
|
513
|
-
case "companionParent":
|
|
514
|
-
return "parent-model";
|
|
515
|
-
case "extensionPoint":
|
|
516
|
-
return "utility";
|
|
517
|
-
case "group":
|
|
518
|
-
return "appearance";
|
|
519
|
-
case "locale":
|
|
520
|
-
return "en";
|
|
521
|
-
case "container":
|
|
522
|
-
case "singleton":
|
|
523
|
-
case "parentAware":
|
|
524
|
-
case "dataServices":
|
|
525
|
-
return true;
|
|
526
|
-
case "dryRun":
|
|
527
|
-
return true;
|
|
528
|
-
default:
|
|
529
|
-
return `my-${argName}`;
|
|
530
|
-
}
|
|
531
|
-
};
|
|
532
|
-
|
|
533
|
-
// Create basic example with most important arguments
|
|
534
|
-
const basicArgs = [];
|
|
535
|
-
const booleanArgs = [
|
|
536
|
-
"container",
|
|
537
|
-
"singleton",
|
|
538
|
-
"parentAware",
|
|
539
|
-
"dataServices",
|
|
540
|
-
"dryRun",
|
|
541
|
-
];
|
|
542
|
-
|
|
543
|
-
// Pick the most relevant arguments for each generator type
|
|
544
|
-
const getRelevantArgs = (args, command) => {
|
|
545
|
-
const relevantArgs = [];
|
|
546
|
-
|
|
547
|
-
// Always prefer name-type arguments first
|
|
548
|
-
const nameArgs = [
|
|
549
|
-
"name",
|
|
550
|
-
"componentName",
|
|
551
|
-
"modelName",
|
|
552
|
-
"workspaceName",
|
|
553
|
-
].filter((arg) => args.includes(arg));
|
|
554
|
-
if (nameArgs.length > 0) {
|
|
555
|
-
relevantArgs.push(nameArgs[0]); // Take the first name argument
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// Then add project-type arguments
|
|
559
|
-
const projectArgs = [
|
|
560
|
-
"project",
|
|
561
|
-
"componentProject",
|
|
562
|
-
"modelProject",
|
|
563
|
-
"registrationProject",
|
|
564
|
-
].filter((arg) => args.includes(arg));
|
|
565
|
-
if (projectArgs.length > 0) {
|
|
566
|
-
relevantArgs.push(projectArgs[0]); // Take the first project argument
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
// Add other specific arguments
|
|
570
|
-
const otherArgs = args.filter(
|
|
571
|
-
(arg) =>
|
|
572
|
-
!nameArgs.includes(arg) &&
|
|
573
|
-
!projectArgs.includes(arg) &&
|
|
574
|
-
!booleanArgs.includes(arg) &&
|
|
575
|
-
arg !== "interactive"
|
|
576
|
-
);
|
|
577
|
-
|
|
578
|
-
// Add up to 2 more relevant arguments
|
|
579
|
-
relevantArgs.push(...otherArgs.slice(0, 2));
|
|
580
|
-
|
|
581
|
-
return relevantArgs;
|
|
582
|
-
};
|
|
583
|
-
|
|
584
|
-
const relevantArgs = getRelevantArgs(args, command);
|
|
585
|
-
|
|
586
|
-
relevantArgs.forEach((argName) => {
|
|
587
|
-
const value = generateExampleValue(argName);
|
|
588
|
-
basicArgs.push(`--${argName} ${value}`);
|
|
589
|
-
});
|
|
590
|
-
|
|
591
|
-
// Create advanced example with boolean flags
|
|
592
|
-
const advancedBooleanArgs = [];
|
|
593
|
-
booleanArgs.forEach((argName) => {
|
|
594
|
-
if (args.includes(argName)) {
|
|
595
|
-
advancedBooleanArgs.push(`--${argName}`);
|
|
596
|
-
}
|
|
597
|
-
});
|
|
598
|
-
|
|
599
|
-
// Show basic example
|
|
600
|
-
if (basicArgs.length > 0) {
|
|
601
|
-
console.log(` kosui ${command} ${basicArgs.join(" ")}`);
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
// Show advanced example with boolean flags if any exist
|
|
605
|
-
if (basicArgs.length > 0 && advancedBooleanArgs.length > 0) {
|
|
606
|
-
console.log(
|
|
607
|
-
` kosui ${command} ${basicArgs
|
|
608
|
-
.slice(0, 2)
|
|
609
|
-
.join(" ")} ${advancedBooleanArgs.join(" ")}`
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// If no basic args, show a minimal example
|
|
614
|
-
if (basicArgs.length === 0) {
|
|
615
|
-
console.log(` kosui ${command} [options]`);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
console.log(` kosui ${command} --interactive # Force interactive mode`);
|
|
620
|
-
console.log(
|
|
621
|
-
` kosui ${command} -i # Force interactive mode (short form)`
|
|
622
|
-
);
|
|
203
|
+
displayGeneratorHelp(command, meta, generator);
|
|
623
204
|
return;
|
|
624
205
|
}
|
|
625
206
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { generateApiTypes } from "./lib/generate-api.mjs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generator for creating OpenAPI service types
|
|
5
|
+
*/
|
|
6
|
+
export default async function register(plop) {
|
|
7
|
+
plop.setGenerator("api:generate", {
|
|
8
|
+
description: "Generate OpenAPI service types for a project",
|
|
9
|
+
prompts: [
|
|
10
|
+
{
|
|
11
|
+
type: "input",
|
|
12
|
+
name: "project",
|
|
13
|
+
message: "Project name",
|
|
14
|
+
validate: (input) => {
|
|
15
|
+
if (!input || input.trim() === "") {
|
|
16
|
+
return "Project name is required";
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
type: "input",
|
|
23
|
+
name: "host",
|
|
24
|
+
message: "API host URL (or 'inherit' to use project.json)",
|
|
25
|
+
default: "inherit",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: "input",
|
|
29
|
+
name: "apps",
|
|
30
|
+
message: "Apps to include (comma-separated, leave empty for all)",
|
|
31
|
+
default: "",
|
|
32
|
+
filter: (input) => {
|
|
33
|
+
if (!input || input.trim() === "") {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
return input.split(",").map((s) => s.trim()).filter(Boolean);
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: "input",
|
|
41
|
+
name: "outputPath",
|
|
42
|
+
message: "Output path (or 'inherit' to use project.json)",
|
|
43
|
+
default: "inherit",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: "input",
|
|
47
|
+
name: "defaultVersion",
|
|
48
|
+
message: "Default version (or 'inherit' to use project.json)",
|
|
49
|
+
default: "inherit",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: "input",
|
|
53
|
+
name: "allAppsVersion",
|
|
54
|
+
message: "Override all apps to specific version (leave empty to use individual versions)",
|
|
55
|
+
default: "",
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
actions: function (answers) {
|
|
59
|
+
return [
|
|
60
|
+
async function generateApi() {
|
|
61
|
+
try {
|
|
62
|
+
const options = {
|
|
63
|
+
project: answers.project,
|
|
64
|
+
host: answers.host === "inherit" ? undefined : answers.host,
|
|
65
|
+
studio: false, // Third-party projects don't use Studio endpoints
|
|
66
|
+
apps: answers.apps,
|
|
67
|
+
excludeCore: true, // Always exclude core services (already in published SDKs)
|
|
68
|
+
outputPath: answers.outputPath === "inherit" ? undefined : (answers.outputPath || undefined),
|
|
69
|
+
defaultVersion: answers.defaultVersion === "inherit" ? undefined : answers.defaultVersion,
|
|
70
|
+
allAppsVersion: answers.allAppsVersion || undefined,
|
|
71
|
+
// Pass CLI overrides if provided (they'll be merged with project.json in generate-api.mjs)
|
|
72
|
+
appVersions: answers.appVersions,
|
|
73
|
+
serviceExportAliases: answers.serviceExportAliases,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const result = await generateApiTypes(options);
|
|
77
|
+
|
|
78
|
+
return `[ok] Generated ${result.filesGenerated} files for ${result.apps.length} apps: ${result.apps.join(", ")}`;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error("Error generating API types:", error);
|
|
81
|
+
throw new Error(`Failed to generate API types: ${error.message}`);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Export metadata for CLI integration
|
|
90
|
+
export const metadata = {
|
|
91
|
+
key: "api:generate",
|
|
92
|
+
name: "Generate OpenAPI service types",
|
|
93
|
+
description: "Generate typed service helpers from OpenAPI specifications",
|
|
94
|
+
namedArguments: {
|
|
95
|
+
project: "project",
|
|
96
|
+
host: "host",
|
|
97
|
+
apps: "apps",
|
|
98
|
+
output: "outputPath",
|
|
99
|
+
"default-version": "defaultVersion",
|
|
100
|
+
"all-apps-version": "allAppsVersion",
|
|
101
|
+
// Advanced options that can be passed as JSON strings or key=value pairs
|
|
102
|
+
alias: "serviceExportAliases",
|
|
103
|
+
"app-version": "appVersions",
|
|
104
|
+
},
|
|
105
|
+
};
|