@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.
Files changed (193) hide show
  1. package/lib/benchmark/benches/lint-with-top-level-rule-report.bench.js +0 -1
  2. package/lib/benchmark/benches/resolve-with-no-external.bench.js +1 -1
  3. package/lib/bundle.d.ts +1 -1
  4. package/lib/bundle.js +9 -6
  5. package/lib/config/all.js +5 -3
  6. package/lib/config/config-resolvers.js +32 -14
  7. package/lib/config/config.d.ts +3 -5
  8. package/lib/config/config.js +7 -4
  9. package/lib/config/load.d.ts +7 -0
  10. package/lib/config/load.js +14 -6
  11. package/lib/config/minimal.js +7 -4
  12. package/lib/config/recommended.js +7 -4
  13. package/lib/config/rules.d.ts +1 -1
  14. package/lib/config/rules.js +1 -1
  15. package/lib/config/types.d.ts +7 -0
  16. package/lib/config/utils.d.ts +2 -2
  17. package/lib/config/utils.js +49 -11
  18. package/lib/decorators/common/registry-dependencies.js +2 -2
  19. package/lib/env.d.ts +3 -0
  20. package/lib/env.js +8 -0
  21. package/lib/format/codeframes.js +16 -10
  22. package/lib/format/format.d.ts +1 -1
  23. package/lib/format/format.js +49 -26
  24. package/lib/index.d.ts +5 -5
  25. package/lib/index.js +3 -1
  26. package/lib/js-yaml/index.js +1 -0
  27. package/lib/lint.js +2 -2
  28. package/lib/logger.d.ts +10 -0
  29. package/lib/logger.js +31 -0
  30. package/lib/output.d.ts +3 -0
  31. package/lib/output.js +9 -0
  32. package/lib/redocly/index.js +10 -9
  33. package/lib/redocly/registry-api-types.d.ts +28 -30
  34. package/lib/redocly/registry-api.d.ts +3 -3
  35. package/lib/redocly/registry-api.js +7 -1
  36. package/lib/ref-utils.js +2 -1
  37. package/lib/resolve.d.ts +1 -1
  38. package/lib/resolve.js +4 -2
  39. package/lib/rules/ajv.d.ts +1 -1
  40. package/lib/rules/ajv.js +7 -7
  41. package/lib/rules/common/assertions/asserts.js +4 -4
  42. package/lib/rules/common/assertions/index.js +1 -1
  43. package/lib/rules/common/no-ambiguous-paths.js +1 -1
  44. package/lib/rules/common/no-identical-paths.js +1 -1
  45. package/lib/rules/common/no-invalid-parameter-examples.js +3 -3
  46. package/lib/rules/common/no-invalid-schema-examples.js +3 -3
  47. package/lib/rules/common/operation-2xx-response.js +1 -1
  48. package/lib/rules/common/operation-4xx-response.js +1 -1
  49. package/lib/rules/common/operation-operationId.js +1 -1
  50. package/lib/rules/common/operation-tag-defined.js +1 -1
  51. package/lib/rules/common/path-not-include-query.js +1 -1
  52. package/lib/rules/common/security-defined.d.ts +2 -0
  53. package/lib/rules/common/{operation-security-defined.js → security-defined.js} +19 -5
  54. package/lib/rules/common/spec.js +14 -3
  55. package/lib/rules/common/tags-alphabetical.js +1 -1
  56. package/lib/rules/oas2/index.d.ts +1 -1
  57. package/lib/rules/oas2/index.js +2 -2
  58. package/lib/rules/oas2/remove-unused-components.js +3 -3
  59. package/lib/rules/oas2/request-mime-type.js +1 -1
  60. package/lib/rules/oas2/response-mime-type.js +1 -1
  61. package/lib/rules/oas3/index.js +8 -4
  62. package/lib/rules/oas3/no-empty-servers.js +1 -1
  63. package/lib/rules/oas3/no-invalid-media-type-examples.js +2 -2
  64. package/lib/rules/oas3/no-server-variables-empty-enum.d.ts +2 -0
  65. package/lib/rules/oas3/{no-servers-empty-enum.js → no-server-variables-empty-enum.js} +5 -5
  66. package/lib/rules/oas3/no-unused-components.js +2 -2
  67. package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.d.ts +5 -0
  68. package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.js +36 -0
  69. package/lib/rules/oas3/remove-unused-components.js +4 -4
  70. package/lib/rules/oas3/request-mime-type.js +1 -1
  71. package/lib/rules/oas3/response-mime-type.js +1 -1
  72. package/lib/rules/oas3/spec-components-invalid-map-name.d.ts +2 -0
  73. package/lib/rules/oas3/spec-components-invalid-map-name.js +46 -0
  74. package/lib/rules/other/stats.d.ts +2 -2
  75. package/lib/rules/other/stats.js +2 -2
  76. package/lib/rules/utils.d.ts +3 -2
  77. package/lib/rules/utils.js +16 -4
  78. package/lib/types/oas2.js +5 -5
  79. package/lib/types/oas3.js +27 -20
  80. package/lib/types/oas3_1.js +3 -3
  81. package/lib/types/redocly-yaml.js +47 -56
  82. package/lib/utils.d.ts +6 -1
  83. package/lib/utils.js +24 -7
  84. package/lib/visitors.d.ts +12 -12
  85. package/lib/visitors.js +15 -3
  86. package/lib/walk.d.ts +2 -1
  87. package/lib/walk.js +6 -3
  88. package/package.json +2 -2
  89. package/src/__tests__/__snapshots__/bundle.test.ts.snap +3 -3
  90. package/src/__tests__/fixtures/extension.js +3 -3
  91. package/src/__tests__/format.test.ts +76 -0
  92. package/src/__tests__/lint.test.ts +106 -131
  93. package/src/__tests__/logger-browser.test.ts +53 -0
  94. package/src/__tests__/logger.test.ts +47 -0
  95. package/src/__tests__/output-browser.test.ts +18 -0
  96. package/src/__tests__/output.test.ts +15 -0
  97. package/src/__tests__/resolve-http.test.ts +1 -1
  98. package/src/__tests__/resolve.test.ts +9 -9
  99. package/src/__tests__/utils-browser.test.ts +11 -0
  100. package/src/__tests__/utils.test.ts +7 -0
  101. package/src/__tests__/walk.test.ts +78 -10
  102. package/src/benchmark/benches/lint-with-top-level-rule-report.bench.ts +0 -1
  103. package/src/benchmark/benches/resolve-with-no-external.bench.ts +1 -1
  104. package/src/bundle.ts +10 -7
  105. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +12 -6
  106. package/src/config/__tests__/config.test.ts +35 -0
  107. package/src/config/__tests__/fixtures/plugin-config.yaml +2 -3
  108. package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +11 -12
  109. package/src/config/__tests__/fixtures/resolve-config/local-config-with-circular.yaml +7 -8
  110. package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +18 -19
  111. package/src/config/__tests__/fixtures/resolve-config/local-config.yaml +9 -10
  112. package/src/config/__tests__/fixtures/resolve-remote-configs/nested-remote-config.yaml +3 -4
  113. package/src/config/__tests__/fixtures/resolve-remote-configs/remote-config.yaml +4 -5
  114. package/src/config/__tests__/load.test.ts +76 -1
  115. package/src/config/__tests__/utils.test.ts +64 -4
  116. package/src/config/all.ts +5 -3
  117. package/src/config/config-resolvers.ts +45 -19
  118. package/src/config/config.ts +10 -8
  119. package/src/config/load.ts +31 -7
  120. package/src/config/minimal.ts +7 -4
  121. package/src/config/recommended.ts +7 -4
  122. package/src/config/rules.ts +2 -2
  123. package/src/config/types.ts +11 -0
  124. package/src/config/utils.ts +115 -25
  125. package/src/decorators/common/registry-dependencies.ts +2 -2
  126. package/src/env.ts +5 -0
  127. package/src/format/codeframes.ts +15 -9
  128. package/src/format/format.ts +59 -34
  129. package/src/index.ts +6 -4
  130. package/src/js-yaml/index.ts +1 -0
  131. package/src/lint.ts +2 -2
  132. package/src/logger.ts +34 -0
  133. package/src/output.ts +7 -0
  134. package/src/redocly/index.ts +7 -4
  135. package/src/redocly/registry-api-types.ts +27 -29
  136. package/src/redocly/registry-api.ts +18 -7
  137. package/src/ref-utils.ts +2 -1
  138. package/src/resolve.ts +7 -5
  139. package/src/rules/__tests__/utils.test.ts +39 -1
  140. package/src/rules/ajv.ts +7 -7
  141. package/src/rules/common/__tests__/no-enum-type-mismatch.test.ts +1 -0
  142. package/src/rules/common/__tests__/operation-2xx-response.test.ts +1 -1
  143. package/src/rules/common/__tests__/operation-4xx-response.test.ts +26 -3
  144. package/src/rules/common/__tests__/security-defined.test.ts +175 -0
  145. package/src/rules/common/__tests__/spec.test.ts +79 -0
  146. package/src/rules/common/assertions/__tests__/utils.test.ts +2 -2
  147. package/src/rules/common/assertions/asserts.ts +4 -4
  148. package/src/rules/common/assertions/index.ts +1 -1
  149. package/src/rules/common/no-ambiguous-paths.ts +1 -1
  150. package/src/rules/common/no-identical-paths.ts +1 -1
  151. package/src/rules/common/no-invalid-parameter-examples.ts +4 -4
  152. package/src/rules/common/no-invalid-schema-examples.ts +4 -4
  153. package/src/rules/common/operation-2xx-response.ts +1 -1
  154. package/src/rules/common/operation-4xx-response.ts +1 -1
  155. package/src/rules/common/operation-operationId.ts +1 -1
  156. package/src/rules/common/operation-tag-defined.ts +1 -1
  157. package/src/rules/common/path-not-include-query.ts +1 -1
  158. package/src/rules/common/{operation-security-defined.ts → security-defined.ts} +20 -5
  159. package/src/rules/common/spec.ts +17 -3
  160. package/src/rules/common/tags-alphabetical.ts +1 -1
  161. package/src/rules/oas2/index.ts +2 -2
  162. package/src/rules/oas2/remove-unused-components.ts +3 -3
  163. package/src/rules/oas2/request-mime-type.ts +1 -1
  164. package/src/rules/oas2/response-mime-type.ts +1 -1
  165. package/src/rules/oas3/__tests__/no-empty-enum-servers.com.test.ts +16 -16
  166. package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +5 -5
  167. package/src/rules/oas3/__tests__/operation-4xx-problem-details-rfc7807.test.ts +145 -0
  168. package/src/rules/oas3/__tests__/spec/spec.test.ts +10 -0
  169. package/src/rules/oas3/__tests__/spec-components-invalid-map-name.test.ts +217 -0
  170. package/src/rules/oas3/index.ts +8 -4
  171. package/src/rules/oas3/no-empty-servers.ts +1 -1
  172. package/src/rules/oas3/no-invalid-media-type-examples.ts +3 -3
  173. package/src/rules/oas3/{no-servers-empty-enum.ts → no-server-variables-empty-enum.ts} +3 -3
  174. package/src/rules/oas3/no-unused-components.ts +2 -2
  175. package/src/rules/oas3/operation-4xx-problem-details-rfc7807.ts +36 -0
  176. package/src/rules/oas3/remove-unused-components.ts +5 -5
  177. package/src/rules/oas3/request-mime-type.ts +1 -1
  178. package/src/rules/oas3/response-mime-type.ts +1 -1
  179. package/src/rules/oas3/spec-components-invalid-map-name.ts +53 -0
  180. package/src/rules/other/stats.ts +2 -2
  181. package/src/rules/utils.ts +17 -3
  182. package/src/types/index.ts +2 -2
  183. package/src/types/oas2.ts +5 -5
  184. package/src/types/oas3.ts +27 -20
  185. package/src/types/oas3_1.ts +3 -3
  186. package/src/types/redocly-yaml.ts +53 -41
  187. package/src/utils.ts +31 -4
  188. package/src/visitors.ts +34 -18
  189. package/src/walk.ts +15 -11
  190. package/tsconfig.tsbuildinfo +1 -1
  191. package/lib/rules/common/operation-security-defined.d.ts +0 -2
  192. package/lib/rules/oas3/no-servers-empty-enum.d.ts +0 -2
  193. 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
+ });
@@ -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 { OperationSecurityDefined } from '../common/operation-security-defined';
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';
@@ -37,7 +37,7 @@ import { NoUndefinedServerVariable } from './no-undefined-server-variable';
37
37
  import { OperationOperationId } from '../common/operation-operationId';
38
38
  import { OperationSummary } from '../common/operation-summary';
39
39
  import { NoAmbiguousPaths } from '../common/no-ambiguous-paths';
40
- import { NoEmptyEnumServers } from './no-servers-empty-enum';
40
+ import { NoServerVariablesEmptyEnum } from './no-server-variables-empty-enum';
41
41
  import { NoHttpVerbsInPaths } from '../common/no-http-verbs-in-paths';
42
42
  import { RequestMimeType } from './request-mime-type';
43
43
  import { ResponseMimeType } from './response-mime-type';
@@ -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
- 'operation-security-defined': OperationSecurityDefined,
86
+ 'security-defined': SecurityDefined,
84
87
  'no-unresolved-refs': NoUnresolvedRefs,
85
88
  'paths-kebab-case': PathsKebabCase,
86
89
  'boolean-parameter-prefixes': BooleanParameterPrefixes,
@@ -89,7 +92,7 @@ export const rules = {
89
92
  'no-identical-paths': NoIdenticalPaths,
90
93
  'no-ambiguous-paths': NoAmbiguousPaths,
91
94
  'no-undefined-server-variable': NoUndefinedServerVariable,
92
- 'no-servers-empty-enum': NoEmptyEnumServers,
95
+ 'no-server-variables-empty-enum': NoServerVariablesEmptyEnum,
93
96
  'no-http-verbs-in-paths': NoHttpVerbsInPaths,
94
97
  'path-excludes-patterns': PathExcludesPatterns,
95
98
  'request-mime-type': RequestMimeType,
@@ -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
- DefinitionRoot(root, { report, location }) {
5
+ Root(root, { report, location }) {
6
6
  if (!root.hasOwnProperty('servers')) {
7
7
  report({
8
8
  message: 'Servers must be present.',
@@ -1,11 +1,11 @@
1
1
  import { Oas3Rule } from '../../visitors';
2
2
  import { Location, isRef } from '../../ref-utils';
3
3
  import { Oas3Example } from '../../typings/openapi';
4
- import { validateExample } from '../utils';
4
+ import { getAdditionalPropertiesOption, validateExample } from '../utils';
5
5
  import { UserContext } from '../../walk';
6
6
 
7
7
  export const ValidContentExamples: Oas3Rule = (opts) => {
8
- const disallowAdditionalProperties = opts.disallowAdditionalProperties ?? true;
8
+ const allowAdditionalProperties = getAdditionalPropertiesOption(opts) ?? false;
9
9
 
10
10
  return {
11
11
  MediaType: {
@@ -40,7 +40,7 @@ export const ValidContentExamples: Oas3Rule = (opts) => {
40
40
  mediaType.schema!,
41
41
  location,
42
42
  ctx,
43
- disallowAdditionalProperties
43
+ allowAdditionalProperties
44
44
  );
45
45
  }
46
46
  },
@@ -6,9 +6,9 @@ enum enumError {
6
6
  invalidDefaultValue = 'invalidDefaultValue',
7
7
  }
8
8
 
9
- export const NoEmptyEnumServers: Oas3Rule = () => {
9
+ export const NoServerVariablesEmptyEnum: Oas3Rule = () => {
10
10
  return {
11
- DefinitionRoot(root, { report, location }) {
11
+ Root(root, { report, location }) {
12
12
  if (!root.servers || root.servers.length === 0) return;
13
13
 
14
14
  const invalidVariables: enumError[] = [];
@@ -48,7 +48,7 @@ function checkEnumVariables(server: Oas3Server): enumError[] | undefined {
48
48
  if (server.variables && Object.keys(server.variables).length === 0) return;
49
49
 
50
50
  const errors: enumError[] = [];
51
- for (var variable in server.variables) {
51
+ for (const variable in server.variables) {
52
52
  const serverVariable = server.variables[variable];
53
53
  if (!serverVariable.enum) continue;
54
54
 
@@ -2,7 +2,7 @@ import { Oas3Rule } from '../../visitors';
2
2
  import { Location } from '../../ref-utils';
3
3
 
4
4
  export const NoUnusedComponents: Oas3Rule = () => {
5
- let components = new Map<string, { used: boolean; location: Location; name: string }>();
5
+ const components = new Map<string, { used: boolean; location: Location; name: string }>();
6
6
 
7
7
  function registerComponent(location: Location, name: string): void {
8
8
  components.set(location.absolutePointer, {
@@ -26,7 +26,7 @@ export const NoUnusedComponents: Oas3Rule = () => {
26
26
  });
27
27
  }
28
28
  },
29
- DefinitionRoot: {
29
+ Root: {
30
30
  leave(_, { report }) {
31
31
  components.forEach((usageInfo) => {
32
32
  if (!usageInfo.used) {
@@ -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
+ };
@@ -4,7 +4,7 @@ import { Oas3Components } from '../../typings/openapi';
4
4
  import { isEmptyObject } from '../../utils';
5
5
 
6
6
  export const RemoveUnusedComponents: Oas3Rule = () => {
7
- let components = new Map<
7
+ const components = new Map<
8
8
  string,
9
9
  { used: boolean; componentType?: keyof Oas3Components; name: string }
10
10
  >();
@@ -38,19 +38,19 @@ export const RemoveUnusedComponents: Oas3Rule = () => {
38
38
  }
39
39
  },
40
40
  },
41
- DefinitionRoot: {
41
+ Root: {
42
42
  leave(root, ctx) {
43
43
  const data = ctx.getVisitorData() as { removedCount: number };
44
44
  data.removedCount = 0;
45
45
 
46
46
  components.forEach((usageInfo) => {
47
47
  const { used, componentType, name } = usageInfo;
48
- if (!used && componentType) {
49
- let componentChild = root.components![componentType];
48
+ if (!used && componentType && root.components) {
49
+ const componentChild = root.components[componentType];
50
50
  delete componentChild![name];
51
51
  data.removedCount++;
52
52
  if (isEmptyObject(componentChild)) {
53
- delete root.components![componentType];
53
+ delete root.components[componentType];
54
54
  }
55
55
  }
56
56
  });
@@ -5,7 +5,7 @@ import { validateMimeTypeOAS3 } from '../../utils';
5
5
 
6
6
  export const RequestMimeType: Oas3Rule = ({ allowedValues }) => {
7
7
  return {
8
- PathMap: {
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
- PathMap: {
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
+ };
@@ -24,7 +24,7 @@ export const Stats = (statsAccumulator: StatsAccumulator) => {
24
24
  statsAccumulator.links.items!.add(link.operationId);
25
25
  },
26
26
  },
27
- DefinitionRoot: {
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
- PathMap: {
44
+ PathsMap: {
45
45
  PathItem: {
46
46
  leave() {
47
47
  statsAccumulator.pathItems.total++;
@@ -3,6 +3,7 @@ import { UserContext } from '../walk';
3
3
  import { Location } from '../ref-utils';
4
4
  import { validateJsonSchema } from './ajv';
5
5
  import { Oas3Schema, Referenced } from '../typings/openapi';
6
+ import { showErrorForDeprecatedField, showWarningForDeprecatedField } from '../utils';
6
7
 
7
8
  export function oasTypeOf(value: unknown) {
8
9
  if (Array.isArray(value)) {
@@ -91,7 +92,7 @@ export function validateExample(
91
92
  schema: Referenced<Oas3Schema>,
92
93
  dataLoc: Location,
93
94
  { resolve, location, report }: UserContext,
94
- disallowAdditionalProperties: boolean
95
+ allowAdditionalProperties: boolean
95
96
  ) {
96
97
  try {
97
98
  const { valid, errors } = validateJsonSchema(
@@ -100,10 +101,10 @@ export function validateExample(
100
101
  location.child('schema'),
101
102
  dataLoc.pointer,
102
103
  resolve,
103
- disallowAdditionalProperties
104
+ allowAdditionalProperties
104
105
  );
105
106
  if (!valid) {
106
- for (let error of errors) {
107
+ for (const error of errors) {
107
108
  report({
108
109
  message: `Example value must conform to the schema: ${error.message}.`,
109
110
  location: {
@@ -123,3 +124,16 @@ export function validateExample(
123
124
  });
124
125
  }
125
126
  }
127
+
128
+ export function getAdditionalPropertiesOption(opts: Record<string, any>): boolean {
129
+ if (opts.disallowAdditionalProperties === undefined) {
130
+ return opts.allowAdditionalProperties;
131
+ }
132
+
133
+ if (opts.allowAdditionalProperties !== undefined) {
134
+ showErrorForDeprecatedField('disallowAdditionalProperties', 'allowAdditionalProperties');
135
+ }
136
+
137
+ showWarningForDeprecatedField('disallowAdditionalProperties', 'allowAdditionalProperties');
138
+ return !opts.disallowAdditionalProperties;
139
+ }
@@ -73,7 +73,7 @@ export function normalizeTypes(
73
73
  normalizedTypes[typeName] = {
74
74
  ...types[typeName],
75
75
  name: typeName,
76
- } as any;
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: any) {
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 DefinitionRoot: NodeType = {
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: 'PathMap',
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 PathMap: NodeType = {
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
- DefinitionRoot,
372
+ Root,
373
373
  Tag,
374
374
  ExternalDocs,
375
375
  SecurityRequirement,
376
376
  Info,
377
377
  Contact,
378
378
  License,
379
- PathMap,
379
+ PathsMap,
380
380
  PathItem,
381
381
  Parameter,
382
382
  ParameterItems,