@redocly/openapi-core 1.0.0-beta.106 → 1.0.0-beta.109
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/benchmark/benches/lint-with-top-level-rule-report.bench.js +0 -1
- package/lib/benchmark/benches/resolve-with-no-external.bench.js +1 -1
- package/lib/bundle.d.ts +1 -1
- package/lib/bundle.js +9 -6
- package/lib/config/all.js +5 -3
- package/lib/config/config-resolvers.js +32 -14
- package/lib/config/config.d.ts +3 -5
- package/lib/config/config.js +7 -4
- package/lib/config/load.d.ts +7 -0
- package/lib/config/load.js +14 -6
- package/lib/config/minimal.js +7 -4
- package/lib/config/recommended.js +7 -4
- package/lib/config/rules.d.ts +1 -1
- package/lib/config/rules.js +1 -1
- package/lib/config/types.d.ts +7 -0
- package/lib/config/utils.d.ts +2 -2
- package/lib/config/utils.js +49 -11
- package/lib/decorators/common/registry-dependencies.js +2 -2
- package/lib/env.d.ts +3 -0
- package/lib/env.js +8 -0
- package/lib/format/codeframes.js +16 -10
- package/lib/format/format.d.ts +1 -1
- package/lib/format/format.js +49 -26
- package/lib/index.d.ts +5 -5
- package/lib/index.js +3 -1
- package/lib/js-yaml/index.js +1 -0
- package/lib/lint.js +2 -2
- package/lib/logger.d.ts +10 -0
- package/lib/logger.js +31 -0
- package/lib/output.d.ts +3 -0
- package/lib/output.js +9 -0
- package/lib/redocly/index.js +10 -9
- package/lib/redocly/registry-api-types.d.ts +28 -30
- package/lib/redocly/registry-api.d.ts +3 -3
- package/lib/redocly/registry-api.js +7 -1
- package/lib/ref-utils.js +2 -1
- package/lib/resolve.d.ts +1 -1
- package/lib/resolve.js +4 -2
- package/lib/rules/ajv.d.ts +1 -1
- package/lib/rules/ajv.js +7 -7
- package/lib/rules/common/assertions/asserts.js +4 -4
- package/lib/rules/common/assertions/index.js +1 -1
- package/lib/rules/common/no-ambiguous-paths.js +1 -1
- package/lib/rules/common/no-identical-paths.js +1 -1
- package/lib/rules/common/no-invalid-parameter-examples.js +3 -3
- package/lib/rules/common/no-invalid-schema-examples.js +3 -3
- package/lib/rules/common/operation-2xx-response.js +1 -1
- package/lib/rules/common/operation-4xx-response.js +1 -1
- package/lib/rules/common/operation-operationId.js +1 -1
- package/lib/rules/common/operation-tag-defined.js +1 -1
- package/lib/rules/common/path-not-include-query.js +1 -1
- package/lib/rules/common/security-defined.d.ts +2 -0
- package/lib/rules/common/{operation-security-defined.js → security-defined.js} +19 -5
- package/lib/rules/common/spec.js +14 -3
- package/lib/rules/common/tags-alphabetical.js +1 -1
- package/lib/rules/oas2/index.d.ts +1 -1
- package/lib/rules/oas2/index.js +2 -2
- package/lib/rules/oas2/remove-unused-components.js +3 -3
- package/lib/rules/oas2/request-mime-type.js +1 -1
- package/lib/rules/oas2/response-mime-type.js +1 -1
- package/lib/rules/oas3/index.js +8 -4
- package/lib/rules/oas3/no-empty-servers.js +1 -1
- package/lib/rules/oas3/no-invalid-media-type-examples.js +2 -2
- package/lib/rules/oas3/no-server-variables-empty-enum.d.ts +2 -0
- package/lib/rules/oas3/{no-servers-empty-enum.js → no-server-variables-empty-enum.js} +5 -5
- package/lib/rules/oas3/no-unused-components.js +2 -2
- package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.d.ts +5 -0
- package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.js +36 -0
- package/lib/rules/oas3/remove-unused-components.js +4 -4
- package/lib/rules/oas3/request-mime-type.js +1 -1
- package/lib/rules/oas3/response-mime-type.js +1 -1
- package/lib/rules/oas3/spec-components-invalid-map-name.d.ts +2 -0
- package/lib/rules/oas3/spec-components-invalid-map-name.js +46 -0
- package/lib/rules/other/stats.d.ts +2 -2
- package/lib/rules/other/stats.js +2 -2
- package/lib/rules/utils.d.ts +3 -2
- package/lib/rules/utils.js +16 -4
- package/lib/types/oas2.js +5 -5
- package/lib/types/oas3.js +27 -20
- package/lib/types/oas3_1.js +3 -3
- package/lib/types/redocly-yaml.js +47 -56
- package/lib/utils.d.ts +6 -1
- package/lib/utils.js +24 -7
- package/lib/visitors.d.ts +12 -12
- package/lib/visitors.js +15 -3
- package/lib/walk.d.ts +2 -1
- package/lib/walk.js +6 -3
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/bundle.test.ts.snap +3 -3
- package/src/__tests__/fixtures/extension.js +3 -3
- package/src/__tests__/format.test.ts +76 -0
- package/src/__tests__/lint.test.ts +106 -131
- package/src/__tests__/logger-browser.test.ts +53 -0
- package/src/__tests__/logger.test.ts +47 -0
- package/src/__tests__/output-browser.test.ts +18 -0
- package/src/__tests__/output.test.ts +15 -0
- package/src/__tests__/resolve-http.test.ts +1 -1
- package/src/__tests__/resolve.test.ts +9 -9
- package/src/__tests__/utils-browser.test.ts +11 -0
- package/src/__tests__/utils.test.ts +7 -0
- package/src/__tests__/walk.test.ts +78 -10
- package/src/benchmark/benches/lint-with-top-level-rule-report.bench.ts +0 -1
- package/src/benchmark/benches/resolve-with-no-external.bench.ts +1 -1
- package/src/bundle.ts +10 -7
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +12 -6
- package/src/config/__tests__/config.test.ts +35 -0
- package/src/config/__tests__/fixtures/plugin-config.yaml +2 -3
- package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +11 -12
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-circular.yaml +7 -8
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +18 -19
- package/src/config/__tests__/fixtures/resolve-config/local-config.yaml +9 -10
- package/src/config/__tests__/fixtures/resolve-remote-configs/nested-remote-config.yaml +3 -4
- package/src/config/__tests__/fixtures/resolve-remote-configs/remote-config.yaml +4 -5
- package/src/config/__tests__/load.test.ts +76 -1
- package/src/config/__tests__/utils.test.ts +64 -4
- package/src/config/all.ts +5 -3
- package/src/config/config-resolvers.ts +45 -19
- package/src/config/config.ts +10 -8
- package/src/config/load.ts +31 -7
- package/src/config/minimal.ts +7 -4
- package/src/config/recommended.ts +7 -4
- package/src/config/rules.ts +2 -2
- package/src/config/types.ts +11 -0
- package/src/config/utils.ts +115 -25
- package/src/decorators/common/registry-dependencies.ts +2 -2
- package/src/env.ts +5 -0
- package/src/format/codeframes.ts +15 -9
- package/src/format/format.ts +59 -34
- package/src/index.ts +6 -4
- package/src/js-yaml/index.ts +1 -0
- package/src/lint.ts +2 -2
- package/src/logger.ts +34 -0
- package/src/output.ts +7 -0
- package/src/redocly/index.ts +7 -4
- package/src/redocly/registry-api-types.ts +27 -29
- package/src/redocly/registry-api.ts +18 -7
- package/src/ref-utils.ts +2 -1
- package/src/resolve.ts +7 -5
- package/src/rules/__tests__/utils.test.ts +39 -1
- package/src/rules/ajv.ts +7 -7
- package/src/rules/common/__tests__/no-enum-type-mismatch.test.ts +1 -0
- package/src/rules/common/__tests__/operation-2xx-response.test.ts +1 -1
- package/src/rules/common/__tests__/operation-4xx-response.test.ts +26 -3
- package/src/rules/common/__tests__/security-defined.test.ts +175 -0
- package/src/rules/common/__tests__/spec.test.ts +79 -0
- package/src/rules/common/assertions/__tests__/utils.test.ts +2 -2
- package/src/rules/common/assertions/asserts.ts +4 -4
- package/src/rules/common/assertions/index.ts +1 -1
- package/src/rules/common/no-ambiguous-paths.ts +1 -1
- package/src/rules/common/no-identical-paths.ts +1 -1
- package/src/rules/common/no-invalid-parameter-examples.ts +4 -4
- package/src/rules/common/no-invalid-schema-examples.ts +4 -4
- package/src/rules/common/operation-2xx-response.ts +1 -1
- package/src/rules/common/operation-4xx-response.ts +1 -1
- package/src/rules/common/operation-operationId.ts +1 -1
- package/src/rules/common/operation-tag-defined.ts +1 -1
- package/src/rules/common/path-not-include-query.ts +1 -1
- package/src/rules/common/{operation-security-defined.ts → security-defined.ts} +20 -5
- package/src/rules/common/spec.ts +17 -3
- package/src/rules/common/tags-alphabetical.ts +1 -1
- package/src/rules/oas2/index.ts +2 -2
- package/src/rules/oas2/remove-unused-components.ts +3 -3
- package/src/rules/oas2/request-mime-type.ts +1 -1
- package/src/rules/oas2/response-mime-type.ts +1 -1
- package/src/rules/oas3/__tests__/no-empty-enum-servers.com.test.ts +16 -16
- package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +5 -5
- package/src/rules/oas3/__tests__/operation-4xx-problem-details-rfc7807.test.ts +145 -0
- package/src/rules/oas3/__tests__/spec/spec.test.ts +10 -0
- package/src/rules/oas3/__tests__/spec-components-invalid-map-name.test.ts +217 -0
- package/src/rules/oas3/index.ts +8 -4
- package/src/rules/oas3/no-empty-servers.ts +1 -1
- package/src/rules/oas3/no-invalid-media-type-examples.ts +3 -3
- package/src/rules/oas3/{no-servers-empty-enum.ts → no-server-variables-empty-enum.ts} +3 -3
- package/src/rules/oas3/no-unused-components.ts +2 -2
- package/src/rules/oas3/operation-4xx-problem-details-rfc7807.ts +36 -0
- package/src/rules/oas3/remove-unused-components.ts +5 -5
- package/src/rules/oas3/request-mime-type.ts +1 -1
- package/src/rules/oas3/response-mime-type.ts +1 -1
- package/src/rules/oas3/spec-components-invalid-map-name.ts +53 -0
- package/src/rules/other/stats.ts +2 -2
- package/src/rules/utils.ts +17 -3
- package/src/types/index.ts +2 -2
- package/src/types/oas2.ts +5 -5
- package/src/types/oas3.ts +27 -20
- package/src/types/oas3_1.ts +3 -3
- package/src/types/redocly-yaml.ts +53 -41
- package/src/utils.ts +31 -4
- package/src/visitors.ts +34 -18
- package/src/walk.ts +15 -11
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/rules/common/operation-security-defined.d.ts +0 -2
- package/lib/rules/oas3/no-servers-empty-enum.d.ts +0 -2
- package/src/rules/common/__tests__/operation-security-defined.test.ts +0 -69
package/src/types/oas3.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { NodeType, listOf, mapOf } from '.';
|
|
|
2
2
|
import { isMappingRef } from '../ref-utils';
|
|
3
3
|
const responseCodeRegexp = /^[0-9][0-9Xx]{2}$/;
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const Root: NodeType = {
|
|
6
6
|
properties: {
|
|
7
7
|
openapi: null,
|
|
8
8
|
info: 'Info',
|
|
@@ -10,7 +10,7 @@ const DefinitionRoot: NodeType = {
|
|
|
10
10
|
security: listOf('SecurityRequirement'),
|
|
11
11
|
tags: listOf('Tag'),
|
|
12
12
|
externalDocs: 'ExternalDocs',
|
|
13
|
-
paths: '
|
|
13
|
+
paths: 'PathsMap',
|
|
14
14
|
components: 'Components',
|
|
15
15
|
'x-webhooks': 'WebhooksMap',
|
|
16
16
|
},
|
|
@@ -38,7 +38,7 @@ const Server: NodeType = {
|
|
|
38
38
|
properties: {
|
|
39
39
|
url: { type: 'string' },
|
|
40
40
|
description: { type: 'string' },
|
|
41
|
-
variables:
|
|
41
|
+
variables: 'ServerVariablesMap',
|
|
42
42
|
},
|
|
43
43
|
required: ['url'],
|
|
44
44
|
};
|
|
@@ -88,7 +88,7 @@ const License: NodeType = {
|
|
|
88
88
|
required: ['name'],
|
|
89
89
|
};
|
|
90
90
|
|
|
91
|
-
const
|
|
91
|
+
const PathsMap: NodeType = {
|
|
92
92
|
properties: {},
|
|
93
93
|
additionalProperties: (_value: any, key: string) =>
|
|
94
94
|
key.startsWith('/') ? 'PathItem' : undefined,
|
|
@@ -132,8 +132,8 @@ const Parameter: NodeType = {
|
|
|
132
132
|
allowReserved: { type: 'boolean' },
|
|
133
133
|
schema: 'Schema',
|
|
134
134
|
example: { isExample: true },
|
|
135
|
-
examples:
|
|
136
|
-
content: '
|
|
135
|
+
examples: 'ExamplesMap',
|
|
136
|
+
content: 'MediaTypesMap',
|
|
137
137
|
},
|
|
138
138
|
required: ['name', 'in'],
|
|
139
139
|
requiredOneOf: ['schema', 'content'],
|
|
@@ -155,7 +155,7 @@ const Operation: NodeType = {
|
|
|
155
155
|
requestBody: 'RequestBody',
|
|
156
156
|
responses: 'ResponsesMap',
|
|
157
157
|
deprecated: { type: 'boolean' },
|
|
158
|
-
callbacks:
|
|
158
|
+
callbacks: 'CallbacksMap',
|
|
159
159
|
'x-codeSamples': listOf('XCodeSample'),
|
|
160
160
|
'x-code-samples': listOf('XCodeSample'), // deprecated
|
|
161
161
|
'x-hideTryItPanel': { type: 'boolean' },
|
|
@@ -175,12 +175,12 @@ const RequestBody: NodeType = {
|
|
|
175
175
|
properties: {
|
|
176
176
|
description: { type: 'string' },
|
|
177
177
|
required: { type: 'boolean' },
|
|
178
|
-
content: '
|
|
178
|
+
content: 'MediaTypesMap',
|
|
179
179
|
},
|
|
180
180
|
required: ['content'],
|
|
181
181
|
};
|
|
182
182
|
|
|
183
|
-
const
|
|
183
|
+
const MediaTypesMap: NodeType = {
|
|
184
184
|
properties: {},
|
|
185
185
|
additionalProperties: 'MediaType',
|
|
186
186
|
};
|
|
@@ -189,8 +189,8 @@ const MediaType: NodeType = {
|
|
|
189
189
|
properties: {
|
|
190
190
|
schema: 'Schema',
|
|
191
191
|
example: { isExample: true },
|
|
192
|
-
examples:
|
|
193
|
-
encoding:
|
|
192
|
+
examples: 'ExamplesMap',
|
|
193
|
+
encoding: 'EncodingsMap',
|
|
194
194
|
},
|
|
195
195
|
};
|
|
196
196
|
|
|
@@ -206,7 +206,7 @@ const Example: NodeType = {
|
|
|
206
206
|
const Encoding: NodeType = {
|
|
207
207
|
properties: {
|
|
208
208
|
contentType: { type: 'string' },
|
|
209
|
-
headers:
|
|
209
|
+
headers: 'HeadersMap',
|
|
210
210
|
style: {
|
|
211
211
|
enum: ['form', 'simple', 'label', 'matrix', 'spaceDelimited', 'pipeDelimited', 'deepObject'],
|
|
212
212
|
},
|
|
@@ -228,9 +228,10 @@ const Header: NodeType = {
|
|
|
228
228
|
allowReserved: { type: 'boolean' },
|
|
229
229
|
schema: 'Schema',
|
|
230
230
|
example: { isExample: true },
|
|
231
|
-
examples:
|
|
232
|
-
content: '
|
|
231
|
+
examples: 'ExamplesMap',
|
|
232
|
+
content: 'MediaTypesMap',
|
|
233
233
|
},
|
|
234
|
+
requiredOneOf: ['schema', 'content'],
|
|
234
235
|
};
|
|
235
236
|
|
|
236
237
|
const ResponsesMap: NodeType = {
|
|
@@ -242,9 +243,9 @@ const ResponsesMap: NodeType = {
|
|
|
242
243
|
const Response: NodeType = {
|
|
243
244
|
properties: {
|
|
244
245
|
description: { type: 'string' },
|
|
245
|
-
headers:
|
|
246
|
-
content: '
|
|
247
|
-
links:
|
|
246
|
+
headers: 'HeadersMap',
|
|
247
|
+
content: 'MediaTypesMap',
|
|
248
|
+
links: 'LinksMap',
|
|
248
249
|
},
|
|
249
250
|
required: ['description'],
|
|
250
251
|
};
|
|
@@ -459,26 +460,31 @@ const SecurityScheme: NodeType = {
|
|
|
459
460
|
};
|
|
460
461
|
|
|
461
462
|
export const Oas3Types: Record<string, NodeType> = {
|
|
462
|
-
|
|
463
|
+
Root,
|
|
463
464
|
Tag,
|
|
464
465
|
ExternalDocs,
|
|
465
466
|
Server,
|
|
466
467
|
ServerVariable,
|
|
468
|
+
ServerVariablesMap: mapOf('ServerVariable'),
|
|
467
469
|
SecurityRequirement,
|
|
468
470
|
Info,
|
|
469
471
|
Contact,
|
|
470
472
|
License,
|
|
471
|
-
|
|
473
|
+
PathsMap,
|
|
472
474
|
PathItem,
|
|
473
475
|
Parameter,
|
|
474
476
|
Operation,
|
|
475
477
|
Callback: mapOf('PathItem'),
|
|
478
|
+
CallbacksMap: mapOf('Callback'),
|
|
476
479
|
RequestBody,
|
|
477
|
-
|
|
480
|
+
MediaTypesMap,
|
|
478
481
|
MediaType,
|
|
479
482
|
Example,
|
|
483
|
+
ExamplesMap: mapOf('Example'),
|
|
480
484
|
Encoding,
|
|
485
|
+
EncodingsMap: mapOf('Encoding'),
|
|
481
486
|
Header,
|
|
487
|
+
HeadersMap: mapOf('Header'),
|
|
482
488
|
ResponsesMap,
|
|
483
489
|
Response,
|
|
484
490
|
Link,
|
|
@@ -488,6 +494,7 @@ export const Oas3Types: Record<string, NodeType> = {
|
|
|
488
494
|
DiscriminatorMapping,
|
|
489
495
|
Discriminator,
|
|
490
496
|
Components,
|
|
497
|
+
LinksMap: mapOf('Link'),
|
|
491
498
|
NamedSchemas: mapOf('Schema'),
|
|
492
499
|
NamedResponses: mapOf('Response'),
|
|
493
500
|
NamedParameters: mapOf('Parameter'),
|
package/src/types/oas3_1.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NodeType, listOf, mapOf } from '.';
|
|
2
2
|
import { Oas3Types } from './oas3';
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const Root: NodeType = {
|
|
5
5
|
properties: {
|
|
6
6
|
openapi: null,
|
|
7
7
|
info: 'Info',
|
|
@@ -9,7 +9,7 @@ const DefinitionRoot: NodeType = {
|
|
|
9
9
|
security: listOf('SecurityRequirement'),
|
|
10
10
|
tags: listOf('Tag'),
|
|
11
11
|
externalDocs: 'ExternalDocs',
|
|
12
|
-
paths: '
|
|
12
|
+
paths: 'PathsMap',
|
|
13
13
|
webhooks: 'WebhooksMap',
|
|
14
14
|
components: 'Components',
|
|
15
15
|
jsonSchemaDialect: { type: 'string' },
|
|
@@ -241,7 +241,7 @@ const SecurityScheme: NodeType = {
|
|
|
241
241
|
export const Oas3_1Types: Record<string, NodeType> = {
|
|
242
242
|
...Oas3Types,
|
|
243
243
|
Info,
|
|
244
|
-
|
|
244
|
+
Root,
|
|
245
245
|
Schema,
|
|
246
246
|
License,
|
|
247
247
|
Components,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NodeType, listOf } from '.';
|
|
2
2
|
import { omitObjectProps, pickObjectProps, isCustomRuleId } from '../utils';
|
|
3
|
+
|
|
3
4
|
const builtInRulesList = [
|
|
4
5
|
'spec',
|
|
5
6
|
'info-description',
|
|
@@ -8,6 +9,7 @@ const builtInRulesList = [
|
|
|
8
9
|
'info-license-url',
|
|
9
10
|
'operation-2xx-response',
|
|
10
11
|
'operation-4xx-response',
|
|
12
|
+
'operation-4xx-problem-details-rfc7807',
|
|
11
13
|
'assertions',
|
|
12
14
|
'operation-operationId-unique',
|
|
13
15
|
'operation-parameters-unique',
|
|
@@ -31,7 +33,7 @@ const builtInRulesList = [
|
|
|
31
33
|
'path-params-defined',
|
|
32
34
|
'parameter-description',
|
|
33
35
|
'operation-singular-tag',
|
|
34
|
-
'
|
|
36
|
+
'security-defined',
|
|
35
37
|
'no-unresolved-refs',
|
|
36
38
|
'paths-kebab-case',
|
|
37
39
|
'boolean-parameter-prefixes',
|
|
@@ -40,7 +42,7 @@ const builtInRulesList = [
|
|
|
40
42
|
'no-identical-paths',
|
|
41
43
|
'no-ambiguous-paths',
|
|
42
44
|
'no-undefined-server-variable',
|
|
43
|
-
'no-
|
|
45
|
+
'no-server-variables-empty-enum',
|
|
44
46
|
'no-http-verbs-in-paths',
|
|
45
47
|
'path-excludes-patterns',
|
|
46
48
|
'request-mime-type',
|
|
@@ -51,31 +53,38 @@ const builtInRulesList = [
|
|
|
51
53
|
'response-contains-header',
|
|
52
54
|
'response-contains-property',
|
|
53
55
|
'scalar-property-missing-example',
|
|
56
|
+
'spec-components-invalid-map-name',
|
|
54
57
|
];
|
|
55
58
|
const nodeTypesList = [
|
|
56
|
-
'
|
|
59
|
+
'Root',
|
|
57
60
|
'Tag',
|
|
58
61
|
'ExternalDocs',
|
|
59
62
|
'Server',
|
|
60
63
|
'ServerVariable',
|
|
64
|
+
'ServerVariablesMap',
|
|
61
65
|
'SecurityRequirement',
|
|
62
66
|
'Info',
|
|
63
67
|
'Contact',
|
|
64
68
|
'License',
|
|
65
|
-
'
|
|
69
|
+
'PathsMap',
|
|
66
70
|
'PathItem',
|
|
67
71
|
'Parameter',
|
|
68
72
|
'Operation',
|
|
69
73
|
'Callback',
|
|
74
|
+
'CallbacksMap',
|
|
70
75
|
'RequestBody',
|
|
71
|
-
'
|
|
76
|
+
'MediaTypesMap',
|
|
72
77
|
'MediaType',
|
|
73
78
|
'Example',
|
|
79
|
+
'ExamplesMap',
|
|
74
80
|
'Encoding',
|
|
81
|
+
'EncodingsMap',
|
|
75
82
|
'Header',
|
|
83
|
+
'HeadersMap',
|
|
76
84
|
'ResponsesMap',
|
|
77
85
|
'Response',
|
|
78
86
|
'Link',
|
|
87
|
+
'LinksMap',
|
|
79
88
|
'Schema',
|
|
80
89
|
'Xml',
|
|
81
90
|
'SchemaProperties',
|
|
@@ -101,6 +110,39 @@ const nodeTypesList = [
|
|
|
101
110
|
'WebhooksMap',
|
|
102
111
|
];
|
|
103
112
|
|
|
113
|
+
const ConfigStyleguide: NodeType = {
|
|
114
|
+
properties: {
|
|
115
|
+
extends: {
|
|
116
|
+
type: 'array',
|
|
117
|
+
items: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
rules: 'Rules',
|
|
122
|
+
oas2Rules: 'Rules',
|
|
123
|
+
oas3_0Rules: 'Rules',
|
|
124
|
+
oas3_1Rules: 'Rules',
|
|
125
|
+
preprocessors: { type: 'object' },
|
|
126
|
+
oas2Preprocessors: { type: 'object' },
|
|
127
|
+
oas3_0Preprocessors: { type: 'object' },
|
|
128
|
+
oas3_1Preprocessors: { type: 'object' },
|
|
129
|
+
decorators: { type: 'object' },
|
|
130
|
+
oas2Decorators: { type: 'object' },
|
|
131
|
+
oas3_0Decorators: { type: 'object' },
|
|
132
|
+
oas3_1Decorators: { type: 'object' },
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const RootConfigStyleguide: NodeType = {
|
|
137
|
+
properties: {
|
|
138
|
+
plugins: {
|
|
139
|
+
type: 'array',
|
|
140
|
+
items: { type: 'string' },
|
|
141
|
+
},
|
|
142
|
+
...ConfigStyleguide.properties,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
|
|
104
146
|
const ConfigRoot: NodeType = {
|
|
105
147
|
properties: {
|
|
106
148
|
organization: { type: 'string' },
|
|
@@ -110,7 +152,8 @@ const ConfigRoot: NodeType = {
|
|
|
110
152
|
properties: {},
|
|
111
153
|
additionalProperties: { properties: { type: 'string' } },
|
|
112
154
|
}, // deprecated
|
|
113
|
-
|
|
155
|
+
...RootConfigStyleguide.properties,
|
|
156
|
+
styleguide: 'RootConfigStyleguide', // deprecated
|
|
114
157
|
lint: 'RootConfigStyleguide', // deprecated
|
|
115
158
|
'features.openapi': 'ConfigReferenceDocs',
|
|
116
159
|
referenceDocs: 'ConfigReferenceDocs', // deprecated
|
|
@@ -119,6 +162,7 @@ const ConfigRoot: NodeType = {
|
|
|
119
162
|
resolve: {
|
|
120
163
|
properties: {
|
|
121
164
|
http: 'ConfigHTTP',
|
|
165
|
+
doNotResolveExamples: { type: 'boolean' },
|
|
122
166
|
},
|
|
123
167
|
},
|
|
124
168
|
},
|
|
@@ -138,7 +182,9 @@ const ConfigApisProperties: NodeType = {
|
|
|
138
182
|
type: 'string',
|
|
139
183
|
},
|
|
140
184
|
},
|
|
141
|
-
|
|
185
|
+
lint: 'ConfigStyleguide', // deprecated
|
|
186
|
+
styleguide: 'ConfigStyleguide', // deprecated
|
|
187
|
+
...ConfigStyleguide.properties,
|
|
142
188
|
'features.openapi': 'ConfigReferenceDocs',
|
|
143
189
|
'features.mockServer': 'ConfigMockServer',
|
|
144
190
|
},
|
|
@@ -156,40 +202,6 @@ const ConfigHTTP: NodeType = {
|
|
|
156
202
|
},
|
|
157
203
|
};
|
|
158
204
|
|
|
159
|
-
const ConfigStyleguide: NodeType = {
|
|
160
|
-
properties: {
|
|
161
|
-
extends: {
|
|
162
|
-
type: 'array',
|
|
163
|
-
items: {
|
|
164
|
-
type: 'string',
|
|
165
|
-
},
|
|
166
|
-
},
|
|
167
|
-
doNotResolveExamples: { type: 'boolean' },
|
|
168
|
-
rules: 'Rules',
|
|
169
|
-
oas2Rules: 'Rules',
|
|
170
|
-
oas3_0Rules: 'Rules',
|
|
171
|
-
oas3_1Rules: 'Rules',
|
|
172
|
-
preprocessors: { type: 'object' },
|
|
173
|
-
oas2Preprocessors: { type: 'object' },
|
|
174
|
-
oas3_0Preprocessors: { type: 'object' },
|
|
175
|
-
oas3_1Preprocessors: { type: 'object' },
|
|
176
|
-
decorators: { type: 'object' },
|
|
177
|
-
oas2Decorators: { type: 'object' },
|
|
178
|
-
oas3_0Decorators: { type: 'object' },
|
|
179
|
-
oas3_1Decorators: { type: 'object' },
|
|
180
|
-
},
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
const RootConfigStyleguide: NodeType = {
|
|
184
|
-
properties: {
|
|
185
|
-
plugins: {
|
|
186
|
-
type: 'array',
|
|
187
|
-
items: { type: 'string' },
|
|
188
|
-
},
|
|
189
|
-
...ConfigStyleguide.properties,
|
|
190
|
-
},
|
|
191
|
-
};
|
|
192
|
-
|
|
193
205
|
const Rules: NodeType = {
|
|
194
206
|
properties: {},
|
|
195
207
|
additionalProperties: (value: unknown, key: string) => {
|
package/src/utils.ts
CHANGED
|
@@ -6,7 +6,8 @@ import * as pluralize from 'pluralize';
|
|
|
6
6
|
import { parseYaml } from './js-yaml';
|
|
7
7
|
import { UserContext } from './walk';
|
|
8
8
|
import { HttpResolveConfig } from './config';
|
|
9
|
-
import { env } from './
|
|
9
|
+
import { env } from './env';
|
|
10
|
+
import { logger, colorize } from './logger';
|
|
10
11
|
|
|
11
12
|
export { parseYaml, stringifyYaml } from './js-yaml';
|
|
12
13
|
|
|
@@ -32,7 +33,7 @@ export async function loadYaml<T>(filename: string): Promise<T> {
|
|
|
32
33
|
return parseYaml(contents) as T;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
export function
|
|
36
|
+
export function isDefined<T>(x: T | undefined): x is T {
|
|
36
37
|
return x !== undefined;
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -95,7 +96,7 @@ export function omitObjectProps<T extends Record<string, unknown>>(
|
|
|
95
96
|
export function splitCamelCaseIntoWords(str: string) {
|
|
96
97
|
const camel = str
|
|
97
98
|
.split(/(?:[-._])|([A-Z][a-z]+)/)
|
|
98
|
-
.filter(
|
|
99
|
+
.filter(isTruthy)
|
|
99
100
|
.map((item) => item.toLocaleLowerCase());
|
|
100
101
|
const caps = str
|
|
101
102
|
.split(/([A-Z]{2,})/)
|
|
@@ -182,7 +183,7 @@ export function isNotString<T>(value: string | T): value is T {
|
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
export function assignExisting<T>(target: Record<string, T>, obj: Record<string, T>) {
|
|
185
|
-
for (
|
|
186
|
+
for (const k of Object.keys(obj)) {
|
|
186
187
|
if (target.hasOwnProperty(k)) {
|
|
187
188
|
target[k] = obj[k];
|
|
188
189
|
}
|
|
@@ -204,3 +205,29 @@ export function doesYamlFileExist(filePath: string): boolean {
|
|
|
204
205
|
fs.existsSync(filePath)
|
|
205
206
|
);
|
|
206
207
|
}
|
|
208
|
+
|
|
209
|
+
export function showWarningForDeprecatedField(deprecatedField: string, updatedField?: string) {
|
|
210
|
+
logger.warn(
|
|
211
|
+
`The '${colorize.red(deprecatedField)}' field is deprecated. ${
|
|
212
|
+
updatedField ? `Use ${colorize.green(updatedField)} instead. ` : ''
|
|
213
|
+
}Read more about this change: https://redocly.com/docs/api-registry/guides/migration-guide-config-file/#changed-properties\n`
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function showErrorForDeprecatedField(deprecatedField: string, updatedField?: string) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`Do not use '${deprecatedField}' field. ${
|
|
220
|
+
updatedField ? `Use '${updatedField}' instead. ` : ''
|
|
221
|
+
}\n`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export type Falsy = undefined | null | false | '' | 0;
|
|
226
|
+
|
|
227
|
+
export function isTruthy<Truthy>(value: Truthy | Falsy): value is Truthy {
|
|
228
|
+
return !!value;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function identity<T>(value: T): T {
|
|
232
|
+
return value;
|
|
233
|
+
}
|
package/src/visitors.ts
CHANGED
|
@@ -27,7 +27,7 @@ import type {
|
|
|
27
27
|
Oas3Callback,
|
|
28
28
|
} from './typings/openapi';
|
|
29
29
|
|
|
30
|
-
import {
|
|
30
|
+
import type {
|
|
31
31
|
Oas2Definition,
|
|
32
32
|
Oas2Tag,
|
|
33
33
|
Oas2ExternalDocs,
|
|
@@ -45,10 +45,11 @@ import {
|
|
|
45
45
|
Oas2SecurityScheme,
|
|
46
46
|
} from './typings/swagger';
|
|
47
47
|
|
|
48
|
-
import { NormalizedNodeType } from './types';
|
|
49
|
-
import { Stack } from './utils';
|
|
50
|
-
import { UserContext, ResolveResult, ProblemSeverity } from './walk';
|
|
51
|
-
import { Location } from './ref-utils';
|
|
48
|
+
import type { NormalizedNodeType } from './types';
|
|
49
|
+
import type { Stack } from './utils';
|
|
50
|
+
import type { UserContext, ResolveResult, ProblemSeverity } from './walk';
|
|
51
|
+
import type { Location } from './ref-utils';
|
|
52
|
+
|
|
52
53
|
export type VisitFunction<T> = (
|
|
53
54
|
node: T,
|
|
54
55
|
ctx: UserContext & { ignoreNextVisitorsOnNode: () => void },
|
|
@@ -70,7 +71,7 @@ type NestedVisitObject<T, P> = VisitObject<T> & NestedVisitor<P>;
|
|
|
70
71
|
|
|
71
72
|
type VisitFunctionOrObject<T> = VisitFunction<T> | VisitObject<T>;
|
|
72
73
|
|
|
73
|
-
type VisitorNode<T
|
|
74
|
+
type VisitorNode<T> = {
|
|
74
75
|
ruleId: string;
|
|
75
76
|
severity: ProblemSeverity;
|
|
76
77
|
context: VisitorLevelContext | VisitorSkippedLevelContext;
|
|
@@ -126,7 +127,7 @@ export type BaseVisitor = {
|
|
|
126
127
|
};
|
|
127
128
|
|
|
128
129
|
type Oas3FlatVisitor = {
|
|
129
|
-
|
|
130
|
+
Root?: VisitFunctionOrObject<Oas3Definition>;
|
|
130
131
|
Tag?: VisitFunctionOrObject<Oas3Tag>;
|
|
131
132
|
ExternalDocs?: VisitFunctionOrObject<Oas3ExternalDocs>;
|
|
132
133
|
Server?: VisitFunctionOrObject<Oas3Server>;
|
|
@@ -135,13 +136,13 @@ type Oas3FlatVisitor = {
|
|
|
135
136
|
Info?: VisitFunctionOrObject<Oas3Info>;
|
|
136
137
|
Contact?: VisitFunctionOrObject<Oas3Contact>;
|
|
137
138
|
License?: VisitFunctionOrObject<Oas3License>;
|
|
138
|
-
|
|
139
|
+
PathsMap?: VisitFunctionOrObject<Record<string, Oas3PathItem>>;
|
|
139
140
|
PathItem?: VisitFunctionOrObject<Oas3PathItem>;
|
|
140
141
|
Callback?: VisitFunctionOrObject<Record<string, Oas3PathItem>>;
|
|
141
142
|
Parameter?: VisitFunctionOrObject<Oas3Parameter>;
|
|
142
143
|
Operation?: VisitFunctionOrObject<Oas3Operation>;
|
|
143
144
|
RequestBody?: VisitFunctionOrObject<Oas3RequestBody>;
|
|
144
|
-
|
|
145
|
+
MediaTypesMap?: VisitFunctionOrObject<Record<string, Oas3MediaType>>;
|
|
145
146
|
MediaType?: VisitFunctionOrObject<Oas3MediaType>;
|
|
146
147
|
Example?: VisitFunctionOrObject<Oas3Example>;
|
|
147
148
|
Encoding?: VisitFunctionOrObject<Oas3Encoding>;
|
|
@@ -173,14 +174,14 @@ type Oas3FlatVisitor = {
|
|
|
173
174
|
};
|
|
174
175
|
|
|
175
176
|
type Oas2FlatVisitor = {
|
|
176
|
-
|
|
177
|
+
Root?: VisitFunctionOrObject<Oas2Definition>;
|
|
177
178
|
Tag?: VisitFunctionOrObject<Oas2Tag>;
|
|
178
179
|
ExternalDocs?: VisitFunctionOrObject<Oas2ExternalDocs>;
|
|
179
180
|
SecurityRequirement?: VisitFunctionOrObject<Oas2SecurityRequirement>;
|
|
180
181
|
Info?: VisitFunctionOrObject<Oas2Info>;
|
|
181
182
|
Contact?: VisitFunctionOrObject<Oas2Contact>;
|
|
182
183
|
License?: VisitFunctionOrObject<Oas2License>;
|
|
183
|
-
|
|
184
|
+
PathsMap?: VisitFunctionOrObject<Record<string, Oas2PathItem>>;
|
|
184
185
|
PathItem?: VisitFunctionOrObject<Oas2PathItem>;
|
|
185
186
|
Parameter?: VisitFunctionOrObject<any>;
|
|
186
187
|
Operation?: VisitFunctionOrObject<Oas2Operation>;
|
|
@@ -197,6 +198,18 @@ type Oas2FlatVisitor = {
|
|
|
197
198
|
SecurityScheme?: VisitFunctionOrObject<Oas2SecurityScheme>;
|
|
198
199
|
};
|
|
199
200
|
|
|
201
|
+
const legacyTypesMap = {
|
|
202
|
+
Root: 'DefinitionRoot',
|
|
203
|
+
ServerVariablesMap: 'ServerVariableMap',
|
|
204
|
+
PathsMap: 'PathMap',
|
|
205
|
+
CallbacksMap: 'CallbackMap',
|
|
206
|
+
MediaTypesMap: 'MediaTypeMap',
|
|
207
|
+
ExamplesMap: 'ExampleMap',
|
|
208
|
+
EncodingsMap: 'EncodingMap',
|
|
209
|
+
HeadersMap: 'HeaderMap',
|
|
210
|
+
LinksMap: 'LinkMap',
|
|
211
|
+
};
|
|
212
|
+
|
|
200
213
|
type Oas3NestedVisitor = {
|
|
201
214
|
[T in keyof Oas3FlatVisitor]: Oas3FlatVisitor[T] extends Function
|
|
202
215
|
? Oas3FlatVisitor[T]
|
|
@@ -225,7 +238,7 @@ export type Oas2TransformVisitor = BaseVisitor &
|
|
|
225
238
|
Oas2FlatVisitor &
|
|
226
239
|
Record<string, VisitFunction<any> | VisitObject<any>>;
|
|
227
240
|
|
|
228
|
-
export type NestedVisitor<T> = Exclude<T, 'any' | 'ref' | '
|
|
241
|
+
export type NestedVisitor<T> = Exclude<T, 'any' | 'ref' | 'Root'>;
|
|
229
242
|
|
|
230
243
|
export type NormalizedOasVisitors<T extends BaseVisitor> = {
|
|
231
244
|
[V in keyof T]-?: {
|
|
@@ -309,7 +322,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
|
|
|
309
322
|
|
|
310
323
|
const possibleChildren = new Set<NormalizedNodeType>();
|
|
311
324
|
|
|
312
|
-
for (
|
|
325
|
+
for (const type of Object.values(from.properties)) {
|
|
313
326
|
if (type === to) {
|
|
314
327
|
addWeakFromStack(ruleConf, stack);
|
|
315
328
|
continue;
|
|
@@ -333,7 +346,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
|
|
|
333
346
|
}
|
|
334
347
|
}
|
|
335
348
|
|
|
336
|
-
for (
|
|
349
|
+
for (const fromType of Array.from(possibleChildren.values())) {
|
|
337
350
|
addWeakNodes(ruleConf, fromType, to, parentContext, stack);
|
|
338
351
|
}
|
|
339
352
|
|
|
@@ -350,7 +363,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
|
|
|
350
363
|
visit: () => undefined,
|
|
351
364
|
depth: 0,
|
|
352
365
|
context: {
|
|
353
|
-
isSkippedLevel: true
|
|
366
|
+
isSkippedLevel: true,
|
|
354
367
|
seen: new Set(),
|
|
355
368
|
parent: parentContext,
|
|
356
369
|
},
|
|
@@ -380,8 +393,11 @@ export function normalizeVisitors<T extends BaseVisitor>(
|
|
|
380
393
|
}
|
|
381
394
|
|
|
382
395
|
for (const typeName of visitorKeys as Array<keyof T>) {
|
|
383
|
-
const typeVisitor = visitor[typeName]
|
|
384
|
-
|
|
396
|
+
const typeVisitor = (visitor[typeName] ||
|
|
397
|
+
visitor[
|
|
398
|
+
legacyTypesMap[typeName as keyof typeof legacyTypesMap] as keyof T
|
|
399
|
+
]) as any as NestedVisitObject<any, T>;
|
|
400
|
+
const normalizedTypeVisitor = normalizedVisitors[typeName];
|
|
385
401
|
|
|
386
402
|
if (!typeVisitor) continue;
|
|
387
403
|
|
|
@@ -407,7 +423,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
|
|
|
407
423
|
activatedOn: null,
|
|
408
424
|
type: types[typeName],
|
|
409
425
|
parent: parentContext,
|
|
410
|
-
isSkippedLevel: false
|
|
426
|
+
isSkippedLevel: false,
|
|
411
427
|
};
|
|
412
428
|
|
|
413
429
|
if (typeof typeVisitor === 'object') {
|
package/src/walk.ts
CHANGED
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
import { pushStack, popStack } from './utils';
|
|
19
19
|
import { OasVersion } from './oas-types';
|
|
20
20
|
import { NormalizedNodeType, isNamedType } from './types';
|
|
21
|
+
import type { RuleSeverity } from './config';
|
|
22
|
+
|
|
21
23
|
type NonUndefined = string | number | boolean | symbol | bigint | object | Record<string, any>;
|
|
22
24
|
|
|
23
25
|
export type ResolveResult<T extends NonUndefined> =
|
|
@@ -66,7 +68,7 @@ export type Problem = {
|
|
|
66
68
|
suggest?: string[];
|
|
67
69
|
location?: Partial<LocationObject> | Array<Partial<LocationObject>>;
|
|
68
70
|
from?: LocationObject;
|
|
69
|
-
forceSeverity?:
|
|
71
|
+
forceSeverity?: RuleSeverity;
|
|
70
72
|
ruleId?: string;
|
|
71
73
|
};
|
|
72
74
|
|
|
@@ -409,17 +411,19 @@ export function walkDocument<T>(opts: {
|
|
|
409
411
|
: [opts.location]
|
|
410
412
|
: [{ ...currentLocation, reportOnKey: false }];
|
|
411
413
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
414
|
+
const ruleSeverity = opts.forceSeverity || severity;
|
|
415
|
+
if (ruleSeverity !== 'off') {
|
|
416
|
+
ctx.problems.push({
|
|
417
|
+
ruleId: opts.ruleId || ruleId,
|
|
418
|
+
severity: ruleSeverity,
|
|
419
|
+
...opts,
|
|
420
|
+
suggest: opts.suggest || [],
|
|
421
|
+
location: loc.map((loc: any) => {
|
|
422
|
+
return { ...currentLocation, reportOnKey: false, ...loc };
|
|
423
|
+
}),
|
|
424
|
+
});
|
|
425
|
+
}
|
|
421
426
|
}
|
|
422
|
-
|
|
423
427
|
function getVisitorDataFn(ruleId: string) {
|
|
424
428
|
ctx.visitorsData[ruleId] = ctx.visitorsData[ruleId] || {};
|
|
425
429
|
return ctx.visitorsData[ruleId];
|