api-core-lib 12.0.85 → 12.0.87

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 +218 -111
  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,140 +322,181 @@ 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 moduleBaseName = module2.moduleName.replace(/Api$/, "");
260
- const camelCaseModuleName = toCamelCase(moduleBaseName);
261
- const allPathParams = /* @__PURE__ */ new Set();
262
- Object.values(module2.actions).forEach((action) => {
263
- action.pathParams.forEach((param) => allPathParams.add(param));
264
- });
265
- const pathParamsType = allPathParams.size > 0 ? `{ ${[...allPathParams].map((p) => `${p}?: string | number`).join("; ")} }` : "never";
266
- let endpointsContent = `// This file is auto-generated. Do not edit directly.
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();
327
+ const enumsToImport = [...module2.enums].sort();
328
+ const createdFileExports = ["config"];
329
+ let configContent = `// This file is auto-generated. Do not edit directly.
267
330
 
331
+ import type { ApiModuleConfig, ActionConfigModule } from 'api-core-lib';
268
332
  `;
269
- endpointsContent += `import type { QueryOptions } from 'api-core-lib';
333
+ if (schemasToImport.length > 0) configContent += `import type { ${schemasToImport.join(", ")} } from './types';
270
334
  `;
271
- const endpointTypesToImport = /* @__PURE__ */ new Set();
272
- Object.values(module2.actions).forEach((action) => {
273
- if (action.inputType !== "undefined" && action.inputType !== "QueryOptions") {
274
- endpointTypesToImport.add(action.inputType);
275
- }
276
- });
277
- if (endpointTypesToImport.size > 0) {
278
- endpointsContent += `import type { ${[...endpointTypesToImport].join(", ")} } from './types';
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`));
352
+ if (schemasToImport.length > 0) {
353
+ if (enumsToImport.length > 0) {
354
+ let enumsContent = `// This file is auto-generated. Do not edit directly.
279
355
 
280
356
  `;
281
- }
282
- endpointsContent += `export const ${camelCaseModuleName}Endpoints = {
357
+ enumsToImport.forEach((enumName) => {
358
+ const enumDef = allEnums.get(enumName);
359
+ if (enumDef) {
360
+ enumsContent += `export const ${enumName} = ${JSON.stringify(enumDef.values)} as const;
283
361
  `;
284
- for (const action of Object.values(module2.actions)) {
285
- const params = [];
286
- if (action.pathParams.length > 0) {
287
- params.push(`params: { ${action.pathParams.map((p) => `${p}: string | number`).join("; ")} }`);
288
- }
289
- if (action.inputType !== "undefined" && action.inputType !== "QueryOptions") {
290
- params.push(`body: ${action.inputType}`);
291
- }
292
- if (action.hasQuery) {
293
- params.push(`query?: QueryOptions`);
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");
294
370
  }
295
- endpointsContent += ` /**
296
- * ${action.method} ${module2.baseEndpoint}${action.path}
297
- * ${action.description}
298
- */
371
+ let typesContent = `// This file is auto-generated. Do not edit directly.
372
+
299
373
  `;
300
- endpointsContent += ` ${action.name}: (${params.join(", ")}) => ({
374
+ if (enumsToImport.length > 0) typesContent += `import type { ${enumsToImport.join(", ")} } from './enums';
375
+
301
376
  `;
302
- endpointsContent += ` action: '${action.name}' as const,
377
+ schemasToImport.forEach((typeName) => {
378
+ const parsedSchema = allSchemas.get(typeName);
379
+ if (parsedSchema) {
380
+ if (parsedSchema.description) typesContent += `/** ${parsedSchema.description} */
303
381
  `;
304
- if (action.pathParams.length > 0) endpointsContent += ` pathParams: params,
382
+ typesContent += `export interface ${typeName} {
305
383
  `;
306
- if (action.inputType !== "undefined" && action.inputType !== "QueryOptions") endpointsContent += ` input: body,
384
+ parsedSchema.properties.forEach((prop) => {
385
+ if (prop.description) typesContent += ` /** ${prop.description} */
307
386
  `;
308
- if (action.hasQuery) endpointsContent += ` input: query,
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};
309
391
  `;
310
- endpointsContent += ` }),
392
+ });
393
+ typesContent += `}
311
394
 
312
395
  `;
313
- }
314
- endpointsContent += `};
315
- `;
316
- import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `${camelCaseModuleName}.endpoints.ts`), endpointsContent);
317
- console.log(import_chalk.default.gray(` \u2713 ${camelCaseModuleName}.endpoints.ts (Type-Safe Endpoints)`));
318
- const hookContent = `// This file is auto-generated. Do not edit directly.
319
-
320
- import { useApiModule, UseApiModuleOptions } from 'api-core-lib/client';
321
- import { apiClient } from '@/lib/api-core/clientApi'; // Assuming a fixed path
322
- import { ${module2.moduleName} as TModuleType } from './config';
323
- import { ${module2.moduleName} } from './config';
324
-
325
- type ModulePathParams = ${pathParamsType};
326
-
327
- // Options for the custom hook, extending the base options with typed path parameters.
328
- type ${moduleBaseName}ApiOptions = Omit<UseApiModuleOptions, 'pathParams'> & {
329
- pathParams?: ModulePathParams;
330
- };
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.
331
402
 
332
- /**
333
- * Custom hook for interacting with the ${moduleBaseName} API module.
334
- * Simplifies API calls by pre-configuring the API client and module.
335
- */
336
- export const use${moduleBaseName}Api = (options: ${moduleBaseName}ApiOptions = {}) => {
337
- return useApiModule<typeof TModuleType['actions']>(apiClient, ${module2.moduleName}, options);
338
- };
403
+ import { z } from 'zod';
339
404
  `;
340
- import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `use${moduleBaseName}.ts`), hookContent);
341
- console.log(import_chalk.default.gray(` \u2713 use${moduleBaseName}.ts (Custom Hook)`));
342
- const providerContent = `// This file is auto-generated. Do not edit directly.
343
- 'use client';
344
-
345
- import React from 'react';
346
- import { ApiModuleProvider } from 'api-core-lib/client';
347
- import { use${moduleBaseName}Api } from './use${moduleBaseName}';
348
-
349
- type Options = Parameters<typeof use${moduleBaseName}Api>[0];
350
-
351
- interface ${moduleBaseName}ProviderProps {
352
- children: React.ReactNode;
353
- options?: Options;
354
- }
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
+ });
355
417
 
356
- /**
357
- * A dedicated React Provider that initializes and provides the ${moduleBaseName} API context.
358
- */
359
- export function ${moduleBaseName}Provider({ children, options = {} }: ${moduleBaseName}ProviderProps) {
360
- const api = use${moduleBaseName}Api(options);
361
- return <ApiModuleProvider value={api}>{children}</ApiModuleProvider>;
362
- }
363
418
  `;
364
- import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `${moduleBaseName}.provider.tsx`), providerContent);
365
- console.log(import_chalk.default.gray(` \u2713 ${moduleBaseName}.provider.tsx (React Provider)`));
366
- const serverContent = `// This file is auto-generated. For server-side use only.
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';
367
430
 
368
- import { createServerApi } from 'api-core-lib/server';
369
- import { serverApiClient } from '@/lib/api-core/serverApi'; // Assuming a fixed path
370
- import { ${module2.moduleName} } from './config';
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)};
371
440
 
372
- /**
373
- * Creates a server-side instance of the ${moduleBaseName} API for pre-fetching data in RSC.
374
- */
375
- export const create${moduleBaseName}ServerApi = () => {
376
- return createServerApi(serverApiClient, ${module2.moduleName});
377
- };
378
441
  `;
379
- import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `${camelCaseModuleName}.server.ts`), serverContent);
380
- console.log(import_chalk.default.gray(` \u2713 ${camelCaseModuleName}.server.ts (Server-Side Helper)`));
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");
447
+ }
381
448
  const indexFilePath = import_path.default.join(moduleOutputPath, "index.ts");
382
- let indexFileContent = import_fs.default.readFileSync(indexFilePath, "utf-8");
383
- indexFileContent += `
384
- export * from './${camelCaseModuleName}.endpoints';`;
385
- indexFileContent += `
386
- export * from './use${moduleBaseName}';`;
387
- indexFileContent += `
388
- export * from './${moduleBaseName}.provider';`;
389
- indexFileContent += `
390
- export * from './${camelCaseModuleName}.server';`;
391
- import_fs.default.writeFileSync(indexFilePath, indexFileContent);
392
- console.log(import_chalk.default.gray(` \u2713 index.ts (Updated with new exports)`));
449
+ const initialIndexContent = `// This file is auto-generated. Do not edit directly.
450
+
451
+ ` + createdFileExports.map((e) => `export * from './${e}';`).join("\n");
452
+ import_fs.default.writeFileSync(indexFilePath, initialIndexContent);
453
+ console.log(import_chalk.default.gray(` \u2713 index.ts (Initial)`));
454
+ const moduleBaseName = module2.moduleName.replace(/Api$/, "");
455
+ const camelCaseModuleName = toCamelCase(moduleBaseName);
456
+ const allPathParams = /* @__PURE__ */ new Set();
457
+ Object.values(module2.actions).forEach((action) => action.pathParams.forEach((param) => allPathParams.add(param)));
458
+ const pathParamsType = allPathParams.size > 0 ? `{ ${[...allPathParams].map((p) => `${p}?: string | number`).join("; ")} }` : "Record<string, never>";
459
+ console.log(import_chalk.default.gray(` \u2713 ${camelCaseModuleName}.endpoints.ts (Type-Safe Endpoints)`));
460
+ console.log(import_chalk.default.gray(` \u2713 use${moduleBaseName}.ts (Custom Hook)`));
461
+ const providerFileName = `${moduleBaseName}.provider.tsx`;
462
+ console.log(import_chalk.default.gray(` \u2713 ${providerFileName} (React Provider)`));
463
+ console.log(import_chalk.default.gray(` \u2713 ${camelCaseModuleName}.server.ts (Server-Side Helper)`));
464
+ const newExports = [
465
+ `
466
+ // Generated API helpers`,
467
+ `export * from './${camelCaseModuleName}.endpoints';`,
468
+ `export * from './use${moduleBaseName}';`,
469
+ `export * from './${moduleBaseName}.provider';`,
470
+ `export * from './${camelCaseModuleName}.server';`
471
+ ].join("\n");
472
+ import_fs.default.appendFileSync(indexFilePath, newExports);
473
+ console.log(import_chalk.default.gray(` \u2713 index.ts (Updated with helpers)`));
474
+ }
475
+ function _propToMock(prop) {
476
+ if (prop.example) return prop.example;
477
+ if (prop.name.match(/image|avatar|logo|url/i)) return "https://via.placeholder.com/150";
478
+ if (prop.enum) return prop.enum[0];
479
+ switch (prop.type) {
480
+ case "string":
481
+ if (prop.format === "email") return "test@example.com";
482
+ if (prop.format === "uuid") return "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11";
483
+ return `Mock ${toPascalCase(prop.name)}`;
484
+ case "integer":
485
+ case "number":
486
+ return 1;
487
+ case "boolean":
488
+ return true;
489
+ case "array":
490
+ return prop.items ? [_propToMock(prop.items)] : [];
491
+ case "object":
492
+ const mock = {};
493
+ if (prop.properties) prop.properties.forEach((p) => {
494
+ mock[p.name] = _propToMock(p);
495
+ });
496
+ return mock;
497
+ default:
498
+ return null;
499
+ }
393
500
  }
394
501
  async function runGenerator(options) {
395
502
  console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator (Sapphire Edition)..."));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "12.0.85",
3
+ "version": "12.0.87",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
6
  "exports": {