api-core-lib 12.0.35 → 12.0.37

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 +101 -38
  2. package/package.json +16 -19
package/dist/cli.cjs CHANGED
@@ -33,9 +33,14 @@ var import_path = __toESM(require("path"), 1);
33
33
  var import_axios = __toESM(require("axios"), 1);
34
34
  var import_chalk = __toESM(require("chalk"), 1);
35
35
  var import_dotenv = __toESM(require("dotenv"), 1);
36
- var import_openapi_typescript = __toESM(require("openapi-typescript"), 1);
36
+ var import_child_process = require("child_process");
37
37
 
38
38
  // src/generator/module-parser.ts
39
+ function refToTypeName(ref) {
40
+ if (!ref) return "unknown";
41
+ const parts = ref.replace(/^#\/components\//, "").split("/");
42
+ return `components["${parts.join('"]["')}"]`;
43
+ }
39
44
  function parseSpecToModules(spec) {
40
45
  const modules = {};
41
46
  for (const apiPath in spec.paths) {
@@ -45,22 +50,23 @@ function parseSpecToModules(spec) {
45
50
  const tagName = endpoint.tags[0];
46
51
  const moduleName = tagName.replace(/[^a-zA-Z0-9]/g, "").replace(/Central|Tenant/g, "") + "Api";
47
52
  if (!modules[moduleName]) {
48
- modules[moduleName] = {
49
- baseEndpoint: "",
50
- // سيتم ملء المسار الكامل في path
51
- actions: {}
52
- };
53
+ modules[moduleName] = { actions: {} };
53
54
  }
54
- const actionName = endpoint.operationId || method + apiPath.replace(/[\/{}]+/g, "_");
55
+ const requestBodyRef = endpoint.requestBody?.content["application/json"]?.schema?.$ref;
56
+ const successResponse = endpoint.responses["200"] || endpoint.responses["201"];
57
+ const responseRef = successResponse?.content?.["application/json"]?.schema?.$ref;
58
+ const actionName = endpoint.operationId || `${method}${apiPath.replace(/[\/{}]+/g, "_")}`;
55
59
  modules[moduleName].actions[actionName] = {
56
60
  method: method.toUpperCase(),
57
61
  path: apiPath,
58
62
  description: endpoint.summary || "No description available.",
59
63
  hasQuery: (endpoint.parameters || []).some((p) => p.in === "query"),
60
64
  autoFetch: method.toUpperCase() === "GET" && !apiPath.includes("{"),
61
- // افتراض ذكي
62
- invalidates: []
63
- // يمكن تركه فارغًا
65
+ invalidates: [],
66
+ // [ميزة جديدة] إضافة الأنواع المستخرجة إلى الكائن
67
+ // سنستخدمها لاحقًا لتوليد الكود الصحيح
68
+ _inputType: refToTypeName(requestBodyRef),
69
+ _outputType: refToTypeName(responseRef)
64
70
  };
65
71
  }
66
72
  }
@@ -69,53 +75,110 @@ function parseSpecToModules(spec) {
69
75
 
70
76
  // src/generator/index.ts
71
77
  async function runGenerator(options) {
72
- console.log(import_chalk.default.cyan(`Starting API module generation...`));
78
+ console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Core Lib Code Generator..."));
73
79
  console.log(import_chalk.default.gray(`Output directory: ${options.output}`));
74
80
  console.log(import_chalk.default.gray(`.env path: ${options.envPath}`));
81
+ console.log("\n" + import_chalk.default.blue("Step 1: Loading environment variables..."));
75
82
  import_dotenv.default.config({ path: options.envPath });
76
- const apiUrl = process.env.API_URL_CONFIG;
77
- if (!apiUrl) {
78
- console.error(import_chalk.default.red("Error: API_URL or NEXT_PUBLIC_API_URL not found in .env file."));
83
+ 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);
84
+ if (!specUrl) {
85
+ console.error(import_chalk.default.red.bold("\n\u274C Error: API specification URL not found."));
86
+ console.error(import_chalk.default.red("Please define either OPENAPI_SPEC_URL (recommended) or API_URL/NEXT_PUBLIC_API_URL in your .env file."));
79
87
  process.exit(1);
80
88
  }
89
+ console.log(import_chalk.default.green("\u2713 Environment variables loaded."));
90
+ const tempSpecPath = import_path.default.join(process.cwd(), `swagger-${Date.now()}.json`);
81
91
  try {
82
- const specUrl = `${apiUrl}`;
83
- console.log(`Fetching OpenAPI spec from ${specUrl}...`);
84
- const response = await import_axios.default.get(specUrl);
92
+ console.log("\n" + import_chalk.default.blue(`Step 2: Fetching OpenAPI spec from ${specUrl}...`));
93
+ const response = await import_axios.default.get(specUrl, { timeout: 15e3 });
85
94
  const spec = response.data;
86
- if (!import_fs.default.existsSync(options.output)) {
87
- import_fs.default.mkdirSync(options.output, { recursive: true });
95
+ if (!spec.openapi || !spec.paths) {
96
+ throw new Error('Invalid OpenAPI specification file. "openapi" or "paths" property is missing.');
88
97
  }
89
- console.log("Generating TypeScript types...");
90
- const typesContent = await (0, import_openapi_typescript.default)(spec);
91
- const typesPath = import_path.default.join(options.output, "api-types.generated.ts");
92
- import_fs.default.writeFileSync(typesPath, typesContent);
93
- console.log(import_chalk.default.green(`\u2713 Types generated successfully at ${typesPath}`));
94
- console.log("Generating API modules...");
98
+ import_fs.default.writeFileSync(tempSpecPath, JSON.stringify(spec, null, 2));
99
+ console.log(import_chalk.default.green(`\u2713 OpenAPI spec saved temporarily to ${tempSpecPath}`));
100
+ console.log("\n" + import_chalk.default.blue("Step 3: Generating organized TypeScript types..."));
101
+ const typesOutputPath = import_path.default.join(options.output, "types");
102
+ const generatorCommand = [
103
+ "npx",
104
+ "@openapitools/openapi-generator-cli",
105
+ "generate",
106
+ "-i",
107
+ `"${tempSpecPath}"`,
108
+ "-g",
109
+ "typescript-axios",
110
+ "-o",
111
+ `"${typesOutputPath}"`,
112
+ "--additional-properties=supportsES6=true,useSingleRequestParameter=true,withInterfaces=true,modelPropertyNaming=original"
113
+ ].join(" ");
114
+ console.log(import_chalk.default.gray(`Executing: ${generatorCommand}`));
115
+ (0, import_child_process.execSync)(generatorCommand, { stdio: "inherit" });
116
+ console.log(import_chalk.default.green(`\u2713 Types generated successfully at ${typesOutputPath}`));
117
+ console.log("\n" + import_chalk.default.blue("Step 4: Generating custom API modules..."));
95
118
  const modules = parseSpecToModules(spec);
119
+ const modulesOutputPath = import_path.default.join(options.output, "modules");
120
+ if (!import_fs.default.existsSync(modulesOutputPath)) {
121
+ import_fs.default.mkdirSync(modulesOutputPath, { recursive: true });
122
+ }
96
123
  for (const moduleName in modules) {
97
- const moduleConfig = modules[moduleName];
124
+ const moduleData = modules[moduleName];
98
125
  const fileName = `${moduleName}.module.ts`;
99
- const filePath = import_path.default.join(options.output, fileName);
100
- const fileContent = `
101
- // This file is auto-generated by api-core-lib.
102
- // Do not edit this file directly.
126
+ const filePath = import_path.default.join(modulesOutputPath, fileName);
127
+ const actionsTypeParts = Object.entries(moduleData.actions).map(([actionName, actionData]) => {
128
+ const inputType = actionData._inputType !== "unknown" ? actionData._inputType : actionData.hasQuery ? "QueryOptions" : "undefined";
129
+ const outputType = actionData._outputType;
130
+ return ` ${actionName}: ActionConfigModule<${inputType}, ${outputType}>;`;
131
+ });
132
+ const actionsTypeDefinition = `{
133
+ ${actionsTypeParts.join("\n")}
134
+ }`;
135
+ const actionsValueParts = Object.entries(moduleData.actions).map(([actionName, actionData]) => {
136
+ const { _inputType, _outputType, ...config } = actionData;
137
+ return ` ${actionName}: ${JSON.stringify(config, null, 2).replace(/\n/g, "\n ")}`;
138
+ });
139
+ const actionsValueDefinition = `{
140
+ ${actionsValueParts.join(",\n")}
141
+ }`;
142
+ const fileContent = `/**
143
+ * This file is auto-generated by api-core-lib.
144
+ * Do not edit this file directly.
145
+ * @module ${moduleName}
146
+ */
103
147
 
104
- import type { ApiModuleConfig } from 'api-core-lib';
105
- import type { paths } from './api-types.generated'; // \u0631\u0628\u0637 \u0627\u0644\u0623\u0646\u0648\u0627\u0639 \u0627\u0644\u0645\u0648\u0644\u062F\u0629
148
+ import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core-lib';
149
+ import type { components } from '../types/api-types.generated';
106
150
 
107
- // A more advanced generator could automatically map the correct input/output types.
108
- // For now, we use 'any' as a placeholder.
109
- export const ${moduleName}Module: ApiModuleConfig<any> = ${JSON.stringify(moduleConfig, null, 2)};
151
+ /**
152
+ * Defines the configuration for the ${moduleName} API module.
153
+ * This is a strongly-typed configuration object that ensures type safety.
154
+ */
155
+ export const ${moduleName}Module: ApiModuleCodeConfig<${actionsTypeDefinition}> = {
156
+ baseEndpoint: '/api/v1', // \u064A\u0645\u0643\u0646\u0643 \u062C\u0639\u0644\u0647 \u062F\u064A\u0646\u0627\u0645\u064A\u0643\u064A\u064B\u0627
157
+ actions: ${actionsValueDefinition},
158
+ };
110
159
  `;
111
160
  import_fs.default.writeFileSync(filePath, fileContent);
112
161
  console.log(import_chalk.default.green(`\u2713 Module generated: ${fileName}`));
113
162
  }
114
- console.log(import_chalk.default.bold.green("\n\u{1F389} API generation complete!"));
163
+ console.log(import_chalk.default.green("\u2713 All custom modules generated."));
164
+ console.log(import_chalk.default.bold.green("\n\u{1F389} API generation complete! All files are located in:"));
165
+ console.log(import_chalk.default.bold.cyan(options.output));
115
166
  } catch (error) {
116
- console.error(import_chalk.default.red("\nAn error occurred during generation:"));
117
- console.error(error.message);
167
+ console.error(import_chalk.default.red.bold("\n\u274C An error occurred during generation:"));
168
+ if (error.response) {
169
+ console.error(import_chalk.default.red(`Network Error: ${error.message} (Status: ${error.response.status})`));
170
+ } else if (error.stderr) {
171
+ console.error(import_chalk.default.red(`Command Execution Error: ${error.message}`));
172
+ console.error(import_chalk.default.gray(error.stderr.toString()));
173
+ } else {
174
+ console.error(import_chalk.default.red(error.message));
175
+ }
118
176
  process.exit(1);
177
+ } finally {
178
+ if (import_fs.default.existsSync(tempSpecPath)) {
179
+ import_fs.default.unlinkSync(tempSpecPath);
180
+ console.log(import_chalk.default.gray("\nTemporary spec file cleaned up."));
181
+ }
119
182
  }
120
183
  }
121
184
 
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "12.0.35",
3
+ "version": "12.0.37",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
-
7
6
  "exports": {
8
- ".": {
7
+ ".": {
9
8
  "types": "./dist/index.d.ts",
10
9
  "import": "./dist/index.js",
11
10
  "require": "./dist/index.cjs"
@@ -21,50 +20,48 @@
21
20
  "require": "./dist/client.cjs"
22
21
  }
23
22
  },
24
-
25
23
  "main": "./dist/index.cjs",
26
24
  "module": "./dist/index.js",
27
25
  "types": "./dist/index.d.ts",
28
26
  "bin": {
29
- "api-core-generate": "./bin/cli-launcher.cjs"
27
+ "api-core-generate": "./bin/cli-launcher.cjs"
30
28
  },
31
29
  "scripts": {
32
- "build": "tsup",
30
+ "build": "tsup",
33
31
  "dev": "tsup --watch"
34
32
  },
35
-
36
33
  "peerDependencies": {
37
34
  "react": ">=19.0.0",
38
35
  "react-dom": ">=19.0.0"
39
36
  },
40
-
41
37
  "dependencies": {
42
38
  "axios": "^1.6.8",
43
39
  "axios-retry": "^4.1.0",
44
- "colorette": "^2.0.20",
45
- "fast-deep-equal": "^3.1.3",
46
- "path": "^0.12.7",
47
- "uuid": "^9.0.1",
48
-
49
40
  "chalk": "^4.1.2",
41
+ "colorette": "^2.0.20",
50
42
  "commander": "^9.4.1",
51
43
  "dotenv": "^16.0.3",
52
- "openapi-typescript": "^6.2.4"
44
+ "fast-deep-equal": "^3.1.3",
45
+ "openapi-typescript": "^6.2.4",
46
+ "path": "^0.12.7",
47
+ "uuid": "^9.0.1"
53
48
  },
54
-
55
49
  "devDependencies": {
56
- "react": "19.1.0",
57
- "react-dom": "19.1.0",
50
+ "@openapitools/openapi-generator-cli": "^2.23.1",
58
51
  "@types/jest": "^30.0.0",
59
52
  "@types/node": "^24.2.1",
60
53
  "@types/react": "^18.3.2",
61
54
  "@types/uuid": "^9.0.8",
62
55
  "javascript-obfuscator": "^4.1.1",
63
56
  "jest": "^30.0.5",
57
+ "react": "19.1.0",
58
+ "react-dom": "19.1.0",
64
59
  "ts-jest": "^29.4.1",
65
60
  "tsup": "^8.0.2",
66
61
  "typescript": "^5.4.5"
67
62
  },
68
-
69
- "files": ["dist" , "bin"]
63
+ "files": [
64
+ "dist",
65
+ "bin"
66
+ ]
70
67
  }