api-core-lib 12.0.63 → 12.0.65

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 +58 -146
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -74,77 +74,10 @@ var import_dotenv = __toESM(require("dotenv"), 1);
74
74
  var import_swagger_parser = __toESM(require("@apidevtools/swagger-parser"), 1);
75
75
  var import_openapi_types = __toESM(require_dist(), 1);
76
76
  var import_json_schema_to_typescript = require("json-schema-to-typescript");
77
- function preprocessSpec(spec) {
78
- if (!spec.components) spec.components = {};
79
- if (!spec.components.schemas) spec.components.schemas = {};
80
- const schemas = spec.components.schemas;
81
- for (const apiPath in spec.paths) {
82
- const pathItem = spec.paths[apiPath];
83
- if (!pathItem) continue;
84
- for (const method in pathItem) {
85
- if (!Object.values(import_openapi_types.OpenAPIV3.HttpMethods).includes(method)) continue;
86
- const endpoint = pathItem[method];
87
- const baseName = _generateBaseNameForSchema(method, apiPath, endpoint.operationId);
88
- const requestBody = endpoint.requestBody;
89
- if (requestBody?.content?.["application/json"]?.schema) {
90
- requestBody.content["application/json"].schema = _normalizeSchema(
91
- requestBody.content["application/json"].schema,
92
- schemas,
93
- baseName,
94
- "Request"
95
- );
96
- }
97
- if (endpoint.responses) {
98
- for (const statusCode in endpoint.responses) {
99
- const response = endpoint.responses[statusCode];
100
- const mediaTypeObject = response.content?.["application/json"];
101
- if (mediaTypeObject?.schema) {
102
- mediaTypeObject.schema = _normalizeSchema(
103
- mediaTypeObject.schema,
104
- // مرر المخطط الأصلي
105
- schemas,
106
- baseName,
107
- `Response${statusCode}`
108
- );
109
- }
110
- }
111
- }
112
- }
113
- }
114
- return spec;
115
- }
116
- function _normalizeSchema(schema, schemas, baseName, suffix) {
117
- if (!schema || "$ref" in schema) {
118
- return schema;
119
- }
120
- if (schema.type === "array" && schema.items) {
121
- schema.items = _normalizeSchema(schema.items, schemas, baseName, suffix.replace("[]", "Item"));
122
- return schema;
123
- }
124
- if (schema.type === "object" && schema.properties) {
125
- const typeName = `${_toPascalCase(baseName)}${_toPascalCase(suffix)}Dto`;
126
- if (!schemas[typeName]) {
127
- schemas[typeName] = schema;
128
- for (const propName in schema.properties) {
129
- schema.properties[propName] = _normalizeSchema(
130
- schema.properties[propName],
131
- schemas,
132
- baseName,
133
- `${_toPascalCase(propName)}Property`
134
- );
135
- }
136
- }
137
- return { $ref: `#/components/schemas/${typeName}` };
138
- }
139
- return schema;
140
- }
141
- function _generateBaseNameForSchema(method, path3, operationId) {
142
- if (operationId) return _toPascalCase(operationId.replace(/_v\d+$/, ""));
143
- const pathPart = path3.replace(/[\/{}]/g, " ").trim();
144
- return `${_toPascalCase(method)} ${_toPascalCase(pathPart)}`;
145
- }
146
77
  function parseSpecToModules(spec) {
147
78
  const modules = {};
79
+ if (!spec.components) spec.components = {};
80
+ if (!spec.components.schemas) spec.components.schemas = {};
148
81
  for (const apiPath in spec.paths) {
149
82
  const pathItem = spec.paths[apiPath];
150
83
  if (!pathItem) continue;
@@ -158,18 +91,7 @@ function parseSpecToModules(spec) {
158
91
  modules[moduleName] = { baseEndpoint: _findCommonBasePath(spec, tagName), actions: {}, types: /* @__PURE__ */ new Set() };
159
92
  }
160
93
  const currentModule = modules[moduleName];
161
- const successResponseKey = Object.keys(endpoint.responses).find((code) => code.startsWith("2"));
162
- const successResponse = successResponseKey ? endpoint.responses[successResponseKey] : void 0;
163
- const responseSchema = successResponse?.content?.["application/json"]?.schema;
164
- const outputType = successResponseKey === "204" ? "void" : _extractTypeNameFromSchema(responseSchema);
165
- const requestBody = endpoint.requestBody;
166
- const requestSchema = requestBody?.content?.["application/json"]?.schema;
167
- let inputType = "undefined";
168
- if (requestSchema) {
169
- inputType = _extractTypeNameFromSchema(requestSchema);
170
- } else if ((endpoint.parameters || []).some((p) => p.in === "query")) {
171
- inputType = "QueryOptions";
172
- }
94
+ const { inputType, outputType } = _extractInputOutputTypes(endpoint, spec.components.schemas);
173
95
  [inputType, outputType].forEach((t) => {
174
96
  if (t && !["unknown", "undefined", "void", "any", "QueryOptions", "Promise"].includes(t)) {
175
97
  currentModule.types.add(t.replace("[]", ""));
@@ -191,66 +113,66 @@ function parseSpecToModules(spec) {
191
113
  }
192
114
  return modules;
193
115
  }
194
- function _extractTypeNameFromSchema(schema) {
116
+ function _extractInputOutputTypes(endpoint, schemas) {
117
+ const operationId = endpoint.operationId || "UnnamedOperation";
118
+ const successResponseKey = Object.keys(endpoint.responses).find((code) => code.startsWith("2"));
119
+ const successResponse = successResponseKey ? endpoint.responses[successResponseKey] : void 0;
120
+ const responseSchema = successResponse?.content?.["application/json"]?.schema;
121
+ const outputType = successResponseKey === "204" ? "void" : _schemaToTypeName(responseSchema, `${operationId}Response`, schemas);
122
+ const requestBody = endpoint.requestBody;
123
+ const requestSchema = requestBody?.content?.["application/json"]?.schema;
124
+ let inputType = "undefined";
125
+ if (requestSchema) {
126
+ inputType = _schemaToTypeName(requestSchema, `${operationId}Request`, schemas);
127
+ } else if ((endpoint.parameters || []).some((p) => p.in === "query")) {
128
+ inputType = "QueryOptions";
129
+ }
130
+ return { inputType, outputType };
131
+ }
132
+ function _schemaToTypeName(schema, name, schemas) {
195
133
  if (!schema) return "unknown";
196
- if ("$ref" in schema && schema.$ref) return _refToTypeName(schema.$ref);
197
- if (!("$ref" in schema)) {
198
- if (schema.type === "array" && schema.items) {
199
- const itemType = _extractTypeNameFromSchema(schema.items);
200
- return itemType !== "unknown" ? `${itemType}[]` : "unknown[]";
201
- }
202
- if (schema.type && ["string", "number", "boolean", "integer"].includes(schema.type)) {
203
- return schema.type === "integer" ? "number" : schema.type;
134
+ if (schema.type === "array" && schema.items) {
135
+ const itemTypeName = _schemaToTypeName(schema.items, `${name}Item`, schemas);
136
+ return `${itemTypeName}[]`;
137
+ }
138
+ if (schema.type === "object" || schema.properties || schema.allOf) {
139
+ const typeName = _toPascalCase(name) + "Dto";
140
+ if (!schemas[typeName]) {
141
+ schemas[typeName] = schema;
204
142
  }
143
+ return typeName;
144
+ }
145
+ if (schema.type && ["string", "number", "boolean", "integer"].includes(schema.type)) {
146
+ return schema.type === "integer" ? "number" : schema.type;
205
147
  }
206
148
  return "unknown";
207
149
  }
208
- async function generateModuleFiles(moduleName, moduleData, spec, outputDir) {
150
+ async function generateModuleFiles(moduleName, moduleData, allSchemas, outputDir) {
209
151
  console.log(import_chalk.default.gray(` Generating files for module: ${import_chalk.default.bold(moduleName)}...`));
210
152
  const moduleFolderPath = import_path.default.join(outputDir, moduleName);
211
- if (!import_fs.default.existsSync(moduleFolderPath)) {
212
- import_fs.default.mkdirSync(moduleFolderPath, { recursive: true });
213
- }
214
- await _generateTypesFile(moduleFolderPath, moduleName, moduleData.types, spec);
153
+ if (!import_fs.default.existsSync(moduleFolderPath)) import_fs.default.mkdirSync(moduleFolderPath, { recursive: true });
154
+ await _generateTypesFile(moduleFolderPath, moduleName, moduleData.types, allSchemas);
215
155
  await _generateConfigFile(moduleFolderPath, moduleName, moduleData);
216
156
  }
217
- async function _generateTypesFile(moduleFolderPath, moduleName, typeNames, spec) {
157
+ async function _generateTypesFile(moduleFolderPath, moduleName, typeNames, allSchemas) {
218
158
  if (typeNames.size === 0) {
219
159
  console.log(import_chalk.default.yellow(` - No types found for module "${moduleName}". Skipping types.ts generation.`));
220
- const typesFilePath2 = import_path.default.join(moduleFolderPath, "types.ts");
221
- import_fs.default.writeFileSync(typesFilePath2, `// No types found for this module.
222
- `);
223
160
  return;
224
161
  }
225
162
  console.log(import_chalk.default.gray(` - Generating types.ts with ${typeNames.size} types...`));
226
163
  let typesContent = `// This file is auto-generated by the API generator. Do not edit.
227
164
 
228
165
  `;
229
- const allSchemas = spec.components?.schemas || {};
230
166
  const compilationOptions = {
231
167
  bannerComment: "",
232
168
  style: { bracketSpacing: true, printWidth: 120, semi: true, singleQuote: true, tabWidth: 2, trailingComma: "es5", useTabs: false },
233
- additionalProperties: false,
234
- declareExternallyReferenced: true
235
- };
236
- const schemaContainer = {
237
- components: {
238
- schemas: allSchemas
239
- }
169
+ additionalProperties: false
240
170
  };
241
171
  for (const typeName of Array.from(typeNames).sort()) {
242
- if (allSchemas[typeName]) {
172
+ const schema = allSchemas[typeName];
173
+ if (schema) {
243
174
  try {
244
- const tempSchemaToCompile = {
245
- $ref: `#/components/schemas/${typeName}`
246
- };
247
- const finalSchema = { ...schemaContainer, ...tempSchemaToCompile };
248
- const tsType = await (0, import_json_schema_to_typescript.compile)(
249
- finalSchema,
250
- typeName,
251
- // <-- هذا الاسم سيُستخدم الآن بنجاح!
252
- compilationOptions
253
- );
175
+ const tsType = await (0, import_json_schema_to_typescript.compile)(schema, typeName, compilationOptions);
254
176
  typesContent += tsType + "\n";
255
177
  } catch (compileError) {
256
178
  console.error(import_chalk.default.red(` - Error compiling type "${typeName}": ${compileError.message}`));
@@ -266,26 +188,24 @@ async function _generateConfigFile(moduleFolderPath, moduleName, moduleData) {
266
188
  const actionsCount = Object.keys(moduleData.actions).length;
267
189
  console.log(import_chalk.default.gray(` - Generating config.ts with ${actionsCount} actions...`));
268
190
  const typeNamesArray = [...moduleData.types].sort();
269
- const typesImportStatement = typeNamesArray.length > 0 ? `import type { ${typeNamesArray.join(", ")} } from './types';` : `// No types to import for this module`;
191
+ const typesImportStatement = typeNamesArray.length > 0 ? `import type { ${typeNamesArray.join(", ")} } from './types';` : ``;
270
192
  const actionsTypeParts = Object.entries(moduleData.actions).map(
271
- ([actionName, actionData]) => ` ${actionName}: ActionConfigModule<${actionData._inputType || "undefined"}, ${actionData._outputType || "unknown"}>;`
193
+ ([actionName, actionData]) => ` ${actionName}: ActionConfigModule<${actionData._inputType}, ${actionData._outputType}>;`
272
194
  );
273
195
  const actionsTypeDefinition = `{
274
196
  ${actionsTypeParts.join("\n")}
275
197
  }`;
276
- const actionsValueParts = Object.entries(moduleData.actions).map(
277
- ([actionName, actionData]) => {
278
- const { _inputType, _outputType, ...config } = actionData;
279
- return ` ${actionName}: ${JSON.stringify(config, null, 2).replace(/\n/g, "\n ")}`;
280
- }
281
- );
198
+ const actionsValueParts = Object.entries(moduleData.actions).map(([actionName, actionData]) => {
199
+ const { _inputType, _outputType, ...config } = actionData;
200
+ return ` ${actionName}: ${JSON.stringify(config, null, 2).replace(/\n/g, "\n ")}`;
201
+ });
282
202
  const actionsValueDefinition = `{
283
203
  ${actionsValueParts.join(",\n")}
284
204
  }`;
285
205
  const configContent = `/* eslint-disable */
286
- // This file is auto-generated by the API generator. Do not edit.
206
+ // This file is auto-generated...
287
207
 
288
- import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core-lib'; // \u0627\u0641\u062A\u0631\u0636 \u0623\u0646 \u0647\u0630\u0627 \u0627\u0644\u0645\u0633\u0627\u0631 \u0635\u062D\u064A\u062D
208
+ import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core-lib';
289
209
  ${typesImportStatement}
290
210
 
291
211
  export const ${moduleName}Module: ApiModuleConfig<${actionsTypeDefinition}> = {
@@ -297,11 +217,7 @@ export const ${moduleName}Module: ApiModuleConfig<${actionsTypeDefinition}> = {
297
217
  import_fs.default.writeFileSync(configFilePath, configContent.trim(), { encoding: "utf-8" });
298
218
  }
299
219
  function _toPascalCase(str) {
300
- return str.replace(/[^a-zA-Z0-9]/g, " ").replace(/(?:^\w|[A-Z]|\b\w)/g, (word) => word.toUpperCase()).replace(/\s+/g, "");
301
- }
302
- function _refToTypeName(ref) {
303
- if (!ref) return "unknown";
304
- return ref.split("/").pop() || "unknown";
220
+ return str.replace(/[^a-zA-Z0-9]/g, " ").replace(/(?:^\w|[A-Z]|\b\w)/g, (w) => w.toUpperCase()).replace(/\s+/g, "");
305
221
  }
306
222
  function _sanitizeTagName(tagName) {
307
223
  return tagName.replace(/[^a-zA-Z0-9]/g, "").replace(/Central|Tenant/g, "");
@@ -341,26 +257,22 @@ async function runGenerator(options) {
341
257
  console.log(import_chalk.default.blue("\u2713 Step 1: Environment variables loaded."));
342
258
  try {
343
259
  console.log(import_chalk.default.blue(`
344
- \u23F3 Step 2: Fetching and validating spec from ${specUrl}...`));
345
- const initialSpec = await import_swagger_parser.default.validate(specUrl, {
346
- dereference: { circular: "ignore" }
347
- });
348
- console.log(import_chalk.default.green("\u2713 Spec fetched and validated successfully."));
349
- console.log(import_chalk.default.blue("\n\u23F3 Step 3: Preprocessing spec to normalize inline schemas..."));
350
- const normalizedSpec = preprocessSpec(initialSpec);
351
- console.log(import_chalk.default.green("\u2713 Spec has been normalized successfully."));
352
- console.log(import_chalk.default.blue("\n\u23F3 Step 4: Parsing spec and generating API modules structure..."));
353
- const modules = parseSpecToModules(normalizedSpec);
260
+ \u23F3 Step 2: Fetching and fully dereferencing spec from ${specUrl}...`));
261
+ const dereferencedSpec = await import_swagger_parser.default.dereference(specUrl);
262
+ 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..."));
264
+ const modules = parseSpecToModules(dereferencedSpec);
354
265
  const modulesCount = Object.keys(modules).length;
355
266
  console.log(import_chalk.default.green(`\u2713 Found ${modulesCount} modules to generate.`));
356
267
  if (modulesCount === 0) {
357
268
  console.log(import_chalk.default.yellow("Warning: No modules were found in the spec."));
358
269
  }
359
- console.log(import_chalk.default.blue("\n\u23F3 Step 5: Generating module files..."));
270
+ console.log(import_chalk.default.blue("\n\u23F3 Step 4: Generating module files..."));
360
271
  const modulesOutputPath = import_path.default.join(options.output, "modules");
272
+ const allSchemas = dereferencedSpec.components?.schemas || {};
361
273
  for (const moduleName in modules) {
362
274
  const moduleData = modules[moduleName];
363
- await generateModuleFiles(moduleName, moduleData, normalizedSpec, modulesOutputPath);
275
+ await generateModuleFiles(moduleName, moduleData, allSchemas, modulesOutputPath);
364
276
  }
365
277
  console.log(import_chalk.default.green("\u2713 All module files generated."));
366
278
  console.log(import_chalk.default.bold.green("\n\u{1F389} API generation complete!"));
@@ -370,7 +282,7 @@ async function runGenerator(options) {
370
282
  }
371
283
  }
372
284
  function getSpecUrl() {
373
- const specUrl = process.env.OPENAPI_SPEC_URL || (process.env.API_URL ? `${process.env.API_URL}/docs-json` : null) || (process.env.NEXT_PUBLIC_API_URL ? `${process.env.NEXT_PUBLIC_API_URL}/docs-json` : null);
285
+ const specUrl = process.env.OPENAPI_SPEC_URL || "./swagger.json";
374
286
  if (!specUrl) {
375
287
  console.error(import_chalk.default.red.bold("\n\u274C Error: API specification URL not found."));
376
288
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "12.0.63",
3
+ "version": "12.0.65",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
6
  "exports": {