api-core-lib 12.0.76 → 12.0.78
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 +104 -147
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -74,6 +74,74 @@ var import_chalk = __toESM(require("chalk"), 1);
|
|
|
74
74
|
var import_dotenv = __toESM(require("dotenv"), 1);
|
|
75
75
|
var import_swagger_parser = __toESM(require("@apidevtools/swagger-parser"), 1);
|
|
76
76
|
var import_openapi_types = __toESM(require_dist(), 1);
|
|
77
|
+
|
|
78
|
+
// src/generator/core/_propToZod.ts
|
|
79
|
+
function _propToZod(prop) {
|
|
80
|
+
let zodChain;
|
|
81
|
+
const getMsg = (key) => `{ "message": "validation.${key}" }`;
|
|
82
|
+
switch (prop.type) {
|
|
83
|
+
case "string":
|
|
84
|
+
if (prop.enumName) {
|
|
85
|
+
zodChain = `z.enum(${prop.enumName})`;
|
|
86
|
+
} else {
|
|
87
|
+
zodChain = "z.string()";
|
|
88
|
+
if (prop.isRequired) {
|
|
89
|
+
zodChain += `.min(1, ${getMsg("string.nonempty")})`;
|
|
90
|
+
}
|
|
91
|
+
if (prop.maxLength !== void 0) zodChain += `.max(${prop.maxLength}, ${getMsg("string.max")})`;
|
|
92
|
+
if (prop.pattern) zodChain += `.regex(/${prop.pattern}/, ${getMsg("string.regex")})`;
|
|
93
|
+
if (prop.format === "email") zodChain += `.email(${getMsg("string.email")})`;
|
|
94
|
+
if (prop.format === "url") zodChain += `.url(${getMsg("string.url")})`;
|
|
95
|
+
if (prop.format === "uuid") zodChain += `.uuid(${getMsg("string.uuid")})`;
|
|
96
|
+
if (prop.format === "datetime") zodChain += `.datetime(${getMsg("string.datetime")})`;
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
case "integer":
|
|
100
|
+
zodChain = `z.number().int(${getMsg("number.integer")})`;
|
|
101
|
+
if (prop.minimum !== void 0) zodChain += `.min(${prop.minimum}, ${getMsg("number.min")})`;
|
|
102
|
+
if (prop.maximum !== void 0) zodChain += `.max(${prop.maximum}, ${getMsg("number.max")})`;
|
|
103
|
+
break;
|
|
104
|
+
case "number":
|
|
105
|
+
zodChain = `z.number()`;
|
|
106
|
+
if (prop.minimum !== void 0) zodChain += `.min(${prop.minimum}, ${getMsg("number.min")})`;
|
|
107
|
+
if (prop.maximum !== void 0) zodChain += `.max(${prop.maximum}, ${getMsg("number.max")})`;
|
|
108
|
+
break;
|
|
109
|
+
case "boolean":
|
|
110
|
+
zodChain = `z.boolean()`;
|
|
111
|
+
break;
|
|
112
|
+
case "array":
|
|
113
|
+
const itemSchema = prop.items ? _propToZod(prop.items) : "z.any()";
|
|
114
|
+
zodChain = `z.array(${itemSchema})`;
|
|
115
|
+
if (prop.minItems !== void 0) zodChain += `.min(${prop.minItems}, ${getMsg("array.min")})`;
|
|
116
|
+
if (prop.maxItems !== void 0) zodChain += `.max(${prop.maxItems}, ${getMsg("array.max")})`;
|
|
117
|
+
break;
|
|
118
|
+
case "object":
|
|
119
|
+
if (prop.properties && prop.properties.length > 0) {
|
|
120
|
+
const shape = prop.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
|
|
121
|
+
zodChain = `z.object({
|
|
122
|
+
${shape}
|
|
123
|
+
})`;
|
|
124
|
+
} else {
|
|
125
|
+
zodChain = "z.record(z.unknown())";
|
|
126
|
+
}
|
|
127
|
+
break;
|
|
128
|
+
default:
|
|
129
|
+
zodChain = "z.any()";
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
if (prop.description) {
|
|
133
|
+
zodChain += `.describe(${JSON.stringify(prop.description)})`;
|
|
134
|
+
}
|
|
135
|
+
if (!prop.isRequired) {
|
|
136
|
+
zodChain += ".optional()";
|
|
137
|
+
}
|
|
138
|
+
if (prop.isNullable) {
|
|
139
|
+
zodChain += ".nullable()";
|
|
140
|
+
}
|
|
141
|
+
return zodChain;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/generator/index.ts
|
|
77
145
|
var DEBUG_MODE = process.env.DEBUG === "true";
|
|
78
146
|
var debugLog = (title, data) => DEBUG_MODE && console.log(import_chalk.default.yellow(`
|
|
79
147
|
[DEBUG: ${title}]`), import_util.default.inspect(data, { depth: 5, colors: true }));
|
|
@@ -101,6 +169,7 @@ function parseSchema(name, schema, allEnums) {
|
|
|
101
169
|
for (const propName in schema.properties) {
|
|
102
170
|
const propSchema = schema.properties[propName];
|
|
103
171
|
let itemSchema;
|
|
172
|
+
let generatedEnumName;
|
|
104
173
|
if (propSchema.type === "array" && propSchema.items) {
|
|
105
174
|
const itemTypeName = `${toPascalCase(name)}${toPascalCase(propName)}Item`;
|
|
106
175
|
itemSchema = parseSchema(itemTypeName, propSchema.items, allEnums).properties[0];
|
|
@@ -108,7 +177,10 @@ function parseSchema(name, schema, allEnums) {
|
|
|
108
177
|
if (propSchema.enum) {
|
|
109
178
|
const enumName = `${toPascalCase(name)}${toPascalCase(propName)}Enum`;
|
|
110
179
|
enums[propName] = propSchema.enum;
|
|
111
|
-
if (!allEnums.has(enumName))
|
|
180
|
+
if (!allEnums.has(enumName)) {
|
|
181
|
+
allEnums.set(enumName, { name: enumName, values: propSchema.enum });
|
|
182
|
+
}
|
|
183
|
+
generatedEnumName = enumName;
|
|
112
184
|
}
|
|
113
185
|
properties.push({
|
|
114
186
|
name: propName,
|
|
@@ -118,9 +190,18 @@ function parseSchema(name, schema, allEnums) {
|
|
|
118
190
|
description: propSchema.description,
|
|
119
191
|
example: propSchema.example,
|
|
120
192
|
enum: propSchema.enum,
|
|
193
|
+
enumName: generatedEnumName,
|
|
194
|
+
// <-- Pass the enum name to the property
|
|
121
195
|
format: propSchema.format,
|
|
122
196
|
items: itemSchema,
|
|
123
|
-
properties: propSchema.properties ? parseSchema(`${name}${toPascalCase(propName)}`, propSchema, allEnums).properties : void 0
|
|
197
|
+
properties: propSchema.properties ? parseSchema(`${name}${toPascalCase(propName)}`, propSchema, allEnums).properties : void 0,
|
|
198
|
+
minLength: propSchema.minLength,
|
|
199
|
+
maxLength: propSchema.maxLength,
|
|
200
|
+
pattern: propSchema.pattern,
|
|
201
|
+
minimum: propSchema.minimum,
|
|
202
|
+
maximum: propSchema.maximum,
|
|
203
|
+
minItems: propSchema.minItems,
|
|
204
|
+
maxItems: propSchema.maxItems
|
|
124
205
|
});
|
|
125
206
|
}
|
|
126
207
|
}
|
|
@@ -194,174 +275,50 @@ async function generateModuleFiles(module2, allSchemas, allEnums, outputDir) {
|
|
|
194
275
|
Generating module: ${import_chalk.default.bold(module2.moduleName)}`));
|
|
195
276
|
const schemasToImport = [...module2.schemas].sort();
|
|
196
277
|
const enumsToImport = [...module2.enums].sort();
|
|
197
|
-
const indexContent = [`// This file is auto-generated.
|
|
278
|
+
const indexContent = [`// This file is auto-generated. Do not edit directly.
|
|
198
279
|
|
|
199
280
|
export * from './config';`];
|
|
200
|
-
let configContent = `/* eslint-disable */
|
|
201
|
-
// This file is auto-generated.
|
|
202
|
-
|
|
203
|
-
import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core-lib';
|
|
204
|
-
`;
|
|
205
|
-
if (schemasToImport.length > 0) configContent += `import type { ${schemasToImport.join(", ")} } from './types';
|
|
206
|
-
`;
|
|
207
|
-
const actionsType = Object.values(module2.actions).map((a) => ` ${a.name}: ActionConfigModule<${a.inputType}, ${a.outputType}>;`).join("\n");
|
|
208
|
-
const actionsValue = Object.values(module2.actions).map((a) => {
|
|
209
|
-
const { inputType, outputType, name, ...c } = a;
|
|
210
|
-
return ` ${name}: ${JSON.stringify(c, null, 2).replace(/\n/g, "\n ")}`;
|
|
211
|
-
}).join(",\n");
|
|
212
|
-
configContent += `
|
|
213
|
-
export const ${module2.moduleName}Module: ApiModuleConfig<{
|
|
214
|
-
${actionsType}
|
|
215
|
-
}> = {
|
|
216
|
-
baseEndpoint: '${module2.baseEndpoint}',
|
|
217
|
-
actions: {
|
|
218
|
-
${actionsValue}
|
|
219
|
-
},
|
|
220
|
-
};
|
|
221
|
-
`;
|
|
222
|
-
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "config.ts"), configContent.trim());
|
|
223
|
-
console.log(import_chalk.default.gray(` \u2713 config.ts`));
|
|
224
281
|
if (schemasToImport.length > 0) {
|
|
225
|
-
|
|
226
|
-
|
|
282
|
+
indexContent.push(`export * from './types';`);
|
|
283
|
+
indexContent.push(`export * from './enums';`);
|
|
284
|
+
let validationContent = `// This file is auto-generated by the API generator. Do not edit directly.
|
|
227
285
|
|
|
286
|
+
import { z } from 'zod';
|
|
228
287
|
`;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (enumDef) {
|
|
232
|
-
enumsContent += `export const ${enumName} = ${JSON.stringify(enumDef.values)} as const;
|
|
233
|
-
`;
|
|
234
|
-
enumsContent += `export type ${enumName} = typeof ${enumName}[number];
|
|
235
|
-
|
|
288
|
+
if (enumsToImport.length > 0) {
|
|
289
|
+
validationContent += `import { ${enumsToImport.join(", ")} } from './enums';
|
|
236
290
|
`;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "enums.ts"), enumsContent);
|
|
240
|
-
console.log(import_chalk.default.gray(` \u2713 enums.ts`));
|
|
241
|
-
indexContent.push(`export * from './enums';`);
|
|
242
291
|
}
|
|
243
|
-
let typesContent = `// This file is auto-generated.
|
|
244
|
-
|
|
245
|
-
`;
|
|
246
|
-
if (enumsToImport.length > 0) typesContent += `import type { ${enumsToImport.join(", ")} } from './enums';
|
|
247
|
-
|
|
248
|
-
`;
|
|
249
292
|
for (const typeName of schemasToImport) {
|
|
250
293
|
const parsedSchema = allSchemas.get(typeName);
|
|
251
294
|
if (parsedSchema) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
295
|
+
const zodShape = parsedSchema.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
|
|
296
|
+
validationContent += `
|
|
297
|
+
/**
|
|
298
|
+
* Zod schema for {@link ${typeName}}.
|
|
255
299
|
`;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
for (const prop of parsedSchema.properties) {
|
|
259
|
-
if (prop.description) typesContent += ` /**
|
|
260
|
-
* ${prop.description}
|
|
261
|
-
${prop.example ? ` * @example ${JSON.stringify(prop.example)}
|
|
262
|
-
` : ""} */
|
|
263
|
-
`;
|
|
264
|
-
let propType = prop.type;
|
|
265
|
-
if (prop.enum) propType = `${toPascalCase(typeName)}${toPascalCase(prop.name)}Enum`;
|
|
266
|
-
else if (prop.items) propType = prop.items.name ? `${toPascalCase(prop.items.name)}[]` : `${prop.items.type || "unknown"}[]`;
|
|
267
|
-
else if (prop.type === "object") propType = prop.properties && prop.properties.length > 0 ? `Record<string, unknown>` : `Record<string, unknown>`;
|
|
268
|
-
typesContent += ` ${prop.name}${prop.isRequired ? "" : "?"}: ${propType};
|
|
300
|
+
if (parsedSchema.description) {
|
|
301
|
+
validationContent += ` * @description ${parsedSchema.description.replace(/\*\//g, "*\\/")}
|
|
269
302
|
`;
|
|
270
303
|
}
|
|
271
|
-
|
|
272
|
-
|
|
304
|
+
validationContent += ` */
|
|
273
305
|
`;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
console.log(import_chalk.default.gray(` \u2713 types.ts`));
|
|
278
|
-
indexContent.push(`export * from './types';`);
|
|
279
|
-
let validationContent = "";
|
|
280
|
-
if (schemasToImport.length > 0) {
|
|
281
|
-
const firstSchemaName = schemasToImport[0];
|
|
282
|
-
validationContent = `
|
|
283
|
-
// =============================================================================
|
|
284
|
-
// III. \u0645\u062B\u0627\u0644 \u0639\u0644\u0649 \u0643\u064A\u0641\u064A\u0629 \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0627\u0644\u0645\u062E\u0637\u0637 \u0641\u064A \u0627\u0644\u0643\u0648\u062F
|
|
285
|
-
// =============================================================================
|
|
286
|
-
/*
|
|
287
|
-
function
|
|
288
|
-
|
|
289
|
-
validate${firstSchemaName}(data: unknown) {
|
|
290
|
-
try {
|
|
291
|
-
const validatedData = ${firstSchemaName}Schema.parse(data);
|
|
292
|
-
console.log("\u2705 Validation successful:", validatedData);
|
|
293
|
-
return { success: true, data: validatedData };
|
|
294
|
-
} catch (error) {
|
|
295
|
-
if (error instanceof ZodError) {
|
|
296
|
-
console.error("\u274C Validation failed:");
|
|
297
|
-
// .format() is great for getting a structured error object
|
|
298
|
-
console.log(JSON.stringify(error.format(), null, 2));
|
|
299
|
-
return { success: false, errors: error.format() };
|
|
300
|
-
}
|
|
301
|
-
throw error; // Rethrow other unexpected errors
|
|
302
|
-
}
|
|
303
|
-
}
|
|
306
|
+
validationContent += `export const ${typeName}Schema = z.object({
|
|
307
|
+
${zodShape}
|
|
308
|
+
});
|
|
304
309
|
|
|
305
|
-
// Example usage with invalid data:
|
|
306
|
-
const invalidData = { /* ... \u0628\u064A\u0627\u0646\u0627\u062A \u063A\u064A\u0631 \u0643\u0627\u0645\u0644\u0629 \u0623\u0648 \u062E\u0627\u0637\u0626\u0629 ... */ };
|
|
307
|
-
// validate${firstSchemaName}(invalidData);
|
|
308
|
-
*/
|
|
309
310
|
`;
|
|
310
|
-
|
|
311
|
-
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "validation.ts"), validationContent);
|
|
312
|
-
console.log(import_chalk.default.gray(` \u2713 validation.ts (with integrated usage example)`));
|
|
313
|
-
indexContent.push(`export * from './validation';`);
|
|
314
|
-
let mocksContent = `// This file is auto-generated.
|
|
315
|
-
import type { ${schemasToImport.join(", ")} } from './types';
|
|
316
|
-
`;
|
|
317
|
-
if (enumsToImport.length > 0) mocksContent += `import { ${enumsToImport.join(", ")} } from './enums';
|
|
318
|
-
|
|
319
|
-
`;
|
|
320
|
-
for (const typeName of schemasToImport) {
|
|
321
|
-
const parsedSchema = allSchemas.get(typeName);
|
|
322
|
-
if (parsedSchema) {
|
|
323
|
-
let mockObject = {};
|
|
324
|
-
parsedSchema.properties.forEach((p) => {
|
|
325
|
-
mockObject[p.name] = _propToMock(p);
|
|
326
|
-
});
|
|
327
|
-
mocksContent += `export const mock${typeName}: ${typeName} = ${JSON.stringify(mockObject, null, 2)};
|
|
328
|
-
|
|
311
|
+
validationContent += `export type ${typeName}Validated = z.infer<typeof ${typeName}Schema>;
|
|
329
312
|
`;
|
|
330
313
|
}
|
|
331
314
|
}
|
|
332
|
-
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "
|
|
333
|
-
console.log(import_chalk.default.gray(` \u2713
|
|
334
|
-
indexContent.push(`export * from './
|
|
315
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "validation.ts"), validationContent);
|
|
316
|
+
console.log(import_chalk.default.gray(` \u2713 validation.ts`));
|
|
317
|
+
indexContent.push(`export * from './validation';`);
|
|
335
318
|
}
|
|
336
319
|
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "index.ts"), indexContent.join("\n"));
|
|
337
320
|
console.log(import_chalk.default.gray(` \u2713 index.ts`));
|
|
338
321
|
}
|
|
339
|
-
function _propToMock(prop) {
|
|
340
|
-
if (prop.example) return prop.example;
|
|
341
|
-
if (prop.name.match(/image|avatar|logo|url/i)) return "https://via.placeholder.com/150";
|
|
342
|
-
if (prop.enum) return prop.enum[0];
|
|
343
|
-
switch (prop.type) {
|
|
344
|
-
case "string":
|
|
345
|
-
if (prop.format === "email") return "test@example.com";
|
|
346
|
-
if (prop.format === "uuid") return "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11";
|
|
347
|
-
return `Mock ${toPascalCase(prop.name)}`;
|
|
348
|
-
case "integer":
|
|
349
|
-
case "number":
|
|
350
|
-
return 1;
|
|
351
|
-
case "boolean":
|
|
352
|
-
return true;
|
|
353
|
-
case "array":
|
|
354
|
-
return prop.items ? [_propToMock(prop.items)] : [];
|
|
355
|
-
case "object":
|
|
356
|
-
const mock = {};
|
|
357
|
-
if (prop.properties) prop.properties.forEach((p) => {
|
|
358
|
-
mock[p.name] = _propToMock(p);
|
|
359
|
-
});
|
|
360
|
-
return mock;
|
|
361
|
-
default:
|
|
362
|
-
return null;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
322
|
async function runGenerator(options) {
|
|
366
323
|
console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator (Sapphire Edition)..."));
|
|
367
324
|
import_dotenv.default.config({ path: options.envPath });
|