api-core-lib 12.0.86 → 12.0.88

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 +215 -12
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -75,6 +75,72 @@ 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
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
+
78
144
  // src/generator/utils/index.ts
79
145
  var getActionName = (opId) => {
80
146
  const cleanOpId = opId.replace(/_v\d+$/, "");
@@ -256,25 +322,139 @@ async function generateModuleFiles(module2, allSchemas, allEnums, outputDir) {
256
322
  if (!import_fs.default.existsSync(moduleOutputPath)) import_fs.default.mkdirSync(moduleOutputPath, { recursive: true });
257
323
  console.log(import_chalk.default.cyan(`
258
324
  Generating module: ${import_chalk.default.bold(module2.moduleName)}`));
259
- const schemasToImport = [...module2.schemas].sort();
325
+ const BUILT_IN_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "void", "undefined", "unknown", "any", "Date", "Promise", "QueryOptions", "Record<string, any>", "Record<string, unknown>"]);
326
+ const schemasToImport = [...module2.schemas].filter((name) => !BUILT_IN_TYPES.has(name)).sort();
260
327
  const enumsToImport = [...module2.enums].sort();
261
- const indexExports = ["config"];
328
+ const createdFileExports = ["config"];
329
+ let configContent = `// This file is auto-generated. Do not edit directly.
330
+
331
+ import type { ApiModuleConfig, ActionConfigModule } from 'api-core-lib';
332
+ `;
333
+ if (schemasToImport.length > 0) configContent += `import type { ${schemasToImport.join(", ")} } from './types';
334
+ `;
335
+ const actionsType = Object.values(module2.actions).map((a) => ` ${a.name}: ActionConfigModule<${a.inputType}, ${a.outputType}>;`).join("\n");
336
+ const actionsValue = Object.values(module2.actions).map((a) => {
337
+ const { inputType, outputType, name, ...c } = a;
338
+ return ` ${name}: ${JSON.stringify(c, null, 2).replace(/\n/g, "\n ")}`;
339
+ }).join(",\n");
340
+ configContent += `
341
+ export const ${module2.moduleName}: ApiModuleConfig<{
342
+ ${actionsType}
343
+ }> = {
344
+ baseEndpoint: '${module2.baseEndpoint}',
345
+ actions: {
346
+ ${actionsValue}
347
+ },
348
+ };
349
+ `;
350
+ import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "config.ts"), configContent.trim());
351
+ console.log(import_chalk.default.gray(` \u2713 config.ts`));
262
352
  if (schemasToImport.length > 0) {
263
- if (enumsToImport.length > 0) indexExports.push("enums");
264
- indexExports.push("types", "validation", "mocks");
353
+ if (enumsToImport.length > 0) {
354
+ let enumsContent = `// This file is auto-generated. Do not edit directly.
355
+
356
+ `;
357
+ enumsToImport.forEach((enumName) => {
358
+ const enumDef = allEnums.get(enumName);
359
+ if (enumDef) {
360
+ enumsContent += `export const ${enumName} = ${JSON.stringify(enumDef.values)} as const;
361
+ `;
362
+ enumsContent += `export type ${enumName} = typeof ${enumName}[number];
363
+
364
+ `;
365
+ }
366
+ });
367
+ import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "enums.ts"), enumsContent.trim());
368
+ console.log(import_chalk.default.gray(` \u2713 enums.ts`));
369
+ createdFileExports.push("enums");
370
+ }
371
+ let typesContent = `// This file is auto-generated. Do not edit directly.
372
+
373
+ `;
374
+ if (enumsToImport.length > 0) typesContent += `import type { ${enumsToImport.join(", ")} } from './enums';
375
+
376
+ `;
377
+ schemasToImport.forEach((typeName) => {
378
+ const parsedSchema = allSchemas.get(typeName);
379
+ if (parsedSchema) {
380
+ if (parsedSchema.description) typesContent += `/** ${parsedSchema.description} */
381
+ `;
382
+ typesContent += `export interface ${typeName} {
383
+ `;
384
+ parsedSchema.properties.forEach((prop) => {
385
+ if (prop.description) typesContent += ` /** ${prop.description} */
386
+ `;
387
+ let propType = prop.enumName || (prop.items ? `${prop.items.type || "any"}[]` : prop.type);
388
+ if (propType === "integer") propType = "number";
389
+ if (propType === "object") propType = "Record<string, any>";
390
+ typesContent += ` ${prop.name}${prop.isRequired ? "" : "?"}: ${propType};
391
+ `;
392
+ });
393
+ typesContent += `}
394
+
395
+ `;
396
+ }
397
+ });
398
+ import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "types.ts"), typesContent.trim());
399
+ console.log(import_chalk.default.gray(` \u2713 types.ts`));
400
+ createdFileExports.push("types");
401
+ let validationContent = `// This file is auto-generated. Do not edit directly.
402
+
403
+ import { z } from 'zod';
404
+ `;
405
+ if (enumsToImport.length > 0) validationContent += `import { ${enumsToImport.join(", ")} } from './enums';
406
+ `;
407
+ schemasToImport.forEach((typeName) => {
408
+ const parsedSchema = allSchemas.get(typeName);
409
+ if (parsedSchema) {
410
+ const zodShape = parsedSchema.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
411
+ validationContent += `
412
+ /** Zod schema for {@link ${typeName}}. */
413
+ `;
414
+ validationContent += `export const ${typeName}Schema = z.object({
415
+ ${zodShape}
416
+ });
417
+
418
+ `;
419
+ validationContent += `export type ${typeName}Validated = z.infer<typeof ${typeName}Schema>;
420
+ `;
421
+ }
422
+ });
423
+ import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "validation.ts"), validationContent.trim());
424
+ console.log(import_chalk.default.gray(` \u2713 validation.ts`));
425
+ createdFileExports.push("validation");
426
+ let mocksContent = `// This file is auto-generated. Do not edit directly.
427
+ import type { ${schemasToImport.join(", ")} } from './types';
428
+ `;
429
+ if (enumsToImport.length > 0) mocksContent += `import { ${enumsToImport.join(", ")} } from './enums';
430
+
431
+ `;
432
+ schemasToImport.forEach((typeName) => {
433
+ const parsedSchema = allSchemas.get(typeName);
434
+ if (parsedSchema) {
435
+ const mockObject = {};
436
+ parsedSchema.properties.forEach((p) => {
437
+ mockObject[p.name] = _propToMock(p);
438
+ });
439
+ mocksContent += `export const mock${typeName}: ${typeName} = ${JSON.stringify(mockObject, null, 2)};
440
+
441
+ `;
442
+ }
443
+ });
444
+ import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "mocks.ts"), mocksContent.trim());
445
+ console.log(import_chalk.default.gray(` \u2713 mocks.ts`));
446
+ createdFileExports.push("mocks");
265
447
  }
448
+ const indexFilePath = import_path.default.join(moduleOutputPath, "index.ts");
266
449
  const initialIndexContent = `// This file is auto-generated. Do not edit directly.
267
450
 
268
- ` + indexExports.map((e) => `export * from './${e}';`).join("\n");
269
- const indexFilePath = import_path.default.join(moduleOutputPath, "index.ts");
451
+ ` + createdFileExports.map((e) => `export * from './${e}';`).join("\n");
270
452
  import_fs.default.writeFileSync(indexFilePath, initialIndexContent);
271
453
  console.log(import_chalk.default.gray(` \u2713 index.ts (Initial)`));
272
454
  const moduleBaseName = module2.moduleName.replace(/Api$/, "");
273
455
  const camelCaseModuleName = toCamelCase(moduleBaseName);
274
456
  const allPathParams = /* @__PURE__ */ new Set();
275
- Object.values(module2.actions).forEach((action) => {
276
- action.pathParams.forEach((param) => allPathParams.add(param));
277
- });
457
+ Object.values(module2.actions).forEach((action) => action.pathParams.forEach((param) => allPathParams.add(param)));
278
458
  const pathParamsType = allPathParams.size > 0 ? `{ ${[...allPathParams].map((p) => `${p}?: string | number`).join("; ")} }` : "Record<string, never>";
279
459
  let endpointsContent = `// This file is auto-generated. Do not edit directly.
280
460
 
@@ -337,14 +517,12 @@ import { ${module2.moduleName} } from './config';
337
517
 
338
518
  type ModulePathParams = ${pathParamsType};
339
519
 
340
- // Options for the custom hook, extending the base options with typed path parameters.
341
520
  type ${moduleBaseName}ApiOptions = Omit<UseApiModuleOptions, 'pathParams'> & {
342
521
  pathParams?: ModulePathParams;
343
522
  };
344
523
 
345
524
  /**
346
525
  * Custom hook for interacting with the ${moduleBaseName} API module.
347
- * Simplifies API calls by pre-configuring the API client and module.
348
526
  */
349
527
  export const use${moduleBaseName}Api = (options: ${moduleBaseName}ApiOptions = {}) => {
350
528
  return useApiModule<typeof TModuleType['actions']>(apiClient, ${module2.moduleName}, options);
@@ -398,12 +576,37 @@ export const create${moduleBaseName}ServerApi = () => {
398
576
  `export * from './${camelCaseModuleName}.endpoints';`,
399
577
  `export * from './use${moduleBaseName}';`,
400
578
  `export * from './${moduleBaseName}.provider';`,
401
- // <-- Note: no .tsx in export
402
579
  `export * from './${camelCaseModuleName}.server';`
403
580
  ].join("\n");
404
581
  import_fs.default.appendFileSync(indexFilePath, newExports);
405
582
  console.log(import_chalk.default.gray(` \u2713 index.ts (Updated with helpers)`));
406
583
  }
584
+ function _propToMock(prop) {
585
+ if (prop.example) return prop.example;
586
+ if (prop.name.match(/image|avatar|logo|url/i)) return "https://via.placeholder.com/150";
587
+ if (prop.enum) return prop.enum[0];
588
+ switch (prop.type) {
589
+ case "string":
590
+ if (prop.format === "email") return "test@example.com";
591
+ if (prop.format === "uuid") return "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11";
592
+ return `Mock ${toPascalCase(prop.name)}`;
593
+ case "integer":
594
+ case "number":
595
+ return 1;
596
+ case "boolean":
597
+ return true;
598
+ case "array":
599
+ return prop.items ? [_propToMock(prop.items)] : [];
600
+ case "object":
601
+ const mock = {};
602
+ if (prop.properties) prop.properties.forEach((p) => {
603
+ mock[p.name] = _propToMock(p);
604
+ });
605
+ return mock;
606
+ default:
607
+ return null;
608
+ }
609
+ }
407
610
  async function runGenerator(options) {
408
611
  console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator (Sapphire Edition)..."));
409
612
  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.86",
3
+ "version": "12.0.88",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
6
  "exports": {