@redocly/openapi-core 1.0.0-beta.108 → 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/resolve-with-no-external.bench.js +1 -1
- package/lib/bundle.d.ts +1 -1
- package/lib/bundle.js +4 -4
- package/lib/config/all.js +3 -1
- package/lib/config/config-resolvers.js +1 -1
- package/lib/config/minimal.js +3 -1
- package/lib/config/recommended.js +3 -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 +42 -4
- package/lib/decorators/common/registry-dependencies.js +1 -1
- package/lib/format/format.d.ts +1 -1
- package/lib/format/format.js +22 -1
- package/lib/lint.js +2 -2
- package/lib/redocly/registry-api.d.ts +0 -1
- package/lib/redocly/registry-api.js +5 -4
- package/lib/resolve.js +3 -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/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} +18 -4
- package/lib/rules/common/spec.js +12 -1
- 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 +1 -1
- 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 +6 -2
- package/lib/rules/oas3/no-empty-servers.js +1 -1
- package/lib/rules/oas3/no-server-variables-empty-enum.js +1 -1
- package/lib/rules/oas3/no-unused-components.js +1 -1
- 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 +1 -1
- 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/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 +46 -55
- package/lib/utils.d.ts +3 -3
- package/lib/utils.js +5 -5
- package/lib/visitors.d.ts +11 -11
- package/lib/visitors.js +13 -1
- package/package.json +1 -1
- 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__/resolve-http.test.ts +1 -1
- package/src/__tests__/resolve.test.ts +9 -9
- package/src/__tests__/walk.test.ts +78 -10
- package/src/benchmark/benches/resolve-with-no-external.bench.ts +1 -1
- package/src/bundle.ts +4 -4
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +6 -2
- 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 +12 -15
- package/src/config/__tests__/utils.test.ts +64 -4
- package/src/config/all.ts +3 -1
- package/src/config/config-resolvers.ts +2 -2
- package/src/config/load.ts +3 -2
- package/src/config/minimal.ts +3 -1
- package/src/config/recommended.ts +3 -1
- package/src/config/rules.ts +2 -2
- package/src/config/types.ts +11 -0
- package/src/config/utils.ts +102 -13
- package/src/decorators/common/registry-dependencies.ts +1 -1
- package/src/format/format.ts +32 -2
- package/src/lint.ts +2 -2
- package/src/redocly/registry-api.ts +5 -4
- package/src/resolve.ts +3 -1
- package/src/rules/__tests__/utils.test.ts +1 -1
- 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/no-ambiguous-paths.ts +1 -1
- package/src/rules/common/no-identical-paths.ts +1 -1
- 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} +19 -4
- package/src/rules/common/spec.ts +15 -1
- 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 +1 -1
- 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__/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 +6 -2
- package/src/rules/oas3/no-empty-servers.ts +1 -1
- package/src/rules/oas3/no-server-variables-empty-enum.ts +1 -1
- package/src/rules/oas3/no-unused-components.ts +1 -1
- package/src/rules/oas3/operation-4xx-problem-details-rfc7807.ts +36 -0
- package/src/rules/oas3/remove-unused-components.ts +1 -1
- 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/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 +52 -40
- package/src/utils.ts +11 -7
- package/src/visitors.ts +29 -13
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/rules/common/operation-security-defined.d.ts +0 -2
- package/src/rules/common/__tests__/operation-security-defined.test.ts +0 -69
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { makeConfig, parseYamlToDocument } from '../../../../__tests__/utils';
|
|
2
|
+
import { outdent } from 'outdent';
|
|
3
|
+
import { lintDocument } from '../../../lint';
|
|
4
|
+
import { BaseResolver } from '../../../resolve';
|
|
5
|
+
|
|
6
|
+
describe('Oas3 spec-components-invalid-map-name', () => {
|
|
7
|
+
it('should report about invalid keys inside components', async () => {
|
|
8
|
+
const document = parseYamlToDocument(outdent`
|
|
9
|
+
openapi: 3.0.0
|
|
10
|
+
info:
|
|
11
|
+
version: 3.0.0
|
|
12
|
+
components:
|
|
13
|
+
parameters:
|
|
14
|
+
my Param:
|
|
15
|
+
name: param
|
|
16
|
+
description: param
|
|
17
|
+
in: path
|
|
18
|
+
examples:
|
|
19
|
+
invalid identifier:
|
|
20
|
+
description: 'Some description'
|
|
21
|
+
value: 21
|
|
22
|
+
responses:
|
|
23
|
+
400 status:
|
|
24
|
+
description: bad request
|
|
25
|
+
schemas:
|
|
26
|
+
first schema:
|
|
27
|
+
type: integer
|
|
28
|
+
format: int64
|
|
29
|
+
`);
|
|
30
|
+
const results = await lintDocument({
|
|
31
|
+
externalRefResolver: new BaseResolver(),
|
|
32
|
+
document,
|
|
33
|
+
config: await makeConfig({
|
|
34
|
+
'spec-components-invalid-map-name': 'error',
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
expect(results).toMatchInlineSnapshot(`
|
|
39
|
+
Array [
|
|
40
|
+
Object {
|
|
41
|
+
"location": Array [
|
|
42
|
+
Object {
|
|
43
|
+
"pointer": "#/components/parameters/my Param",
|
|
44
|
+
"reportOnKey": true,
|
|
45
|
+
"source": Source {
|
|
46
|
+
"absoluteRef": "",
|
|
47
|
+
"body": "openapi: 3.0.0
|
|
48
|
+
info:
|
|
49
|
+
version: 3.0.0
|
|
50
|
+
components:
|
|
51
|
+
parameters:
|
|
52
|
+
my Param:
|
|
53
|
+
name: param
|
|
54
|
+
description: param
|
|
55
|
+
in: path
|
|
56
|
+
examples:
|
|
57
|
+
invalid identifier:
|
|
58
|
+
description: 'Some description'
|
|
59
|
+
value: 21
|
|
60
|
+
responses:
|
|
61
|
+
400 status:
|
|
62
|
+
description: bad request
|
|
63
|
+
schemas:
|
|
64
|
+
first schema:
|
|
65
|
+
type: integer
|
|
66
|
+
format: int64 ",
|
|
67
|
+
"mimeType": undefined,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
"message": "The map key in parameters \\"my Param\\" does not match the regular expression \\"^[a-zA-Z0-9\\\\.\\\\-_]+$\\"",
|
|
72
|
+
"ruleId": "spec-components-invalid-map-name",
|
|
73
|
+
"severity": "error",
|
|
74
|
+
"suggest": Array [],
|
|
75
|
+
},
|
|
76
|
+
Object {
|
|
77
|
+
"location": Array [
|
|
78
|
+
Object {
|
|
79
|
+
"pointer": "#/components/schemas/first schema",
|
|
80
|
+
"reportOnKey": true,
|
|
81
|
+
"source": Source {
|
|
82
|
+
"absoluteRef": "",
|
|
83
|
+
"body": "openapi: 3.0.0
|
|
84
|
+
info:
|
|
85
|
+
version: 3.0.0
|
|
86
|
+
components:
|
|
87
|
+
parameters:
|
|
88
|
+
my Param:
|
|
89
|
+
name: param
|
|
90
|
+
description: param
|
|
91
|
+
in: path
|
|
92
|
+
examples:
|
|
93
|
+
invalid identifier:
|
|
94
|
+
description: 'Some description'
|
|
95
|
+
value: 21
|
|
96
|
+
responses:
|
|
97
|
+
400 status:
|
|
98
|
+
description: bad request
|
|
99
|
+
schemas:
|
|
100
|
+
first schema:
|
|
101
|
+
type: integer
|
|
102
|
+
format: int64 ",
|
|
103
|
+
"mimeType": undefined,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
"message": "The map key in schemas \\"first schema\\" does not match the regular expression \\"^[a-zA-Z0-9\\\\.\\\\-_]+$\\"",
|
|
108
|
+
"ruleId": "spec-components-invalid-map-name",
|
|
109
|
+
"severity": "error",
|
|
110
|
+
"suggest": Array [],
|
|
111
|
+
},
|
|
112
|
+
Object {
|
|
113
|
+
"location": Array [
|
|
114
|
+
Object {
|
|
115
|
+
"pointer": "#/components/responses/400 status",
|
|
116
|
+
"reportOnKey": true,
|
|
117
|
+
"source": Source {
|
|
118
|
+
"absoluteRef": "",
|
|
119
|
+
"body": "openapi: 3.0.0
|
|
120
|
+
info:
|
|
121
|
+
version: 3.0.0
|
|
122
|
+
components:
|
|
123
|
+
parameters:
|
|
124
|
+
my Param:
|
|
125
|
+
name: param
|
|
126
|
+
description: param
|
|
127
|
+
in: path
|
|
128
|
+
examples:
|
|
129
|
+
invalid identifier:
|
|
130
|
+
description: 'Some description'
|
|
131
|
+
value: 21
|
|
132
|
+
responses:
|
|
133
|
+
400 status:
|
|
134
|
+
description: bad request
|
|
135
|
+
schemas:
|
|
136
|
+
first schema:
|
|
137
|
+
type: integer
|
|
138
|
+
format: int64 ",
|
|
139
|
+
"mimeType": undefined,
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
"message": "The map key in responses \\"400 status\\" does not match the regular expression \\"^[a-zA-Z0-9\\\\.\\\\-_]+$\\"",
|
|
144
|
+
"ruleId": "spec-components-invalid-map-name",
|
|
145
|
+
"severity": "error",
|
|
146
|
+
"suggest": Array [],
|
|
147
|
+
},
|
|
148
|
+
Object {
|
|
149
|
+
"location": Array [
|
|
150
|
+
Object {
|
|
151
|
+
"pointer": "#/components/examples/invalid identifier",
|
|
152
|
+
"reportOnKey": true,
|
|
153
|
+
"source": Source {
|
|
154
|
+
"absoluteRef": "",
|
|
155
|
+
"body": "openapi: 3.0.0
|
|
156
|
+
info:
|
|
157
|
+
version: 3.0.0
|
|
158
|
+
components:
|
|
159
|
+
parameters:
|
|
160
|
+
my Param:
|
|
161
|
+
name: param
|
|
162
|
+
description: param
|
|
163
|
+
in: path
|
|
164
|
+
examples:
|
|
165
|
+
invalid identifier:
|
|
166
|
+
description: 'Some description'
|
|
167
|
+
value: 21
|
|
168
|
+
responses:
|
|
169
|
+
400 status:
|
|
170
|
+
description: bad request
|
|
171
|
+
schemas:
|
|
172
|
+
first schema:
|
|
173
|
+
type: integer
|
|
174
|
+
format: int64 ",
|
|
175
|
+
"mimeType": undefined,
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
"message": "The map key in examples \\"invalid identifier\\" does not match the regular expression \\"^[a-zA-Z0-9\\\\.\\\\-_]+$\\"",
|
|
180
|
+
"ruleId": "spec-components-invalid-map-name",
|
|
181
|
+
"severity": "error",
|
|
182
|
+
"suggest": Array [],
|
|
183
|
+
},
|
|
184
|
+
]
|
|
185
|
+
`);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should not report a key of the example does not match the regular expression', async () => {
|
|
189
|
+
const document = parseYamlToDocument(outdent`
|
|
190
|
+
openapi: 3.0.0
|
|
191
|
+
info:
|
|
192
|
+
version: 3.0.0
|
|
193
|
+
paths:
|
|
194
|
+
/store/subscribe:
|
|
195
|
+
post:
|
|
196
|
+
parameters:
|
|
197
|
+
- name: petId
|
|
198
|
+
in: path
|
|
199
|
+
schema:
|
|
200
|
+
type: integer
|
|
201
|
+
format: int64
|
|
202
|
+
examples:
|
|
203
|
+
valid-identifier-1.key:
|
|
204
|
+
description: 'Some description'
|
|
205
|
+
value: 21
|
|
206
|
+
`);
|
|
207
|
+
const results = await lintDocument({
|
|
208
|
+
externalRefResolver: new BaseResolver(),
|
|
209
|
+
document,
|
|
210
|
+
config: await makeConfig({
|
|
211
|
+
'spec-components-invalid-map-name': 'error',
|
|
212
|
+
}),
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
expect(results).toMatchInlineSnapshot(`Array []`);
|
|
216
|
+
});
|
|
217
|
+
});
|
package/src/rules/oas3/index.ts
CHANGED
|
@@ -25,7 +25,7 @@ import { NoUnusedComponents } from './no-unused-components';
|
|
|
25
25
|
import { PathNotIncludeQuery } from '../common/path-not-include-query';
|
|
26
26
|
import { ParameterDescription } from '../common/parameter-description';
|
|
27
27
|
import { OperationSingularTag } from '../common/operation-singular-tag';
|
|
28
|
-
import {
|
|
28
|
+
import { SecurityDefined } from '../common/security-defined';
|
|
29
29
|
import { NoUnresolvedRefs } from '../no-unresolved-refs';
|
|
30
30
|
import { BooleanParameterPrefixes } from './boolean-parameter-prefixes';
|
|
31
31
|
import { PathsKebabCase } from '../common/paths-kebab-case';
|
|
@@ -48,6 +48,8 @@ import { NoInvalidParameterExamples } from '../common/no-invalid-parameter-examp
|
|
|
48
48
|
import { ResponseContainsHeader } from '../common/response-contains-header';
|
|
49
49
|
import { ResponseContainsProperty } from './response-contains-property';
|
|
50
50
|
import { ScalarPropertyMissingExample } from '../common/scalar-property-missing-example';
|
|
51
|
+
import { SpecComponentsInvalidMapName } from './spec-components-invalid-map-name';
|
|
52
|
+
import { Operation4xxProblemDetailsRfc7807 } from './operation-4xx-problem-details-rfc7807';
|
|
51
53
|
|
|
52
54
|
export const rules = {
|
|
53
55
|
spec: OasSpec,
|
|
@@ -57,6 +59,7 @@ export const rules = {
|
|
|
57
59
|
'info-license-url': InfoLicenseUrl,
|
|
58
60
|
'operation-2xx-response': Operation2xxResponse,
|
|
59
61
|
'operation-4xx-response': Operation4xxResponse,
|
|
62
|
+
'operation-4xx-problem-details-rfc7807': Operation4xxProblemDetailsRfc7807,
|
|
60
63
|
assertions: Assertions,
|
|
61
64
|
'operation-operationId-unique': OperationIdUnique,
|
|
62
65
|
'operation-parameters-unique': OperationParametersUnique,
|
|
@@ -80,7 +83,7 @@ export const rules = {
|
|
|
80
83
|
'path-params-defined': PathParamsDefined,
|
|
81
84
|
'parameter-description': ParameterDescription,
|
|
82
85
|
'operation-singular-tag': OperationSingularTag,
|
|
83
|
-
'
|
|
86
|
+
'security-defined': SecurityDefined,
|
|
84
87
|
'no-unresolved-refs': NoUnresolvedRefs,
|
|
85
88
|
'paths-kebab-case': PathsKebabCase,
|
|
86
89
|
'boolean-parameter-prefixes': BooleanParameterPrefixes,
|
|
@@ -100,6 +103,7 @@ export const rules = {
|
|
|
100
103
|
'response-contains-header': ResponseContainsHeader,
|
|
101
104
|
'response-contains-property': ResponseContainsProperty,
|
|
102
105
|
'scalar-property-missing-example': ScalarPropertyMissingExample,
|
|
106
|
+
'spec-components-invalid-map-name': SpecComponentsInvalidMapName,
|
|
103
107
|
} as Oas3RuleSet;
|
|
104
108
|
|
|
105
109
|
export const preprocessors = {};
|
|
@@ -2,7 +2,7 @@ import { Oas3Rule } from '../../visitors';
|
|
|
2
2
|
|
|
3
3
|
export const NoEmptyServers: Oas3Rule = () => {
|
|
4
4
|
return {
|
|
5
|
-
|
|
5
|
+
Root(root, { report, location }) {
|
|
6
6
|
if (!root.hasOwnProperty('servers')) {
|
|
7
7
|
report({
|
|
8
8
|
message: 'Servers must be present.',
|
|
@@ -8,7 +8,7 @@ enum enumError {
|
|
|
8
8
|
|
|
9
9
|
export const NoServerVariablesEmptyEnum: Oas3Rule = () => {
|
|
10
10
|
return {
|
|
11
|
-
|
|
11
|
+
Root(root, { report, location }) {
|
|
12
12
|
if (!root.servers || root.servers.length === 0) return;
|
|
13
13
|
|
|
14
14
|
const invalidVariables: enumError[] = [];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Oas3MediaType, Oas3Response, Oas3Schema } from 'core/src/typings/openapi';
|
|
2
|
+
import { Oas3Rule } from '../../visitors';
|
|
3
|
+
import { UserContext } from '../../walk';
|
|
4
|
+
import { validateDefinedAndNonEmpty } from '../utils';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Validation according rfc7807 - https://datatracker.ietf.org/doc/html/rfc7807
|
|
8
|
+
*/
|
|
9
|
+
export const Operation4xxProblemDetailsRfc7807: Oas3Rule = () => {
|
|
10
|
+
return {
|
|
11
|
+
Response: {
|
|
12
|
+
skip(_response: Oas3Response, key: string | number) {
|
|
13
|
+
return !/4[Xx0-9]{2}/.test(`${key}`);
|
|
14
|
+
},
|
|
15
|
+
enter(response: Oas3Response, { report, location }: UserContext) {
|
|
16
|
+
if (!response.content || !response.content['application/problem+json'])
|
|
17
|
+
report({
|
|
18
|
+
message: 'Response `4xx` must have content-type `application/problem+json`.',
|
|
19
|
+
location: location.key(),
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
MediaType: {
|
|
23
|
+
skip(_response: Oas3MediaType, key: string | number) {
|
|
24
|
+
return key !== 'application/problem+json';
|
|
25
|
+
},
|
|
26
|
+
enter(media: Oas3MediaType, ctx: UserContext) {
|
|
27
|
+
validateDefinedAndNonEmpty('schema', media, ctx);
|
|
28
|
+
},
|
|
29
|
+
SchemaProperties(schema: Oas3Schema, ctx: UserContext) {
|
|
30
|
+
validateDefinedAndNonEmpty('type', schema, ctx);
|
|
31
|
+
validateDefinedAndNonEmpty('title', schema, ctx);
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -5,7 +5,7 @@ import { validateMimeTypeOAS3 } from '../../utils';
|
|
|
5
5
|
|
|
6
6
|
export const RequestMimeType: Oas3Rule = ({ allowedValues }) => {
|
|
7
7
|
return {
|
|
8
|
-
|
|
8
|
+
PathsMap: {
|
|
9
9
|
RequestBody: {
|
|
10
10
|
leave(requestBody: Oas3RequestBody, ctx: UserContext) {
|
|
11
11
|
validateMimeTypeOAS3({ type: 'consumes', value: requestBody }, ctx, allowedValues);
|
|
@@ -5,7 +5,7 @@ import { validateMimeTypeOAS3 } from '../../utils';
|
|
|
5
5
|
|
|
6
6
|
export const ResponseMimeType: Oas3Rule = ({ allowedValues }) => {
|
|
7
7
|
return {
|
|
8
|
-
|
|
8
|
+
PathsMap: {
|
|
9
9
|
Response: {
|
|
10
10
|
leave(response: Oas3Response, ctx: UserContext) {
|
|
11
11
|
validateMimeTypeOAS3({ type: 'produces', value: response }, ctx, allowedValues);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Oas3Rule } from '../../visitors';
|
|
2
|
+
import { Problem, UserContext } from '../../walk';
|
|
3
|
+
import { Location } from '../../ref-utils';
|
|
4
|
+
|
|
5
|
+
export const SpecComponentsInvalidMapName: Oas3Rule = () => {
|
|
6
|
+
const KEYS_REGEX = '^[a-zA-Z0-9\\.\\-_]+$';
|
|
7
|
+
|
|
8
|
+
function validateKey(
|
|
9
|
+
key: string | number,
|
|
10
|
+
report: (problem: Problem) => void,
|
|
11
|
+
location: Location,
|
|
12
|
+
component: string
|
|
13
|
+
) {
|
|
14
|
+
if (!new RegExp(KEYS_REGEX).test(key as string)) {
|
|
15
|
+
report({
|
|
16
|
+
message: `The map key in ${component} "${key}" does not match the regular expression "${KEYS_REGEX}"`,
|
|
17
|
+
location: location.key(),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
Components: {
|
|
24
|
+
Parameter(_node, { key, report, location }: UserContext) {
|
|
25
|
+
validateKey(key, report, location, 'parameters');
|
|
26
|
+
},
|
|
27
|
+
Response(_node, { key, report, location }: UserContext) {
|
|
28
|
+
validateKey(key, report, location, 'responses');
|
|
29
|
+
},
|
|
30
|
+
Schema(_node, { key, report, location }: UserContext) {
|
|
31
|
+
validateKey(key, report, location, 'schemas');
|
|
32
|
+
},
|
|
33
|
+
Example(_node, { key, report, location }: UserContext) {
|
|
34
|
+
validateKey(key, report, location, 'examples');
|
|
35
|
+
},
|
|
36
|
+
RequestBody(_node, { key, report, location }: UserContext) {
|
|
37
|
+
validateKey(key, report, location, 'requestBodies');
|
|
38
|
+
},
|
|
39
|
+
Header(_node, { key, report, location }: UserContext) {
|
|
40
|
+
validateKey(key, report, location, 'headers');
|
|
41
|
+
},
|
|
42
|
+
SecurityScheme(_node, { key, report, location }: UserContext) {
|
|
43
|
+
validateKey(key, report, location, 'securitySchemas');
|
|
44
|
+
},
|
|
45
|
+
Link(_node, { key, report, location }: UserContext) {
|
|
46
|
+
validateKey(key, report, location, 'links');
|
|
47
|
+
},
|
|
48
|
+
Callback(_node, { key, report, location }: UserContext) {
|
|
49
|
+
validateKey(key, report, location, 'callbacks');
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
};
|
package/src/rules/other/stats.ts
CHANGED
|
@@ -24,7 +24,7 @@ export const Stats = (statsAccumulator: StatsAccumulator) => {
|
|
|
24
24
|
statsAccumulator.links.items!.add(link.operationId);
|
|
25
25
|
},
|
|
26
26
|
},
|
|
27
|
-
|
|
27
|
+
Root: {
|
|
28
28
|
leave() {
|
|
29
29
|
statsAccumulator.parameters.total = statsAccumulator.parameters.items!.size;
|
|
30
30
|
statsAccumulator.refs.total = statsAccumulator.refs.items!.size;
|
|
@@ -41,7 +41,7 @@ export const Stats = (statsAccumulator: StatsAccumulator) => {
|
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
43
|
},
|
|
44
|
-
|
|
44
|
+
PathsMap: {
|
|
45
45
|
PathItem: {
|
|
46
46
|
leave() {
|
|
47
47
|
statsAccumulator.pathItems.total++;
|
package/src/types/index.ts
CHANGED
|
@@ -73,7 +73,7 @@ export function normalizeTypes(
|
|
|
73
73
|
normalizedTypes[typeName] = {
|
|
74
74
|
...types[typeName],
|
|
75
75
|
name: typeName,
|
|
76
|
-
} as
|
|
76
|
+
} as NormalizedNodeType;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
for (const type of Object.values(normalizedTypes)) {
|
|
@@ -81,7 +81,7 @@ export function normalizeTypes(
|
|
|
81
81
|
}
|
|
82
82
|
return normalizedTypes;
|
|
83
83
|
|
|
84
|
-
function normalizeType(type:
|
|
84
|
+
function normalizeType(type: NormalizedNodeType) {
|
|
85
85
|
if (type.additionalProperties) {
|
|
86
86
|
type.additionalProperties = resolveType(type.additionalProperties);
|
|
87
87
|
}
|
package/src/types/oas2.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { NodeType, listOf, mapOf } from '.';
|
|
|
2
2
|
|
|
3
3
|
const responseCodeRegexp = /^[0-9][0-9Xx]{2}$/;
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const Root: NodeType = {
|
|
6
6
|
properties: {
|
|
7
7
|
swagger: { type: 'string' },
|
|
8
8
|
info: 'Info',
|
|
@@ -11,7 +11,7 @@ const DefinitionRoot: NodeType = {
|
|
|
11
11
|
schemes: { type: 'array', items: { type: 'string' } },
|
|
12
12
|
consumes: { type: 'array', items: { type: 'string' } },
|
|
13
13
|
produces: { type: 'array', items: { type: 'string' } },
|
|
14
|
-
paths: '
|
|
14
|
+
paths: 'PathsMap',
|
|
15
15
|
definitions: 'NamedSchemas',
|
|
16
16
|
parameters: 'NamedParameters',
|
|
17
17
|
responses: 'NamedResponses',
|
|
@@ -51,7 +51,7 @@ const License: NodeType = {
|
|
|
51
51
|
required: ['name'],
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
-
const
|
|
54
|
+
const PathsMap: NodeType = {
|
|
55
55
|
properties: {},
|
|
56
56
|
additionalProperties: (_value: any, key: string) =>
|
|
57
57
|
key.startsWith('/') ? 'PathItem' : undefined,
|
|
@@ -369,14 +369,14 @@ const SecurityRequirement: NodeType = {
|
|
|
369
369
|
};
|
|
370
370
|
|
|
371
371
|
export const Oas2Types: Record<string, NodeType> = {
|
|
372
|
-
|
|
372
|
+
Root,
|
|
373
373
|
Tag,
|
|
374
374
|
ExternalDocs,
|
|
375
375
|
SecurityRequirement,
|
|
376
376
|
Info,
|
|
377
377
|
Contact,
|
|
378
378
|
License,
|
|
379
|
-
|
|
379
|
+
PathsMap,
|
|
380
380
|
PathItem,
|
|
381
381
|
Parameter,
|
|
382
382
|
ParameterItems,
|
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,
|