api-core-lib 12.0.68 → 12.0.69

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 +70 -52
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -76,7 +76,7 @@ var import_swagger_parser = __toESM(require("@apidevtools/swagger-parser"), 1);
76
76
  var import_openapi_types = __toESM(require_dist(), 1);
77
77
  var DEBUG_MODE = process.env.DEBUG === "true";
78
78
  var debugLog = (title, data) => DEBUG_MODE && console.log(import_chalk.default.yellow(`
79
- [DEBUG: ${title}]`), import_util.default.inspect(data, { depth: 4, colors: true }));
79
+ [DEBUG: ${title}]`), import_util.default.inspect(data, { depth, colors: true }));
80
80
  var toPascalCase = (str) => str.replace(/[^a-zA-Z0-9_]/g, " ").replace(/(?:^\w|[A-Z]|\b\w)/g, (w) => w.toUpperCase()).replace(/\s+/g, "");
81
81
  var toCamelCase = (str) => {
82
82
  const s = toPascalCase(str);
@@ -96,23 +96,18 @@ var findCommonPath = (paths) => {
96
96
  };
97
97
  var generateFriendlyMessage = (fieldName, validation) => {
98
98
  const friendlyName = fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase());
99
- switch (validation) {
100
- case "required":
101
- return `${friendlyName} is required.`;
102
- case "email":
103
- return `Please enter a valid email for ${friendlyName}.`;
104
- default:
105
- return `Invalid value for ${friendlyName}.`;
106
- }
99
+ return `${friendlyName} is required.`;
107
100
  };
108
- function parseSchema(name, schema) {
101
+ function parseSchema(name, schema, allEnums) {
109
102
  const properties = [];
103
+ const enums = {};
110
104
  if (schema.properties) {
111
105
  for (const propName in schema.properties) {
112
106
  const propSchema = schema.properties[propName];
113
- let items = void 0;
114
- if (propSchema.type === "array" && propSchema.items) {
115
- items = parseSchema("item", propSchema.items).properties[0];
107
+ if (propSchema.enum) {
108
+ const enumName = `${toPascalCase(name)}${toPascalCase(propName)}Enum`;
109
+ enums[propName] = propSchema.enum;
110
+ if (!allEnums.has(enumName)) allEnums.set(enumName, { name: enumName, values: propSchema.enum });
116
111
  }
117
112
  properties.push({
118
113
  name: propName,
@@ -123,24 +118,24 @@ function parseSchema(name, schema) {
123
118
  example: propSchema.example,
124
119
  enum: propSchema.enum,
125
120
  format: propSchema.format,
126
- items,
127
- // نستخدم المتغير الذي تم حسابه بأمان
128
- properties: propSchema.properties ? parseSchema("sub-object", propSchema).properties : void 0
121
+ items: propSchema.type === "array" && propSchema.items ? parseSchema(`${name}${toPascalCase(propName)}Item`, propSchema.items, allEnums).properties[0] : void 0,
122
+ properties: propSchema.properties ? parseSchema(`${name}${toPascalCase(propName)}`, propSchema, allEnums).properties : void 0
129
123
  });
130
124
  }
131
125
  }
132
- return { name, description: schema.description, properties };
126
+ return { name, description: schema.description, properties, enums };
133
127
  }
134
128
  function parseSpecToModules(spec) {
135
129
  const modules = /* @__PURE__ */ new Map();
136
130
  const allSchemas = /* @__PURE__ */ new Map();
131
+ const allEnums = /* @__PURE__ */ new Map();
137
132
  const modulePaths = /* @__PURE__ */ new Map();
138
133
  const registerSchema = (schema, baseName) => {
139
134
  if (!schema) return "unknown";
140
135
  if (schema.type === "array" && schema.items) return `${registerSchema(schema.items, `${baseName}Item`)}[]`;
141
136
  if (schema.type === "object" || schema.properties || schema.allOf || !schema.type) {
142
137
  const typeName = toPascalCase(baseName.replace(/_v\d+(Request|Response)$/, "$1"));
143
- if (!allSchemas.has(typeName)) allSchemas.set(typeName, parseSchema(typeName, schema));
138
+ if (!allSchemas.has(typeName)) allSchemas.set(typeName, parseSchema(typeName, schema, allEnums));
144
139
  return typeName;
145
140
  }
146
141
  return schema.type === "integer" ? "number" : schema.type || "unknown";
@@ -154,7 +149,7 @@ function parseSpecToModules(spec) {
154
149
  if (!endpoint.operationId) continue;
155
150
  const moduleName = getModuleName(endpoint.operationId);
156
151
  if (!modules.has(moduleName)) {
157
- modules.set(moduleName, { moduleName, baseEndpoint: "", actions: {}, schemas: /* @__PURE__ */ new Set() });
152
+ modules.set(moduleName, { moduleName, baseEndpoint: "", actions: {}, schemas: /* @__PURE__ */ new Set(), enums: /* @__PURE__ */ new Set() });
158
153
  modulePaths.set(moduleName, []);
159
154
  }
160
155
  const currentModule = modules.get(moduleName);
@@ -170,35 +165,33 @@ function parseSpecToModules(spec) {
170
165
  const cleanType = t.replace("[]", "");
171
166
  if (cleanType && !["unknown", "undefined", "void", "any", "QueryOptions", "Promise"].includes(cleanType)) {
172
167
  currentModule.schemas.add(cleanType);
168
+ const schemaDef = allSchemas.get(cleanType);
169
+ if (schemaDef) Object.keys(schemaDef.enums).forEach((propName) => currentModule.enums.add(`${toPascalCase(cleanType)}${toPascalCase(propName)}Enum`));
173
170
  }
174
171
  });
175
- const actionName = getActionName(endpoint.operationId);
176
- currentModule.actions[actionName] = { name: actionName, method: method.toUpperCase(), path: apiPath, description: endpoint.summary || "", hasQuery: (endpoint.parameters || []).some((p) => p.in === "query"), autoFetch: method.toUpperCase() === "GET" && !apiPath.includes("{"), requiresAuth: !!endpoint.security && endpoint.security.length > 0, inputType, outputType };
172
+ currentModule.actions[getActionName(endpoint.operationId)] = { name: getActionName(endpoint.operationId), method: method.toUpperCase(), path: apiPath, description: endpoint.summary || "", hasQuery: (endpoint.parameters || []).some((p) => p.in === "query"), autoFetch: method.toUpperCase() === "GET" && !apiPath.includes("{"), requiresAuth: !!endpoint.security && endpoint.security.length > 0, inputType, outputType };
177
173
  }
178
174
  }
179
175
  modules.forEach((mod, name) => {
180
- const basePath = findCommonPath(modulePaths.get(name));
181
- mod.baseEndpoint = basePath;
182
- Object.values(mod.actions).forEach((action) => {
183
- const relativePath = action.path.replace(basePath, "").replace(/^\//, "");
184
- action.path = relativePath === "" ? "/" : relativePath;
185
- });
176
+ mod.baseEndpoint = findCommonPath(modulePaths.get(name));
177
+ Object.values(mod.actions).forEach((action) => action.path = action.path.replace(mod.baseEndpoint, "").replace(/^\//, "") || "/");
186
178
  });
187
179
  debugLog("Final Parsed Modules", Object.fromEntries(modules));
188
- return { modules, allSchemas };
180
+ return { modules, allSchemas, allEnums };
189
181
  }
190
- async function generateModuleFiles(module2, allSchemas, outputDir) {
182
+ async function generateModuleFiles(module2, allSchemas, allEnums, outputDir) {
191
183
  const moduleOutputPath = import_path.default.join(outputDir, module2.moduleName);
192
184
  if (!import_fs.default.existsSync(moduleOutputPath)) import_fs.default.mkdirSync(moduleOutputPath, { recursive: true });
193
185
  console.log(import_chalk.default.cyan(`
194
186
  Generating module: ${import_chalk.default.bold(module2.moduleName)}`));
195
- const typesToImport = [...module2.schemas].sort();
187
+ const schemasToImport = [...module2.schemas].sort();
188
+ const enumsToImport = [...module2.enums].sort();
196
189
  let configContent = `/* eslint-disable */
197
190
  // This file is auto-generated.
198
191
 
199
192
  import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core-lib';
200
193
  `;
201
- if (typesToImport.length > 0) configContent += `import type { ${typesToImport.join(", ")} } from './types';
194
+ if (schemasToImport.length > 0) configContent += `import type { ${schemasToImport.join(", ")} } from './types';
202
195
  `;
203
196
  const actionsType = Object.values(module2.actions).map((a) => ` ${a.name}: ActionConfigModule<${a.inputType}, ${a.outputType}>;`).join("\n");
204
197
  const actionsValue = Object.values(module2.actions).map((a) => {
@@ -220,11 +213,32 @@ ${actionsValue}
220
213
  const indexContent = [`// This file is auto-generated.
221
214
 
222
215
  export * from './config';`];
223
- if (typesToImport.length > 0) {
216
+ if (schemasToImport.length > 0) {
217
+ if (enumsToImport.length > 0) {
218
+ let enumsContent = `// This file is auto-generated.
219
+
220
+ `;
221
+ for (const enumName of enumsToImport) {
222
+ const enumDef = allEnums.get(enumName);
223
+ if (enumDef) {
224
+ enumsContent += `export const ${enumName} = ${JSON.stringify(enumDef.values)} as const;
225
+ `;
226
+ enumsContent += `export type ${enumName} = typeof ${enumName}[number];
227
+
228
+ `;
229
+ }
230
+ }
231
+ import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "enums.ts"), enumsContent);
232
+ console.log(import_chalk.default.gray(` \u2713 enums.ts`));
233
+ indexContent.push(`export * from './enums';`);
234
+ }
224
235
  let typesContent = `// This file is auto-generated.
225
236
 
226
237
  `;
227
- for (const typeName of typesToImport) {
238
+ if (enumsToImport.length > 0) typesContent += `import type { ${enumsToImport.join(", ")} } from './enums';
239
+
240
+ `;
241
+ for (const typeName of schemasToImport) {
228
242
  const parsedSchema = allSchemas.get(typeName);
229
243
  if (parsedSchema) {
230
244
  if (parsedSchema.description) typesContent += `/**
@@ -240,8 +254,9 @@ ${prop.example ? ` * @example ${JSON.stringify(prop.example)}
240
254
  ` : ""} */
241
255
  `;
242
256
  let propType = prop.type;
243
- if (prop.enum) propType = prop.enum.map((e) => typeof e === "string" ? `'${e}'` : e).join(" | ");
244
- else if (prop.items) propType = `${toPascalCase(prop.items.name)}[]`;
257
+ if (prop.enum) propType = `${toPascalCase(typeName)}${toPascalCase(prop.name)}Enum`;
258
+ else if (prop.items) propType = prop.items.properties ? `${toPascalCase(`${typeName}${toPascalCase(prop.name)}Item`)}[]` : `${prop.items.type}[]`;
259
+ else if (prop.properties) propType = `Record<string, unknown>`;
245
260
  typesContent += ` ${prop.name}${prop.isRequired ? "" : "?"}: ${propType};
246
261
  `;
247
262
  }
@@ -255,12 +270,14 @@ ${prop.example ? ` * @example ${JSON.stringify(prop.example)}
255
270
  indexContent.push(`export * from './types';`);
256
271
  let validationContent = `// This file is auto-generated.
257
272
  import { z } from 'zod';
273
+ `;
274
+ if (enumsToImport.length > 0) validationContent += `import { ${enumsToImport.join(", ")} } from './enums';
258
275
 
259
276
  `;
260
- for (const typeName of typesToImport) {
277
+ for (const typeName of schemasToImport) {
261
278
  const parsedSchema = allSchemas.get(typeName);
262
279
  if (parsedSchema) {
263
- let zodShape = parsedSchema.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
280
+ let zodShape = parsedSchema.properties.map((p) => ` ${p.name}: ${_propToZod(p, typeName)}`).join(",\n");
264
281
  validationContent += `export const ${typeName}Schema = z.object({
265
282
  ${zodShape}
266
283
  });
@@ -272,10 +289,12 @@ ${zodShape}
272
289
  console.log(import_chalk.default.gray(` \u2713 validation.ts`));
273
290
  indexContent.push(`export * from './validation';`);
274
291
  let mocksContent = `// This file is auto-generated.
275
- import type { ${typesToImport.join(", ")} } from './types';
292
+ import type { ${schemasToImport.join(", ")} } from './types';
293
+ `;
294
+ if (enumsToImport.length > 0) mocksContent += `import { ${enumsToImport.map((e) => e.replace(/Enum$/, "")).join(", ")} } from './enums';
276
295
 
277
296
  `;
278
- for (const typeName of typesToImport) {
297
+ for (const typeName of schemasToImport) {
279
298
  const parsedSchema = allSchemas.get(typeName);
280
299
  if (parsedSchema) {
281
300
  let mockObject = {};
@@ -294,30 +313,30 @@ import type { ${typesToImport.join(", ")} } from './types';
294
313
  import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "index.ts"), indexContent.join("\n"));
295
314
  console.log(import_chalk.default.gray(` \u2713 index.ts`));
296
315
  }
297
- function _propToZod(prop) {
316
+ function _propToZod(prop, parentName) {
298
317
  let zodString = "z.any()";
299
- const requiredMsg = { required_error: prop.description || generateFriendlyMessage(prop.name, "required") };
318
+ const errorMapParams = { errorMap: () => ({ message: prop.description || generateFriendlyMessage(prop.name, "required") }) };
300
319
  switch (prop.type) {
301
320
  case "string":
302
- zodString = `z.string(${JSON.stringify(requiredMsg)})`;
321
+ zodString = `z.string(${JSON.stringify(errorMapParams)})`;
303
322
  if (prop.format === "email") zodString += `.email({ message: "${generateFriendlyMessage(prop.name, "email")}" })`;
304
323
  if (prop.format === "uuid") zodString += `.uuid()`;
305
- if (prop.enum) zodString = `z.enum(${JSON.stringify(prop.enum)}, ${JSON.stringify(requiredMsg)})`;
324
+ if (prop.enum) zodString = `z.enum(${toPascalCase(parentName)}${toPascalCase(prop.name)}Enum)`;
306
325
  break;
307
326
  case "integer":
308
327
  case "number":
309
- zodString = `z.number(${JSON.stringify(requiredMsg)})`;
328
+ zodString = `z.number(${JSON.stringify(errorMapParams)})`;
310
329
  break;
311
330
  case "boolean":
312
- zodString = `z.boolean(${JSON.stringify(requiredMsg)})`;
331
+ zodString = `z.boolean(${JSON.stringify(errorMapParams)})`;
313
332
  break;
314
333
  case "array":
315
- zodString = `z.array(${prop.items ? _propToZod(prop.items) : "z.any()"})`;
334
+ zodString = `z.array(${prop.items ? _propToZod(prop.items, `${parentName}${toPascalCase(prop.name)}Item`) : "z.any()"})`;
316
335
  break;
317
336
  case "object":
318
- let shape = "z.any()";
337
+ let shape = "z.record(z.unknown())";
319
338
  if (prop.properties) shape = `z.object({
320
- ${prop.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n")}
339
+ ${prop.properties.map((p) => ` ${p.name}: ${_propToZod(p, `${parentName}${toPascalCase(prop.name)}`)}`).join(",\n")}
321
340
  })`;
322
341
  zodString = shape;
323
342
  break;
@@ -353,7 +372,7 @@ function _propToMock(prop) {
353
372
  }
354
373
  }
355
374
  async function runGenerator(options) {
356
- console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator (Phoenix Edition)..."));
375
+ console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator (Diamond Edition)..."));
357
376
  import_dotenv.default.config({ path: options.envPath });
358
377
  const specUrl = process.env.OPENAPI_SPEC_URL || "./swagger.json";
359
378
  try {
@@ -361,13 +380,12 @@ async function runGenerator(options) {
361
380
  \u23F3 Step 1: Dereferencing spec from ${specUrl}...`));
362
381
  const spec = await import_swagger_parser.default.dereference(specUrl);
363
382
  console.log(import_chalk.default.green("\u2713 Spec fully dereferenced."));
364
- debugLog("Dereferenced Spec", spec);
365
383
  console.log(import_chalk.default.blue("\n\u23F3 Step 2: Parsing spec with intelligent grouping..."));
366
- const { modules, allSchemas } = parseSpecToModules(spec);
384
+ const { modules, allSchemas, allEnums } = parseSpecToModules(spec);
367
385
  console.log(import_chalk.default.green(`\u2713 Found and grouped ${modules.size} logical modules.`));
368
386
  console.log(import_chalk.default.blue("\n\u23F3 Step 3: Generating all module files..."));
369
387
  for (const module2 of modules.values()) {
370
- await generateModuleFiles(module2, allSchemas, options.output);
388
+ await generateModuleFiles(module2, allSchemas, allEnums, options.output);
371
389
  }
372
390
  console.log(import_chalk.default.green("\n\u2713 All module files generated successfully."));
373
391
  console.log(import_chalk.default.bold.green("\n\u{1F389} API generation complete! Your development platform is ready."));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "12.0.68",
3
+ "version": "12.0.69",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
6
  "exports": {