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.
Files changed (2) hide show
  1. package/dist/cli.cjs +104 -147
  2. 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)) allEnums.set(enumName, { name: enumName, values: propSchema.enum });
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
- if (enumsToImport.length > 0) {
226
- let enumsContent = `// This file is auto-generated.
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
- for (const enumName of enumsToImport) {
230
- const enumDef = allEnums.get(enumName);
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
- if (parsedSchema.description) typesContent += `/**
253
- * ${parsedSchema.description}
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
- typesContent += `export interface ${typeName} {
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
- typesContent += `}
272
-
304
+ validationContent += ` */
273
305
  `;
274
- }
275
- }
276
- import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "types.ts"), typesContent);
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, "mocks.ts"), mocksContent);
333
- console.log(import_chalk.default.gray(` \u2713 mocks.ts`));
334
- indexContent.push(`export * from './mocks';`);
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 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "12.0.76",
3
+ "version": "12.0.78",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
6
  "exports": {