@redocly/cli 1.0.0-beta.103 → 1.0.0-beta.106
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/bin/cli.js +1 -1
- package/lib/__mocks__/@redocly/openapi-core.d.ts +2 -1
- package/lib/__mocks__/@redocly/openapi-core.js +2 -1
- package/lib/__mocks__/perf_hooks.js +1 -1
- package/lib/__mocks__/utils.d.ts +1 -1
- package/lib/__mocks__/utils.js +2 -2
- package/lib/__tests__/commands/bundle.test.js +52 -17
- package/lib/__tests__/commands/join.test.js +4 -4
- package/lib/__tests__/commands/lint.test.js +14 -8
- package/lib/__tests__/commands/push-region.test.js +2 -2
- package/lib/__tests__/commands/push.test.js +18 -18
- package/lib/__tests__/fixtures/config.d.ts +1 -1
- package/lib/__tests__/fixtures/config.js +1 -1
- package/lib/commands/bundle.d.ts +4 -12
- package/lib/commands/bundle.js +12 -11
- package/lib/commands/join.d.ts +1 -1
- package/lib/commands/join.js +109 -58
- package/lib/commands/lint.d.ts +3 -9
- package/lib/commands/lint.js +14 -11
- package/lib/commands/preview-docs/index.d.ts +3 -5
- package/lib/commands/preview-docs/index.js +14 -14
- package/lib/commands/push.d.ts +6 -6
- package/lib/commands/push.js +26 -26
- package/lib/commands/split/__tests__/index.test.js +8 -8
- package/lib/commands/split/index.d.ts +1 -1
- package/lib/commands/split/index.js +12 -11
- package/lib/commands/split/types.d.ts +2 -2
- package/lib/commands/split/types.js +2 -2
- package/lib/commands/stats.d.ts +1 -1
- package/lib/commands/stats.js +9 -7
- package/lib/index.js +12 -16
- package/lib/js-utils.js +2 -2
- package/lib/types.d.ts +13 -1
- package/lib/utils.d.ts +4 -4
- package/lib/utils.js +15 -17
- package/package.json +2 -2
- package/src/__mocks__/@redocly/openapi-core.ts +1 -0
- package/src/__mocks__/perf_hooks.ts +2 -2
- package/src/__mocks__/utils.ts +3 -1
- package/src/__tests__/commands/bundle.test.ts +71 -22
- package/src/__tests__/commands/join.test.ts +8 -8
- package/src/__tests__/commands/lint.test.ts +24 -11
- package/src/__tests__/commands/push-region.test.ts +2 -2
- package/src/__tests__/commands/push.test.ts +19 -24
- package/src/__tests__/fixtures/config.ts +1 -1
- package/src/__tests__/utils.test.ts +5 -8
- package/src/commands/bundle.ts +28 -40
- package/src/commands/join.ts +213 -121
- package/src/commands/lint.ts +30 -30
- package/src/commands/login.ts +2 -2
- package/src/commands/preview-docs/index.ts +33 -40
- package/src/commands/preview-docs/preview-server/preview-server.ts +6 -6
- package/src/commands/preview-docs/preview-server/server.ts +1 -1
- package/src/commands/push.ts +44 -53
- package/src/commands/split/__tests__/index.test.ts +47 -30
- package/src/commands/split/index.ts +84 -46
- package/src/commands/split/types.ts +19 -7
- package/src/commands/stats.ts +27 -24
- package/src/index.ts +16 -20
- package/src/js-utils.ts +2 -2
- package/src/types.ts +14 -1
- package/src/utils.ts +53 -53
- package/tsconfig.tsbuildinfo +1 -1
package/src/commands/join.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
OasVersion,
|
|
9
9
|
BaseResolver,
|
|
10
10
|
Document,
|
|
11
|
-
|
|
11
|
+
StyleguideConfig,
|
|
12
12
|
Oas3Tag,
|
|
13
13
|
loadConfig,
|
|
14
14
|
formatProblems,
|
|
@@ -19,12 +19,12 @@ import {
|
|
|
19
19
|
} from '@redocly/openapi-core';
|
|
20
20
|
|
|
21
21
|
import {
|
|
22
|
-
|
|
22
|
+
getFallbackApisOrExit,
|
|
23
23
|
printExecutionTime,
|
|
24
24
|
handleError,
|
|
25
25
|
printLintTotals,
|
|
26
26
|
writeYaml,
|
|
27
|
-
exitWithError
|
|
27
|
+
exitWithError,
|
|
28
28
|
} from '../utils';
|
|
29
29
|
import { isObject, isString } from '../js-utils';
|
|
30
30
|
|
|
@@ -34,8 +34,8 @@ const xTagGroups = 'x-tagGroups';
|
|
|
34
34
|
let potentialConflictsTotal = 0;
|
|
35
35
|
|
|
36
36
|
type JoinDocumentContext = {
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
api: string;
|
|
38
|
+
apiFilename: string;
|
|
39
39
|
tags: Oas3Tag[];
|
|
40
40
|
potentialConflicts: any;
|
|
41
41
|
tagsPrefix: string;
|
|
@@ -43,7 +43,7 @@ type JoinDocumentContext = {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
type JoinArgv = {
|
|
46
|
-
|
|
46
|
+
apis: string[];
|
|
47
47
|
lint?: boolean;
|
|
48
48
|
'prefix-tags-with-info-prop'?: string;
|
|
49
49
|
'prefix-tags-with-filename'?: boolean;
|
|
@@ -51,11 +51,10 @@ type JoinArgv = {
|
|
|
51
51
|
'without-x-tag-groups'?: boolean;
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
-
|
|
55
54
|
export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
56
55
|
const startedAt = performance.now();
|
|
57
|
-
if (argv.
|
|
58
|
-
return exitWithError(`At least 2
|
|
56
|
+
if (argv.apis.length < 2) {
|
|
57
|
+
return exitWithError(`At least 2 apis should be provided. \n\n`);
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
const {
|
|
@@ -73,27 +72,29 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
73
72
|
|
|
74
73
|
if (usedTagsOptions.length > 1) {
|
|
75
74
|
return exitWithError(
|
|
76
|
-
`You use ${yellow(usedTagsOptions.join(', '))} together.\nPlease choose only one! \n\n
|
|
75
|
+
`You use ${yellow(usedTagsOptions.join(', '))} together.\nPlease choose only one! \n\n`
|
|
77
76
|
);
|
|
78
77
|
}
|
|
79
|
-
|
|
78
|
+
|
|
80
79
|
const config: Config = await loadConfig();
|
|
81
|
-
const
|
|
80
|
+
const apis = await getFallbackApisOrExit(argv.apis, config);
|
|
82
81
|
const externalRefResolver = new BaseResolver(config.resolve);
|
|
83
82
|
const documents = await Promise.all(
|
|
84
|
-
|
|
83
|
+
apis.map(
|
|
85
84
|
({ path }) => externalRefResolver.resolveDocument(null, path, true) as Promise<Document>
|
|
86
85
|
)
|
|
87
86
|
);
|
|
88
87
|
|
|
89
88
|
const bundleResults = await Promise.all(
|
|
90
|
-
documents.map(document =>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
documents.map((document) =>
|
|
90
|
+
bundleDocument({
|
|
91
|
+
document,
|
|
92
|
+
config: config.styleguide,
|
|
93
|
+
externalRefResolver,
|
|
94
|
+
}).catch((e) => {
|
|
95
|
+
exitWithError(`${e.message}: ${blue(document.source.absoluteRef)}`);
|
|
96
|
+
})
|
|
97
|
+
)
|
|
97
98
|
);
|
|
98
99
|
|
|
99
100
|
for (const { problems, bundle: document } of bundleResults as any) {
|
|
@@ -101,17 +102,23 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
101
102
|
if (fileTotals.errors) {
|
|
102
103
|
formatProblems(problems, {
|
|
103
104
|
totals: fileTotals,
|
|
104
|
-
version: document.parsed.version
|
|
105
|
+
version: document.parsed.version,
|
|
105
106
|
});
|
|
106
|
-
exitWithError(
|
|
107
|
+
exitWithError(
|
|
108
|
+
`❌ Errors encountered while bundling ${blue(
|
|
109
|
+
document.source.absoluteRef
|
|
110
|
+
)}: join will not proceed.\n`
|
|
111
|
+
);
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
114
|
|
|
110
115
|
for (const document of documents) {
|
|
111
116
|
try {
|
|
112
|
-
const version = detectOpenAPI(document.parsed)
|
|
117
|
+
const version = detectOpenAPI(document.parsed);
|
|
113
118
|
if (version !== OasVersion.Version3_0) {
|
|
114
|
-
return exitWithError(
|
|
119
|
+
return exitWithError(
|
|
120
|
+
`Only OpenAPI 3 is supported: ${blue(document.source.absoluteRef)} \n\n`
|
|
121
|
+
);
|
|
115
122
|
}
|
|
116
123
|
} catch (e) {
|
|
117
124
|
return exitWithError(`${e.message}: ${blue(document.source.absoluteRef)}`);
|
|
@@ -120,7 +127,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
120
127
|
|
|
121
128
|
if (argv.lint) {
|
|
122
129
|
for (const document of documents) {
|
|
123
|
-
await
|
|
130
|
+
await validateApi(document, config.styleguide, externalRefResolver, packageVersion);
|
|
124
131
|
}
|
|
125
132
|
}
|
|
126
133
|
|
|
@@ -137,24 +144,37 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
137
144
|
for (const document of documents) {
|
|
138
145
|
const openapi = document.parsed;
|
|
139
146
|
const { tags, info } = openapi;
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const tagsPrefix = prefixTagsWithFilename
|
|
147
|
+
const api = path.relative(process.cwd(), document.source.absoluteRef);
|
|
148
|
+
const apiFilename = getApiFilename(api);
|
|
149
|
+
const tagsPrefix = prefixTagsWithFilename
|
|
150
|
+
? apiFilename
|
|
151
|
+
: getInfoPrefix(info, prefixTagsWithInfoProp, 'tags');
|
|
143
152
|
const componentsPrefix = getInfoPrefix(info, prefixComponentsWithInfoProp, COMPONENTS);
|
|
144
153
|
|
|
145
154
|
if (openapi.hasOwnProperty('x-tagGroups')) {
|
|
146
|
-
process.stderr.write(yellow(`warning: x-tagGroups at ${blue(
|
|
155
|
+
process.stderr.write(yellow(`warning: x-tagGroups at ${blue(api)} will be skipped \n`));
|
|
147
156
|
}
|
|
148
157
|
|
|
149
|
-
const context = {
|
|
150
|
-
|
|
158
|
+
const context = {
|
|
159
|
+
api,
|
|
160
|
+
apiFilename,
|
|
161
|
+
tags,
|
|
162
|
+
potentialConflicts,
|
|
163
|
+
tagsPrefix,
|
|
164
|
+
componentsPrefix,
|
|
165
|
+
};
|
|
166
|
+
if (tags) {
|
|
167
|
+
populateTags(context);
|
|
168
|
+
}
|
|
151
169
|
collectServers(openapi);
|
|
152
170
|
collectInfoDescriptions(openapi, context);
|
|
153
171
|
collectExternalDocs(openapi, context);
|
|
154
172
|
collectPaths(openapi, context);
|
|
155
173
|
collectComponents(openapi, context);
|
|
156
174
|
collectXWebhooks(openapi, context);
|
|
157
|
-
if (componentsPrefix) {
|
|
175
|
+
if (componentsPrefix) {
|
|
176
|
+
replace$Refs(openapi, componentsPrefix);
|
|
177
|
+
}
|
|
158
178
|
}
|
|
159
179
|
|
|
160
180
|
iteratePotentialConflicts(potentialConflicts, withoutXTagGroups);
|
|
@@ -163,14 +183,14 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
163
183
|
|
|
164
184
|
if (potentialConflictsTotal) {
|
|
165
185
|
return exitWithError(`Please fix conflicts before running ${yellow('join')}.`);
|
|
166
|
-
}
|
|
186
|
+
}
|
|
167
187
|
|
|
168
188
|
writeYaml(joinedDef, specFilename, noRefs);
|
|
169
189
|
printExecutionTime('join', startedAt, specFilename);
|
|
170
190
|
|
|
171
191
|
function populateTags({
|
|
172
|
-
|
|
173
|
-
|
|
192
|
+
api,
|
|
193
|
+
apiFilename,
|
|
174
194
|
tags,
|
|
175
195
|
potentialConflicts,
|
|
176
196
|
tagsPrefix,
|
|
@@ -194,55 +214,57 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
194
214
|
const tagDuplicate = joinedDef.tags.find((t: Oas3Tag) => t.name === entrypointTagName);
|
|
195
215
|
|
|
196
216
|
if (tagDuplicate && withoutXTagGroups) {
|
|
197
|
-
// If tag already exist and `without-x-tag-groups` option
|
|
198
|
-
// check if description are different for potential conflicts warning
|
|
217
|
+
// If tag already exist and `without-x-tag-groups` option,
|
|
218
|
+
// check if description are different for potential conflicts warning.
|
|
199
219
|
const isTagDescriptionNotEqual =
|
|
200
220
|
tag.hasOwnProperty('description') && tagDuplicate.description !== tag.description;
|
|
201
221
|
|
|
202
222
|
potentialConflicts.tags.description[entrypointTagName].push(
|
|
203
|
-
...(isTagDescriptionNotEqual ? [
|
|
223
|
+
...(isTagDescriptionNotEqual ? [api] : [])
|
|
204
224
|
);
|
|
205
|
-
} else {
|
|
206
|
-
// Instead add tag to joinedDef;
|
|
225
|
+
} else if (!tagDuplicate) {
|
|
226
|
+
// Instead add tag to joinedDef if there no duplicate;
|
|
207
227
|
tag['x-displayName'] = tag['x-displayName'] || tag.name;
|
|
208
228
|
tag.name = entrypointTagName;
|
|
209
229
|
joinedDef.tags.push(tag);
|
|
210
230
|
|
|
211
231
|
if (withoutXTagGroups) {
|
|
212
|
-
potentialConflicts.tags.description[entrypointTagName] = [
|
|
232
|
+
potentialConflicts.tags.description[entrypointTagName] = [api];
|
|
213
233
|
}
|
|
214
234
|
}
|
|
215
235
|
|
|
216
236
|
if (!withoutXTagGroups) {
|
|
217
|
-
createXTagGroups(
|
|
218
|
-
|
|
237
|
+
createXTagGroups(apiFilename);
|
|
238
|
+
if (!tagDuplicate) {
|
|
239
|
+
populateXTagGroups(entrypointTagName, getIndexGroup(apiFilename));
|
|
240
|
+
}
|
|
219
241
|
}
|
|
220
242
|
|
|
221
243
|
const doesEntrypointExist =
|
|
222
244
|
!potentialConflicts.tags.all[entrypointTagName] ||
|
|
223
245
|
(potentialConflicts.tags.all[entrypointTagName] &&
|
|
224
|
-
!potentialConflicts.tags.all[entrypointTagName].includes(
|
|
246
|
+
!potentialConflicts.tags.all[entrypointTagName].includes(api));
|
|
225
247
|
potentialConflicts.tags.all[entrypointTagName] = [
|
|
226
248
|
...(potentialConflicts.tags.all[entrypointTagName] || []),
|
|
227
|
-
...(!withoutXTagGroups && doesEntrypointExist ? [
|
|
249
|
+
...(!withoutXTagGroups && doesEntrypointExist ? [api] : []),
|
|
228
250
|
];
|
|
229
251
|
}
|
|
230
252
|
}
|
|
231
253
|
|
|
232
|
-
function getIndexGroup(
|
|
233
|
-
return joinedDef[xTagGroups].findIndex((item: any) => item.name ===
|
|
254
|
+
function getIndexGroup(apiFilename: string): number {
|
|
255
|
+
return joinedDef[xTagGroups].findIndex((item: any) => item.name === apiFilename);
|
|
234
256
|
}
|
|
235
257
|
|
|
236
|
-
function createXTagGroups(
|
|
258
|
+
function createXTagGroups(apiFilename: string) {
|
|
237
259
|
if (!joinedDef.hasOwnProperty(xTagGroups)) {
|
|
238
260
|
joinedDef[xTagGroups] = [];
|
|
239
261
|
}
|
|
240
262
|
|
|
241
|
-
if (!joinedDef[xTagGroups].some((g: any) => g.name ===
|
|
242
|
-
joinedDef[xTagGroups].push({ name:
|
|
263
|
+
if (!joinedDef[xTagGroups].some((g: any) => g.name === apiFilename)) {
|
|
264
|
+
joinedDef[xTagGroups].push({ name: apiFilename, tags: [] });
|
|
243
265
|
}
|
|
244
266
|
|
|
245
|
-
const indexGroup = getIndexGroup(
|
|
267
|
+
const indexGroup = getIndexGroup(apiFilename);
|
|
246
268
|
|
|
247
269
|
if (!joinedDef[xTagGroups][indexGroup].hasOwnProperty(Tags)) {
|
|
248
270
|
joinedDef[xTagGroups][indexGroup][Tags] = [];
|
|
@@ -250,7 +272,9 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
250
272
|
}
|
|
251
273
|
|
|
252
274
|
function populateXTagGroups(entrypointTagName: string, indexGroup: number) {
|
|
253
|
-
if (
|
|
275
|
+
if (
|
|
276
|
+
!joinedDef[xTagGroups][indexGroup][Tags].find((t: Oas3Tag) => t.name === entrypointTagName)
|
|
277
|
+
) {
|
|
254
278
|
joinedDef[xTagGroups][indexGroup][Tags].push(entrypointTagName);
|
|
255
279
|
}
|
|
256
280
|
}
|
|
@@ -258,7 +282,9 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
258
282
|
function collectServers(openapi: Oas3Definition) {
|
|
259
283
|
const { servers } = openapi;
|
|
260
284
|
if (servers) {
|
|
261
|
-
if (!joinedDef.hasOwnProperty('servers')) {
|
|
285
|
+
if (!joinedDef.hasOwnProperty('servers')) {
|
|
286
|
+
joinedDef['servers'] = [];
|
|
287
|
+
}
|
|
262
288
|
for (const server of servers) {
|
|
263
289
|
if (!joinedDef.servers.some((s: any) => s.url === server.url)) {
|
|
264
290
|
joinedDef.servers.push(server);
|
|
@@ -269,14 +295,11 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
269
295
|
|
|
270
296
|
function collectInfoDescriptions(
|
|
271
297
|
openapi: Oas3Definition,
|
|
272
|
-
{
|
|
273
|
-
entrypointFilename,
|
|
274
|
-
componentsPrefix
|
|
275
|
-
}: JoinDocumentContext
|
|
298
|
+
{ apiFilename, componentsPrefix }: JoinDocumentContext
|
|
276
299
|
) {
|
|
277
300
|
const { info } = openapi;
|
|
278
301
|
if (info?.description) {
|
|
279
|
-
const groupIndex = joinedDef[xTagGroups] ? getIndexGroup(
|
|
302
|
+
const groupIndex = joinedDef[xTagGroups] ? getIndexGroup(apiFilename) : -1;
|
|
280
303
|
if (
|
|
281
304
|
joinedDef.hasOwnProperty(xTagGroups) &&
|
|
282
305
|
groupIndex !== -1 &&
|
|
@@ -285,17 +308,19 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
285
308
|
) {
|
|
286
309
|
joinedDef[xTagGroups][groupIndex]['description'] = addComponentsPrefix(
|
|
287
310
|
info.description,
|
|
288
|
-
componentsPrefix
|
|
311
|
+
componentsPrefix!
|
|
289
312
|
);
|
|
290
313
|
}
|
|
291
314
|
}
|
|
292
315
|
}
|
|
293
316
|
|
|
294
|
-
function collectExternalDocs(openapi: Oas3Definition, {
|
|
317
|
+
function collectExternalDocs(openapi: Oas3Definition, { api }: JoinDocumentContext) {
|
|
295
318
|
const { externalDocs } = openapi;
|
|
296
319
|
if (externalDocs) {
|
|
297
320
|
if (joinedDef.hasOwnProperty('externalDocs')) {
|
|
298
|
-
process.stderr.write(
|
|
321
|
+
process.stderr.write(
|
|
322
|
+
yellow(`warning: skip externalDocs from ${blue(path.basename(api))} \n`)
|
|
323
|
+
);
|
|
299
324
|
return;
|
|
300
325
|
}
|
|
301
326
|
joinedDef['externalDocs'] = externalDocs;
|
|
@@ -304,42 +329,74 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
304
329
|
|
|
305
330
|
function collectPaths(
|
|
306
331
|
openapi: Oas3Definition,
|
|
307
|
-
{
|
|
308
|
-
entrypointFilename,
|
|
309
|
-
entrypoint,
|
|
310
|
-
potentialConflicts,
|
|
311
|
-
tagsPrefix,
|
|
312
|
-
componentsPrefix
|
|
313
|
-
}: JoinDocumentContext
|
|
332
|
+
{ apiFilename, api, potentialConflicts, tagsPrefix, componentsPrefix }: JoinDocumentContext
|
|
314
333
|
) {
|
|
315
334
|
const { paths } = openapi;
|
|
316
335
|
if (paths) {
|
|
317
|
-
if (!joinedDef.hasOwnProperty('paths')) {
|
|
336
|
+
if (!joinedDef.hasOwnProperty('paths')) {
|
|
337
|
+
joinedDef['paths'] = {};
|
|
338
|
+
}
|
|
318
339
|
for (const path of Object.keys(paths)) {
|
|
319
|
-
if (!joinedDef.paths.hasOwnProperty(path)) {
|
|
320
|
-
|
|
340
|
+
if (!joinedDef.paths.hasOwnProperty(path)) {
|
|
341
|
+
joinedDef.paths[path] = {};
|
|
342
|
+
}
|
|
343
|
+
if (!potentialConflicts.paths.hasOwnProperty(path)) {
|
|
344
|
+
potentialConflicts.paths[path] = {};
|
|
345
|
+
}
|
|
321
346
|
for (const operation of Object.keys(paths[path])) {
|
|
322
347
|
// @ts-ignore
|
|
323
348
|
const pathOperation = paths[path][operation];
|
|
324
349
|
joinedDef.paths[path][operation] = pathOperation;
|
|
325
|
-
potentialConflicts.paths[path][operation] = [
|
|
350
|
+
potentialConflicts.paths[path][operation] = [
|
|
351
|
+
...(potentialConflicts.paths[path][operation] || []),
|
|
352
|
+
api,
|
|
353
|
+
];
|
|
326
354
|
const { operationId } = pathOperation;
|
|
327
355
|
if (operationId) {
|
|
328
|
-
if (!potentialConflicts.paths.hasOwnProperty('operationIds')) {
|
|
329
|
-
|
|
356
|
+
if (!potentialConflicts.paths.hasOwnProperty('operationIds')) {
|
|
357
|
+
potentialConflicts.paths['operationIds'] = {};
|
|
358
|
+
}
|
|
359
|
+
potentialConflicts.paths.operationIds[operationId] = [
|
|
360
|
+
...(potentialConflicts.paths.operationIds[operationId] || []),
|
|
361
|
+
api,
|
|
362
|
+
];
|
|
330
363
|
}
|
|
331
364
|
let { tags, security } = joinedDef.paths[path][operation];
|
|
332
365
|
if (tags) {
|
|
333
|
-
joinedDef.paths[path][operation].tags = tags.map((tag: string) =>
|
|
334
|
-
|
|
366
|
+
joinedDef.paths[path][operation].tags = tags.map((tag: string) =>
|
|
367
|
+
addPrefix(tag, tagsPrefix)
|
|
368
|
+
);
|
|
369
|
+
populateTags({
|
|
370
|
+
api,
|
|
371
|
+
apiFilename,
|
|
372
|
+
tags: formatTags(tags),
|
|
373
|
+
potentialConflicts,
|
|
374
|
+
tagsPrefix,
|
|
375
|
+
componentsPrefix,
|
|
376
|
+
});
|
|
335
377
|
} else {
|
|
336
|
-
joinedDef.paths[path][operation]['tags'] = [
|
|
337
|
-
|
|
378
|
+
joinedDef.paths[path][operation]['tags'] = [
|
|
379
|
+
addPrefix('other', tagsPrefix || apiFilename),
|
|
380
|
+
];
|
|
381
|
+
populateTags({
|
|
382
|
+
api,
|
|
383
|
+
apiFilename,
|
|
384
|
+
tags: formatTags(['other']),
|
|
385
|
+
potentialConflicts,
|
|
386
|
+
tagsPrefix: tagsPrefix || apiFilename,
|
|
387
|
+
componentsPrefix,
|
|
388
|
+
});
|
|
338
389
|
}
|
|
339
390
|
if (!security && openapi.hasOwnProperty('security')) {
|
|
340
|
-
joinedDef.paths[path][operation]['security'] = addSecurityPrefix(
|
|
391
|
+
joinedDef.paths[path][operation]['security'] = addSecurityPrefix(
|
|
392
|
+
openapi.security,
|
|
393
|
+
componentsPrefix!
|
|
394
|
+
);
|
|
341
395
|
} else if (pathOperation.security) {
|
|
342
|
-
joinedDef.paths[path][operation].security = addSecurityPrefix(
|
|
396
|
+
joinedDef.paths[path][operation].security = addSecurityPrefix(
|
|
397
|
+
pathOperation.security,
|
|
398
|
+
componentsPrefix!
|
|
399
|
+
);
|
|
343
400
|
}
|
|
344
401
|
}
|
|
345
402
|
}
|
|
@@ -348,15 +405,13 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
348
405
|
|
|
349
406
|
function collectComponents(
|
|
350
407
|
openapi: Oas3Definition,
|
|
351
|
-
{
|
|
352
|
-
entrypoint,
|
|
353
|
-
potentialConflicts,
|
|
354
|
-
componentsPrefix
|
|
355
|
-
}: JoinDocumentContext
|
|
408
|
+
{ api, potentialConflicts, componentsPrefix }: JoinDocumentContext
|
|
356
409
|
) {
|
|
357
410
|
const { components } = openapi;
|
|
358
411
|
if (components) {
|
|
359
|
-
if (!joinedDef.hasOwnProperty(COMPONENTS)) {
|
|
412
|
+
if (!joinedDef.hasOwnProperty(COMPONENTS)) {
|
|
413
|
+
joinedDef[COMPONENTS] = {};
|
|
414
|
+
}
|
|
360
415
|
for (const component of Object.keys(components)) {
|
|
361
416
|
if (!potentialConflicts[COMPONENTS].hasOwnProperty(component)) {
|
|
362
417
|
potentialConflicts[COMPONENTS][component] = {};
|
|
@@ -367,7 +422,8 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
367
422
|
for (const item of Object.keys(componentObj)) {
|
|
368
423
|
const componentPrefix = addPrefix(item, componentsPrefix!);
|
|
369
424
|
potentialConflicts.components[component][componentPrefix] = [
|
|
370
|
-
...(potentialConflicts.components[component][item] || []),
|
|
425
|
+
...(potentialConflicts.components[component][item] || []),
|
|
426
|
+
{ [api]: componentObj[item] },
|
|
371
427
|
];
|
|
372
428
|
joinedDef.components[component][componentPrefix] = componentObj[item];
|
|
373
429
|
}
|
|
@@ -377,40 +433,53 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
377
433
|
|
|
378
434
|
function collectXWebhooks(
|
|
379
435
|
openapi: Oas3Definition,
|
|
380
|
-
{
|
|
381
|
-
entrypointFilename,
|
|
382
|
-
entrypoint,
|
|
383
|
-
potentialConflicts,
|
|
384
|
-
tagsPrefix,
|
|
385
|
-
componentsPrefix
|
|
386
|
-
}: JoinDocumentContext
|
|
436
|
+
{ apiFilename, api, potentialConflicts, tagsPrefix, componentsPrefix }: JoinDocumentContext
|
|
387
437
|
) {
|
|
388
438
|
const xWebhooks = 'x-webhooks';
|
|
389
439
|
// @ts-ignore
|
|
390
440
|
const openapiXWebhooks = openapi[xWebhooks];
|
|
391
441
|
if (openapiXWebhooks) {
|
|
392
|
-
if (!joinedDef.hasOwnProperty(xWebhooks)) {
|
|
442
|
+
if (!joinedDef.hasOwnProperty(xWebhooks)) {
|
|
443
|
+
joinedDef[xWebhooks] = {};
|
|
444
|
+
}
|
|
393
445
|
for (const webhook of Object.keys(openapiXWebhooks)) {
|
|
394
446
|
joinedDef[xWebhooks][webhook] = openapiXWebhooks[webhook];
|
|
395
447
|
|
|
396
|
-
if (!potentialConflicts.xWebhooks.hasOwnProperty(webhook)) {
|
|
448
|
+
if (!potentialConflicts.xWebhooks.hasOwnProperty(webhook)) {
|
|
449
|
+
potentialConflicts.xWebhooks[webhook] = {};
|
|
450
|
+
}
|
|
397
451
|
for (const operation of Object.keys(openapiXWebhooks[webhook])) {
|
|
398
|
-
potentialConflicts.xWebhooks[webhook][operation] = [
|
|
452
|
+
potentialConflicts.xWebhooks[webhook][operation] = [
|
|
453
|
+
...(potentialConflicts.xWebhooks[webhook][operation] || []),
|
|
454
|
+
api,
|
|
455
|
+
];
|
|
399
456
|
}
|
|
400
457
|
for (const operationKey of Object.keys(joinedDef[xWebhooks][webhook])) {
|
|
401
458
|
let { tags } = joinedDef[xWebhooks][webhook][operationKey];
|
|
402
459
|
if (tags) {
|
|
403
|
-
joinedDef[xWebhooks][webhook][operationKey].tags = tags.map((tag: string) =>
|
|
404
|
-
|
|
460
|
+
joinedDef[xWebhooks][webhook][operationKey].tags = tags.map((tag: string) =>
|
|
461
|
+
addPrefix(tag, tagsPrefix)
|
|
462
|
+
);
|
|
463
|
+
populateTags({
|
|
464
|
+
api,
|
|
465
|
+
apiFilename,
|
|
466
|
+
tags: formatTags(tags),
|
|
467
|
+
potentialConflicts,
|
|
468
|
+
tagsPrefix,
|
|
469
|
+
componentsPrefix,
|
|
470
|
+
});
|
|
405
471
|
}
|
|
406
472
|
}
|
|
407
473
|
}
|
|
408
474
|
}
|
|
409
475
|
}
|
|
410
476
|
|
|
411
|
-
function addInfoSectionAndSpecVersion(
|
|
412
|
-
|
|
413
|
-
|
|
477
|
+
function addInfoSectionAndSpecVersion(
|
|
478
|
+
documents: any,
|
|
479
|
+
prefixComponentsWithInfoProp: string | undefined
|
|
480
|
+
) {
|
|
481
|
+
const firstApi = documents[0];
|
|
482
|
+
const openapi = firstApi.parsed;
|
|
414
483
|
const componentsPrefix = getInfoPrefix(openapi.info, prefixComponentsWithInfoProp, COMPONENTS);
|
|
415
484
|
if (!openapi.openapi) exitWithError('Version of specification is not found in. \n');
|
|
416
485
|
if (!openapi.info) exitWithError('Info section is not found in specification. \n');
|
|
@@ -473,9 +542,9 @@ function duplicateTagDescriptionWarning(conflicts: [string, any][]) {
|
|
|
473
542
|
process.stderr.write(
|
|
474
543
|
yellow(
|
|
475
544
|
`\nwarning: ${tagsKeys.length} conflict(s) on the ${red(
|
|
476
|
-
tagsKeys.join(joinString)
|
|
477
|
-
)} tags description.\n
|
|
478
|
-
)
|
|
545
|
+
tagsKeys.join(joinString)
|
|
546
|
+
)} tags description.\n`
|
|
547
|
+
)
|
|
479
548
|
);
|
|
480
549
|
}
|
|
481
550
|
|
|
@@ -501,12 +570,12 @@ function filterConflicts(entities: object) {
|
|
|
501
570
|
return Object.entries(entities).filter(([_, files]) => files.length > 1);
|
|
502
571
|
}
|
|
503
572
|
|
|
504
|
-
function
|
|
505
|
-
return path.basename(filePath, path.extname(filePath))
|
|
573
|
+
function getApiFilename(filePath: string) {
|
|
574
|
+
return path.basename(filePath, path.extname(filePath));
|
|
506
575
|
}
|
|
507
576
|
|
|
508
577
|
function addPrefix(tag: string, tagsPrefix: string) {
|
|
509
|
-
return tagsPrefix ? tagsPrefix +'_'+ tag : tag;
|
|
578
|
+
return tagsPrefix ? tagsPrefix + '_' + tag : tag;
|
|
510
579
|
}
|
|
511
580
|
|
|
512
581
|
function formatTags(tags: string[]) {
|
|
@@ -517,26 +586,44 @@ function addComponentsPrefix(description: string, componentsPrefix: string) {
|
|
|
517
586
|
return description.replace(/"(#\/components\/.*?)"/g, (match) => {
|
|
518
587
|
const componentName = path.basename(match);
|
|
519
588
|
return match.replace(componentName, addPrefix(componentName, componentsPrefix));
|
|
520
|
-
})
|
|
589
|
+
});
|
|
521
590
|
}
|
|
522
591
|
|
|
523
592
|
function addSecurityPrefix(security: any, componentsPrefix: string) {
|
|
524
|
-
return componentsPrefix
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
593
|
+
return componentsPrefix
|
|
594
|
+
? security?.map((s: any) => {
|
|
595
|
+
const key = Object.keys(s)[0];
|
|
596
|
+
return { [componentsPrefix + '_' + key]: s[key] };
|
|
597
|
+
})
|
|
598
|
+
: security;
|
|
528
599
|
}
|
|
529
600
|
|
|
530
601
|
function getInfoPrefix(info: any, prefixArg: string | undefined, type: string) {
|
|
531
602
|
if (!prefixArg) return '';
|
|
532
603
|
if (!info) exitWithError('Info section is not found in specification. \n');
|
|
533
|
-
if (!info[prefixArg])
|
|
534
|
-
|
|
535
|
-
|
|
604
|
+
if (!info[prefixArg])
|
|
605
|
+
exitWithError(
|
|
606
|
+
`${yellow(`prefix-${type}-with-info-prop`)} argument value is not found in info section. \n`
|
|
607
|
+
);
|
|
608
|
+
if (!isString(info[prefixArg]))
|
|
609
|
+
exitWithError(
|
|
610
|
+
`${yellow(`prefix-${type}-with-info-prop`)} argument value should be string. \n\n`
|
|
611
|
+
);
|
|
612
|
+
if (info[prefixArg].length > 50)
|
|
613
|
+
exitWithError(
|
|
614
|
+
`${yellow(
|
|
615
|
+
`prefix-${type}-with-info-prop`
|
|
616
|
+
)} argument value length should not exceed 50 characters. \n\n`
|
|
617
|
+
);
|
|
536
618
|
return info[prefixArg];
|
|
537
619
|
}
|
|
538
620
|
|
|
539
|
-
async function
|
|
621
|
+
async function validateApi(
|
|
622
|
+
document: Document,
|
|
623
|
+
config: StyleguideConfig,
|
|
624
|
+
externalRefResolver: BaseResolver,
|
|
625
|
+
packageVersion: string
|
|
626
|
+
) {
|
|
540
627
|
try {
|
|
541
628
|
const results = await lintDocument({ document, config, externalRefResolver });
|
|
542
629
|
const fileTotals = getTotals(results);
|
|
@@ -559,7 +646,7 @@ function replace$Refs(obj: any, componentsPrefix: string) {
|
|
|
559
646
|
crawl(obj, (node: any) => {
|
|
560
647
|
if (node.$ref && isString(node.$ref) && node.$ref.startsWith(`#/${COMPONENTS}/`)) {
|
|
561
648
|
const name = path.basename(node.$ref);
|
|
562
|
-
node.$ref = node.$ref.replace(name, componentsPrefix +'_'+ name);
|
|
649
|
+
node.$ref = node.$ref.replace(name, componentsPrefix + '_' + name);
|
|
563
650
|
} else if (
|
|
564
651
|
node.discriminator &&
|
|
565
652
|
node.discriminator.mapping &&
|
|
@@ -568,9 +655,14 @@ function replace$Refs(obj: any, componentsPrefix: string) {
|
|
|
568
655
|
const { mapping } = node.discriminator;
|
|
569
656
|
for (const name of Object.keys(mapping)) {
|
|
570
657
|
if (isString(mapping[name]) && mapping[name].startsWith(`#/${COMPONENTS}/`)) {
|
|
571
|
-
mapping[name] = mapping[name]
|
|
572
|
-
|
|
573
|
-
|
|
658
|
+
mapping[name] = mapping[name]
|
|
659
|
+
.split('/')
|
|
660
|
+
.map((name: string, i: number, arr: []) => {
|
|
661
|
+
return arr.length - 1 === i && !name.includes(componentsPrefix)
|
|
662
|
+
? componentsPrefix + '_' + name
|
|
663
|
+
: name;
|
|
664
|
+
})
|
|
665
|
+
.join('/');
|
|
574
666
|
}
|
|
575
667
|
}
|
|
576
668
|
}
|