@redocly/openapi-core 1.0.0-beta.96 → 1.0.0-beta.99

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 (106) hide show
  1. package/lib/bundle.d.ts +2 -0
  2. package/lib/bundle.js +6 -3
  3. package/lib/config/all.js +1 -0
  4. package/lib/config/config-resolvers.d.ts +1 -1
  5. package/lib/config/config-resolvers.js +31 -2
  6. package/lib/config/config.d.ts +4 -1
  7. package/lib/config/config.js +18 -12
  8. package/lib/format/format.js +2 -1
  9. package/lib/redocly/index.js +10 -26
  10. package/lib/redocly/registry-api-types.d.ts +1 -0
  11. package/lib/redocly/registry-api.d.ts +1 -1
  12. package/lib/redocly/registry-api.js +2 -1
  13. package/lib/ref-utils.js +1 -0
  14. package/lib/rules/common/response-contains-header.d.ts +2 -0
  15. package/lib/rules/common/response-contains-header.js +29 -0
  16. package/lib/rules/common/scalar-property-missing-example.d.ts +2 -0
  17. package/lib/rules/common/scalar-property-missing-example.js +41 -0
  18. package/lib/rules/oas2/index.d.ts +3 -0
  19. package/lib/rules/oas2/index.js +6 -0
  20. package/lib/rules/oas2/response-contains-property.d.ts +2 -0
  21. package/lib/rules/oas2/response-contains-property.js +38 -0
  22. package/lib/rules/oas3/index.js +6 -0
  23. package/lib/rules/oas3/response-contains-property.d.ts +2 -0
  24. package/lib/rules/oas3/response-contains-property.js +40 -0
  25. package/lib/types/oas2.js +3 -1
  26. package/lib/types/oas3.js +21 -8
  27. package/lib/types/oas3_1.js +12 -8
  28. package/lib/types/redocly-yaml.js +12 -0
  29. package/lib/typings/openapi.d.ts +5 -2
  30. package/lib/typings/swagger.d.ts +2 -0
  31. package/lib/utils.d.ts +1 -1
  32. package/lib/utils.js +5 -3
  33. package/package.json +3 -3
  34. package/{__tests__ → src/__tests__}/__snapshots__/bundle.test.ts.snap +26 -0
  35. package/{__tests__ → src/__tests__}/bundle.test.ts +30 -6
  36. package/{__tests__ → src/__tests__}/codeframes.test.ts +3 -3
  37. package/{__tests__ → src/__tests__}/fixtures/extension.js +0 -0
  38. package/{__tests__ → src/__tests__}/fixtures/refs/definitions.yaml +0 -0
  39. package/{__tests__ → src/__tests__}/fixtures/refs/examples.yaml +0 -0
  40. package/{__tests__ → src/__tests__}/fixtures/refs/external-request-body.yaml +0 -0
  41. package/{__tests__ → src/__tests__}/fixtures/refs/externalref.yaml +0 -0
  42. package/{__tests__ → src/__tests__}/fixtures/refs/hosted.yaml +0 -0
  43. package/{__tests__ → src/__tests__}/fixtures/refs/openapi-with-external-refs-conflicting-names.yaml +0 -0
  44. package/{__tests__ → src/__tests__}/fixtures/refs/openapi-with-external-refs.yaml +0 -0
  45. package/src/__tests__/fixtures/refs/openapi-with-url-refs.yaml +18 -0
  46. package/{__tests__ → src/__tests__}/fixtures/refs/param-b.yaml +0 -0
  47. package/{__tests__ → src/__tests__}/fixtures/refs/param-c.yaml +0 -0
  48. package/{__tests__ → src/__tests__}/fixtures/refs/rename.yaml +0 -0
  49. package/{__tests__ → src/__tests__}/fixtures/refs/requestBody.yaml +0 -0
  50. package/{__tests__ → src/__tests__}/fixtures/refs/schema-a.yaml +0 -0
  51. package/{__tests__ → src/__tests__}/fixtures/refs/simple.yaml +0 -0
  52. package/{__tests__ → src/__tests__}/fixtures/refs/vendor.schema.yaml +0 -0
  53. package/{__tests__ → src/__tests__}/fixtures/resolve/External.yaml +0 -0
  54. package/{__tests__ → src/__tests__}/fixtures/resolve/External2.yaml +0 -0
  55. package/{__tests__ → src/__tests__}/fixtures/resolve/description.md +0 -0
  56. package/{__tests__ → src/__tests__}/fixtures/resolve/externalInfo.yaml +0 -0
  57. package/{__tests__ → src/__tests__}/fixtures/resolve/externalLicense.yaml +0 -0
  58. package/{__tests__ → src/__tests__}/fixtures/resolve/openapi-with-back.yaml +0 -0
  59. package/{__tests__ → src/__tests__}/fixtures/resolve/openapi-with-md-description.yaml +0 -0
  60. package/{__tests__ → src/__tests__}/fixtures/resolve/openapi.yaml +0 -0
  61. package/{__tests__ → src/__tests__}/fixtures/resolve/schemas/type-a.yaml +0 -0
  62. package/{__tests__ → src/__tests__}/fixtures/resolve/schemas/type-b.yaml +0 -0
  63. package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/a.yaml +0 -0
  64. package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/components.yaml +0 -0
  65. package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/schemas.yaml +0 -0
  66. package/src/__tests__/lint.test.ts +13 -0
  67. package/{__tests__ → src/__tests__}/login.test.ts +1 -1
  68. package/{__tests__ → src/__tests__}/normalizeVisitors.test.ts +4 -4
  69. package/{__tests__ → src/__tests__}/ref-utils.test.ts +5 -5
  70. package/{__tests__ → src/__tests__}/resolve-http.test.ts +4 -4
  71. package/{__tests__ → src/__tests__}/resolve.test.ts +4 -4
  72. package/src/__tests__/utils.test.ts +12 -1
  73. package/{__tests__ → src/__tests__}/walk.test.ts +5 -5
  74. package/src/bundle.ts +18 -3
  75. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +18 -1
  76. package/src/config/__tests__/config-resolvers.test.ts +32 -1
  77. package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +5 -0
  78. package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +7 -0
  79. package/src/config/all.ts +1 -0
  80. package/src/config/config-resolvers.ts +58 -3
  81. package/src/config/config.ts +21 -12
  82. package/src/format/format.ts +2 -1
  83. package/src/redocly/index.ts +12 -41
  84. package/src/redocly/registry-api-types.ts +1 -0
  85. package/src/redocly/registry-api.ts +2 -0
  86. package/src/ref-utils.ts +1 -0
  87. package/src/rules/common/__tests__/scalar-property-missing-example.test.ts +207 -0
  88. package/src/rules/common/response-contains-header.ts +30 -0
  89. package/src/rules/common/scalar-property-missing-example.ts +55 -0
  90. package/src/rules/oas2/__tests__/response-contains-header.test.ts +174 -0
  91. package/src/rules/oas2/__tests__/response-contains-property.test.ts +155 -0
  92. package/src/rules/oas2/index.ts +6 -0
  93. package/src/rules/oas2/response-contains-property.ts +36 -0
  94. package/src/rules/oas3/__tests__/response-contains-header.test.ts +273 -0
  95. package/src/rules/oas3/__tests__/response-contains-property.test.ts +403 -0
  96. package/src/rules/oas3/index.ts +6 -0
  97. package/src/rules/oas3/response-contains-property.ts +38 -0
  98. package/src/types/oas2.ts +2 -0
  99. package/src/types/oas3.ts +18 -7
  100. package/src/types/oas3_1.ts +11 -7
  101. package/src/types/redocly-yaml.ts +12 -0
  102. package/src/typings/openapi.ts +4 -1
  103. package/src/typings/swagger.ts +2 -0
  104. package/src/utils.ts +6 -2
  105. package/tsconfig.tsbuildinfo +1 -1
  106. package/__tests__/lint.test.ts +0 -17
@@ -0,0 +1,273 @@
1
+ import { outdent } from 'outdent';
2
+ import { lintDocument } from '../../../lint';
3
+ import { parseYamlToDocument, makeConfig } from '../../../../__tests__/utils';
4
+ import { BaseResolver } from '../../../resolve';
5
+
6
+ describe('Oas3 response-contains-header', () => {
7
+ it('should report a response object not containing the header', async () => {
8
+ const document = parseYamlToDocument(outdent`
9
+ openapi: 3.0.3
10
+ info:
11
+ version: 3.0.0
12
+ paths:
13
+ /store/subscribe:
14
+ post:
15
+ responses:
16
+ '200':
17
+ description: successful operation
18
+ headers:
19
+ X-Rate-Limit:
20
+ description: calls per hour allowed by the user
21
+ schema:
22
+ type: integer
23
+ format: int32
24
+ `);
25
+
26
+ const results = await lintDocument({
27
+ externalRefResolver: new BaseResolver(),
28
+ document,
29
+ config: await makeConfig({
30
+ 'response-contains-header': {
31
+ severity: 'error',
32
+ names: { '200': ['Content-Length'] },
33
+ },
34
+ }),
35
+ });
36
+ expect(results).toMatchInlineSnapshot(`
37
+ Array [
38
+ Object {
39
+ "location": Array [
40
+ Object {
41
+ "pointer": "#/paths/~1store~1subscribe/post/responses/200/headers",
42
+ "reportOnKey": true,
43
+ "source": Source {
44
+ "absoluteRef": "",
45
+ "body": "openapi: 3.0.3
46
+ info:
47
+ version: 3.0.0
48
+ paths:
49
+ /store/subscribe:
50
+ post:
51
+ responses:
52
+ '200':
53
+ description: successful operation
54
+ headers:
55
+ X-Rate-Limit:
56
+ description: calls per hour allowed by the user
57
+ schema:
58
+ type: integer
59
+ format: int32",
60
+ "mimeType": undefined,
61
+ },
62
+ },
63
+ ],
64
+ "message": "Response object must contain a \\"Content-Length\\" header.",
65
+ "ruleId": "response-contains-header",
66
+ "severity": "error",
67
+ "suggest": Array [],
68
+ },
69
+ ]
70
+ `);
71
+ });
72
+
73
+ it('should report response objects not containing headers for a subset of status codes', async () => {
74
+ const document = parseYamlToDocument(outdent`
75
+ openapi: 3.0.3
76
+ info:
77
+ version: 3.0.0
78
+ paths:
79
+ /store/subscribe:
80
+ post:
81
+ responses:
82
+ '200':
83
+ description: successful operation
84
+ headers:
85
+ X-Rate-Limit:
86
+ description: calls per hour allowed by the user
87
+ schema:
88
+ type: integer
89
+ format: int32
90
+ 400:
91
+ description: error
92
+ headers:
93
+ AccessForbidden:
94
+ description: Access forbidden
95
+ content:
96
+ application/json:
97
+ schema:
98
+ type: object
99
+ properties:
100
+ status:
101
+ type: integer
102
+ description: The HTTP status code.
103
+ error:
104
+ type: string
105
+ `);
106
+ const results = await lintDocument({
107
+ externalRefResolver: new BaseResolver(),
108
+ document,
109
+ config: await makeConfig({
110
+ 'response-contains-header': {
111
+ severity: 'error',
112
+ names: {
113
+ '2XX': ['x-request-id'],
114
+ '400': ['Content-Length'],
115
+ },
116
+ },
117
+ }),
118
+ });
119
+ expect(results).toMatchInlineSnapshot(`
120
+ Array [
121
+ Object {
122
+ "location": Array [
123
+ Object {
124
+ "pointer": "#/paths/~1store~1subscribe/post/responses/200/headers",
125
+ "reportOnKey": true,
126
+ "source": Source {
127
+ "absoluteRef": "",
128
+ "body": "openapi: 3.0.3
129
+ info:
130
+ version: 3.0.0
131
+ paths:
132
+ /store/subscribe:
133
+ post:
134
+ responses:
135
+ '200':
136
+ description: successful operation
137
+ headers:
138
+ X-Rate-Limit:
139
+ description: calls per hour allowed by the user
140
+ schema:
141
+ type: integer
142
+ format: int32
143
+ 400:
144
+ description: error
145
+ headers:
146
+ AccessForbidden:
147
+ description: Access forbidden
148
+ content:
149
+ application/json:
150
+ schema:
151
+ type: object
152
+ properties:
153
+ status:
154
+ type: integer
155
+ description: The HTTP status code.
156
+ error:
157
+ type: string",
158
+ "mimeType": undefined,
159
+ },
160
+ },
161
+ ],
162
+ "message": "Response object must contain a \\"x-request-id\\" header.",
163
+ "ruleId": "response-contains-header",
164
+ "severity": "error",
165
+ "suggest": Array [],
166
+ },
167
+ Object {
168
+ "location": Array [
169
+ Object {
170
+ "pointer": "#/paths/~1store~1subscribe/post/responses/400/headers",
171
+ "reportOnKey": true,
172
+ "source": Source {
173
+ "absoluteRef": "",
174
+ "body": "openapi: 3.0.3
175
+ info:
176
+ version: 3.0.0
177
+ paths:
178
+ /store/subscribe:
179
+ post:
180
+ responses:
181
+ '200':
182
+ description: successful operation
183
+ headers:
184
+ X-Rate-Limit:
185
+ description: calls per hour allowed by the user
186
+ schema:
187
+ type: integer
188
+ format: int32
189
+ 400:
190
+ description: error
191
+ headers:
192
+ AccessForbidden:
193
+ description: Access forbidden
194
+ content:
195
+ application/json:
196
+ schema:
197
+ type: object
198
+ properties:
199
+ status:
200
+ type: integer
201
+ description: The HTTP status code.
202
+ error:
203
+ type: string",
204
+ "mimeType": undefined,
205
+ },
206
+ },
207
+ ],
208
+ "message": "Response object must contain a \\"Content-Length\\" header.",
209
+ "ruleId": "response-contains-header",
210
+ "severity": "error",
211
+ "suggest": Array [],
212
+ },
213
+ ]
214
+ `);
215
+ });
216
+
217
+ it('should not report response objects containing specified headers', async () => {
218
+ const document = parseYamlToDocument(outdent`
219
+ openapi: 3.0.3
220
+ info:
221
+ version: 3.0.0
222
+ paths:
223
+ /store/subscribe:
224
+ post:
225
+ responses:
226
+ '200':
227
+ description: successful operation
228
+ headers:
229
+ X-Rate-Limit:
230
+ description: calls per hour allowed by the user
231
+ schema:
232
+ type: integer
233
+ format: int32
234
+ x-request-id:
235
+ description: Request ID
236
+ schema:
237
+ type: string
238
+ 400:
239
+ description: error
240
+ headers:
241
+ AccessForbidden:
242
+ description: Access forbidden
243
+ content:
244
+ application/json:
245
+ schema:
246
+ type: object
247
+ properties:
248
+ status:
249
+ type: integer
250
+ description: The HTTP status code.
251
+ error:
252
+ type: string
253
+ Content-Length:
254
+ description: The number of bytes in the file
255
+ schema:
256
+ type: integer
257
+ `);
258
+ const results = await lintDocument({
259
+ externalRefResolver: new BaseResolver(),
260
+ document,
261
+ config: await makeConfig({
262
+ 'response-contains-header': {
263
+ severity: 'error',
264
+ names: {
265
+ '2xx': ['x-request-id'],
266
+ '400': ['Content-Length'],
267
+ },
268
+ },
269
+ }),
270
+ });
271
+ expect(results).toMatchInlineSnapshot(`Array []`);
272
+ });
273
+ });
@@ -0,0 +1,403 @@
1
+ import { outdent } from 'outdent';
2
+ import { lintDocument } from '../../../lint';
3
+ import { parseYamlToDocument, makeConfig } from '../../../../__tests__/utils';
4
+ import { BaseResolver } from '../../../resolve';
5
+
6
+ describe('Oas3 response-contains-property', () => {
7
+ it('should report a response object not containing the property', async () => {
8
+ const document = parseYamlToDocument(outdent`
9
+ openapi: 3.0.3
10
+ info:
11
+ version: 3.0.0
12
+ paths:
13
+ /store/subscribe:
14
+ post:
15
+ responses:
16
+ '201':
17
+ content:
18
+ application/json:
19
+ schema:
20
+ type: object
21
+ properties:
22
+ subscriptionId:
23
+ type: string
24
+ example: AAA-123-BBB-456
25
+ `);
26
+ const results = await lintDocument({
27
+ externalRefResolver: new BaseResolver(),
28
+ document,
29
+ config: await makeConfig({
30
+ 'response-contains-property': {
31
+ severity: 'error',
32
+ names: { 201: ['id'] },
33
+ },
34
+ }),
35
+ });
36
+ expect(results).toMatchInlineSnapshot(`
37
+ Array [
38
+ Object {
39
+ "location": Array [
40
+ Object {
41
+ "pointer": "#/paths/~1store~1subscribe/post/responses/201/content/application~1json/schema/properties",
42
+ "reportOnKey": true,
43
+ "source": Source {
44
+ "absoluteRef": "",
45
+ "body": "openapi: 3.0.3
46
+ info:
47
+ version: 3.0.0
48
+ paths:
49
+ /store/subscribe:
50
+ post:
51
+ responses:
52
+ '201':
53
+ content:
54
+ application/json:
55
+ schema:
56
+ type: object
57
+ properties:
58
+ subscriptionId:
59
+ type: string
60
+ example: AAA-123-BBB-456",
61
+ "mimeType": undefined,
62
+ },
63
+ },
64
+ ],
65
+ "message": "Response object must contain a top-level \\"id\\" property.",
66
+ "ruleId": "response-contains-property",
67
+ "severity": "error",
68
+ "suggest": Array [],
69
+ },
70
+ ]
71
+ `);
72
+ });
73
+
74
+ it('should report response objects not containing props for a subset of status codes', async () => {
75
+ const document = parseYamlToDocument(outdent`
76
+ openapi: 3.0.3
77
+ info:
78
+ version: 3.0.0
79
+ paths:
80
+ /store/subscribe:
81
+ post:
82
+ responses:
83
+ '201':
84
+ content:
85
+ application/json:
86
+ schema:
87
+ type: object
88
+ properties:
89
+ subscriptionId:
90
+ type: string
91
+ example: AAA-123-BBB-456
92
+ 400:
93
+ content:
94
+ application/json:
95
+ schema:
96
+ type: object
97
+ properties:
98
+ status:
99
+ type: integer
100
+ description: error
101
+ `);
102
+ const results = await lintDocument({
103
+ externalRefResolver: new BaseResolver(),
104
+ document,
105
+ config: await makeConfig({
106
+ 'response-contains-property': {
107
+ severity: 'error',
108
+ names: { '2xx': ['id'], '400': ['error'] },
109
+ },
110
+ }),
111
+ });
112
+ expect(results).toMatchInlineSnapshot(`
113
+ Array [
114
+ Object {
115
+ "location": Array [
116
+ Object {
117
+ "pointer": "#/paths/~1store~1subscribe/post/responses/201/content/application~1json/schema/properties",
118
+ "reportOnKey": true,
119
+ "source": Source {
120
+ "absoluteRef": "",
121
+ "body": "openapi: 3.0.3
122
+ info:
123
+ version: 3.0.0
124
+ paths:
125
+ /store/subscribe:
126
+ post:
127
+ responses:
128
+ '201':
129
+ content:
130
+ application/json:
131
+ schema:
132
+ type: object
133
+ properties:
134
+ subscriptionId:
135
+ type: string
136
+ example: AAA-123-BBB-456
137
+ 400:
138
+ content:
139
+ application/json:
140
+ schema:
141
+ type: object
142
+ properties:
143
+ status:
144
+ type: integer
145
+ description: error",
146
+ "mimeType": undefined,
147
+ },
148
+ },
149
+ ],
150
+ "message": "Response object must contain a top-level \\"id\\" property.",
151
+ "ruleId": "response-contains-property",
152
+ "severity": "error",
153
+ "suggest": Array [],
154
+ },
155
+ Object {
156
+ "location": Array [
157
+ Object {
158
+ "pointer": "#/paths/~1store~1subscribe/post/responses/400/content/application~1json/schema/properties",
159
+ "reportOnKey": true,
160
+ "source": Source {
161
+ "absoluteRef": "",
162
+ "body": "openapi: 3.0.3
163
+ info:
164
+ version: 3.0.0
165
+ paths:
166
+ /store/subscribe:
167
+ post:
168
+ responses:
169
+ '201':
170
+ content:
171
+ application/json:
172
+ schema:
173
+ type: object
174
+ properties:
175
+ subscriptionId:
176
+ type: string
177
+ example: AAA-123-BBB-456
178
+ 400:
179
+ content:
180
+ application/json:
181
+ schema:
182
+ type: object
183
+ properties:
184
+ status:
185
+ type: integer
186
+ description: error",
187
+ "mimeType": undefined,
188
+ },
189
+ },
190
+ ],
191
+ "message": "Response object must contain a top-level \\"error\\" property.",
192
+ "ruleId": "response-contains-property",
193
+ "severity": "error",
194
+ "suggest": Array [],
195
+ },
196
+ ]
197
+ `);
198
+ });
199
+
200
+ it('should not report response objects containing specified properties', async () => {
201
+ const document = parseYamlToDocument(outdent`
202
+ openapi: 3.0.3
203
+ info:
204
+ version: 3.0.0
205
+ paths:
206
+ /store/subscribe:
207
+ post:
208
+ responses:
209
+ '201':
210
+ content:
211
+ application/json:
212
+ schema:
213
+ type: object
214
+ properties:
215
+ subscriptionId:
216
+ type: string
217
+ example: AAA-123-BBB-456
218
+ id: some-id
219
+ 400:
220
+ content:
221
+ application/json:
222
+ schema:
223
+ type: object
224
+ properties:
225
+ status:
226
+ type: integer
227
+ error:
228
+ type: string
229
+ `);
230
+ const results = await lintDocument({
231
+ externalRefResolver: new BaseResolver(),
232
+ document,
233
+ config: await makeConfig({
234
+ 'response-contains-property': {
235
+ severity: 'error',
236
+ names: { '2xx': ['id'], '400': ['error'] },
237
+ },
238
+ }),
239
+ });
240
+ expect(results).toMatchInlineSnapshot(`Array []`);
241
+ });
242
+
243
+ it('should not report a response object when schema type is not object', async () => {
244
+ const document = parseYamlToDocument(outdent`
245
+ openapi: 3.0.3
246
+ info:
247
+ version: 3.0.0
248
+ paths:
249
+ /store/subscribe:
250
+ post:
251
+ responses:
252
+ '201':
253
+ content:
254
+ text/plain:
255
+ schema:
256
+ type: string
257
+ `);
258
+ const results = await lintDocument({
259
+ externalRefResolver: new BaseResolver(),
260
+ document,
261
+ config: await makeConfig({
262
+ 'response-contains-property': {
263
+ severity: 'error',
264
+ names: { 201: ['id'] },
265
+ },
266
+ }),
267
+ });
268
+ expect(results).toMatchInlineSnapshot(`Array []`);
269
+ });
270
+
271
+ it('should not report response objects when there is no `names` field specified', async () => {
272
+ const document = parseYamlToDocument(outdent`
273
+ openapi: 3.0.3
274
+ info:
275
+ version: 3.0.0
276
+ paths:
277
+ /store/subscribe:
278
+ post:
279
+ responses:
280
+ '201':
281
+ content:
282
+ application/json:
283
+ schema:
284
+ type: object
285
+ properties:
286
+ subscriptionId:
287
+ type: string
288
+ example: AAA-123-BBB-456
289
+ 400:
290
+ content:
291
+ application/json:
292
+ schema:
293
+ type: object
294
+ properties:
295
+ status:
296
+ type: integer
297
+ description: error
298
+ `);
299
+ const results = await lintDocument({
300
+ externalRefResolver: new BaseResolver(),
301
+ document,
302
+ config: await makeConfig({
303
+ 'response-contains-property': {
304
+ severity: 'error',
305
+ },
306
+ }),
307
+ });
308
+ expect(results).toMatchInlineSnapshot(`Array []`);
309
+ });
310
+
311
+ it('should not report response objects for 204 status code', async () => {
312
+ const document = parseYamlToDocument(outdent`
313
+ openapi: 3.0.3
314
+ info:
315
+ version: 3.0.0
316
+ paths:
317
+ /store/subscribe:
318
+ post:
319
+ responses:
320
+ '204':
321
+ content:
322
+ application/json:
323
+ schema:
324
+ type: object
325
+ properties:
326
+ subscriptionId:
327
+ type: string
328
+ example: AAA-123-BBB-456
329
+ `);
330
+ const results = await lintDocument({
331
+ externalRefResolver: new BaseResolver(),
332
+ document,
333
+ config: await makeConfig({
334
+ 'response-contains-property': {
335
+ severity: 'error',
336
+ names: { '2xx': ['id'] },
337
+ },
338
+ }),
339
+ });
340
+ expect(results).toMatchInlineSnapshot(`Array []`);
341
+ });
342
+
343
+ it('should report response objects when there are no properties', async () => {
344
+ const document = parseYamlToDocument(outdent`
345
+ openapi: 3.0.3
346
+ info:
347
+ version: 3.0.0
348
+ paths:
349
+ /store/subscribe:
350
+ post:
351
+ responses:
352
+ 200:
353
+ content:
354
+ application/json:
355
+ schema:
356
+ type: object
357
+
358
+ `);
359
+ const results = await lintDocument({
360
+ externalRefResolver: new BaseResolver(),
361
+ document,
362
+ config: await makeConfig({
363
+ 'response-contains-property': {
364
+ severity: 'error',
365
+ names: { '2xx': ['id'] },
366
+ },
367
+ }),
368
+ });
369
+ expect(results).toMatchInlineSnapshot(`
370
+ Array [
371
+ Object {
372
+ "location": Array [
373
+ Object {
374
+ "pointer": "#/paths/~1store~1subscribe/post/responses/200/content/application~1json/schema/properties",
375
+ "reportOnKey": true,
376
+ "source": Source {
377
+ "absoluteRef": "",
378
+ "body": "openapi: 3.0.3
379
+ info:
380
+ version: 3.0.0
381
+ paths:
382
+ /store/subscribe:
383
+ post:
384
+ responses:
385
+ 200:
386
+ content:
387
+ application/json:
388
+ schema:
389
+ type: object
390
+ ",
391
+ "mimeType": undefined,
392
+ },
393
+ },
394
+ ],
395
+ "message": "Response object must contain a top-level \\"id\\" property.",
396
+ "ruleId": "response-contains-property",
397
+ "severity": "error",
398
+ "suggest": Array [],
399
+ },
400
+ ]
401
+ `);
402
+ });
403
+ });
@@ -45,6 +45,9 @@ import { PathSegmentPlural } from '../common/path-segment-plural';
45
45
  import { PathExcludesPatterns } from '../common/path-excludes-patterns';
46
46
  import { NoInvalidSchemaExamples } from '../common/no-invalid-schema-examples';
47
47
  import { NoInvalidParameterExamples } from '../common/no-invalid-parameter-examples';
48
+ import { ResponseContainsHeader } from '../common/response-contains-header';
49
+ import { ResponseContainsProperty } from './response-contains-property';
50
+ import { ScalarPropertyMissingExample } from '../common/scalar-property-missing-example';
48
51
 
49
52
  export const rules = {
50
53
  spec: OasSpec,
@@ -94,6 +97,9 @@ export const rules = {
94
97
  'path-segment-plural': PathSegmentPlural,
95
98
  'no-invalid-schema-examples': NoInvalidSchemaExamples,
96
99
  'no-invalid-parameter-examples': NoInvalidParameterExamples,
100
+ 'response-contains-header': ResponseContainsHeader,
101
+ 'response-contains-property': ResponseContainsProperty,
102
+ 'scalar-property-missing-example': ScalarPropertyMissingExample,
97
103
  } as Oas3RuleSet;
98
104
 
99
105
  export const preprocessors = {};