api-core-lib 12.0.65 → 12.0.66

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 +56 -63
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -76,32 +76,34 @@ var import_openapi_types = __toESM(require_dist(), 1);
76
76
  var import_json_schema_to_typescript = require("json-schema-to-typescript");
77
77
  function parseSpecToModules(spec) {
78
78
  const modules = {};
79
+ const modulePaths = {};
79
80
  if (!spec.components) spec.components = {};
80
81
  if (!spec.components.schemas) spec.components.schemas = {};
82
+ const allSchemas = spec.components.schemas;
81
83
  for (const apiPath in spec.paths) {
82
84
  const pathItem = spec.paths[apiPath];
83
85
  if (!pathItem) continue;
84
86
  for (const method in pathItem) {
85
87
  if (!Object.values(import_openapi_types.OpenAPIV3.HttpMethods).includes(method)) continue;
86
88
  const endpoint = pathItem[method];
87
- if (!endpoint.tags || endpoint.tags.length === 0) continue;
88
- const tagName = endpoint.tags[0];
89
- const moduleName = _sanitizeTagName(tagName) + "Api";
89
+ if (!endpoint.operationId) continue;
90
+ const moduleName = _getModuleNameFromOperationId(endpoint.operationId);
90
91
  if (!modules[moduleName]) {
91
- modules[moduleName] = { baseEndpoint: _findCommonBasePath(spec, tagName), actions: {}, types: /* @__PURE__ */ new Set() };
92
+ modules[moduleName] = { baseEndpoint: "", actions: {}, types: /* @__PURE__ */ new Set() };
93
+ modulePaths[moduleName] = [];
92
94
  }
93
- const currentModule = modules[moduleName];
94
- const { inputType, outputType } = _extractInputOutputTypes(endpoint, spec.components.schemas);
95
+ modulePaths[moduleName].push(apiPath);
96
+ const { inputType, outputType } = _extractInputOutputTypes(endpoint, allSchemas);
95
97
  [inputType, outputType].forEach((t) => {
96
98
  if (t && !["unknown", "undefined", "void", "any", "QueryOptions", "Promise"].includes(t)) {
97
- currentModule.types.add(t.replace("[]", ""));
99
+ modules[moduleName].types.add(t.replace("[]", ""));
98
100
  }
99
101
  });
100
- const actionName = _sanitizeActionName(endpoint.operationId, method, apiPath);
101
- const relativePath = apiPath.replace(currentModule.baseEndpoint, "").replace(/^\//, "");
102
- currentModule.actions[actionName] = {
102
+ const actionName = _sanitizeActionName(endpoint.operationId);
103
+ modules[moduleName].actions[actionName] = {
103
104
  method: method.toUpperCase(),
104
- path: relativePath === "" ? "/" : relativePath,
105
+ path: apiPath,
106
+ // سنقوم بتعديل هذا لاحقًا ليصبح نسبيًا
105
107
  description: endpoint.summary || "",
106
108
  hasQuery: (endpoint.parameters || []).some((p) => p.in === "query"),
107
109
  autoFetch: method.toUpperCase() === "GET" && !apiPath.includes("{"),
@@ -111,6 +113,15 @@ function parseSpecToModules(spec) {
111
113
  };
112
114
  }
113
115
  }
116
+ for (const moduleName in modules) {
117
+ const basePath = _findCommonBasePath(modulePaths[moduleName]);
118
+ modules[moduleName].baseEndpoint = basePath;
119
+ for (const actionName in modules[moduleName].actions) {
120
+ const action = modules[moduleName].actions[actionName];
121
+ const relativePath = action.path.replace(basePath, "").replace(/^\//, "");
122
+ action.path = relativePath === "" ? "/" : relativePath;
123
+ }
124
+ }
114
125
  return modules;
115
126
  }
116
127
  function _extractInputOutputTypes(endpoint, schemas) {
@@ -136,7 +147,7 @@ function _schemaToTypeName(schema, name, schemas) {
136
147
  return `${itemTypeName}[]`;
137
148
  }
138
149
  if (schema.type === "object" || schema.properties || schema.allOf) {
139
- const typeName = _toPascalCase(name) + "Dto";
150
+ const typeName = _toPascalCase(name);
140
151
  if (!schemas[typeName]) {
141
152
  schemas[typeName] = schema;
142
153
  }
@@ -145,6 +156,13 @@ function _schemaToTypeName(schema, name, schemas) {
145
156
  if (schema.type && ["string", "number", "boolean", "integer"].includes(schema.type)) {
146
157
  return schema.type === "integer" ? "number" : schema.type;
147
158
  }
159
+ if (Object.keys(schema).length === 0) {
160
+ const typeName = _toPascalCase(name);
161
+ if (!schemas[typeName]) {
162
+ schemas[typeName] = { type: "object", properties: {}, description: "Represents a dynamic or empty object." };
163
+ }
164
+ return typeName;
165
+ }
148
166
  return "unknown";
149
167
  }
150
168
  async function generateModuleFiles(moduleName, moduleData, allSchemas, outputDir) {
@@ -156,7 +174,7 @@ async function generateModuleFiles(moduleName, moduleData, allSchemas, outputDir
156
174
  }
157
175
  async function _generateTypesFile(moduleFolderPath, moduleName, typeNames, allSchemas) {
158
176
  if (typeNames.size === 0) {
159
- console.log(import_chalk.default.yellow(` - No types found for module "${moduleName}". Skipping types.ts generation.`));
177
+ console.log(import_chalk.default.yellow(` - No types for module "${moduleName}". Skipping types.ts.`));
160
178
  return;
161
179
  }
162
180
  console.log(import_chalk.default.gray(` - Generating types.ts with ${typeNames.size} types...`));
@@ -178,7 +196,7 @@ async function _generateTypesFile(moduleFolderPath, moduleName, typeNames, allSc
178
196
  console.error(import_chalk.default.red(` - Error compiling type "${typeName}": ${compileError.message}`));
179
197
  }
180
198
  } else {
181
- console.log(import_chalk.default.yellow(` - Warning: Schema for type "${typeName}" not found, skipping.`));
199
+ console.log(import_chalk.default.yellow(` - Warning: Schema for type "${typeName}" not found.`));
182
200
  }
183
201
  }
184
202
  const typesFilePath = import_path.default.join(moduleFolderPath, "types.ts");
@@ -219,54 +237,42 @@ export const ${moduleName}Module: ApiModuleConfig<${actionsTypeDefinition}> = {
219
237
  function _toPascalCase(str) {
220
238
  return str.replace(/[^a-zA-Z0-9]/g, " ").replace(/(?:^\w|[A-Z]|\b\w)/g, (w) => w.toUpperCase()).replace(/\s+/g, "");
221
239
  }
222
- function _sanitizeTagName(tagName) {
223
- return tagName.replace(/[^a-zA-Z0-9]/g, "").replace(/Central|Tenant/g, "");
240
+ function _getModuleNameFromOperationId(operationId) {
241
+ const controllerName = operationId.split("_")[0].replace(/Controller$/, "");
242
+ return `${controllerName}Api`;
224
243
  }
225
- function _sanitizeActionName(operationId, method, path3) {
226
- if (operationId) {
227
- const name = operationId.split("_").slice(1).join("_");
228
- const sanitized = name.charAt(0).toLowerCase() + name.slice(1).replace(/_v\d+$/, "");
229
- return sanitized || "action";
230
- }
231
- const pathPart = path3.replace(/[\/{}]/g, "_").replace(/^_|_$/g, "");
232
- return `${method.toLowerCase()}_${pathPart}`;
244
+ function _sanitizeActionName(operationId) {
245
+ const nameParts = operationId.split("_");
246
+ if (nameParts.length <= 1) return operationId;
247
+ const actionPart = nameParts[1];
248
+ return actionPart.charAt(0).toLowerCase() + actionPart.slice(1);
233
249
  }
234
- function _findCommonBasePath(spec, tagName) {
235
- const paths = Object.keys(spec.paths).filter((p) => {
236
- const pathItem = spec.paths[p];
237
- if (!pathItem) return false;
238
- for (const method in pathItem) {
239
- const endpoint = pathItem[method];
240
- if (endpoint.tags?.includes(tagName)) return true;
241
- }
242
- return false;
243
- });
244
- if (paths.length === 0) return "/";
245
- let commonPrefix = paths[0];
246
- for (let i = 1; i < paths.length; i++) {
247
- while (paths[i].indexOf(commonPrefix) !== 0) {
248
- commonPrefix = commonPrefix.substring(0, commonPrefix.length - 1);
249
- }
250
+ function _findCommonBasePath(paths) {
251
+ if (!paths || paths.length === 0) return "/";
252
+ const sortedPaths = [...paths].sort();
253
+ const first = sortedPaths[0];
254
+ const last = sortedPaths[sortedPaths.length - 1];
255
+ let i = 0;
256
+ while (i < first.length && first.charAt(i) === last.charAt(i)) {
257
+ i++;
250
258
  }
251
- return commonPrefix.substring(0, commonPrefix.lastIndexOf("/") + 1) || "/";
259
+ let prefix = first.substring(0, i);
260
+ return prefix.substring(0, prefix.lastIndexOf("/") + 1) || "/";
252
261
  }
253
262
  async function runGenerator(options) {
254
263
  console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Core Lib Code Generator..."));
255
264
  import_dotenv.default.config({ path: options.envPath });
256
- const specUrl = getSpecUrl();
265
+ const specUrl = process.env.OPENAPI_SPEC_URL || "./swagger.json";
257
266
  console.log(import_chalk.default.blue("\u2713 Step 1: Environment variables loaded."));
258
267
  try {
259
268
  console.log(import_chalk.default.blue(`
260
269
  \u23F3 Step 2: Fetching and fully dereferencing spec from ${specUrl}...`));
261
270
  const dereferencedSpec = await import_swagger_parser.default.dereference(specUrl);
262
271
  console.log(import_chalk.default.green("\u2713 Spec fetched and fully dereferenced successfully."));
263
- console.log(import_chalk.default.blue("\n\u23F3 Step 3: Parsing spec and generating API modules structure..."));
272
+ console.log(import_chalk.default.blue("\n\u23F3 Step 3: Parsing spec using intelligent grouping..."));
264
273
  const modules = parseSpecToModules(dereferencedSpec);
265
274
  const modulesCount = Object.keys(modules).length;
266
- console.log(import_chalk.default.green(`\u2713 Found ${modulesCount} modules to generate.`));
267
- if (modulesCount === 0) {
268
- console.log(import_chalk.default.yellow("Warning: No modules were found in the spec."));
269
- }
275
+ console.log(import_chalk.default.green(`\u2713 Found and grouped ${modulesCount} logical modules.`));
270
276
  console.log(import_chalk.default.blue("\n\u23F3 Step 4: Generating module files..."));
271
277
  const modulesOutputPath = import_path.default.join(options.output, "modules");
272
278
  const allSchemas = dereferencedSpec.components?.schemas || {};
@@ -278,24 +284,11 @@ async function runGenerator(options) {
278
284
  console.log(import_chalk.default.bold.green("\n\u{1F389} API generation complete!"));
279
285
  console.log(import_chalk.default.bold.cyan(` Output directory: ${options.output}`));
280
286
  } catch (error) {
281
- handleGenerationError(error);
282
- }
283
- }
284
- function getSpecUrl() {
285
- const specUrl = process.env.OPENAPI_SPEC_URL || "./swagger.json";
286
- if (!specUrl) {
287
- console.error(import_chalk.default.red.bold("\n\u274C Error: API specification URL not found."));
287
+ console.error(import_chalk.default.red.bold("\n\u274C An error occurred during generation:"));
288
+ console.error(import_chalk.default.red(`Error Message: ${error.message}`));
289
+ if (error.stack) console.error(import_chalk.default.gray(error.stack));
288
290
  process.exit(1);
289
291
  }
290
- return specUrl;
291
- }
292
- function handleGenerationError(error) {
293
- console.error(import_chalk.default.red.bold("\n\u274C An error occurred during generation:"));
294
- console.error(import_chalk.default.red(`Error Message: ${error.message}`));
295
- if (error.stack) {
296
- console.error(import_chalk.default.gray(error.stack));
297
- }
298
- process.exit(1);
299
292
  }
300
293
 
301
294
  // src/cli.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "12.0.65",
3
+ "version": "12.0.66",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
6
  "exports": {