api-core-lib 12.0.68 → 12.0.69
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/cli.cjs +70 -52
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -76,7 +76,7 @@ var import_swagger_parser = __toESM(require("@apidevtools/swagger-parser"), 1);
|
|
|
76
76
|
var import_openapi_types = __toESM(require_dist(), 1);
|
|
77
77
|
var DEBUG_MODE = process.env.DEBUG === "true";
|
|
78
78
|
var debugLog = (title, data) => DEBUG_MODE && console.log(import_chalk.default.yellow(`
|
|
79
|
-
[DEBUG: ${title}]`), import_util.default.inspect(data, { depth
|
|
79
|
+
[DEBUG: ${title}]`), import_util.default.inspect(data, { depth, colors: true }));
|
|
80
80
|
var toPascalCase = (str) => str.replace(/[^a-zA-Z0-9_]/g, " ").replace(/(?:^\w|[A-Z]|\b\w)/g, (w) => w.toUpperCase()).replace(/\s+/g, "");
|
|
81
81
|
var toCamelCase = (str) => {
|
|
82
82
|
const s = toPascalCase(str);
|
|
@@ -96,23 +96,18 @@ var findCommonPath = (paths) => {
|
|
|
96
96
|
};
|
|
97
97
|
var generateFriendlyMessage = (fieldName, validation) => {
|
|
98
98
|
const friendlyName = fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase());
|
|
99
|
-
|
|
100
|
-
case "required":
|
|
101
|
-
return `${friendlyName} is required.`;
|
|
102
|
-
case "email":
|
|
103
|
-
return `Please enter a valid email for ${friendlyName}.`;
|
|
104
|
-
default:
|
|
105
|
-
return `Invalid value for ${friendlyName}.`;
|
|
106
|
-
}
|
|
99
|
+
return `${friendlyName} is required.`;
|
|
107
100
|
};
|
|
108
|
-
function parseSchema(name, schema) {
|
|
101
|
+
function parseSchema(name, schema, allEnums) {
|
|
109
102
|
const properties = [];
|
|
103
|
+
const enums = {};
|
|
110
104
|
if (schema.properties) {
|
|
111
105
|
for (const propName in schema.properties) {
|
|
112
106
|
const propSchema = schema.properties[propName];
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
107
|
+
if (propSchema.enum) {
|
|
108
|
+
const enumName = `${toPascalCase(name)}${toPascalCase(propName)}Enum`;
|
|
109
|
+
enums[propName] = propSchema.enum;
|
|
110
|
+
if (!allEnums.has(enumName)) allEnums.set(enumName, { name: enumName, values: propSchema.enum });
|
|
116
111
|
}
|
|
117
112
|
properties.push({
|
|
118
113
|
name: propName,
|
|
@@ -123,24 +118,24 @@ function parseSchema(name, schema) {
|
|
|
123
118
|
example: propSchema.example,
|
|
124
119
|
enum: propSchema.enum,
|
|
125
120
|
format: propSchema.format,
|
|
126
|
-
items,
|
|
127
|
-
|
|
128
|
-
properties: propSchema.properties ? parseSchema("sub-object", propSchema).properties : void 0
|
|
121
|
+
items: propSchema.type === "array" && propSchema.items ? parseSchema(`${name}${toPascalCase(propName)}Item`, propSchema.items, allEnums).properties[0] : void 0,
|
|
122
|
+
properties: propSchema.properties ? parseSchema(`${name}${toPascalCase(propName)}`, propSchema, allEnums).properties : void 0
|
|
129
123
|
});
|
|
130
124
|
}
|
|
131
125
|
}
|
|
132
|
-
return { name, description: schema.description, properties };
|
|
126
|
+
return { name, description: schema.description, properties, enums };
|
|
133
127
|
}
|
|
134
128
|
function parseSpecToModules(spec) {
|
|
135
129
|
const modules = /* @__PURE__ */ new Map();
|
|
136
130
|
const allSchemas = /* @__PURE__ */ new Map();
|
|
131
|
+
const allEnums = /* @__PURE__ */ new Map();
|
|
137
132
|
const modulePaths = /* @__PURE__ */ new Map();
|
|
138
133
|
const registerSchema = (schema, baseName) => {
|
|
139
134
|
if (!schema) return "unknown";
|
|
140
135
|
if (schema.type === "array" && schema.items) return `${registerSchema(schema.items, `${baseName}Item`)}[]`;
|
|
141
136
|
if (schema.type === "object" || schema.properties || schema.allOf || !schema.type) {
|
|
142
137
|
const typeName = toPascalCase(baseName.replace(/_v\d+(Request|Response)$/, "$1"));
|
|
143
|
-
if (!allSchemas.has(typeName)) allSchemas.set(typeName, parseSchema(typeName, schema));
|
|
138
|
+
if (!allSchemas.has(typeName)) allSchemas.set(typeName, parseSchema(typeName, schema, allEnums));
|
|
144
139
|
return typeName;
|
|
145
140
|
}
|
|
146
141
|
return schema.type === "integer" ? "number" : schema.type || "unknown";
|
|
@@ -154,7 +149,7 @@ function parseSpecToModules(spec) {
|
|
|
154
149
|
if (!endpoint.operationId) continue;
|
|
155
150
|
const moduleName = getModuleName(endpoint.operationId);
|
|
156
151
|
if (!modules.has(moduleName)) {
|
|
157
|
-
modules.set(moduleName, { moduleName, baseEndpoint: "", actions: {}, schemas: /* @__PURE__ */ new Set() });
|
|
152
|
+
modules.set(moduleName, { moduleName, baseEndpoint: "", actions: {}, schemas: /* @__PURE__ */ new Set(), enums: /* @__PURE__ */ new Set() });
|
|
158
153
|
modulePaths.set(moduleName, []);
|
|
159
154
|
}
|
|
160
155
|
const currentModule = modules.get(moduleName);
|
|
@@ -170,35 +165,33 @@ function parseSpecToModules(spec) {
|
|
|
170
165
|
const cleanType = t.replace("[]", "");
|
|
171
166
|
if (cleanType && !["unknown", "undefined", "void", "any", "QueryOptions", "Promise"].includes(cleanType)) {
|
|
172
167
|
currentModule.schemas.add(cleanType);
|
|
168
|
+
const schemaDef = allSchemas.get(cleanType);
|
|
169
|
+
if (schemaDef) Object.keys(schemaDef.enums).forEach((propName) => currentModule.enums.add(`${toPascalCase(cleanType)}${toPascalCase(propName)}Enum`));
|
|
173
170
|
}
|
|
174
171
|
});
|
|
175
|
-
|
|
176
|
-
currentModule.actions[actionName] = { name: actionName, method: method.toUpperCase(), path: apiPath, description: endpoint.summary || "", hasQuery: (endpoint.parameters || []).some((p) => p.in === "query"), autoFetch: method.toUpperCase() === "GET" && !apiPath.includes("{"), requiresAuth: !!endpoint.security && endpoint.security.length > 0, inputType, outputType };
|
|
172
|
+
currentModule.actions[getActionName(endpoint.operationId)] = { name: getActionName(endpoint.operationId), method: method.toUpperCase(), path: apiPath, description: endpoint.summary || "", hasQuery: (endpoint.parameters || []).some((p) => p.in === "query"), autoFetch: method.toUpperCase() === "GET" && !apiPath.includes("{"), requiresAuth: !!endpoint.security && endpoint.security.length > 0, inputType, outputType };
|
|
177
173
|
}
|
|
178
174
|
}
|
|
179
175
|
modules.forEach((mod, name) => {
|
|
180
|
-
|
|
181
|
-
mod.
|
|
182
|
-
Object.values(mod.actions).forEach((action) => {
|
|
183
|
-
const relativePath = action.path.replace(basePath, "").replace(/^\//, "");
|
|
184
|
-
action.path = relativePath === "" ? "/" : relativePath;
|
|
185
|
-
});
|
|
176
|
+
mod.baseEndpoint = findCommonPath(modulePaths.get(name));
|
|
177
|
+
Object.values(mod.actions).forEach((action) => action.path = action.path.replace(mod.baseEndpoint, "").replace(/^\//, "") || "/");
|
|
186
178
|
});
|
|
187
179
|
debugLog("Final Parsed Modules", Object.fromEntries(modules));
|
|
188
|
-
return { modules, allSchemas };
|
|
180
|
+
return { modules, allSchemas, allEnums };
|
|
189
181
|
}
|
|
190
|
-
async function generateModuleFiles(module2, allSchemas, outputDir) {
|
|
182
|
+
async function generateModuleFiles(module2, allSchemas, allEnums, outputDir) {
|
|
191
183
|
const moduleOutputPath = import_path.default.join(outputDir, module2.moduleName);
|
|
192
184
|
if (!import_fs.default.existsSync(moduleOutputPath)) import_fs.default.mkdirSync(moduleOutputPath, { recursive: true });
|
|
193
185
|
console.log(import_chalk.default.cyan(`
|
|
194
186
|
Generating module: ${import_chalk.default.bold(module2.moduleName)}`));
|
|
195
|
-
const
|
|
187
|
+
const schemasToImport = [...module2.schemas].sort();
|
|
188
|
+
const enumsToImport = [...module2.enums].sort();
|
|
196
189
|
let configContent = `/* eslint-disable */
|
|
197
190
|
// This file is auto-generated.
|
|
198
191
|
|
|
199
192
|
import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core-lib';
|
|
200
193
|
`;
|
|
201
|
-
if (
|
|
194
|
+
if (schemasToImport.length > 0) configContent += `import type { ${schemasToImport.join(", ")} } from './types';
|
|
202
195
|
`;
|
|
203
196
|
const actionsType = Object.values(module2.actions).map((a) => ` ${a.name}: ActionConfigModule<${a.inputType}, ${a.outputType}>;`).join("\n");
|
|
204
197
|
const actionsValue = Object.values(module2.actions).map((a) => {
|
|
@@ -220,11 +213,32 @@ ${actionsValue}
|
|
|
220
213
|
const indexContent = [`// This file is auto-generated.
|
|
221
214
|
|
|
222
215
|
export * from './config';`];
|
|
223
|
-
if (
|
|
216
|
+
if (schemasToImport.length > 0) {
|
|
217
|
+
if (enumsToImport.length > 0) {
|
|
218
|
+
let enumsContent = `// This file is auto-generated.
|
|
219
|
+
|
|
220
|
+
`;
|
|
221
|
+
for (const enumName of enumsToImport) {
|
|
222
|
+
const enumDef = allEnums.get(enumName);
|
|
223
|
+
if (enumDef) {
|
|
224
|
+
enumsContent += `export const ${enumName} = ${JSON.stringify(enumDef.values)} as const;
|
|
225
|
+
`;
|
|
226
|
+
enumsContent += `export type ${enumName} = typeof ${enumName}[number];
|
|
227
|
+
|
|
228
|
+
`;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "enums.ts"), enumsContent);
|
|
232
|
+
console.log(import_chalk.default.gray(` \u2713 enums.ts`));
|
|
233
|
+
indexContent.push(`export * from './enums';`);
|
|
234
|
+
}
|
|
224
235
|
let typesContent = `// This file is auto-generated.
|
|
225
236
|
|
|
226
237
|
`;
|
|
227
|
-
|
|
238
|
+
if (enumsToImport.length > 0) typesContent += `import type { ${enumsToImport.join(", ")} } from './enums';
|
|
239
|
+
|
|
240
|
+
`;
|
|
241
|
+
for (const typeName of schemasToImport) {
|
|
228
242
|
const parsedSchema = allSchemas.get(typeName);
|
|
229
243
|
if (parsedSchema) {
|
|
230
244
|
if (parsedSchema.description) typesContent += `/**
|
|
@@ -240,8 +254,9 @@ ${prop.example ? ` * @example ${JSON.stringify(prop.example)}
|
|
|
240
254
|
` : ""} */
|
|
241
255
|
`;
|
|
242
256
|
let propType = prop.type;
|
|
243
|
-
if (prop.enum) propType =
|
|
244
|
-
else if (prop.items) propType = `${toPascalCase(prop.
|
|
257
|
+
if (prop.enum) propType = `${toPascalCase(typeName)}${toPascalCase(prop.name)}Enum`;
|
|
258
|
+
else if (prop.items) propType = prop.items.properties ? `${toPascalCase(`${typeName}${toPascalCase(prop.name)}Item`)}[]` : `${prop.items.type}[]`;
|
|
259
|
+
else if (prop.properties) propType = `Record<string, unknown>`;
|
|
245
260
|
typesContent += ` ${prop.name}${prop.isRequired ? "" : "?"}: ${propType};
|
|
246
261
|
`;
|
|
247
262
|
}
|
|
@@ -255,12 +270,14 @@ ${prop.example ? ` * @example ${JSON.stringify(prop.example)}
|
|
|
255
270
|
indexContent.push(`export * from './types';`);
|
|
256
271
|
let validationContent = `// This file is auto-generated.
|
|
257
272
|
import { z } from 'zod';
|
|
273
|
+
`;
|
|
274
|
+
if (enumsToImport.length > 0) validationContent += `import { ${enumsToImport.join(", ")} } from './enums';
|
|
258
275
|
|
|
259
276
|
`;
|
|
260
|
-
for (const typeName of
|
|
277
|
+
for (const typeName of schemasToImport) {
|
|
261
278
|
const parsedSchema = allSchemas.get(typeName);
|
|
262
279
|
if (parsedSchema) {
|
|
263
|
-
let zodShape = parsedSchema.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
|
|
280
|
+
let zodShape = parsedSchema.properties.map((p) => ` ${p.name}: ${_propToZod(p, typeName)}`).join(",\n");
|
|
264
281
|
validationContent += `export const ${typeName}Schema = z.object({
|
|
265
282
|
${zodShape}
|
|
266
283
|
});
|
|
@@ -272,10 +289,12 @@ ${zodShape}
|
|
|
272
289
|
console.log(import_chalk.default.gray(` \u2713 validation.ts`));
|
|
273
290
|
indexContent.push(`export * from './validation';`);
|
|
274
291
|
let mocksContent = `// This file is auto-generated.
|
|
275
|
-
import type { ${
|
|
292
|
+
import type { ${schemasToImport.join(", ")} } from './types';
|
|
293
|
+
`;
|
|
294
|
+
if (enumsToImport.length > 0) mocksContent += `import { ${enumsToImport.map((e) => e.replace(/Enum$/, "")).join(", ")} } from './enums';
|
|
276
295
|
|
|
277
296
|
`;
|
|
278
|
-
for (const typeName of
|
|
297
|
+
for (const typeName of schemasToImport) {
|
|
279
298
|
const parsedSchema = allSchemas.get(typeName);
|
|
280
299
|
if (parsedSchema) {
|
|
281
300
|
let mockObject = {};
|
|
@@ -294,30 +313,30 @@ import type { ${typesToImport.join(", ")} } from './types';
|
|
|
294
313
|
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "index.ts"), indexContent.join("\n"));
|
|
295
314
|
console.log(import_chalk.default.gray(` \u2713 index.ts`));
|
|
296
315
|
}
|
|
297
|
-
function _propToZod(prop) {
|
|
316
|
+
function _propToZod(prop, parentName) {
|
|
298
317
|
let zodString = "z.any()";
|
|
299
|
-
const
|
|
318
|
+
const errorMapParams = { errorMap: () => ({ message: prop.description || generateFriendlyMessage(prop.name, "required") }) };
|
|
300
319
|
switch (prop.type) {
|
|
301
320
|
case "string":
|
|
302
|
-
zodString = `z.string(${JSON.stringify(
|
|
321
|
+
zodString = `z.string(${JSON.stringify(errorMapParams)})`;
|
|
303
322
|
if (prop.format === "email") zodString += `.email({ message: "${generateFriendlyMessage(prop.name, "email")}" })`;
|
|
304
323
|
if (prop.format === "uuid") zodString += `.uuid()`;
|
|
305
|
-
if (prop.enum) zodString = `z.enum(${
|
|
324
|
+
if (prop.enum) zodString = `z.enum(${toPascalCase(parentName)}${toPascalCase(prop.name)}Enum)`;
|
|
306
325
|
break;
|
|
307
326
|
case "integer":
|
|
308
327
|
case "number":
|
|
309
|
-
zodString = `z.number(${JSON.stringify(
|
|
328
|
+
zodString = `z.number(${JSON.stringify(errorMapParams)})`;
|
|
310
329
|
break;
|
|
311
330
|
case "boolean":
|
|
312
|
-
zodString = `z.boolean(${JSON.stringify(
|
|
331
|
+
zodString = `z.boolean(${JSON.stringify(errorMapParams)})`;
|
|
313
332
|
break;
|
|
314
333
|
case "array":
|
|
315
|
-
zodString = `z.array(${prop.items ? _propToZod(prop.items) : "z.any()"})`;
|
|
334
|
+
zodString = `z.array(${prop.items ? _propToZod(prop.items, `${parentName}${toPascalCase(prop.name)}Item`) : "z.any()"})`;
|
|
316
335
|
break;
|
|
317
336
|
case "object":
|
|
318
|
-
let shape = "z.
|
|
337
|
+
let shape = "z.record(z.unknown())";
|
|
319
338
|
if (prop.properties) shape = `z.object({
|
|
320
|
-
${prop.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n")}
|
|
339
|
+
${prop.properties.map((p) => ` ${p.name}: ${_propToZod(p, `${parentName}${toPascalCase(prop.name)}`)}`).join(",\n")}
|
|
321
340
|
})`;
|
|
322
341
|
zodString = shape;
|
|
323
342
|
break;
|
|
@@ -353,7 +372,7 @@ function _propToMock(prop) {
|
|
|
353
372
|
}
|
|
354
373
|
}
|
|
355
374
|
async function runGenerator(options) {
|
|
356
|
-
console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator (
|
|
375
|
+
console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator (Diamond Edition)..."));
|
|
357
376
|
import_dotenv.default.config({ path: options.envPath });
|
|
358
377
|
const specUrl = process.env.OPENAPI_SPEC_URL || "./swagger.json";
|
|
359
378
|
try {
|
|
@@ -361,13 +380,12 @@ async function runGenerator(options) {
|
|
|
361
380
|
\u23F3 Step 1: Dereferencing spec from ${specUrl}...`));
|
|
362
381
|
const spec = await import_swagger_parser.default.dereference(specUrl);
|
|
363
382
|
console.log(import_chalk.default.green("\u2713 Spec fully dereferenced."));
|
|
364
|
-
debugLog("Dereferenced Spec", spec);
|
|
365
383
|
console.log(import_chalk.default.blue("\n\u23F3 Step 2: Parsing spec with intelligent grouping..."));
|
|
366
|
-
const { modules, allSchemas } = parseSpecToModules(spec);
|
|
384
|
+
const { modules, allSchemas, allEnums } = parseSpecToModules(spec);
|
|
367
385
|
console.log(import_chalk.default.green(`\u2713 Found and grouped ${modules.size} logical modules.`));
|
|
368
386
|
console.log(import_chalk.default.blue("\n\u23F3 Step 3: Generating all module files..."));
|
|
369
387
|
for (const module2 of modules.values()) {
|
|
370
|
-
await generateModuleFiles(module2, allSchemas, options.output);
|
|
388
|
+
await generateModuleFiles(module2, allSchemas, allEnums, options.output);
|
|
371
389
|
}
|
|
372
390
|
console.log(import_chalk.default.green("\n\u2713 All module files generated successfully."));
|
|
373
391
|
console.log(import_chalk.default.bold.green("\n\u{1F389} API generation complete! Your development platform is ready."));
|