api-core-lib 12.0.73 → 12.0.75

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 +194 -71
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -74,6 +74,110 @@ 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 getRuleMessage = (rule, defaultKey) => {
82
+ const customMessages = prop.errorMessages;
83
+ const message = customMessages?.[rule] || defaultKey;
84
+ return `{ "message": "${message}" }`;
85
+ };
86
+ switch (prop.type) {
87
+ case "string": {
88
+ if (prop.enum && prop.enum.length > 0) {
89
+ const messages = {
90
+ required_error: prop.errorMessages?.required || "validation.required",
91
+ invalid_type_error: prop.errorMessages?.invalid_type || "validation.string.enum"
92
+ };
93
+ zodChain = `z.enum(${JSON.stringify(prop.enum)}, ${JSON.stringify(messages)})`;
94
+ } else {
95
+ zodChain = "z.string()";
96
+ if (prop.isRequired) {
97
+ zodChain += `.min(1, ${getRuleMessage("minLength", "validation.string.nonempty")})`;
98
+ }
99
+ if (prop.maxLength !== void 0) {
100
+ zodChain += `.max(${prop.maxLength}, ${getRuleMessage("maxLength", "validation.string.max")})`;
101
+ }
102
+ if (prop.pattern) {
103
+ zodChain += `.regex(/${prop.pattern}/, ${getRuleMessage("pattern", "validation.string.regex")})`;
104
+ }
105
+ if (prop.format) {
106
+ const msg = getRuleMessage("format", `validation.string.${prop.format}`);
107
+ if (prop.format === "email") zodChain += `.email(${msg})`;
108
+ if (prop.format === "url") zodChain += `.url(${msg})`;
109
+ if (prop.format === "uuid") zodChain += `.uuid(${msg})`;
110
+ if (prop.format === "datetime") zodChain += `.datetime(${msg})`;
111
+ }
112
+ }
113
+ break;
114
+ }
115
+ case "integer": {
116
+ zodChain = `z.number().int(${getRuleMessage("integer", "validation.number.integer")})`;
117
+ if (prop.minimum !== void 0) {
118
+ zodChain += `.min(${prop.minimum}, ${getRuleMessage("minimum", "validation.number.min")})`;
119
+ }
120
+ if (prop.maximum !== void 0) {
121
+ zodChain += `.max(${prop.maximum}, ${getRuleMessage("maximum", "validation.number.max")})`;
122
+ }
123
+ break;
124
+ }
125
+ case "number": {
126
+ zodChain = "z.number()";
127
+ if (prop.minimum !== void 0) {
128
+ zodChain += `.min(${prop.minimum}, ${getRuleMessage("minimum", "validation.number.min")})`;
129
+ }
130
+ if (prop.maximum !== void 0) {
131
+ zodChain += `.max(${prop.maximum}, ${getRuleMessage("maximum", "validation.number.max")})`;
132
+ }
133
+ break;
134
+ }
135
+ case "boolean": {
136
+ zodChain = "z.boolean()";
137
+ break;
138
+ }
139
+ case "array": {
140
+ const itemSchema = prop.items ? _propToZod(prop.items) : "z.any()";
141
+ zodChain = `z.array(${itemSchema})`;
142
+ if (prop.minItems !== void 0) {
143
+ zodChain += `.min(${prop.minItems}, ${getRuleMessage("minItems", "validation.array.min")})`;
144
+ }
145
+ if (prop.maxItems !== void 0) {
146
+ zodChain += `.max(${prop.maxItems}, ${getRuleMessage("maxItems", "validation.array.max")})`;
147
+ }
148
+ break;
149
+ }
150
+ case "object": {
151
+ if (prop.properties && prop.properties.length > 0) {
152
+ const shape = prop.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
153
+ zodChain = `z.object({
154
+ ${shape}
155
+ })`;
156
+ } else {
157
+ zodChain = "z.record(z.unknown())";
158
+ }
159
+ break;
160
+ }
161
+ default:
162
+ zodChain = "z.any()";
163
+ break;
164
+ }
165
+ if (prop.description) {
166
+ zodChain += `.describe(${JSON.stringify(prop.description)})`;
167
+ }
168
+ if (!prop.isRequired) {
169
+ zodChain += ".optional()";
170
+ }
171
+ if (prop.isNullable) {
172
+ zodChain += ".nullable()";
173
+ }
174
+ if (prop.defaultValue !== void 0) {
175
+ zodChain += `.default(${JSON.stringify(prop.defaultValue)})`;
176
+ }
177
+ return zodChain;
178
+ }
179
+
180
+ // src/generator/index.ts
77
181
  var DEBUG_MODE = process.env.DEBUG === "true";
78
182
  var debugLog = (title, data) => DEBUG_MODE && console.log(import_chalk.default.yellow(`
79
183
  [DEBUG: ${title}]`), import_util.default.inspect(data, { depth: 5, colors: true }));
@@ -276,25 +380,109 @@ ${prop.example ? ` * @example ${JSON.stringify(prop.example)}
276
380
  import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "types.ts"), typesContent);
277
381
  console.log(import_chalk.default.gray(` \u2713 types.ts`));
278
382
  indexContent.push(`export * from './types';`);
279
- let validationContent = `// This file is auto-generated.
280
- import { z } from 'zod';
281
- `;
282
- if (enumsToImport.length > 0) validationContent += `import { ${enumsToImport.join(", ")} } from './enums';
383
+ const validationFileHeader = `// This file is auto-generated.
384
+ import { z, ZodIssueCode, ZodError } from 'zod';
385
+ ${enumsToImport.length > 0 ? `import { ${enumsToImport.join(", ")} } from './enums';
386
+ ` : ""}
387
+ // =============================================================================
388
+ // I. \u0625\u0639\u062F\u0627\u062F \u062E\u0631\u064A\u0637\u0629 \u0623\u062E\u0637\u0627\u0621 \u0639\u0627\u0644\u0645\u064A\u0629 (Global Error Map) \u0644\u062F\u0639\u0645 \u0627\u0644\u062A\u0631\u062C\u0645\u0629
389
+ // =============================================================================
390
+ //
391
+ // \u0645\u0644\u0627\u062D\u0638\u0629 \u0647\u0627\u0645\u0629: \u0641\u064A \u062A\u0637\u0628\u064A\u0642 \u062D\u0642\u064A\u0642\u064A\u060C \u064A\u062C\u0628 \u062A\u0639\u0631\u064A\u0641 \u0647\u0630\u0647 \u0627\u0644\u062E\u0631\u064A\u0637\u0629 \u0645\u0631\u0629 \u0648\u0627\u062D\u062F\u0629 \u0641\u0642\u0637
392
+ // \u0641\u064A \u0646\u0642\u0637\u0629 \u0627\u0644\u062F\u062E\u0648\u0644 \u0644\u062A\u0637\u0628\u064A\u0642\u0643 (entry-point). \u062A\u0645 \u0648\u0636\u0639\u0647\u0627 \u0647\u0646\u0627 \u0644\u0644\u062A\u0648\u0636\u064A\u062D.
393
+ //
394
+ // \u0627\u0644\u0647\u062F\u0641: \u0631\u0628\u0637 \u0645\u0641\u0627\u062A\u064A\u062D \u0627\u0644\u062A\u0631\u062C\u0645\u0629 (\u0645\u062B\u0644 "validation.required") \u0627\u0644\u062A\u064A \u062A\u0645 \u062A\u0648\u0644\u064A\u062F\u0647\u0627
395
+ // \u0641\u064A \u0627\u0644\u0645\u062E\u0637\u0637\u0627\u062A \u0623\u062F\u0646\u0627\u0647 \u0628\u0631\u0633\u0627\u0626\u0644 \u062D\u0642\u064A\u0642\u064A\u0629 \u064A\u0645\u0643\u0646 \u0639\u0631\u0636\u0647\u0627 \u0644\u0644\u0645\u0633\u062A\u062E\u062F\u0645.
396
+
397
+ // 1. \u0645\u062B\u0627\u0644 \u0628\u0633\u064A\u0637 \u0644\u062F\u0627\u0644\u0629 \u062A\u0631\u062C\u0645\u0629 (\u0641\u064A \u062A\u0637\u0628\u064A\u0642\u0643 \u0633\u062A\u0633\u062A\u062E\u062F\u0645 \u0645\u0643\u062A\u0628\u0629 \u0645\u062B\u0644 i18next)
398
+ const t = (key: string, args?: any): string => {
399
+ // \u0647\u0646\u0627 \u062A\u0636\u0639 \u0645\u0646\u0637\u0642 \u0627\u0644\u062A\u0631\u062C\u0645\u0629 \u0627\u0644\u062D\u0642\u064A\u0642\u064A \u0627\u0644\u062E\u0627\u0635 \u0628\u0643.
400
+ // \u0647\u0630\u0627 \u0645\u062C\u0631\u062F \u0645\u062B\u0627\u0644 \u0628\u0633\u064A\u0637.
401
+ if (key === 'validation.string.nonempty') return '\u0647\u0630\u0627 \u0627\u0644\u062D\u0642\u0644 \u0645\u0637\u0644\u0648\u0628 \u0648\u0644\u0627 \u064A\u0645\u0643\u0646 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0641\u0627\u0631\u063A\u064B\u0627.';
402
+ if (key === 'validation.string.email') return '\u0627\u0644\u0631\u062C\u0627\u0621 \u0625\u062F\u062E\u0627\u0644 \u0628\u0631\u064A\u062F \u0625\u0644\u0643\u062A\u0631\u0648\u0646\u064A \u0635\u0627\u0644\u062D.';
403
+ if (key === 'validation.required') return '\u0647\u0630\u0627 \u0627\u0644\u062D\u0642\u0644 \u0625\u0644\u0632\u0627\u0645\u064A.';
404
+ // \u0631\u0633\u0627\u0644\u0629 \u0627\u062D\u062A\u064A\u0627\u0637\u064A\u0629
405
+ return key.split('.').pop()?.replace(/_/g, ' ') || key;
406
+ };
407
+
408
+ // 2. \u062A\u0639\u0631\u064A\u0641 \u062E\u0631\u064A\u0637\u0629 \u0627\u0644\u0623\u062E\u0637\u0627\u0621 \u0627\u0644\u0645\u062E\u0635\u0635\u0629
409
+ const customErrorMap: z.ZodErrorMap = (issue, ctx) => {
410
+ if (issue.message) {
411
+ // \u0625\u0630\u0627 \u0643\u0627\u0646\u062A \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0647\u064A \u0645\u0641\u062A\u0627\u062D \u062A\u0631\u062C\u0645\u0629\u060C \u0642\u0645 \u0628\u062A\u0631\u062C\u0645\u062A\u0647\u0627
412
+ if (issue.message.startsWith('validation.')) {
413
+ return { message: t(issue.message) };
414
+ }
415
+ // \u0648\u0625\u0644\u0627\u060C \u0641\u0647\u064A \u0631\u0633\u0627\u0644\u0629 \u0645\u062E\u0635\u0635\u0629 \u0645\u0628\u0627\u0634\u0631\u0629
416
+ return { message: issue.message };
417
+ }
418
+
419
+ // \u062A\u0631\u062C\u0645\u0629 \u0627\u0644\u0623\u062E\u0637\u0627\u0621 \u0627\u0644\u0627\u0641\u062A\u0631\u0627\u0636\u064A\u0629 \u0627\u0644\u0639\u0627\u0645\u0629
420
+ if (issue.code === ZodIssueCode.invalid_type) {
421
+ return { message: t('validation.required') };
422
+ }
423
+
424
+ return { message: ctx.defaultError };
425
+ };
426
+
427
+ // 3. \u0642\u0645 \u0628\u062A\u0639\u064A\u064A\u0646 \u0627\u0644\u062E\u0631\u064A\u0637\u0629 \u0627\u0644\u0645\u062E\u0635\u0635\u0629 \u0639\u0627\u0644\u0645\u064A\u064B\u0627 (\u064A\u062C\u0628 \u0639\u0645\u0644 \u0630\u0644\u0643 \u0645\u0631\u0629 \u0648\u0627\u062D\u062F\u0629 \u0641\u064A \u0627\u0644\u062A\u0637\u0628\u064A\u0642)
428
+ z.setErrorMap(customErrorMap);
283
429
 
430
+ // =============================================================================
431
+ // II. \u0645\u062E\u0637\u0637\u0627\u062A \u0627\u0644\u062A\u062D\u0642\u0642 \u0627\u0644\u0645\u0648\u0644\u062F\u0629 \u062A\u0644\u0642\u0627\u0626\u064A\u064B\u0627 (Generated Validation Schemas)
432
+ // =============================================================================
284
433
  `;
434
+ let validationContent = validationFileHeader;
285
435
  for (const typeName of schemasToImport) {
286
436
  const parsedSchema = allSchemas.get(typeName);
287
437
  if (parsedSchema) {
288
438
  let zodShape = parsedSchema.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
439
+ validationContent += `
440
+ /**
441
+ * Schema for validating ${typeName} objects.
442
+ * @description ${parsedSchema.description || ""}
443
+ */
444
+ `;
289
445
  validationContent += `export const ${typeName}Schema = z.object({
290
446
  ${zodShape}
291
447
  });
292
-
448
+ `;
449
+ validationContent += `export type ${typeName}Schema = z.infer<typeof ${typeName}Schema>;
293
450
  `;
294
451
  }
295
452
  }
453
+ if (schemasToImport.length > 0) {
454
+ const firstSchemaName = schemasToImport[0];
455
+ validationContent += `
456
+ // =============================================================================
457
+ // 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
458
+ // =============================================================================
459
+ /*
460
+ function
461
+
462
+ validate${firstSchemaName}(data: unknown) {
463
+ try {
464
+ const validatedData = ${firstSchemaName}Schema.parse(data);
465
+ console.log("\u2705 Validation successful:", validatedData);
466
+ return { success: true, data: validatedData };
467
+ } catch (error) {
468
+ if (error instanceof ZodError) {
469
+ console.error("\u274C Validation failed:");
470
+ // .format() is great for getting a structured error object
471
+ console.log(JSON.stringify(error.format(), null, 2));
472
+ return { success: false, errors: error.format() };
473
+ }
474
+ throw error; // Rethrow other unexpected errors
475
+ }
476
+ }
477
+
478
+ // Example usage with invalid data:
479
+ const invalidData = { /* ... \u0628\u064A\u0627\u0646\u0627\u062A \u063A\u064A\u0631 \u0643\u0627\u0645\u0644\u0629 \u0623\u0648 \u062E\u0627\u0637\u0626\u0629 ... */ };
480
+ // validate${firstSchemaName}(invalidData);
481
+ */
482
+ `;
483
+ }
296
484
  import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "validation.ts"), validationContent);
297
- console.log(import_chalk.default.gray(` \u2713 validation.ts`));
485
+ console.log(import_chalk.default.gray(` \u2713 validation.ts (with integrated usage example)`));
298
486
  indexContent.push(`export * from './validation';`);
299
487
  let mocksContent = `// This file is auto-generated.
300
488
  import type { ${schemasToImport.join(", ")} } from './types';
@@ -321,71 +509,6 @@ import type { ${schemasToImport.join(", ")} } from './types';
321
509
  import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "index.ts"), indexContent.join("\n"));
322
510
  console.log(import_chalk.default.gray(` \u2713 index.ts`));
323
511
  }
324
- function _propToZod(prop) {
325
- let chain;
326
- const requiredErrorMessage = { required_error: `${prop.name} is required.` };
327
- switch (prop.type) {
328
- case "string":
329
- chain = `z.string({ ...requiredErrorMessage, invalid_type_error: "Expected a string for ${prop.name}" })`;
330
- if (prop.format === "email") chain += `.email({ message: "Invalid email address for ${prop.name}" })`;
331
- if (prop.format === "uuid") chain += `.uuid({ message: "Invalid UUID for ${prop.name}" })`;
332
- if (prop.format === "url") chain += `.url({ message: "Invalid URL for ${prop.name}" })`;
333
- if (prop.format === "datetime") chain += `.datetime({ message: "Invalid datetime format for ${prop.name}" })`;
334
- if (prop.minLength !== void 0) chain += `.min(${prop.minLength}, { message: "${prop.name} must be at least ${prop.minLength} characters long" })`;
335
- if (prop.maxLength !== void 0) chain += `.max(${prop.maxLength}, { message: "${prop.name} must be at most ${prop.maxLength} characters long" })`;
336
- if (prop.pattern) chain += `.regex(/${prop.pattern}/, { message: "Invalid format for ${prop.name}" })`;
337
- if (prop.enum) {
338
- if (prop.enum.length > 0) {
339
- chain = `z.enum(${JSON.stringify(prop.enum)})`;
340
- } else {
341
- chain = `z.string().refine(() => false, { message: "Enum for ${prop.name} is empty" })`;
342
- }
343
- }
344
- break;
345
- case "integer":
346
- chain = `z.number({ ...requiredErrorMessage, invalid_type_error: "Expected a number for ${prop.name}" }).int({ message: "${prop.name} must be an integer" })`;
347
- if (prop.minimum !== void 0) chain += `.min(${prop.minimum}, { message: "${prop.name} must be at least ${prop.minimum}" })`;
348
- if (prop.maximum !== void 0) chain += `.max(${prop.maximum}, { message: "${prop.name} must be at most ${prop.maximum}" })`;
349
- break;
350
- case "number":
351
- chain = `z.number({ ...requiredErrorMessage, invalid_type_error: "Expected a number for ${prop.name}" })`;
352
- if (prop.minimum !== void 0) chain += `.min(${prop.minimum}, { message: "${prop.name} must be at least ${prop.minimum}" })`;
353
- if (prop.maximum !== void 0) chain += `.max(${prop.maximum}, { message: "${prop.name} must be at most ${prop.maximum}" })`;
354
- break;
355
- case "boolean":
356
- chain = `z.boolean({ ...requiredErrorMessage, invalid_type_error: "Expected a boolean for ${prop.name}" })`;
357
- break;
358
- case "array":
359
- const itemSchema = prop.items ? _propToZod(prop.items) : "z.any()";
360
- chain = `z.array(${itemSchema})`;
361
- if (prop.minItems !== void 0) chain += `.min(${prop.minItems}, { message: "${prop.name} must contain at least ${prop.minItems} item(s)" })`;
362
- if (prop.maxItems !== void 0) chain += `.max(${prop.maxItems}, { message: "${prop.name} must contain at most ${prop.maxItems} item(s)" })`;
363
- break;
364
- case "object":
365
- if (prop.properties && prop.properties.length > 0) {
366
- const shape = prop.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
367
- chain = `z.object({
368
- ${shape}
369
- })`;
370
- } else {
371
- chain = "z.record(z.unknown())";
372
- }
373
- break;
374
- default:
375
- chain = "z.any()";
376
- break;
377
- }
378
- if (prop.description) {
379
- chain += `.describe(${JSON.stringify(prop.description)})`;
380
- }
381
- if (!prop.isRequired) {
382
- chain += ".optional()";
383
- }
384
- if (prop.isNullable) {
385
- chain += ".nullable()";
386
- }
387
- return chain;
388
- }
389
512
  function _propToMock(prop) {
390
513
  if (prop.example) return prop.example;
391
514
  if (prop.name.match(/image|avatar|logo|url/i)) return "https://via.placeholder.com/150";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "12.0.73",
3
+ "version": "12.0.75",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
6
  "exports": {