@paulpugovkin/api-docs-axios-ts-generator 1.0.17 → 1.2.0

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/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "@paulpugovkin/api-docs-axios-ts-generator",
3
- "version": "1.0.17",
3
+ "version": "1.2.0",
4
4
  "description": "Generate TypeScript interfaces and axios classes from OpenAPI documentation",
5
- "main": "src/index.js",
5
+ "main": "dist/index.js",
6
6
  "bin": {
7
- "api-docs-generator": "./bin/cli.js"
7
+ "api-docs-generator": "dist/index.js"
8
8
  },
9
- "types": "src/types/index.d.ts",
10
9
  "scripts": {
11
10
  "generate-services": "npx @paulpugovkin/api-docs-axios-ts-generator --config api-docs-generator.config.js",
12
11
  "dev": "node scripts/dev.js",
13
12
  "dev:ts": "ts-node scripts/dev.ts",
13
+ "build": "tsup",
14
+ "prepublishOnly": "npm run build",
14
15
  "postinstall": "node src/scripts/createConfigFile.js"
15
16
  },
16
17
  "keywords": [
@@ -27,35 +28,23 @@
27
28
  "author": "",
28
29
  "license": "MIT",
29
30
  "dependencies": {
30
- "commander": "^11.0.0",
31
- "node-fetch": "^2.7.0",
31
+ "commander": "^11.0.0"
32
+ },
33
+ "peerDependencies": {
32
34
  "axios": "^1.6.0"
33
35
  },
34
36
  "devDependencies": {
35
37
  "@types/node": "^20.0.0",
38
+ "tsup": "^8.5.1",
36
39
  "typescript": "^5.0.0"
37
40
  },
38
41
  "engines": {
39
- "node": ">=14.0.0"
42
+ "node": ">=18.0.0"
40
43
  },
41
44
  "files": [
42
- "src/index.min.js",
43
- "src/clean-generated-folder",
44
- "src/collect-genereted-files",
45
- "src/generate-class",
46
- "src/generate-index-file-with-public-api",
47
- "src/generate-interface",
48
- "src/generate-js-doc",
49
- "src/generate-main-index-file",
50
- "src/generate-method",
51
- "src/generators",
52
- "src/map-type",
53
- "src/parse-and-generate",
54
- "src/resolve-type",
45
+ "dist",
55
46
  "src/scripts",
56
47
  "src/templates",
57
- "src/update-api-docs-json",
58
- "bin",
59
48
  "README.md",
60
49
  "LICENSE"
61
50
  ],
package/bin/cli.js DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * CLI entry point for api-docs-axios-ts-generator
5
- */
6
- require('../src/index.js');
@@ -1,21 +0,0 @@
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};
@@ -1,33 +0,0 @@
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
- }
@@ -1,42 +0,0 @@
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
- const path = require('path');
10
-
11
- function generateClass(name, methods, usedInterfaces, config) {
12
- const axiosResponseImport =
13
- 'import { AxiosResponse, AxiosRequestConfig } from "axios";\n';
14
-
15
- // Определяем пути импорта из конфигурации
16
- const axiosPath = config?.imports?.axiosPath || 'axios';
17
- const baseUrlPath = config?.imports?.baseUrlPath || './config/axios/axios';
18
-
19
- // Определяем базовый путь для импорта интерфейсов (папка выше, чем папка с классами)
20
- const interfaceImportPath = config?.outputDir
21
- ? path.relative(path.join(config.outputDir, 'classes'), config.outputDir)
22
- : '../../';
23
-
24
- // Импорты интерфейсов
25
- let interfaceImport = '';
26
- if (usedInterfaces && usedInterfaces.size > 0) {
27
- interfaceImport = Array.from(usedInterfaces)
28
- .sort()
29
- .map((interfaceName) => `import { ${interfaceName} } from '${interfaceImportPath}';`)
30
- .join("\n");
31
- }
32
-
33
- // Импорты axios
34
- const axiosImport = `\nimport axios from '${axiosPath}'`;
35
- const baseApiUrl = `\nimport { BASE_URL } from '${baseUrlPath}'`;
36
-
37
- const imports = `${axiosResponseImport}${interfaceImport}${axiosImport}${baseApiUrl}`;
38
- const tsMethods = methods.join("\n");
39
- return `${imports}\n\nexport class ${name} {\n${tsMethods}\n}\n`;
40
- }
41
-
42
- module.exports = {generateClass};
@@ -1,45 +0,0 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- /**
5
- * Генерирует файл `index.ts`, экспортирующий все модули из указанной папки.
6
- * @param {string} targetDir - Папка, для которой нужно сгенерировать экспорт.
7
- * @param {string} outputFile - Полный путь для записи файла `index.ts`.
8
- */
9
- function generateIndexFileWithOpenApi(targetDir, outputFile) {
10
- const exports = [];
11
-
12
- // Рекурсивно перебираем все файлы в целевой директории
13
- function walkDir(currentDir) {
14
- const entries = fs.readdirSync(currentDir, {withFileTypes: true});
15
-
16
- for (const entry of entries) {
17
- const fullPath = path.join(currentDir, entry.name);
18
-
19
- if (entry.isDirectory()) {
20
- // Рекурсивный вызов для папок
21
- walkDir(fullPath);
22
- } else if (
23
- entry.isFile() &&
24
- entry.name.endsWith(".ts") &&
25
- entry.name !== "index.ts"
26
- ) {
27
- // Вычисляем относительный путь
28
- const relativePath = path
29
- .relative(targetDir, fullPath)
30
- .replace(/\\/g, "/");
31
- const modulePath = relativePath.replace(/\.ts$/, "");
32
- exports.push(`export * from './${modulePath}';`);
33
- }
34
- }
35
- }
36
-
37
- walkDir(targetDir); // Запуск обхода с целевой директории
38
-
39
- // Записываем все экспорты в файл index.ts
40
- fs.writeFileSync(outputFile, exports.join("\n"), {encoding: "utf-8"});
41
-
42
- console.log(`Generated ${outputFile} with ${exports.length} exports.`);
43
- }
44
-
45
- module.exports = {generateIndexFileWithOpenApi};
@@ -1,81 +0,0 @@
1
- const {resolveType} = require("../resolve-type/resolveType"); // Импорт функции resolveType
2
- const path = require("path");
3
-
4
- function capitalizeOnlyFirst(text) {
5
- return text ? text.charAt(0).toUpperCase() + text.slice(1) : text;
6
- }
7
-
8
- function mergeAllOf(allOf, schemaRefs, usedInterfaces) {
9
- let mergedProperties = {};
10
- let extendsInterfaces = [];
11
-
12
- for (const item of allOf) {
13
- if (item.$ref) {
14
- const refName = item.$ref.split("/").pop();
15
- usedInterfaces.add(refName);
16
- extendsInterfaces.push(refName);
17
- } else if (item.properties) {
18
- mergedProperties = {...mergedProperties, ...item.properties};
19
- }
20
- }
21
-
22
- return {mergedProperties, extendsInterfaces};
23
- }
24
-
25
- function processOneOf(oneOf, schemaRefs, usedInterfaces) {
26
- const unionTypes = [];
27
-
28
- for (const item of oneOf) {
29
- if (item.$ref) {
30
- const refName = item.$ref.split("/").pop();
31
- usedInterfaces.add(refName);
32
- unionTypes.push(refName);
33
- }
34
- }
35
-
36
- return unionTypes;
37
- }
38
-
39
- function generateInterface(name, schema, schemaRefs, config) {
40
- const usedInterfaces = new Set();
41
- let properties = schema.properties || {};
42
- let extendsInterfaces = [];
43
-
44
- // Обработка allOf
45
- if (schema.allOf) {
46
- const merged = mergeAllOf(schema.allOf, schemaRefs, usedInterfaces);
47
- properties = {...properties, ...merged.mergedProperties};
48
- extendsInterfaces = merged.extendsInterfaces;
49
- }
50
-
51
- // Обработка oneOf
52
- if (schema.oneOf) {
53
- const unionTypes = processOneOf(schema.oneOf, schemaRefs, usedInterfaces);
54
- extendsInterfaces.push(...unionTypes);
55
- }
56
-
57
- const props = [];
58
-
59
- for (const [propName, propDetails] of Object.entries(properties)) {
60
- const tsType = resolveType(propDetails, schemaRefs, usedInterfaces);
61
- props.push(` ${propName}: ${tsType};`);
62
- }
63
-
64
- // Определяем базовый путь для импорта интерфейсов
65
- const interfaceImportPath = config?.outputDir
66
- ? path.relative(path.join(config.outputDir, 'interfaces'), config.outputDir)
67
- : './';
68
-
69
- const imports = Array.from(usedInterfaces)
70
- .sort()
71
- .map((interfaceName) => `import { ${interfaceName} } from '${interfaceImportPath}';`)
72
- .join("\n");
73
-
74
- const extendsClause = extendsInterfaces.length
75
- ? ` extends ${extendsInterfaces.join(", ")}`
76
- : "";
77
-
78
- return `${imports}\n\nexport interface ${capitalizeOnlyFirst(name)}${extendsClause} {\n${props.join("\n")}\n}\n`;
79
- }
80
-
81
- module.exports = {generateInterface};
@@ -1,136 +0,0 @@
1
- const {resolveType} = require("../resolve-type/resolveType");
2
-
3
- /**
4
- * Функция для генерации JSDoc на основе массива объектов
5
- * @param {object} method - объект метода
6
- * @returns {string} - JSDoc строка
7
- */
8
- function generateJSDoc(method) {
9
-
10
- let valueArg = ""
11
-
12
- let formDataArg = ""
13
-
14
- const params = method.parameters || [];
15
-
16
- const summary = method.summary || "";
17
-
18
- const docLines = [`/**`];
19
-
20
- if (method.requestBody) {
21
- const content = method.requestBody.content || {};
22
- if (content["application/json"]) {
23
- const schema = content["application/json"].schema || {};
24
- if (schema.oneOf) {
25
- valueArg = schema.oneOf.map(s => s.$ref.split("/").pop()).join(' | ');
26
- } else if (schema.$ref) {
27
- const refName = schema.$ref.split("/").pop();
28
- if (!!refName) {
29
- valueArg = refName
30
- }
31
- }
32
- }
33
- if (content["multipart/form-data"]) {
34
- formDataArg = 'FormData'
35
- }
36
- }
37
-
38
- if (!!summary) {
39
- docLines.push(` * @description ${summary}`);
40
- }
41
-
42
- if (!!formDataArg) {
43
- docLines.push(` * @param {${formDataArg}} data - тело запроса`)
44
- }
45
-
46
- if (!!valueArg) {
47
- docLines.push(` * @param {${valueArg}} values - тело запроса`)
48
- }
49
-
50
- const queryParams = {}; // Хранилище для параметров с in: 'query'
51
- const otherParams = []; // Хранилище для всех остальных параметров
52
-
53
- // Разделение параметров на query и остальные
54
- params.forEach((param) => {
55
- if (param.in === "query") {
56
- if (param.name.includes(".")) {
57
- const [objectName, propertyName] = param.name.split(".");
58
- if (!queryParams[objectName]) {
59
- queryParams[objectName] = [];
60
- }
61
- queryParams[objectName].push({
62
- propertyName,
63
- description: param.description || "",
64
- type: param.schema.type || "string",
65
- required: param.required || false,
66
- });
67
- } else {
68
- if (!queryParams[param.name]) {
69
- queryParams[param.name] = [];
70
- }
71
- queryParams[param.name].push({
72
- description: param.description || "",
73
- type: param.schema.type || "string",
74
- required: param.required || false,
75
- });
76
- }
77
- } else {
78
- otherParams.push({
79
- name: param.name,
80
- description: param.description || "",
81
- type: param.schema.type || "string",
82
- required: param.required || false,
83
- });
84
- }
85
- });
86
-
87
- // Добавляем queryParams в JSDoc
88
- if (Object.keys(queryParams).length > 0) {
89
- docLines.push(` * @param {object} queryParams`);
90
- Object.keys(queryParams).forEach((key) => {
91
- const group = queryParams[key];
92
- // Сортировка: сначала обязательные параметры
93
- const sortedGroup = group.sort(
94
- (a, b) => (b.required ? 1 : 0) - (a.required ? 1 : 0)
95
- );
96
- if (
97
- sortedGroup.length === 1 &&
98
- sortedGroup[0].propertyName === undefined
99
- ) {
100
- // Одиночный параметр без вложенности
101
- const param = sortedGroup[0];
102
- const jsType = param.type === "integer" ? "number" : param.type;
103
- docLines.push(
104
- ` * @param {${jsType}} queryParams.${key} - ${param.description}`
105
- );
106
- } else {
107
- // Вложенные параметры
108
- docLines.push(
109
- ` * @param {object} queryParams.${key} - Query parameter`
110
- );
111
- sortedGroup.forEach((subParam) => {
112
- const {propertyName, description, type} = subParam;
113
- const jsType = type === "integer" ? "number" : type;
114
- docLines.push(
115
- ` * @param {${jsType}} queryParams.${key}.${propertyName} - ${description}`
116
- );
117
- });
118
- }
119
- });
120
- }
121
-
122
- // Сортировка других параметров: сначала обязательные
123
- const sortedOtherParams = otherParams.sort(
124
- (a, b) => (b.required ? 1 : 0) - (a.required ? 1 : 0)
125
- );
126
- sortedOtherParams.forEach((param) => {
127
- const jsType = param.type === "integer" ? "number" : param.type;
128
- docLines.push(` * @param {${jsType}} ${param.name} - ${param.description}`);
129
- });
130
-
131
- docLines.push(` * @param {AxiosRequestConfig} config - Конфигурация axios`);
132
- docLines.push(` */`);
133
- return docLines.join("\n");
134
- }
135
-
136
- module.exports = {generateJSDoc};
@@ -1,21 +0,0 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- /**
5
- * Генерирует главный `index.ts` файл в указанной папке, экспортирующий `openapi.ts` из интерфейсов и классов.
6
- * @param {string} outputDir - Корневая папка, где будет создан `index.ts`.
7
- */
8
- function generateMainIndexFile(outputDir) {
9
- const indexFilePath = path.join(outputDir, "index.ts");
10
- const exports = [
11
- "export * from './interfaces/';",
12
- "export * from './classes/';",
13
- ];
14
-
15
- // Создание или перезапись index.ts
16
- fs.writeFileSync(indexFilePath, exports.join("\n"), {encoding: "utf-8"});
17
-
18
- console.log(`Generated main index.ts at ${indexFilePath}.`);
19
- }
20
-
21
- module.exports = {generateMainIndexFile};