@paulpugovkin/api-docs-axios-ts-generator 1.0.5

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.
package/README.md ADDED
@@ -0,0 +1,310 @@
1
+ # API Docs Axios TS Generator
2
+
3
+ Generate TypeScript interfaces and axios classes from OpenAPI (Swagger) specifications.
4
+
5
+ ## Features
6
+
7
+ - πŸš€ Generate TypeScript interfaces from OpenAPI schemas
8
+ - πŸ“¦ Generate axios classes with API methods
9
+ - πŸ”§ Flexible configuration via TypeScript file
10
+ - 🏷️ Tag filtering (include/exclude)
11
+ - πŸ“ Generation modes: single class or multiple by tags
12
+ - βš™οΈ Automatic axios configuration generation
13
+ - 🎯 Support for spreading user axios configurations
14
+ - πŸ“ JSDoc comments for methods
15
+ - πŸ”„ Backward compatibility with CLI arguments
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install -g @paulpugovkin/api-docs-axios-ts-generator
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### 1. Install as project dependency
26
+
27
+ ```bash
28
+ npm install --save-dev @paulpugovkin/api-docs-axios-ts-generator
29
+ ```
30
+
31
+ Add script to your `package.json`:
32
+
33
+ ```json
34
+ {
35
+ "scripts": {
36
+ "generate-services": "npx @paulpugovkin/api-docs-axios-ts-generator --config api-docs-generator.config.js"
37
+ }
38
+ }
39
+ ```
40
+
41
+ Now you can run generation:
42
+
43
+ ```bash
44
+ npm run generate-services
45
+ ```
46
+
47
+
48
+ ### 2. Use as global tool
49
+
50
+ ```bash
51
+ # Install as global tool
52
+ npm install -g @paulpugovkin/api-docs-axios-ts-generator
53
+
54
+ # Run generation
55
+ api-docs-generator --config api-docs-generator.config.js
56
+
57
+ # Or via npx
58
+ npx @paulpugovkin/api-docs-axios-ts-generator --config api-docs-generator.config.js
59
+ ```
60
+
61
+ ### 3. Create configuration file
62
+
63
+ A default configuration file `api-docs-generator.config.js` is automatically created in your project root during installation. You can modify this file to suit your needs.
64
+
65
+ If you need to create it manually, create `api-docs-generator.config.js` file in the root of your project:
66
+
67
+ ```javascript
68
+ module.exports = {
69
+ // URL to fetch OpenAPI specification from
70
+ apiDocsUrl: 'https://api.example.com/v3/api-docs.json',
71
+
72
+ // Output directory for generated files
73
+ outputDir: './src/api',
74
+
75
+ // Tag filtering options
76
+ tags: {
77
+ include: ['api_tag_users', 'api_tag_products'],
78
+ },
79
+
80
+ // Grouping mode for API methods
81
+ groupBy: 'tag',
82
+
83
+ // Class generation mode
84
+ classMode: 'multiple',
85
+
86
+ // Generation options
87
+ options: {
88
+ generateAxiosConfig: true,
89
+ allowAxiosConfigSpread: true,
90
+ },
91
+
92
+ // Axios configuration settings
93
+ axios: {
94
+ baseURL: 'https://api.example.com',
95
+ timeout: 30000,
96
+ },
97
+ };
98
+ ```
99
+
100
+ ### 4. Use generated API
101
+
102
+ ```typescript
103
+ import { UsersApi, ProductsApi } from './src/api';
104
+
105
+ // Use API
106
+ const usersApi = new UsersApi();
107
+ const productsApi = new ProductsApi();
108
+
109
+ // Get user
110
+ const user = await usersApi.getUserById(123);
111
+
112
+ // With custom axios configuration
113
+ const user = await usersApi.getUserById(123, {
114
+ headers: {
115
+ 'X-Custom-Header': 'value',
116
+ },
117
+ timeout: 5000,
118
+ });
119
+ ```
120
+
121
+ ## Configuration
122
+
123
+ ### Main parameters
124
+
125
+ | Parameter | Type | Required | Description |
126
+ |-----------|------|--------------|------------|
127
+ | `apiDocsUrl` | `string` | No* | URL to fetch OpenAPI specification |
128
+ | `apiDocsPath` | `string` | No* | Local path to OpenAPI specification file |
129
+ | `outputDir` | `string` | Yes | Output directory for generated files |
130
+
131
+ *One of `apiDocsUrl` or `apiDocsPath` is required.
132
+
133
+ ### Tag filtering
134
+
135
+ ```typescript
136
+ tags: {
137
+ include?: string[]; // Tags to include
138
+ exclude?: string[]; // Tags to exclude
139
+ prefix?: string; // Tag prefix (default "api_tag_")
140
+ }
141
+ ```
142
+
143
+ ### Grouping modes
144
+
145
+ ```typescript
146
+ groupBy: 'tag' | 'all' | 'path';
147
+ ```
148
+
149
+ - `'tag'` - grouping by tags (multiple classes)
150
+ - `'all'` - all methods in one class
151
+ - `'path'` - grouping by API paths
152
+
153
+ ### Class generation modes
154
+
155
+ ```typescript
156
+ classMode: 'single' | 'multiple';
157
+ ```
158
+
159
+ - `'single'` - one class for all methods
160
+ - `'multiple'` - multiple classes by grouping
161
+
162
+ ### Naming options
163
+
164
+ ```typescript
165
+ naming: {
166
+ className?: (tag: string) => string;
167
+ interfaceName?: (name: string) => string;
168
+ methodName?: (operationId: string) => string;
169
+ }
170
+ ```
171
+
172
+ ### Import options
173
+
174
+ ```typescript
175
+ imports: {
176
+ axiosPath?: string; // Path to import axios (default 'axios')
177
+ baseUrlPath?: string; // Path to import BASE_URL
178
+ }
179
+ ```
180
+
181
+ ### Generation options
182
+
183
+ ```typescript
184
+ options: {
185
+ generateJSDoc?: boolean; // Generate JSDoc (default true)
186
+ generateIndexFiles?: boolean; // Generate index files (default true)
187
+ cleanOutputDir?: boolean; // Clean output directory (default true)
188
+ generateAxiosConfig?: boolean; // Generate axios configuration (default true)
189
+ allowAxiosConfigSpread?: boolean; // Allow spreading axios configs (default true)
190
+ }
191
+ ```
192
+
193
+ ### Axios settings
194
+
195
+ ```typescript
196
+ axios: {
197
+ baseURL?: string;
198
+ timeout?: number;
199
+ headers?: Record<string, string>;
200
+ withCredentials?: boolean;
201
+ }
202
+ ```
203
+
204
+ ## Spreading user axios configurations
205
+
206
+ When `allowAxiosConfigSpread: true` is enabled, API methods support passing user configurations:
207
+
208
+ ```typescript
209
+ // Generated method
210
+ async getUserById(id: number, config?: AxiosRequestConfig): Promise<AxiosResponse<User>>
211
+
212
+ // Usage
213
+ const response = await usersApi.getUserById(123, {
214
+ headers: {
215
+ 'X-Custom-Header': 'value',
216
+ },
217
+ timeout: 5000,
218
+ params: {
219
+ fields: 'id,name,email',
220
+ },
221
+ });
222
+ ```
223
+
224
+ ## Generated files structure
225
+
226
+ ```
227
+ outputDir/
228
+ β”œβ”€β”€ config/
229
+ β”‚ └── axios/
230
+ β”‚ └── axios.ts # Axios configuration with interceptors
231
+ β”œβ”€β”€ interfaces/
232
+ β”‚ β”œβ”€β”€ User.ts
233
+ β”‚ β”œβ”€β”€ Product.ts
234
+ β”‚ └── index.ts
235
+ β”œβ”€β”€ classes/
236
+ β”‚ β”œβ”€β”€ UsersApi.ts
237
+ β”‚ β”œβ”€β”€ ProductsApi.ts
238
+ β”‚ └── index.ts
239
+ └── index.ts
240
+ ```
241
+
242
+ ## CLI options
243
+
244
+ ```
245
+ Usage: api-docs-generator [options]
246
+
247
+ Options:
248
+ -V, --version output the version number
249
+ -c, --config <path> Path to configuration file
250
+ --api-docs-url <url> URL to fetch OpenAPI documentation
251
+ --api-docs-path <path> Local path to OpenAPI documentation file
252
+ --output-dir <dir> Output directory for generated files
253
+ --clean Clean output directory before generation
254
+ -h, --help display help for command
255
+ ```
256
+
257
+ ## Configuration examples
258
+
259
+ ### Generate by tags (multiple classes)
260
+
261
+ ```typescript
262
+ {
263
+ tags: {
264
+ include: ['api_tag_users', 'api_tag_products'],
265
+ },
266
+ groupBy: 'tag',
267
+ classMode: 'multiple',
268
+ }
269
+ ```
270
+
271
+ ### Generate single class
272
+
273
+ ```typescript
274
+ {
275
+ groupBy: 'all',
276
+ classMode: 'single',
277
+ }
278
+ ```
279
+
280
+ ### Exclude tags
281
+
282
+ ```typescript
283
+ {
284
+ tags: {
285
+ exclude: ['api_tag_internal', 'api_tag_admin'],
286
+ },
287
+ }
288
+ ```
289
+
290
+ ### Generate with axios configuration
291
+
292
+ ```typescript
293
+ {
294
+ options: {
295
+ generateAxiosConfig: true,
296
+ },
297
+ axios: {
298
+ baseURL: 'https://api.example.com',
299
+ timeout: 30000,
300
+ headers: {
301
+ 'Content-Type': 'application/json',
302
+ 'X-API-Key': 'your-api-key',
303
+ },
304
+ },
305
+ }
306
+ ```
307
+
308
+ ## License
309
+
310
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * CLI entry point for api-docs-axios-ts-generator
5
+ */
6
+ require('../src/index.js');
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@paulpugovkin/api-docs-axios-ts-generator",
3
+ "version": "1.0.5",
4
+ "description": "Generate TypeScript interfaces and axios classes from OpenAPI documentation",
5
+ "main": "src/index.min.js",
6
+ "bin": {
7
+ "api-docs-generator": "./src/index.min.js"
8
+ },
9
+ "types": "src/types/index.d.ts",
10
+ "scripts": {
11
+ "generate-services": "npx @paulpugovkin/api-docs-axios-ts-generator --config api-docs-generator.config.js",
12
+ "postinstall": "node src/scripts/createConfigFile.js"
13
+ },
14
+ "keywords": [
15
+ "openapi",
16
+ "swagger",
17
+ "typescript",
18
+ "axios",
19
+ "generator",
20
+ "api-client",
21
+ "code-generation",
22
+ "api",
23
+ "rest"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "commander": "^11.0.0",
29
+ "node-fetch": "^2.7.0",
30
+ "axios": "^1.6.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "typescript": "^5.0.0"
35
+ },
36
+ "engines": {
37
+ "node": ">=14.0.0"
38
+ },
39
+ "files": [
40
+ "src",
41
+ "bin",
42
+ "README.md",
43
+ "LICENSE"
44
+ ],
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+https://github.com/PaulPugovkin/api-docs-axios-ts-generator.git"
48
+ },
49
+ "bugs": {
50
+ "url": "https://github.com/PaulPugovkin/api-docs-axios-ts-generator/issues"
51
+ },
52
+ "homepage": "https://github.com/PaulPugovkin/api-docs-axios-ts-generator#readme"
53
+ }
@@ -0,0 +1,21 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ /**
5
+ * УдаляСт содСрТимоС ΠΏΠ°ΠΏΠΊΠΈ ΠΈ пСрСсоздаСт Π΅Ρ‘.
6
+ * @param {string} outputDir - ΠŸΡƒΡ‚ΡŒ ΠΊ ΠΏΠ°ΠΏΠΊΠ΅.
7
+ */
8
+ function cleanGeneratedFolder(outputDir) {
9
+ if (fs.existsSync(outputDir)) {
10
+ fs.rmSync(outputDir, {recursive: true}); // УдаляСм ΠΏΠ°ΠΏΠΊΡƒ ΠΈ всС Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹
11
+ console.log(`Deleted: ${outputDir}`);
12
+ }
13
+
14
+ fs.mkdirSync(outputDir, {recursive: true}); // Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ ΠΏΠ°ΠΏΠΊΡƒ
15
+ fs.mkdirSync(path.join(outputDir, "interfaces"), {recursive: true});
16
+ fs.mkdirSync(path.join(outputDir, "classes"), {recursive: true});
17
+
18
+ console.log(`Recreated necessary directories.`);
19
+ }
20
+
21
+ module.exports = {cleanGeneratedFolder};
@@ -0,0 +1,33 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ function collectGeneratedFiles(outputDir) {
5
+ const classFiles = [];
6
+ const interfaceFiles = [];
7
+
8
+ // РСкурсивный ΠΎΠ±Ρ…ΠΎΠ΄ ΠΏΠ°ΠΏΠΎΠΊ
9
+ function walkDir(currentPath) {
10
+ const entries = fs.readdirSync(currentPath, {withFileTypes: true});
11
+ for (const entry of entries) {
12
+ const fullPath = path.join(currentPath, entry.name);
13
+
14
+ if (entry.isDirectory()) {
15
+ walkDir(fullPath); // РСкурсивный Π²Ρ‹Π·ΠΎΠ² для ΠΏΠ°ΠΏΠΎΠΊ
16
+ } else if (
17
+ entry.isFile() &&
18
+ entry.name.endsWith(".ts") &&
19
+ entry.name !== "index.ts"
20
+ ) {
21
+ if (fullPath.includes("interfaces")) {
22
+ interfaceFiles.push(fullPath);
23
+ } else {
24
+ classFiles.push(fullPath);
25
+ }
26
+ }
27
+ }
28
+ }
29
+
30
+ walkDir(outputDir); // Запуск ΠΎΠ±Ρ…ΠΎΠ΄Π° с ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ ΠΏΠ°ΠΏΠΊΠΈ
31
+
32
+ return {classFiles, interfaceFiles};
33
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ для Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°
3
+ */
4
+ import { GeneratorConfig } from '../types/config.types';
5
+
6
+ export const defaultConfig: Partial<GeneratorConfig> = {
7
+ outputDir: './generated',
8
+ interfacesDir: './generated/interfaces',
9
+ classesDir: './generated/classes',
10
+ groupBy: 'tag',
11
+ classMode: 'multiple',
12
+ tags: {
13
+ prefix: 'api_tag_',
14
+ },
15
+ imports: {
16
+ axiosPath: 'axios',
17
+ baseUrlPath: './config/axios/axios',
18
+ },
19
+ options: {
20
+ generateJSDoc: true,
21
+ generateIndexFiles: true,
22
+ cleanOutputDir: true,
23
+ generateAxiosConfig: true,
24
+ allowAxiosConfigSpread: true,
25
+ },
26
+ axios: {
27
+ baseURL: '',
28
+ timeout: 30000,
29
+ headers: {
30
+ 'Content-Type': 'application/json',
31
+ },
32
+ },
33
+ };
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°
3
+ */
4
+ // @ts-ignore - Node.js types
5
+ import fs from 'fs';
6
+ // @ts-ignore - Node.js types
7
+ import path from 'path';
8
+ import { GeneratorConfig } from '../types/config.types';
9
+ import { defaultConfig } from './defaultConfig';
10
+ import { validateConfig } from './validateConfig';
11
+
12
+ /**
13
+ * Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ ΠΈΠ· Ρ„Π°ΠΉΠ»Π°
14
+ * @param configPath - ΠŸΡƒΡ‚ΡŒ ΠΊ Ρ„Π°ΠΉΠ»Ρƒ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
15
+ * @returns ΠžΠ±ΡŠΠ΅ΠΊΡ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
16
+ */
17
+ async function loadConfigFile(configPath: string): Promise<Partial<GeneratorConfig>> {
18
+ const resolvedPath = path.resolve(configPath);
19
+
20
+ if (!fs.existsSync(resolvedPath)) {
21
+ throw new Error(`Configuration file not found: ${resolvedPath}`);
22
+ }
23
+
24
+ // УдаляСм кэш для ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ горячСй ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ
25
+ // @ts-ignore
26
+ delete require.cache[require.resolve(resolvedPath)];
27
+
28
+ try {
29
+ // @ts-ignore
30
+ const userConfig = require(resolvedPath);
31
+ return userConfig.default || userConfig;
32
+ } catch (error) {
33
+ throw new Error(`Failed to load configuration from ${resolvedPath}: ${error}`);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ (ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠ°Ρ ΠΏΠ΅Ρ€Π΅ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ Π΄Π΅Ρ„ΠΎΠ»Ρ‚Π½ΡƒΡŽ)
39
+ * @param defaults - ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
40
+ * @param userConfig - ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠ°Ρ конфигурация
41
+ * @returns ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½Ρ‘Π½Π½Π°Ρ конфигурация
42
+ */
43
+ function mergeConfigs(
44
+ defaults: Partial<GeneratorConfig>,
45
+ userConfig: Partial<GeneratorConfig>
46
+ ): GeneratorConfig {
47
+ const merged: any = {
48
+ ...defaults,
49
+ ...userConfig,
50
+ };
51
+
52
+ // Π“Π»ΡƒΠ±ΠΎΠΊΠΎΠ΅ слияниС для Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²
53
+ if (defaults.tags && userConfig.tags) {
54
+ merged.tags = { ...defaults.tags, ...userConfig.tags };
55
+ }
56
+
57
+ if (defaults.naming && userConfig.naming) {
58
+ merged.naming = { ...defaults.naming, ...userConfig.naming };
59
+ }
60
+
61
+ if (defaults.imports && userConfig.imports) {
62
+ merged.imports = { ...defaults.imports, ...userConfig.imports };
63
+ }
64
+
65
+ if (defaults.options && userConfig.options) {
66
+ merged.options = { ...defaults.options, ...userConfig.options };
67
+ }
68
+
69
+ if (defaults.axios && userConfig.axios) {
70
+ merged.axios = { ...defaults.axios, ...userConfig.axios };
71
+ // Π“Π»ΡƒΠ±ΠΎΠΊΠΎΠ΅ слияниС для headers
72
+ if (defaults.axios.headers && userConfig.axios.headers) {
73
+ merged.axios.headers = { ...defaults.axios.headers, ...userConfig.axios.headers };
74
+ }
75
+ }
76
+
77
+ return merged as GeneratorConfig;
78
+ }
79
+
80
+ /**
81
+ * Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°
82
+ * @param configPath - ΠŸΡƒΡ‚ΡŒ ΠΊ Ρ„Π°ΠΉΠ»Ρƒ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ (ΠΎΠΏΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ)
83
+ * @param cliOverrides - ΠŸΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΡ ΠΈΠ· CLI Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²
84
+ * @returns Полная конфигурация Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°
85
+ */
86
+ export async function loadConfig(
87
+ configPath?: string,
88
+ cliOverrides?: Partial<GeneratorConfig>
89
+ ): Promise<GeneratorConfig> {
90
+ let userConfig: Partial<GeneratorConfig> = {};
91
+
92
+ // Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° ΠΈΠ· Ρ„Π°ΠΉΠ»Π°, Ссли ΡƒΠΊΠ°Π·Π°Π½
93
+ if (configPath) {
94
+ console.log(`Loading configuration from: ${configPath}`);
95
+ userConfig = await loadConfigFile(configPath);
96
+ } else {
97
+ console.log('No configuration file specified, using default configuration');
98
+ }
99
+
100
+ // БлияниС с ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠ΅ΠΉ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
101
+ let mergedConfig = mergeConfigs(defaultConfig, userConfig);
102
+
103
+ // ΠŸΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠΉ ΠΈΠ· CLI
104
+ if (cliOverrides) {
105
+ mergedConfig = mergeConfigs(mergedConfig, cliOverrides);
106
+ }
107
+
108
+ // Валидация ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
109
+ validateConfig(mergedConfig);
110
+
111
+ return mergedConfig;
112
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Валидация ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°
3
+ */
4
+ import { GeneratorConfig } from '../types/config.types';
5
+
6
+ export function validateConfig(config: GeneratorConfig): void {
7
+ // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ поля outputDir
8
+ if (!config.outputDir) {
9
+ throw new Error('Configuration error: outputDir is required');
10
+ }
11
+
12
+ // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°, Ρ‡Ρ‚ΠΎ ΡƒΠΊΠ°Π·Π°Π½ Π»ΠΈΠ±ΠΎ apiDocsUrl, Π»ΠΈΠ±ΠΎ apiDocsPath
13
+ if (!config.apiDocsUrl && !config.apiDocsPath) {
14
+ throw new Error('Configuration error: either apiDocsUrl or apiDocsPath must be specified');
15
+ }
16
+
17
+ // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° groupBy
18
+ if (config.groupBy && !['tag', 'all', 'path'].includes(config.groupBy)) {
19
+ throw new Error(`Configuration error: invalid groupBy value "${config.groupBy}". Must be one of: tag, all, path`);
20
+ }
21
+
22
+ // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° classMode
23
+ if (config.classMode && !['single', 'multiple'].includes(config.classMode)) {
24
+ throw new Error(`Configuration error: invalid classMode value "${config.classMode}". Must be one of: single, multiple`);
25
+ }
26
+
27
+ // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠΈ ΠΏΠΎ Ρ‚Π΅Π³Π°ΠΌ
28
+ if (config.tags) {
29
+ if (config.tags.include && config.tags.exclude) {
30
+ console.warn('Warning: Both include and exclude tags are specified. Include will take precedence.');
31
+ }
32
+
33
+ if (config.tags.include && config.tags.include.length === 0) {
34
+ console.warn('Warning: tags.include is empty. No tags will be filtered.');
35
+ }
36
+ }
37
+
38
+ // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° совмСстимости groupBy ΠΈ classMode
39
+ if (config.groupBy === 'all' && config.classMode === 'multiple') {
40
+ console.warn('Warning: groupBy="all" with classMode="multiple" will generate only one class. Consider using classMode="single".');
41
+ }
42
+
43
+ // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° настроСк axios
44
+ if (config.axios) {
45
+ if (config.axios.timeout !== undefined && config.axios.timeout < 0) {
46
+ throw new Error('Configuration error: axios.timeout must be a positive number');
47
+ }
48
+ }
49
+
50
+ // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΎΠΏΡ†ΠΈΠΉ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ
51
+ if (config.options) {
52
+ if (config.options.generateAxiosConfig && !config.axios) {
53
+ console.warn('Warning: generateAxiosConfig is true but no axios config provided. Using default values.');
54
+ }
55
+ }
56
+
57
+ console.log('Configuration validated successfully.');
58
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * ГСнСрация классов TypeScript
3
+ * @param {string} name - НазваниС класса
4
+ * @param {string[]} methods - Бписок ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² класса
5
+ * @param {Set<string>} usedInterfaces - Набор ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Ρ… интСрфСйсов
6
+ * @param {Object} config - ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°
7
+ * @returns {string} - Π‘Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ класса TypeScript
8
+ */
9
+ function generateClass(name, methods, usedInterfaces, config) {
10
+ const axiosResponseImport =
11
+ 'import { AxiosResponse, AxiosRequestConfig } from "axios";\n';
12
+
13
+ // ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ ΠΏΡƒΡ‚ΠΈ ΠΈΠΌΠΏΠΎΡ€Ρ‚Π° ΠΈΠ· ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
14
+ const axiosPath = config?.imports?.axiosPath || 'axios';
15
+ const baseUrlPath = config?.imports?.baseUrlPath || './config/axios/axios';
16
+
17
+ // Π˜ΠΌΠΏΠΎΡ€Ρ‚Ρ‹ интСрфСйсов
18
+ let interfaceImport = '';
19
+ if (usedInterfaces && usedInterfaces.size > 0) {
20
+ interfaceImport = Array.from(usedInterfaces)
21
+ .sort()
22
+ .map((interfaceName) => `import { ${interfaceName} } from '../../';`)
23
+ .join("\n");
24
+ }
25
+
26
+ // Π˜ΠΌΠΏΠΎΡ€Ρ‚Ρ‹ axios
27
+ const axiosImport = `\nimport axios from '${axiosPath}'`;
28
+ const baseApiUrl = `\nimport { BASE_URL } from '${baseUrlPath}'`;
29
+
30
+ const imports = `${axiosResponseImport}${interfaceImport}${axiosImport}${baseApiUrl}`;
31
+ const tsMethods = methods.join("\n");
32
+ return `${imports}\n\nexport class ${name} {\n${tsMethods}\n}\n`;
33
+ }
34
+
35
+ module.exports = {generateClass};