@redocly/openapi-core 1.0.0-beta.116 → 1.0.0-beta.118
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/lib/bundle.d.ts +1 -1
- package/lib/config/config-resolvers.js +13 -8
- package/lib/decorators/common/media-type-examples-override.d.ts +2 -0
- package/lib/decorators/common/media-type-examples-override.js +53 -0
- package/lib/decorators/oas3/index.d.ts +1 -0
- package/lib/decorators/oas3/index.js +2 -0
- package/lib/index.d.ts +2 -2
- package/lib/index.js +3 -1
- package/lib/resolve.js +3 -0
- package/lib/rules/common/assertions/asserts.js +10 -2
- package/lib/rules/common/assertions/utils.js +12 -6
- package/lib/rules/common/spec.js +7 -4
- package/lib/rules/oas3/spec-components-invalid-map-name.js +26 -5
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +7 -1
- package/lib/types/oas2.js +16 -11
- package/lib/types/oas3.js +28 -11
- package/lib/types/oas3_1.js +6 -0
- package/lib/types/redocly-yaml.js +1 -0
- package/lib/utils.d.ts +1 -0
- package/lib/utils.js +6 -1
- package/lib/visitors.d.ts +3 -1
- package/lib/visitors.js +4 -0
- package/lib/walk.js +8 -0
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/bundle.test.ts.snap +10 -0
- package/src/config/config-resolvers.ts +12 -8
- package/src/decorators/__tests__/media-type-examples-override.test.ts +665 -0
- package/src/decorators/__tests__/resources/request.yaml +3 -0
- package/src/decorators/__tests__/resources/response.yaml +3 -0
- package/src/decorators/common/media-type-examples-override.ts +79 -0
- package/src/decorators/oas3/index.ts +2 -0
- package/src/index.ts +2 -1
- package/src/resolve.ts +4 -1
- package/src/rules/common/assertions/__tests__/asserts.test.ts +89 -19
- package/src/rules/common/assertions/asserts.ts +10 -1
- package/src/rules/common/assertions/utils.ts +15 -6
- package/src/rules/common/spec.ts +8 -5
- package/src/rules/oas3/__tests__/spec-components-invalid-map-name.test.ts +88 -0
- package/src/rules/oas3/spec-components-invalid-map-name.ts +26 -5
- package/src/types/index.ts +9 -0
- package/src/types/oas2.ts +16 -12
- package/src/types/oas3.ts +28 -12
- package/src/types/oas3_1.ts +6 -0
- package/src/types/redocly-yaml.ts +1 -0
- package/src/utils.ts +5 -0
- package/src/visitors.ts +7 -1
- package/src/walk.ts +15 -1
- package/tsconfig.tsbuildinfo +1 -1
package/src/types/oas3.ts
CHANGED
|
@@ -17,6 +17,7 @@ const Root: NodeType = {
|
|
|
17
17
|
'x-ignoredHeaderParameters': { type: 'array', items: { type: 'string' } },
|
|
18
18
|
},
|
|
19
19
|
required: ['openapi', 'paths', 'info'],
|
|
20
|
+
extensionsPrefix: 'x-',
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const Tag: NodeType = {
|
|
@@ -28,6 +29,7 @@ const Tag: NodeType = {
|
|
|
28
29
|
'x-displayName': { type: 'string' },
|
|
29
30
|
},
|
|
30
31
|
required: ['name'],
|
|
32
|
+
extensionsPrefix: 'x-',
|
|
31
33
|
};
|
|
32
34
|
|
|
33
35
|
const TagGroup: NodeType = {
|
|
@@ -35,6 +37,7 @@ const TagGroup: NodeType = {
|
|
|
35
37
|
name: { type: 'string' },
|
|
36
38
|
tags: { type: 'array', items: { type: 'string' } },
|
|
37
39
|
},
|
|
40
|
+
extensionsPrefix: 'x-',
|
|
38
41
|
};
|
|
39
42
|
|
|
40
43
|
const ExternalDocs: NodeType = {
|
|
@@ -43,6 +46,7 @@ const ExternalDocs: NodeType = {
|
|
|
43
46
|
url: { type: 'string' },
|
|
44
47
|
},
|
|
45
48
|
required: ['url'],
|
|
49
|
+
extensionsPrefix: 'x-',
|
|
46
50
|
};
|
|
47
51
|
|
|
48
52
|
const Server: NodeType = {
|
|
@@ -52,6 +56,7 @@ const Server: NodeType = {
|
|
|
52
56
|
variables: 'ServerVariablesMap',
|
|
53
57
|
},
|
|
54
58
|
required: ['url'],
|
|
59
|
+
extensionsPrefix: 'x-',
|
|
55
60
|
};
|
|
56
61
|
|
|
57
62
|
const ServerVariable: NodeType = {
|
|
@@ -64,6 +69,7 @@ const ServerVariable: NodeType = {
|
|
|
64
69
|
description: null,
|
|
65
70
|
},
|
|
66
71
|
required: ['default'],
|
|
72
|
+
extensionsPrefix: 'x-',
|
|
67
73
|
};
|
|
68
74
|
|
|
69
75
|
const SecurityRequirement: NodeType = {
|
|
@@ -82,6 +88,7 @@ const Info: NodeType = {
|
|
|
82
88
|
'x-logo': 'Logo',
|
|
83
89
|
},
|
|
84
90
|
required: ['title', 'version'],
|
|
91
|
+
extensionsPrefix: 'x-',
|
|
85
92
|
};
|
|
86
93
|
|
|
87
94
|
const Logo: NodeType = {
|
|
@@ -99,6 +106,7 @@ const Contact: NodeType = {
|
|
|
99
106
|
url: { type: 'string' },
|
|
100
107
|
email: { type: 'string' },
|
|
101
108
|
},
|
|
109
|
+
extensionsPrefix: 'x-',
|
|
102
110
|
};
|
|
103
111
|
|
|
104
112
|
const License: NodeType = {
|
|
@@ -107,6 +115,7 @@ const License: NodeType = {
|
|
|
107
115
|
url: { type: 'string' },
|
|
108
116
|
},
|
|
109
117
|
required: ['name'],
|
|
118
|
+
extensionsPrefix: 'x-',
|
|
110
119
|
};
|
|
111
120
|
|
|
112
121
|
const Paths: NodeType = {
|
|
@@ -136,6 +145,7 @@ const PathItem: NodeType = {
|
|
|
136
145
|
patch: 'Operation',
|
|
137
146
|
trace: 'Operation',
|
|
138
147
|
},
|
|
148
|
+
extensionsPrefix: 'x-',
|
|
139
149
|
};
|
|
140
150
|
|
|
141
151
|
const Parameter: NodeType = {
|
|
@@ -158,6 +168,7 @@ const Parameter: NodeType = {
|
|
|
158
168
|
},
|
|
159
169
|
required: ['name', 'in'],
|
|
160
170
|
requiredOneOf: ['schema', 'content'],
|
|
171
|
+
extensionsPrefix: 'x-',
|
|
161
172
|
};
|
|
162
173
|
|
|
163
174
|
const Operation: NodeType = {
|
|
@@ -180,9 +191,9 @@ const Operation: NodeType = {
|
|
|
180
191
|
'x-codeSamples': 'XCodeSampleList',
|
|
181
192
|
'x-code-samples': 'XCodeSampleList', // deprecated
|
|
182
193
|
'x-hideTryItPanel': { type: 'boolean' },
|
|
183
|
-
'x-meta': 'XMetaList',
|
|
184
194
|
},
|
|
185
195
|
required: ['responses'],
|
|
196
|
+
extensionsPrefix: 'x-',
|
|
186
197
|
};
|
|
187
198
|
|
|
188
199
|
const XCodeSample: NodeType = {
|
|
@@ -200,6 +211,7 @@ const RequestBody: NodeType = {
|
|
|
200
211
|
content: 'MediaTypesMap',
|
|
201
212
|
},
|
|
202
213
|
required: ['content'],
|
|
214
|
+
extensionsPrefix: 'x-',
|
|
203
215
|
};
|
|
204
216
|
|
|
205
217
|
const MediaTypesMap: NodeType = {
|
|
@@ -214,6 +226,7 @@ const MediaType: NodeType = {
|
|
|
214
226
|
examples: 'ExamplesMap',
|
|
215
227
|
encoding: 'EncodingMap',
|
|
216
228
|
},
|
|
229
|
+
extensionsPrefix: 'x-',
|
|
217
230
|
};
|
|
218
231
|
|
|
219
232
|
const Example: NodeType = {
|
|
@@ -223,6 +236,7 @@ const Example: NodeType = {
|
|
|
223
236
|
description: { type: 'string' },
|
|
224
237
|
externalValue: { type: 'string' },
|
|
225
238
|
},
|
|
239
|
+
extensionsPrefix: 'x-',
|
|
226
240
|
};
|
|
227
241
|
|
|
228
242
|
const Encoding: NodeType = {
|
|
@@ -235,6 +249,7 @@ const Encoding: NodeType = {
|
|
|
235
249
|
explode: { type: 'boolean' },
|
|
236
250
|
allowReserved: { type: 'boolean' },
|
|
237
251
|
},
|
|
252
|
+
extensionsPrefix: 'x-',
|
|
238
253
|
};
|
|
239
254
|
|
|
240
255
|
const EnumDescriptions: NodeType = {
|
|
@@ -259,6 +274,7 @@ const Header: NodeType = {
|
|
|
259
274
|
content: 'MediaTypesMap',
|
|
260
275
|
},
|
|
261
276
|
requiredOneOf: ['schema', 'content'],
|
|
277
|
+
extensionsPrefix: 'x-',
|
|
262
278
|
};
|
|
263
279
|
|
|
264
280
|
const Responses: NodeType = {
|
|
@@ -276,6 +292,7 @@ const Response: NodeType = {
|
|
|
276
292
|
'x-summary': { type: 'string' },
|
|
277
293
|
},
|
|
278
294
|
required: ['description'],
|
|
295
|
+
extensionsPrefix: 'x-',
|
|
279
296
|
};
|
|
280
297
|
|
|
281
298
|
const Link: NodeType = {
|
|
@@ -287,6 +304,7 @@ const Link: NodeType = {
|
|
|
287
304
|
description: { type: 'string' },
|
|
288
305
|
server: 'Server',
|
|
289
306
|
},
|
|
307
|
+
extensionsPrefix: 'x-',
|
|
290
308
|
};
|
|
291
309
|
|
|
292
310
|
const Schema: NodeType = {
|
|
@@ -351,6 +369,7 @@ const Schema: NodeType = {
|
|
|
351
369
|
'x-additionalPropertiesName': { type: 'string' },
|
|
352
370
|
'x-explicitMappingOnly': { type: 'boolean' },
|
|
353
371
|
},
|
|
372
|
+
extensionsPrefix: 'x-',
|
|
354
373
|
};
|
|
355
374
|
|
|
356
375
|
const Xml: NodeType = {
|
|
@@ -361,6 +380,7 @@ const Xml: NodeType = {
|
|
|
361
380
|
attribute: { type: 'boolean' },
|
|
362
381
|
wrapped: { type: 'boolean' },
|
|
363
382
|
},
|
|
383
|
+
extensionsPrefix: 'x-',
|
|
364
384
|
};
|
|
365
385
|
|
|
366
386
|
const SchemaProperties: NodeType = {
|
|
@@ -385,6 +405,7 @@ const Discriminator: NodeType = {
|
|
|
385
405
|
mapping: 'DiscriminatorMapping',
|
|
386
406
|
},
|
|
387
407
|
required: ['propertyName'],
|
|
408
|
+
extensionsPrefix: 'x-',
|
|
388
409
|
};
|
|
389
410
|
|
|
390
411
|
const Components: NodeType = {
|
|
@@ -399,6 +420,7 @@ const Components: NodeType = {
|
|
|
399
420
|
links: 'NamedLinks',
|
|
400
421
|
callbacks: 'NamedCallbacks',
|
|
401
422
|
},
|
|
423
|
+
extensionsPrefix: 'x-',
|
|
402
424
|
};
|
|
403
425
|
|
|
404
426
|
const ImplicitFlow: NodeType = {
|
|
@@ -408,6 +430,7 @@ const ImplicitFlow: NodeType = {
|
|
|
408
430
|
authorizationUrl: { type: 'string' },
|
|
409
431
|
},
|
|
410
432
|
required: ['authorizationUrl', 'scopes'],
|
|
433
|
+
extensionsPrefix: 'x-',
|
|
411
434
|
};
|
|
412
435
|
|
|
413
436
|
const PasswordFlow: NodeType = {
|
|
@@ -417,6 +440,7 @@ const PasswordFlow: NodeType = {
|
|
|
417
440
|
tokenUrl: { type: 'string' },
|
|
418
441
|
},
|
|
419
442
|
required: ['tokenUrl', 'scopes'],
|
|
443
|
+
extensionsPrefix: 'x-',
|
|
420
444
|
};
|
|
421
445
|
|
|
422
446
|
const ClientCredentials: NodeType = {
|
|
@@ -426,6 +450,7 @@ const ClientCredentials: NodeType = {
|
|
|
426
450
|
tokenUrl: { type: 'string' },
|
|
427
451
|
},
|
|
428
452
|
required: ['tokenUrl', 'scopes'],
|
|
453
|
+
extensionsPrefix: 'x-',
|
|
429
454
|
};
|
|
430
455
|
|
|
431
456
|
const AuthorizationCode: NodeType = {
|
|
@@ -443,6 +468,7 @@ const AuthorizationCode: NodeType = {
|
|
|
443
468
|
},
|
|
444
469
|
},
|
|
445
470
|
required: ['authorizationUrl', 'tokenUrl', 'scopes'],
|
|
471
|
+
extensionsPrefix: 'x-',
|
|
446
472
|
};
|
|
447
473
|
|
|
448
474
|
const OAuth2Flows: NodeType = {
|
|
@@ -452,6 +478,7 @@ const OAuth2Flows: NodeType = {
|
|
|
452
478
|
clientCredentials: 'ClientCredentials',
|
|
453
479
|
authorizationCode: 'AuthorizationCode',
|
|
454
480
|
},
|
|
481
|
+
extensionsPrefix: 'x-',
|
|
455
482
|
};
|
|
456
483
|
|
|
457
484
|
const SecurityScheme: NodeType = {
|
|
@@ -497,15 +524,6 @@ const SecurityScheme: NodeType = {
|
|
|
497
524
|
extensionsPrefix: 'x-',
|
|
498
525
|
};
|
|
499
526
|
|
|
500
|
-
const XMeta: NodeType = {
|
|
501
|
-
properties: {
|
|
502
|
-
title: { type: 'string' },
|
|
503
|
-
description: { type: 'string' },
|
|
504
|
-
keywords: { type: 'string' },
|
|
505
|
-
image: { type: 'string' },
|
|
506
|
-
},
|
|
507
|
-
};
|
|
508
|
-
|
|
509
527
|
const XUsePkce: NodeType = {
|
|
510
528
|
properties: {
|
|
511
529
|
disableManualConfiguration: { type: 'boolean' },
|
|
@@ -574,8 +592,6 @@ export const Oas3Types: Record<string, NodeType> = {
|
|
|
574
592
|
SecurityScheme,
|
|
575
593
|
XCodeSample,
|
|
576
594
|
XCodeSampleList: listOf('XCodeSample'),
|
|
577
|
-
XMeta,
|
|
578
|
-
XMetaList: listOf('XMeta'),
|
|
579
595
|
XUsePkce,
|
|
580
596
|
WebhooksMap,
|
|
581
597
|
};
|
package/src/types/oas3_1.ts
CHANGED
|
@@ -16,6 +16,7 @@ const Root: NodeType = {
|
|
|
16
16
|
},
|
|
17
17
|
required: ['openapi', 'info'],
|
|
18
18
|
requiredOneOf: ['paths', 'components', 'webhooks'],
|
|
19
|
+
extensionsPrefix: 'x-',
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
const License: NodeType = {
|
|
@@ -25,6 +26,7 @@ const License: NodeType = {
|
|
|
25
26
|
identifier: { type: 'string' },
|
|
26
27
|
},
|
|
27
28
|
required: ['name'],
|
|
29
|
+
extensionsPrefix: 'x-',
|
|
28
30
|
};
|
|
29
31
|
|
|
30
32
|
const Info: NodeType = {
|
|
@@ -38,6 +40,7 @@ const Info: NodeType = {
|
|
|
38
40
|
license: 'License',
|
|
39
41
|
},
|
|
40
42
|
required: ['title', 'version'],
|
|
43
|
+
extensionsPrefix: 'x-',
|
|
41
44
|
};
|
|
42
45
|
|
|
43
46
|
const Components: NodeType = {
|
|
@@ -53,6 +56,7 @@ const Components: NodeType = {
|
|
|
53
56
|
callbacks: 'NamedCallbacks',
|
|
54
57
|
pathItems: 'NamedPathItems',
|
|
55
58
|
},
|
|
59
|
+
extensionsPrefix: 'x-',
|
|
56
60
|
};
|
|
57
61
|
|
|
58
62
|
const Operation: NodeType = {
|
|
@@ -76,6 +80,7 @@ const Operation: NodeType = {
|
|
|
76
80
|
'x-code-samples': listOf('XCodeSample'), // deprecated
|
|
77
81
|
'x-hideTryItPanel': { type: 'boolean' },
|
|
78
82
|
},
|
|
83
|
+
extensionsPrefix: 'x-',
|
|
79
84
|
};
|
|
80
85
|
|
|
81
86
|
const Schema: NodeType = {
|
|
@@ -167,6 +172,7 @@ const Schema: NodeType = {
|
|
|
167
172
|
$comment: { type: 'string' },
|
|
168
173
|
'x-tags': { type: 'array', items: { type: 'string' } },
|
|
169
174
|
},
|
|
175
|
+
extensionsPrefix: 'x-',
|
|
170
176
|
};
|
|
171
177
|
|
|
172
178
|
const SecurityScheme: NodeType = {
|
package/src/utils.ts
CHANGED
|
@@ -153,6 +153,11 @@ export function readFileAsStringSync(filePath: string) {
|
|
|
153
153
|
return fs.readFileSync(filePath, 'utf-8');
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
export function yamlAndJsonSyncReader<T>(filePath: string): T {
|
|
157
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
158
|
+
return parseYaml(content) as T;
|
|
159
|
+
}
|
|
160
|
+
|
|
156
161
|
export function isPathParameter(pathSegment: string) {
|
|
157
162
|
return pathSegment.startsWith('{') && pathSegment.endsWith('}');
|
|
158
163
|
}
|
package/src/visitors.ts
CHANGED
|
@@ -45,7 +45,7 @@ import type {
|
|
|
45
45
|
Oas2SecurityScheme,
|
|
46
46
|
} from './typings/swagger';
|
|
47
47
|
|
|
48
|
-
import
|
|
48
|
+
import { NormalizedNodeType, SpecExtension } from './types';
|
|
49
49
|
import type { Stack } from './utils';
|
|
50
50
|
import type { UserContext, ResolveResult, ProblemSeverity } from './walk';
|
|
51
51
|
import type { Location } from './ref-utils';
|
|
@@ -177,6 +177,7 @@ type Oas3FlatVisitor = {
|
|
|
177
177
|
AuthorizationCode?: VisitFunctionOrObject<Oas3SecurityScheme['flows']['authorizationCode']>;
|
|
178
178
|
OAuth2Flows?: VisitFunctionOrObject<Oas3SecurityScheme['flows']>;
|
|
179
179
|
SecurityScheme?: VisitFunctionOrObject<Oas3SecurityScheme>;
|
|
180
|
+
SpecExtension?: VisitFunctionOrObject<unknown>;
|
|
180
181
|
};
|
|
181
182
|
|
|
182
183
|
type Oas2FlatVisitor = {
|
|
@@ -202,6 +203,7 @@ type Oas2FlatVisitor = {
|
|
|
202
203
|
NamedResponses?: VisitFunctionOrObject<Record<string, Oas2Response>>;
|
|
203
204
|
NamedParameters?: VisitFunctionOrObject<Record<string, Oas2Parameter>>;
|
|
204
205
|
SecurityScheme?: VisitFunctionOrObject<Oas2SecurityScheme>;
|
|
206
|
+
SpecExtension?: VisitFunctionOrObject<unknown>;
|
|
205
207
|
};
|
|
206
208
|
|
|
207
209
|
const legacyTypesMap = {
|
|
@@ -354,6 +356,10 @@ export function normalizeVisitors<T extends BaseVisitor>(
|
|
|
354
356
|
}
|
|
355
357
|
}
|
|
356
358
|
|
|
359
|
+
if (from.extensionsPrefix) {
|
|
360
|
+
possibleChildren.add(SpecExtension);
|
|
361
|
+
}
|
|
362
|
+
|
|
357
363
|
for (const fromType of Array.from(possibleChildren.values())) {
|
|
358
364
|
addWeakNodes(ruleConf, fromType, to, parentContext, stack);
|
|
359
365
|
}
|
package/src/walk.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from './resolve';
|
|
18
18
|
import { pushStack, popStack } from './utils';
|
|
19
19
|
import { OasVersion } from './oas-types';
|
|
20
|
-
import { NormalizedNodeType, isNamedType } from './types';
|
|
20
|
+
import { NormalizedNodeType, isNamedType, SpecExtension } from './types';
|
|
21
21
|
import type { RuleSeverity } from './config';
|
|
22
22
|
|
|
23
23
|
type NonUndefined = string | number | boolean | symbol | bigint | object | Record<string, any>;
|
|
@@ -280,6 +280,12 @@ export function walkDocument<T>(opts: {
|
|
|
280
280
|
const props = Object.keys(type.properties);
|
|
281
281
|
if (type.additionalProperties) {
|
|
282
282
|
props.push(...Object.keys(resolvedNode).filter((k) => !props.includes(k)));
|
|
283
|
+
} else if (type.extensionsPrefix) {
|
|
284
|
+
props.push(
|
|
285
|
+
...Object.keys(resolvedNode).filter((k) =>
|
|
286
|
+
k.startsWith(type.extensionsPrefix as string)
|
|
287
|
+
)
|
|
288
|
+
);
|
|
283
289
|
}
|
|
284
290
|
|
|
285
291
|
if (isRef(node)) {
|
|
@@ -300,6 +306,14 @@ export function walkDocument<T>(opts: {
|
|
|
300
306
|
if (propType === undefined) propType = type.additionalProperties;
|
|
301
307
|
if (typeof propType === 'function') propType = propType(value, propName);
|
|
302
308
|
|
|
309
|
+
if (
|
|
310
|
+
propType === undefined &&
|
|
311
|
+
type.extensionsPrefix &&
|
|
312
|
+
propName.startsWith(type.extensionsPrefix)
|
|
313
|
+
) {
|
|
314
|
+
propType = SpecExtension;
|
|
315
|
+
}
|
|
316
|
+
|
|
303
317
|
if (!isNamedType(propType) && propType?.directResolveAs) {
|
|
304
318
|
propType = propType.directResolveAs;
|
|
305
319
|
value = { $ref: value };
|