@paulpugovkin/api-docs-axios-ts-generator 1.1.0 → 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/README.md +237 -495
- package/dist/index.js +78 -0
- package/package.json +11 -22
- package/bin/cli.js +0 -6
- package/src/clean-generated-folder/cleanGeneratedFolder.js +0 -21
- package/src/collect-genereted-files/collectGeneratedFiles.js +0 -33
- package/src/generate-class/generateClass.js +0 -42
- package/src/generate-index-file-with-public-api/generateIndexFileWithPublicApi.js +0 -45
- package/src/generate-interface/generateInterface.js +0 -81
- package/src/generate-js-doc/generateJSDoc.js +0 -136
- package/src/generate-main-index-file/generateMainIndexFile.js +0 -21
- package/src/generate-method/generateMethod.js +0 -264
- package/src/generators/axiosConfigGenerator.js +0 -79
- package/src/index.js +0 -187
- package/src/map-type/mapType.js +0 -19
- package/src/parse-and-generate/parseAndGenerate.js +0 -190
- package/src/resolve-type/resolveType.js +0 -54
- package/src/update-api-docs-json/updateApiDocsJson.js +0 -33
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const {
|
|
4
|
-
generateInterface,
|
|
5
|
-
} = require("../generate-interface/generateInterface");
|
|
6
|
-
const {generateMethod} = require("../generate-method/generateMethod");
|
|
7
|
-
const {generateClass} = require("../generate-class/generateClass");
|
|
8
|
-
|
|
9
|
-
// Проверяем и создаем директории
|
|
10
|
-
function ensureDir(dirPath) {
|
|
11
|
-
if (!fs.existsSync(dirPath)) {
|
|
12
|
-
fs.mkdirSync(dirPath, {recursive: true});
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Проверяем наличие тега с учётом префикса
|
|
17
|
-
function containsApiTag(array, config) {
|
|
18
|
-
const prefix = config?.tags?.prefix || "api_tag_";
|
|
19
|
-
|
|
20
|
-
for (const item of array) {
|
|
21
|
-
if (item.includes(prefix)) {
|
|
22
|
-
return item;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return "";
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Проверяем, проходит ли тег через фильтрацию
|
|
29
|
-
function isTagIncluded(tag, config) {
|
|
30
|
-
const {include, exclude, prefix} = config?.tags || {};
|
|
31
|
-
|
|
32
|
-
// Если указан список включения, проверяем, есть ли тег в нём
|
|
33
|
-
if (include && include.length > 0) {
|
|
34
|
-
return include.includes(tag);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Если указан список исключения, проверяем, что тег не в нём
|
|
38
|
-
if (exclude && exclude.length > 0) {
|
|
39
|
-
return !exclude.includes(tag);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Если нет фильтров, включаем все теги с нужным префиксом
|
|
43
|
-
const prefixToCheck = prefix || "api_tag_";
|
|
44
|
-
return tag.includes(prefixToCheck);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Группировка методов по тегам
|
|
48
|
-
function groupMethodsByTag(methods, config) {
|
|
49
|
-
const grouped = {};
|
|
50
|
-
const prefix = config?.tags?.prefix || "api_tag_";
|
|
51
|
-
|
|
52
|
-
for (const method of methods) {
|
|
53
|
-
if (!method.tag) continue;
|
|
54
|
-
|
|
55
|
-
// Применяем пользовательскую функцию именования, если есть
|
|
56
|
-
const groupName = config?.naming?.className
|
|
57
|
-
? config.naming.className(method.tag)
|
|
58
|
-
: method.tag.replace(prefix, "");
|
|
59
|
-
|
|
60
|
-
if (!grouped[groupName]) {
|
|
61
|
-
grouped[groupName] = [];
|
|
62
|
-
}
|
|
63
|
-
grouped[groupName].push(method);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return grouped;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Основная функция парсинга и генерации файлов
|
|
70
|
-
async function parseAndGenerate(jsonFile, config) {
|
|
71
|
-
const spec = JSON.parse(fs.readFileSync(jsonFile, {encoding: "utf-8"}));
|
|
72
|
-
|
|
73
|
-
// Определяем пути из конфигурации
|
|
74
|
-
const outputDir = config.outputDir || path.resolve(process.cwd(), "generated");
|
|
75
|
-
const interfacesDir = config.interfacesDir || path.join(outputDir, "interfaces");
|
|
76
|
-
const classesDir = config.classesDir || path.join(outputDir, "classes");
|
|
77
|
-
|
|
78
|
-
ensureDir(interfacesDir);
|
|
79
|
-
ensureDir(classesDir);
|
|
80
|
-
|
|
81
|
-
const schemaRefs = spec?.components?.schemas || {};
|
|
82
|
-
|
|
83
|
-
// Генерация интерфейсов
|
|
84
|
-
if (spec?.components?.schemas) {
|
|
85
|
-
for (const [schemaName, schema] of Object.entries(schemaRefs)) {
|
|
86
|
-
const interfaceCode = generateInterface(
|
|
87
|
-
schemaName,
|
|
88
|
-
schema,
|
|
89
|
-
schemaRefs,
|
|
90
|
-
config
|
|
91
|
-
);
|
|
92
|
-
fs.writeFileSync(
|
|
93
|
-
path.join(interfacesDir, `${schemaName}.ts`),
|
|
94
|
-
interfaceCode,
|
|
95
|
-
{encoding: "utf-8"}
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Сбор методов из спецификации
|
|
101
|
-
const allMethods = [];
|
|
102
|
-
|
|
103
|
-
if (spec?.paths) {
|
|
104
|
-
for (const [pathKey, methods] of Object.entries(spec.paths)) {
|
|
105
|
-
for (const [methodType, methodDetails] of Object.entries(methods)) {
|
|
106
|
-
if (methodDetails?.tags) {
|
|
107
|
-
const tag = containsApiTag(methodDetails.tags, config);
|
|
108
|
-
|
|
109
|
-
// Пропускаем методы без тега
|
|
110
|
-
if (!tag) continue;
|
|
111
|
-
|
|
112
|
-
// Проверяем фильтрацию по тегам
|
|
113
|
-
if (!isTagIncluded(tag, config)) continue;
|
|
114
|
-
|
|
115
|
-
allMethods.push({
|
|
116
|
-
operationId: methodDetails.operationId,
|
|
117
|
-
methodDetails,
|
|
118
|
-
pathKey,
|
|
119
|
-
methodType,
|
|
120
|
-
tag,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Определяем режим группировки
|
|
128
|
-
const groupBy = config.groupBy || "tag";
|
|
129
|
-
|
|
130
|
-
if (groupBy === "all" || config.classMode === "single") {
|
|
131
|
-
// Все методы в одном классе
|
|
132
|
-
const className = config?.naming?.className
|
|
133
|
-
? config.naming.className("all")
|
|
134
|
-
: "ApiClient";
|
|
135
|
-
|
|
136
|
-
const usedInterfaces = new Set();
|
|
137
|
-
const methodCodes = allMethods.map((method) =>
|
|
138
|
-
generateMethod(
|
|
139
|
-
method.operationId,
|
|
140
|
-
method.methodDetails,
|
|
141
|
-
method.pathKey,
|
|
142
|
-
method.methodType,
|
|
143
|
-
schemaRefs,
|
|
144
|
-
usedInterfaces,
|
|
145
|
-
config
|
|
146
|
-
)
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
const classCode = generateClass(className, methodCodes, usedInterfaces, config);
|
|
150
|
-
fs.writeFileSync(
|
|
151
|
-
path.join(classesDir, `${className}.ts`),
|
|
152
|
-
classCode,
|
|
153
|
-
{encoding: "utf-8"}
|
|
154
|
-
);
|
|
155
|
-
} else {
|
|
156
|
-
// Группировка по тегам
|
|
157
|
-
const groupedMethods = groupMethodsByTag(allMethods, config);
|
|
158
|
-
|
|
159
|
-
for (const [groupName, methods] of Object.entries(groupedMethods)) {
|
|
160
|
-
const usedInterfaces = new Set();
|
|
161
|
-
const methodCodes = methods.map((method) =>
|
|
162
|
-
generateMethod(
|
|
163
|
-
method.operationId,
|
|
164
|
-
method.methodDetails,
|
|
165
|
-
method.pathKey,
|
|
166
|
-
method.methodType,
|
|
167
|
-
schemaRefs,
|
|
168
|
-
usedInterfaces,
|
|
169
|
-
config
|
|
170
|
-
)
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
const className = config?.naming?.className
|
|
174
|
-
? config.naming.className(methods[0].tag)
|
|
175
|
-
: groupName + "Api";
|
|
176
|
-
|
|
177
|
-
const classCode = generateClass(className, methodCodes, usedInterfaces, config);
|
|
178
|
-
fs.writeFileSync(
|
|
179
|
-
path.join(classesDir, `${className}.ts`),
|
|
180
|
-
classCode,
|
|
181
|
-
{encoding: "utf-8"}
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
console.log(`Generated ${allMethods.length} API methods.`);
|
|
187
|
-
console.log(`Generated ${Object.keys(schemaRefs).length} interfaces.`);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
module.exports = {parseAndGenerate};
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
const { mapType } = require("../map-type/mapType");
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Определяет тип с учётом ссылок на другие интерфейсы и конструкций oneOf.
|
|
5
|
-
* @param {Object} propDetails - Детали свойства из OpenAPI.
|
|
6
|
-
* @param {Object<string, string>} schemaRefs - Ссылки на схемы.
|
|
7
|
-
* @param {Set<string>} usedInterfaces - Множество используемых интерфейсов.
|
|
8
|
-
* @returns {string} - Определённый тип TypeScript.
|
|
9
|
-
*/
|
|
10
|
-
function resolveType(propDetails, schemaRefs, usedInterfaces) {
|
|
11
|
-
// Обработка ссылок ($ref)
|
|
12
|
-
if (propDetails["$ref"]) {
|
|
13
|
-
const refPath = propDetails["$ref"];
|
|
14
|
-
const refName = refPath.split("/").pop();
|
|
15
|
-
usedInterfaces.add(refName);
|
|
16
|
-
return refName;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Обработка массивов (array)
|
|
20
|
-
if (propDetails.type === 'array') {
|
|
21
|
-
const itemType = resolveType(propDetails.items || {}, schemaRefs, usedInterfaces);
|
|
22
|
-
return `Array<${itemType}>`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Обработка объектов (object)
|
|
26
|
-
if (propDetails.type === 'object') {
|
|
27
|
-
if (propDetails.properties) {
|
|
28
|
-
return "{" + Object.entries(propDetails.properties)
|
|
29
|
-
.map(([key, value]) => `${key}: ${resolveType(value, schemaRefs, usedInterfaces)}`)
|
|
30
|
-
.join("; ") + "}";
|
|
31
|
-
}
|
|
32
|
-
return "Record<string, any>";
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Обработка перечислений (enum)
|
|
36
|
-
if (propDetails.enum) {
|
|
37
|
-
return propDetails.enum.map(value => `"${value}"`).join(" | ");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Обработка конструкции oneOf
|
|
41
|
-
if (propDetails.oneOf) {
|
|
42
|
-
const oneOfTypes = propDetails.oneOf.map(item => resolveType(item, schemaRefs, usedInterfaces));
|
|
43
|
-
return oneOfTypes.join(' | ');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Обработка простых типов (string, number и т.д.)
|
|
47
|
-
if (propDetails.type) {
|
|
48
|
-
return mapType(propDetails.type);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return "any"; // Если тип не определён
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
module.exports = { resolveType };
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const fetch = require("node-fetch");
|
|
3
|
-
const path = require("path");
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Загружает JSON по ссылке и сохраняет его локально.
|
|
7
|
-
* @param {string} url - URL для загрузки.
|
|
8
|
-
* @param {string} localFile - Путь для сохранения данных.
|
|
9
|
-
*/
|
|
10
|
-
async function updateApiDocsJson(url, localFile) {
|
|
11
|
-
try {
|
|
12
|
-
console.log(`Fetching API docs from: ${url}`);
|
|
13
|
-
const response = await fetch(url);
|
|
14
|
-
|
|
15
|
-
if (!response.ok) {
|
|
16
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const data = await response.json();
|
|
20
|
-
|
|
21
|
-
// Убедитесь, что директория для сохранения файла существует
|
|
22
|
-
fs.mkdirSync(path.dirname(localFile), {recursive: true});
|
|
23
|
-
fs.writeFileSync(localFile, JSON.stringify(data, null, 2), {
|
|
24
|
-
encoding: "utf-8",
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
console.log(`Updated and saved API docs to: ${localFile}`);
|
|
28
|
-
} catch (error) {
|
|
29
|
-
console.error(`Failed to fetch or save the OpenAPI docs: ${error.message}`);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
module.exports = {updateApiDocsJson};
|