@goast/core 0.2.2 → 0.3.1
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 +65 -11
- package/cjs/lib/codegen/config.js +5 -1
- package/cjs/lib/codegen/generator.js +28 -35
- package/cjs/lib/codegen/internal-utils.js +1 -2
- package/cjs/lib/collect/collector.js +1 -2
- package/cjs/lib/collect/helpers.js +2 -3
- package/cjs/lib/internal-utils.js +1 -2
- package/cjs/lib/parse/deref-proxy.js +1 -2
- package/cjs/lib/parse/parser.js +114 -126
- package/cjs/lib/transform/helpers.js +10 -10
- package/cjs/lib/transform/transform-document.js +5 -3
- package/cjs/lib/transform/transform-endpoint.js +35 -10
- package/cjs/lib/transform/transform-schema.js +5 -3
- package/cjs/lib/transform/transformer.js +1 -2
- package/cjs/lib/utils/array.utils.js +1 -2
- package/cjs/lib/utils/class.utils.js +3 -4
- package/cjs/lib/utils/common.utils.js +12 -13
- package/cjs/lib/utils/condition.js +1 -2
- package/cjs/lib/utils/endpoint.utils.js +1 -2
- package/cjs/lib/utils/error.utils.js +1 -2
- package/cjs/lib/utils/file-system.utils.js +21 -26
- package/cjs/lib/utils/generator.utils.js +1 -2
- package/cjs/lib/utils/object.utils.js +1 -2
- package/cjs/lib/utils/schema.utils.js +12 -4
- package/cjs/lib/utils/source-builder.js +5 -3
- package/cjs/lib/utils/string-builder/options.js +3 -0
- package/cjs/lib/utils/string-builder/string-builder.js +1 -1
- package/cjs/lib/utils/string-builder/utils.js +5 -6
- package/cjs/lib/utils/string.utils.js +27 -28
- package/cjs/lib/utils/type.utils.js +2 -3
- package/esm/lib/codegen/config.js +5 -1
- package/esm/lib/codegen/generator.js +28 -35
- package/esm/lib/parse/parser.js +114 -127
- package/esm/lib/transform/transform-document.js +4 -1
- package/esm/lib/transform/transform-endpoint.js +34 -8
- package/esm/lib/transform/transform-schema.js +4 -1
- package/esm/lib/utils/file-system.utils.js +19 -24
- package/esm/lib/utils/schema.utils.js +10 -1
- package/esm/lib/utils/source-builder.js +6 -4
- package/esm/lib/utils/string-builder/options.js +3 -0
- package/esm/lib/utils/string-builder/string-builder.js +1 -1
- package/esm/lib/utils/string.utils.js +7 -7
- package/package.json +16 -5
- package/types/lib/codegen/config.d.ts +8 -0
- package/types/lib/utils/source-builder.d.ts +11 -1
- package/types/lib/utils/string-builder/options.d.ts +8 -2
- package/types/lib/utils/string.utils.types.d.ts +1 -0
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.adjustCasing = adjustCasing;
|
|
4
|
+
exports.lowercase = lowercase;
|
|
5
|
+
exports.uppercase = uppercase;
|
|
6
|
+
exports.capitalize = capitalize;
|
|
7
|
+
exports.uncapitalize = uncapitalize;
|
|
8
|
+
exports.getWords = getWords;
|
|
9
|
+
exports.wordToCasing = wordToCasing;
|
|
10
|
+
exports.toCasing = toCasing;
|
|
11
|
+
exports.toCamelCase = toCamelCase;
|
|
12
|
+
exports.toPascalCase = toPascalCase;
|
|
13
|
+
exports.toKebabCase = toKebabCase;
|
|
14
|
+
exports.toSnakeCase = toSnakeCase;
|
|
15
|
+
exports.toCustomCase = toCustomCase;
|
|
16
|
+
exports.escapeRegExp = escapeRegExp;
|
|
17
|
+
exports.spliceString = spliceString;
|
|
18
|
+
exports.trimIndent = trimIndent;
|
|
19
|
+
exports.trimEnd = trimEnd;
|
|
20
|
+
exports.trimStart = trimStart;
|
|
21
|
+
exports.trim = trim;
|
|
22
|
+
exports.removeStr = removeStr;
|
|
4
23
|
const common_utils_1 = require("./common.utils");
|
|
5
24
|
function adjustCasing(a, b) {
|
|
6
25
|
if (typeof a === 'string') {
|
|
@@ -8,33 +27,28 @@ function adjustCasing(a, b) {
|
|
|
8
27
|
return b;
|
|
9
28
|
}
|
|
10
29
|
else {
|
|
11
|
-
return
|
|
30
|
+
return { casing: a, ...b };
|
|
12
31
|
}
|
|
13
32
|
}
|
|
14
33
|
else if (typeof b === 'string') {
|
|
15
|
-
return
|
|
34
|
+
return { ...a, casing: b };
|
|
16
35
|
}
|
|
17
36
|
else {
|
|
18
|
-
return
|
|
37
|
+
return { ...a, ...b };
|
|
19
38
|
}
|
|
20
39
|
}
|
|
21
|
-
exports.adjustCasing = adjustCasing;
|
|
22
40
|
function lowercase(str) {
|
|
23
41
|
return str.toLowerCase();
|
|
24
42
|
}
|
|
25
|
-
exports.lowercase = lowercase;
|
|
26
43
|
function uppercase(str) {
|
|
27
44
|
return str.toUpperCase();
|
|
28
45
|
}
|
|
29
|
-
exports.uppercase = uppercase;
|
|
30
46
|
function capitalize(str) {
|
|
31
47
|
return (str.charAt(0).toUpperCase() + str.slice(1));
|
|
32
48
|
}
|
|
33
|
-
exports.capitalize = capitalize;
|
|
34
49
|
function uncapitalize(str) {
|
|
35
50
|
return (str.charAt(0).toLowerCase() + str.slice(1));
|
|
36
51
|
}
|
|
37
|
-
exports.uncapitalize = uncapitalize;
|
|
38
52
|
/**
|
|
39
53
|
* Gets the words from a string. Words are separated by capital letters. Leading numbers are removed. Non-alphanumerical characters are removed and interpreted as word seperators. Multiple uppercase letters are interpreted as one word.
|
|
40
54
|
* @param str The string to get the words from.
|
|
@@ -56,7 +70,6 @@ function getWords(str) {
|
|
|
56
70
|
// Split into words
|
|
57
71
|
return (_a = str.match(/[A-Z]{2,}(?=[A-Z0-9-]|$)|[a-zA-Z][a-z]*|[0-9]+/g)) !== null && _a !== void 0 ? _a : [];
|
|
58
72
|
}
|
|
59
|
-
exports.getWords = getWords;
|
|
60
73
|
/**
|
|
61
74
|
* Converts a word to a given casing.
|
|
62
75
|
* @param str The word to convert.
|
|
@@ -102,7 +115,6 @@ function wordToCasing(str, casing) {
|
|
|
102
115
|
.join('');
|
|
103
116
|
}
|
|
104
117
|
}
|
|
105
|
-
exports.wordToCasing = wordToCasing;
|
|
106
118
|
function toCasing(str, casing) {
|
|
107
119
|
let options;
|
|
108
120
|
let casingType;
|
|
@@ -128,7 +140,6 @@ function toCasing(str, casing) {
|
|
|
128
140
|
return wordToCasing(getWords(str).join(''), casingType);
|
|
129
141
|
}
|
|
130
142
|
}
|
|
131
|
-
exports.toCasing = toCasing;
|
|
132
143
|
function addPrefixAndSuffix(str, { prefix, suffix }) {
|
|
133
144
|
if (prefix) {
|
|
134
145
|
str = prefix + str;
|
|
@@ -151,7 +162,7 @@ function addPrefixAndSuffix(str, { prefix, suffix }) {
|
|
|
151
162
|
* toCamelCase('Foo bAR', { suffix: 'bar' }) // => 'fooBarbar'
|
|
152
163
|
*/
|
|
153
164
|
function toCamelCase(str, options) {
|
|
154
|
-
const opts =
|
|
165
|
+
const opts = { keepOriginalCase: false, ...options };
|
|
155
166
|
const words = getWords(str);
|
|
156
167
|
const camelCase = words
|
|
157
168
|
.map((word, index) => index === 0
|
|
@@ -160,7 +171,6 @@ function toCamelCase(str, options) {
|
|
|
160
171
|
.join('');
|
|
161
172
|
return addPrefixAndSuffix(camelCase, opts);
|
|
162
173
|
}
|
|
163
|
-
exports.toCamelCase = toCamelCase;
|
|
164
174
|
/**
|
|
165
175
|
* Converts a string to pascal case.
|
|
166
176
|
* @param str The string to convert.
|
|
@@ -174,14 +184,13 @@ exports.toCamelCase = toCamelCase;
|
|
|
174
184
|
* toPascalCase('foo bAR', { suffix: 'bar' }) // => 'FooBarbar'
|
|
175
185
|
*/
|
|
176
186
|
function toPascalCase(str, options) {
|
|
177
|
-
const opts =
|
|
187
|
+
const opts = { keepOriginalCase: false, ...options };
|
|
178
188
|
const words = getWords(str);
|
|
179
189
|
const pascalCase = words
|
|
180
190
|
.map((word) => wordToCasing(word, opts.keepOriginalCase ? 'first-upper' : 'first-upper-then-lower'))
|
|
181
191
|
.join('');
|
|
182
192
|
return addPrefixAndSuffix(pascalCase, opts);
|
|
183
193
|
}
|
|
184
|
-
exports.toPascalCase = toPascalCase;
|
|
185
194
|
/**
|
|
186
195
|
* Converts a string to kebab case.
|
|
187
196
|
* @param str The string to convert.
|
|
@@ -196,14 +205,13 @@ exports.toPascalCase = toPascalCase;
|
|
|
196
205
|
* toKebabCase('Foo bAR', { suffix: 'bar' }) // => 'foo-barbar'
|
|
197
206
|
*/
|
|
198
207
|
function toKebabCase(str, options) {
|
|
199
|
-
const opts =
|
|
208
|
+
const opts = { wordCasing: 'all-lower', ...options };
|
|
200
209
|
const words = getWords(str);
|
|
201
210
|
const kebabCase = words
|
|
202
211
|
.map((word, index) => { var _a; return index === 0 ? wordToCasing(word, (_a = opts.firstWordCasing) !== null && _a !== void 0 ? _a : opts.wordCasing) : wordToCasing(word, opts.wordCasing); })
|
|
203
212
|
.join('-');
|
|
204
213
|
return addPrefixAndSuffix(kebabCase, opts);
|
|
205
214
|
}
|
|
206
|
-
exports.toKebabCase = toKebabCase;
|
|
207
215
|
/**
|
|
208
216
|
* Converts a string to snake case.
|
|
209
217
|
* @param str The string to convert.
|
|
@@ -218,14 +226,13 @@ exports.toKebabCase = toKebabCase;
|
|
|
218
226
|
* toSnakeCase('Foo bAR', { suffix: 'bar' }) // => 'FOO_BARbar'
|
|
219
227
|
*/
|
|
220
228
|
function toSnakeCase(str, options) {
|
|
221
|
-
const opts =
|
|
229
|
+
const opts = { wordCasing: 'all-upper', ...options };
|
|
222
230
|
const words = getWords(str);
|
|
223
231
|
const snakeCase = words
|
|
224
232
|
.map((word, index) => { var _a; return index === 0 ? wordToCasing(word, (_a = opts.firstWordCasing) !== null && _a !== void 0 ? _a : opts.wordCasing) : wordToCasing(word, opts.wordCasing); })
|
|
225
233
|
.join('_');
|
|
226
234
|
return addPrefixAndSuffix(snakeCase, opts);
|
|
227
235
|
}
|
|
228
|
-
exports.toSnakeCase = toSnakeCase;
|
|
229
236
|
/**
|
|
230
237
|
* Converts a string to a custom case.
|
|
231
238
|
* @param str The string to convert.
|
|
@@ -253,7 +260,6 @@ function toCustomCase(str, options) {
|
|
|
253
260
|
const customCase = words.map(wordMapFn).join((_a = options.wordSeparator) !== null && _a !== void 0 ? _a : '');
|
|
254
261
|
return addPrefixAndSuffix(customCase, options);
|
|
255
262
|
}
|
|
256
|
-
exports.toCustomCase = toCustomCase;
|
|
257
263
|
/**
|
|
258
264
|
* Escapes a string to be used in a regular expression.
|
|
259
265
|
* @param str The string to escape.
|
|
@@ -261,7 +267,6 @@ exports.toCustomCase = toCustomCase;
|
|
|
261
267
|
function escapeRegExp(str) {
|
|
262
268
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
263
269
|
}
|
|
264
|
-
exports.escapeRegExp = escapeRegExp;
|
|
265
270
|
/**
|
|
266
271
|
* Removes characters from a string and, if necessary, inserts new characters in their place, returning the spliced string.
|
|
267
272
|
* @param str The string to splice.
|
|
@@ -273,7 +278,6 @@ exports.escapeRegExp = escapeRegExp;
|
|
|
273
278
|
function spliceString(str, start, deleteCount, insert) {
|
|
274
279
|
return str.slice(0, start) + insert + str.slice(start + deleteCount);
|
|
275
280
|
}
|
|
276
|
-
exports.spliceString = spliceString;
|
|
277
281
|
/**
|
|
278
282
|
* Removes leading indentation based on the last line. Also removes the first line if it is empty.
|
|
279
283
|
* @param str The string to trim.
|
|
@@ -285,7 +289,6 @@ function trimIndent(str) {
|
|
|
285
289
|
return str;
|
|
286
290
|
return str.replace(/^\r?\n/, '').replace(new RegExp(`^ {0,${indent.length}}`, 'gm'), '');
|
|
287
291
|
}
|
|
288
|
-
exports.trimIndent = trimIndent;
|
|
289
292
|
function isNonLineBreakWhitespaceChar(char) {
|
|
290
293
|
return (char === ' ' ||
|
|
291
294
|
char === '\t' ||
|
|
@@ -319,7 +322,6 @@ function trimEnd(str, includeNewLine = true) {
|
|
|
319
322
|
;
|
|
320
323
|
return str.substring(0, i);
|
|
321
324
|
}
|
|
322
|
-
exports.trimEnd = trimEnd;
|
|
323
325
|
function trimStart(str, includeNewLine = true) {
|
|
324
326
|
if (includeNewLine)
|
|
325
327
|
return str.trimStart();
|
|
@@ -328,7 +330,6 @@ function trimStart(str, includeNewLine = true) {
|
|
|
328
330
|
;
|
|
329
331
|
return str.substring(i);
|
|
330
332
|
}
|
|
331
|
-
exports.trimStart = trimStart;
|
|
332
333
|
function trim(str, includeNewLine = true) {
|
|
333
334
|
if (includeNewLine)
|
|
334
335
|
return str.trim();
|
|
@@ -340,7 +341,6 @@ function trim(str, includeNewLine = true) {
|
|
|
340
341
|
;
|
|
341
342
|
return str.substring(s, e);
|
|
342
343
|
}
|
|
343
|
-
exports.trim = trim;
|
|
344
344
|
function removeStr(str, rem) {
|
|
345
345
|
let i = str.indexOf(rem);
|
|
346
346
|
if (i === -1)
|
|
@@ -354,4 +354,3 @@ function removeStr(str, rem) {
|
|
|
354
354
|
}
|
|
355
355
|
return result + str.substring(s);
|
|
356
356
|
}
|
|
357
|
-
exports.removeStr = removeStr;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.stringUnionToArray = stringUnionToArray;
|
|
4
|
+
exports.suggestionsAsString = suggestionsAsString;
|
|
4
5
|
function stringUnionToArray() {
|
|
5
6
|
return (...elements) => elements;
|
|
6
7
|
}
|
|
7
|
-
exports.stringUnionToArray = stringUnionToArray;
|
|
8
8
|
function suggestionsAsString(value) {
|
|
9
9
|
return value;
|
|
10
10
|
}
|
|
11
|
-
exports.suggestionsAsString = suggestionsAsString;
|
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
import { defaultSourceBuilderOptions } from '../utils/source-builder';
|
|
2
|
-
export const defaultOpenApiGeneratorConfig =
|
|
2
|
+
export const defaultOpenApiGeneratorConfig = {
|
|
3
|
+
...defaultSourceBuilderOptions,
|
|
4
|
+
outputDir: 'generated',
|
|
5
|
+
clearOutputDir: true,
|
|
6
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { __awaiter } from "tslib";
|
|
2
1
|
import { resolve } from 'path';
|
|
3
2
|
import { emptyDir, ensureDir } from 'fs-extra';
|
|
4
3
|
import { defaultOpenApiGeneratorConfig } from './config';
|
|
@@ -24,46 +23,40 @@ class _OpenApiGenerator {
|
|
|
24
23
|
useValue(value, config) {
|
|
25
24
|
return this.use(ActionProvider.fromValue(value, 'generate'), config);
|
|
26
25
|
}
|
|
27
|
-
generate(data) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
input = mergeDeep(input, result);
|
|
46
|
-
}
|
|
26
|
+
async generate(data) {
|
|
27
|
+
const absOutputPath = resolve(this._config.outputDir);
|
|
28
|
+
if (this._config.clearOutputDir) {
|
|
29
|
+
await emptyDir(absOutputPath);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
await ensureDir(absOutputPath);
|
|
33
|
+
}
|
|
34
|
+
let input = {};
|
|
35
|
+
for (const generator of this._providers) {
|
|
36
|
+
const context = {
|
|
37
|
+
data,
|
|
38
|
+
input,
|
|
39
|
+
config: this._config,
|
|
40
|
+
};
|
|
41
|
+
const result = generator.provider.run(context, generator.config);
|
|
42
|
+
if (result) {
|
|
43
|
+
input = mergeDeep(input, result);
|
|
47
44
|
}
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
}
|
|
46
|
+
return input;
|
|
50
47
|
}
|
|
51
|
-
parseAndGenerate(...fileNames) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return yield this.generate(data);
|
|
55
|
-
});
|
|
48
|
+
async parseAndGenerate(...fileNames) {
|
|
49
|
+
const data = await this._parser.parseApisAndTransform(...fileNames);
|
|
50
|
+
return await this.generate(data);
|
|
56
51
|
}
|
|
57
|
-
parseAndGenerateFromDir(dir, options) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return this.parseAndGenerate(...(yield getFiles(dir, Object.assign(Object.assign({}, options), { filter }))));
|
|
61
|
-
});
|
|
52
|
+
async parseAndGenerateFromDir(dir, options) {
|
|
53
|
+
const filter = (file) => { var _a, _b; return (file.endsWith('.yml') || file.endsWith('.yaml') || file.endsWith('.json')) && ((_b = (_a = options === null || options === void 0 ? void 0 : options.filter) === null || _a === void 0 ? void 0 : _a.call(options, file)) !== null && _b !== void 0 ? _b : true); };
|
|
54
|
+
return this.parseAndGenerate(...(await getFiles(dir, { ...options, filter })));
|
|
62
55
|
}
|
|
63
56
|
}
|
|
64
57
|
export class OpenApiGenerator extends _OpenApiGenerator {
|
|
65
58
|
constructor(config) {
|
|
66
|
-
super(
|
|
59
|
+
super({ ...defaultOpenApiGeneratorConfig, ...config }, [], new OpenApiParser());
|
|
67
60
|
}
|
|
68
61
|
}
|
|
69
62
|
function mergeDeep(target, ...sources) {
|
|
@@ -96,7 +89,7 @@ export class OpenApiGenerationProviderBase {
|
|
|
96
89
|
return this.onGenerate(ctx);
|
|
97
90
|
}
|
|
98
91
|
getProviderContext(context, config, defaultConfig) {
|
|
99
|
-
const c =
|
|
92
|
+
const c = { ...context.config, ...defaultConfig, ...config };
|
|
100
93
|
return Object.assign(context, {
|
|
101
94
|
config: c,
|
|
102
95
|
});
|
package/esm/lib/parse/parser.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { __awaiter } from "tslib";
|
|
2
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
2
|
import path from 'path';
|
|
4
3
|
import { cwd } from 'process';
|
|
@@ -13,150 +12,138 @@ export class OpenApiParser {
|
|
|
13
12
|
constructor() {
|
|
14
13
|
this._loadedDocuments = new Map();
|
|
15
14
|
}
|
|
16
|
-
parseApisAndTransform(...fileNames) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return transformed;
|
|
22
|
-
});
|
|
15
|
+
async parseApisAndTransform(...fileNames) {
|
|
16
|
+
const flatFileNames = [].concat(...fileNames);
|
|
17
|
+
const apis = await Promise.all(flatFileNames.map((fileName) => this.parseApi(fileName)));
|
|
18
|
+
const transformed = this.transformApis(apis);
|
|
19
|
+
return transformed;
|
|
23
20
|
}
|
|
24
|
-
parseApi(fileName) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return yield this.dereference(absoluteFilePath, '', doc.document);
|
|
29
|
-
});
|
|
21
|
+
async parseApi(fileName) {
|
|
22
|
+
const absoluteFilePath = this.isUrl(fileName) ? fileName : path.resolve(cwd(), fileName);
|
|
23
|
+
const doc = await this.loadDocument(absoluteFilePath);
|
|
24
|
+
return await this.dereference(absoluteFilePath, '', doc.document);
|
|
30
25
|
}
|
|
31
26
|
transformApis(apis) {
|
|
32
27
|
const collectedData = collectOpenApi(apis);
|
|
33
28
|
const transformedData = transformOpenApi(collectedData);
|
|
34
29
|
return transformedData;
|
|
35
30
|
}
|
|
36
|
-
dereference(file, path, value) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return existingComponent;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
existingDocument = yield this.loadDocument(file);
|
|
47
|
-
}
|
|
48
|
-
const result = createDerefProxy(value, {
|
|
49
|
-
file,
|
|
50
|
-
path,
|
|
51
|
-
document: existingDocument.dereferencedDocument,
|
|
52
|
-
originalComponent: value,
|
|
53
|
-
});
|
|
54
|
-
existingDocument.dereferencedComponents.set(path, result);
|
|
55
|
-
if (value.$ref) {
|
|
56
|
-
result.$ref = (yield this.resolveReference(file, value));
|
|
31
|
+
async dereference(file, path, value) {
|
|
32
|
+
let existingDocument = this._loadedDocuments.get(file);
|
|
33
|
+
if (existingDocument) {
|
|
34
|
+
const existingComponent = existingDocument.dereferencedComponents.get(path);
|
|
35
|
+
if (existingComponent) {
|
|
36
|
+
return existingComponent;
|
|
57
37
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
existingDocument = await this.loadDocument(file);
|
|
41
|
+
}
|
|
42
|
+
const result = createDerefProxy(value, {
|
|
43
|
+
file,
|
|
44
|
+
path,
|
|
45
|
+
document: existingDocument.dereferencedDocument,
|
|
46
|
+
originalComponent: value,
|
|
47
|
+
});
|
|
48
|
+
existingDocument.dereferencedComponents.set(path, result);
|
|
49
|
+
if (value.$ref) {
|
|
50
|
+
result.$ref = (await this.resolveReference(file, value));
|
|
51
|
+
}
|
|
52
|
+
for (const key of Object.keys(value)) {
|
|
53
|
+
if (key === '$ref')
|
|
54
|
+
continue;
|
|
55
|
+
const v = value[key];
|
|
56
|
+
if (isNullish(v))
|
|
57
|
+
continue;
|
|
58
|
+
if (typeof v === 'object') {
|
|
59
|
+
if (Array.isArray(v)) {
|
|
60
|
+
result[key] = await Promise.all(v.map(async (v, index) => {
|
|
61
|
+
if (v && typeof v === 'object') {
|
|
62
|
+
return await this.dereference(file, `${path}/${String(key)}/${index}`, v);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
return v;
|
|
66
|
+
}
|
|
67
|
+
}));
|
|
78
68
|
}
|
|
79
|
-
|
|
80
|
-
result[key] =
|
|
69
|
+
else {
|
|
70
|
+
result[key] = await this.dereference(file, `${path}/${String(key)}`, v);
|
|
81
71
|
}
|
|
82
72
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
resolveReference(file, ref) {
|
|
87
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
-
const [refFile, refPath] = ref.$ref.split('#');
|
|
89
|
-
let absoluteRefFile = refFile;
|
|
90
|
-
if (!/\S/.test(refFile)) {
|
|
91
|
-
absoluteRefFile = file;
|
|
92
|
-
}
|
|
93
|
-
else if (!this.isUrl(refFile)) {
|
|
94
|
-
absoluteRefFile = path.resolve(path.dirname(file), refFile);
|
|
73
|
+
if (typeof v === 'string' && path.endsWith('/discriminator/mapping')) {
|
|
74
|
+
result[key] = await this.resolveReference(file, { $ref: v });
|
|
95
75
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (value && typeof value === 'object') {
|
|
99
|
-
return this.dereference(absoluteRefFile, refPath, value);
|
|
100
|
-
}
|
|
101
|
-
return undefined;
|
|
102
|
-
});
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
103
78
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
79
|
+
async resolveReference(file, ref) {
|
|
80
|
+
const [refFile, refPath] = ref.$ref.split('#');
|
|
81
|
+
let absoluteRefFile = refFile;
|
|
82
|
+
if (!/\S/.test(refFile)) {
|
|
83
|
+
absoluteRefFile = file;
|
|
84
|
+
}
|
|
85
|
+
else if (!this.isUrl(refFile)) {
|
|
86
|
+
absoluteRefFile = path.resolve(path.dirname(file), refFile);
|
|
87
|
+
}
|
|
88
|
+
const doc = await this.loadDocument(absoluteRefFile);
|
|
89
|
+
const value = getDeepProperty(doc.document, refPath.replace(/[/]/g, '.'));
|
|
90
|
+
if (value && typeof value === 'object') {
|
|
91
|
+
return this.dereference(absoluteRefFile, refPath, value);
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
async loadDocument(fileOrUrl) {
|
|
96
|
+
const existingDocument = this._loadedDocuments.get(fileOrUrl);
|
|
97
|
+
if (existingDocument) {
|
|
98
|
+
return existingDocument;
|
|
99
|
+
}
|
|
100
|
+
const documentContent = await this.getDocumentContent(fileOrUrl);
|
|
101
|
+
const extname = path.extname(fileOrUrl).toLowerCase();
|
|
102
|
+
let parsedDocument;
|
|
103
|
+
if (extname === '.json') {
|
|
104
|
+
parsedDocument = this.tryParseJson(documentContent);
|
|
105
|
+
}
|
|
106
|
+
else if (extname === '.yaml' || extname === '.yml') {
|
|
107
|
+
parsedDocument = this.tryParseYaml(documentContent);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
parsedDocument = this.tryParseJson(documentContent);
|
|
111
|
+
if (parsedDocument !== undefined) {
|
|
117
112
|
parsedDocument = this.tryParseYaml(documentContent);
|
|
118
113
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
file: fileOrUrl,
|
|
131
|
-
path: '',
|
|
132
|
-
originalComponent: doc,
|
|
133
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
134
|
-
document: undefined,
|
|
135
|
-
});
|
|
136
|
-
deref.$src.document = deref;
|
|
137
|
-
const loadedDocument = {
|
|
138
|
-
file: fileOrUrl,
|
|
139
|
-
document: doc,
|
|
140
|
-
dereferencedDocument: deref,
|
|
141
|
-
dereferencedComponents: new Map(),
|
|
142
|
-
};
|
|
143
|
-
this._loadedDocuments.set(fileOrUrl, loadedDocument);
|
|
144
|
-
return loadedDocument;
|
|
114
|
+
}
|
|
115
|
+
if (parsedDocument === undefined) {
|
|
116
|
+
throw new Error(`Unable to parse ${fileOrUrl}`);
|
|
117
|
+
}
|
|
118
|
+
const doc = (parsedDocument !== null && parsedDocument !== void 0 ? parsedDocument : {});
|
|
119
|
+
const deref = createDerefProxy(doc, {
|
|
120
|
+
file: fileOrUrl,
|
|
121
|
+
path: '',
|
|
122
|
+
originalComponent: doc,
|
|
123
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
124
|
+
document: undefined,
|
|
145
125
|
});
|
|
126
|
+
deref.$src.document = deref;
|
|
127
|
+
const loadedDocument = {
|
|
128
|
+
file: fileOrUrl,
|
|
129
|
+
document: doc,
|
|
130
|
+
dereferencedDocument: deref,
|
|
131
|
+
dereferencedComponents: new Map(),
|
|
132
|
+
};
|
|
133
|
+
this._loadedDocuments.set(fileOrUrl, loadedDocument);
|
|
134
|
+
return loadedDocument;
|
|
146
135
|
}
|
|
147
|
-
getDocumentContent(fileOrUrl) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
throw new Error(`Unable to download ${fileOrUrl}: ${res.statusText}`);
|
|
153
|
-
}
|
|
154
|
-
return yield res.text();
|
|
136
|
+
async getDocumentContent(fileOrUrl) {
|
|
137
|
+
if (this.isUrl(fileOrUrl)) {
|
|
138
|
+
const res = await nodeFetch(fileOrUrl);
|
|
139
|
+
if (!res.ok) {
|
|
140
|
+
throw new Error(`Unable to download ${fileOrUrl}: ${res.statusText}`);
|
|
155
141
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
142
|
+
return await res.text();
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
return (await fs.readFile(fileOrUrl)).toString();
|
|
146
|
+
}
|
|
160
147
|
}
|
|
161
148
|
isUrl(fileOrUrl) {
|
|
162
149
|
return /^https?:\/\//i.test(fileOrUrl);
|
|
@@ -14,7 +14,10 @@ function transformTag(context, tag, isReference = false) {
|
|
|
14
14
|
const ref = tag.$ref ? transformTag(context, tag.$ref, true) : undefined;
|
|
15
15
|
const id = context.idGenerator.generateId('service');
|
|
16
16
|
const service = {
|
|
17
|
-
$src:
|
|
17
|
+
$src: {
|
|
18
|
+
...tag.$src,
|
|
19
|
+
component: tag,
|
|
20
|
+
},
|
|
18
21
|
$ref: ref,
|
|
19
22
|
id,
|
|
20
23
|
name: (_a = tag.name) !== null && _a !== void 0 ? _a : id,
|