@redocly/openapi-core 1.0.0-beta.110 → 1.0.0-beta.112

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 (93) hide show
  1. package/lib/config/all.js +0 -1
  2. package/lib/config/config-resolvers.js +42 -34
  3. package/lib/config/load.d.ts +1 -1
  4. package/lib/config/load.js +5 -5
  5. package/lib/config/minimal.js +0 -1
  6. package/lib/config/recommended.js +0 -1
  7. package/lib/rules/common/assertions/asserts.d.ts +22 -5
  8. package/lib/rules/common/assertions/asserts.js +25 -0
  9. package/lib/rules/common/assertions/index.d.ts +27 -2
  10. package/lib/rules/common/assertions/index.js +6 -29
  11. package/lib/rules/common/assertions/utils.d.ts +7 -14
  12. package/lib/rules/common/assertions/utils.js +129 -97
  13. package/lib/rules/common/no-ambiguous-paths.js +1 -1
  14. package/lib/rules/common/no-identical-paths.js +4 -4
  15. package/lib/rules/common/operation-2xx-response.js +2 -2
  16. package/lib/rules/common/operation-4xx-response.js +2 -2
  17. package/lib/rules/common/path-not-include-query.js +1 -1
  18. package/lib/rules/common/path-params-defined.js +7 -2
  19. package/lib/rules/common/response-contains-header.js +2 -2
  20. package/lib/rules/common/security-defined.js +10 -5
  21. package/lib/rules/common/spec.js +14 -12
  22. package/lib/rules/oas2/index.d.ts +0 -1
  23. package/lib/rules/oas2/index.js +0 -2
  24. package/lib/rules/oas3/index.js +0 -2
  25. package/lib/rules/oas3/request-mime-type.js +1 -1
  26. package/lib/rules/oas3/response-mime-type.js +1 -1
  27. package/lib/rules/other/stats.d.ts +1 -1
  28. package/lib/rules/other/stats.js +1 -1
  29. package/lib/rules/utils.d.ts +1 -0
  30. package/lib/rules/utils.js +17 -1
  31. package/lib/types/oas2.js +6 -6
  32. package/lib/types/oas3.js +11 -11
  33. package/lib/types/oas3_1.js +3 -3
  34. package/lib/types/redocly-yaml.js +58 -31
  35. package/lib/utils.d.ts +2 -0
  36. package/lib/utils.js +19 -1
  37. package/lib/visitors.d.ts +9 -7
  38. package/lib/visitors.js +12 -3
  39. package/lib/walk.js +7 -1
  40. package/package.json +1 -1
  41. package/src/__tests__/__snapshots__/bundle.test.ts.snap +1 -1
  42. package/src/__tests__/lint.test.ts +24 -5
  43. package/src/__tests__/utils.test.ts +11 -0
  44. package/src/__tests__/walk.test.ts +2 -2
  45. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +1 -3
  46. package/src/config/__tests__/config-resolvers.test.ts +30 -5
  47. package/src/config/__tests__/fixtures/load-redocly.yaml +4 -0
  48. package/src/config/__tests__/fixtures/resolve-config/local-config-with-custom-function.yaml +6 -4
  49. package/src/config/__tests__/load.test.ts +4 -1
  50. package/src/config/all.ts +0 -1
  51. package/src/config/config-resolvers.ts +44 -20
  52. package/src/config/load.ts +8 -5
  53. package/src/config/minimal.ts +0 -1
  54. package/src/config/recommended.ts +0 -1
  55. package/src/rules/common/__tests__/operation-2xx-response.test.ts +37 -0
  56. package/src/rules/common/__tests__/operation-4xx-response.test.ts +37 -0
  57. package/src/rules/common/__tests__/path-params-defined.test.ts +69 -0
  58. package/src/rules/common/__tests__/security-defined.test.ts +6 -6
  59. package/src/rules/common/__tests__/spec.test.ts +125 -0
  60. package/src/rules/common/assertions/__tests__/asserts.test.ts +7 -3
  61. package/src/rules/common/assertions/__tests__/index.test.ts +41 -20
  62. package/src/rules/common/assertions/__tests__/utils.test.ts +44 -18
  63. package/src/rules/common/assertions/asserts.ts +60 -8
  64. package/src/rules/common/assertions/index.ts +36 -46
  65. package/src/rules/common/assertions/utils.ts +204 -127
  66. package/src/rules/common/no-ambiguous-paths.ts +1 -1
  67. package/src/rules/common/no-identical-paths.ts +4 -4
  68. package/src/rules/common/operation-2xx-response.ts +2 -2
  69. package/src/rules/common/operation-4xx-response.ts +2 -2
  70. package/src/rules/common/path-not-include-query.ts +1 -1
  71. package/src/rules/common/path-params-defined.ts +9 -2
  72. package/src/rules/common/response-contains-header.ts +6 -1
  73. package/src/rules/common/security-defined.ts +10 -5
  74. package/src/rules/common/spec.ts +15 -11
  75. package/src/rules/oas2/index.ts +0 -2
  76. package/src/rules/oas3/__tests__/response-contains-header.test.ts +116 -0
  77. package/src/rules/oas3/index.ts +0 -2
  78. package/src/rules/oas3/request-mime-type.ts +1 -1
  79. package/src/rules/oas3/response-mime-type.ts +1 -1
  80. package/src/rules/other/stats.ts +1 -1
  81. package/src/rules/utils.ts +22 -0
  82. package/src/types/oas2.ts +6 -6
  83. package/src/types/oas3.ts +11 -11
  84. package/src/types/oas3_1.ts +3 -3
  85. package/src/types/redocly-yaml.ts +58 -33
  86. package/src/utils.ts +18 -0
  87. package/src/visitors.ts +32 -11
  88. package/src/walk.ts +8 -1
  89. package/tsconfig.tsbuildinfo +1 -1
  90. package/lib/rules/common/info-description.d.ts +0 -2
  91. package/lib/rules/common/info-description.js +0 -12
  92. package/src/rules/common/__tests__/info-description.test.ts +0 -102
  93. package/src/rules/common/info-description.ts +0 -10
@@ -3,12 +3,14 @@ lint:
3
3
  no-invalid-media-type-examples: warn
4
4
  operation-4xx-response: off
5
5
  assert/tag-description:
6
- subject: Tag
7
- property: description
6
+ subject:
7
+ type: Tag
8
+ property: description
8
9
  message: Tag description must have at least 3 words.
9
10
  severity: error
10
- test-plugin/checkWordsCount:
11
- min: 3
11
+ assertions:
12
+ test-plugin/checkWordsCount:
13
+ min: 3
12
14
  plugins:
13
15
  - plugin.js
14
16
  extends:
@@ -49,7 +49,10 @@ describe('loadConfig', () => {
49
49
 
50
50
  it('should call callback if such passed', async () => {
51
51
  const mockFn = jest.fn();
52
- await loadConfig({ processRawConfig: mockFn });
52
+ await loadConfig({
53
+ configPath: path.join(__dirname, './fixtures/load-redocly.yaml'),
54
+ processRawConfig: mockFn,
55
+ });
53
56
  expect(mockFn).toHaveBeenCalled();
54
57
  });
55
58
  });
package/src/config/all.ts CHANGED
@@ -2,7 +2,6 @@ import type { PluginStyleguideConfig } from './types';
2
2
 
3
3
  export default {
4
4
  rules: {
5
- 'info-description': 'error',
6
5
  'info-contact': 'error',
7
6
  'info-license': 'error',
8
7
  'info-license-url': 'error',
@@ -1,5 +1,6 @@
1
1
  import * as path from 'path';
2
2
  import { isAbsoluteUrl } from '../ref-utils';
3
+ import { pickDefined } from '../utils';
3
4
  import { BaseResolver } from '../resolve';
4
5
  import { defaultPlugin } from './builtIn';
5
6
  import {
@@ -21,10 +22,16 @@ import type {
21
22
  DeprecatedInRawConfig,
22
23
  } from './types';
23
24
  import { isBrowser } from '../env';
24
- import { isNotString, isString, isDefined, parseYaml } from '../utils';
25
+ import { isNotString, isString, isDefined, parseYaml, keysOf } from '../utils';
25
26
  import { Config } from './config';
26
27
  import { colorize, logger } from '../logger';
27
- import { asserts, buildAssertCustomFunction } from '../rules/common/assertions/asserts';
28
+ import {
29
+ Asserts,
30
+ AssertionFn,
31
+ asserts,
32
+ buildAssertCustomFunction,
33
+ } from '../rules/common/assertions/asserts';
34
+ import type { Assertion, AssertionDefinition, RawAssertion } from '../rules/common/assertions';
28
35
 
29
36
  export async function resolveConfig(rawConfig: RawConfig, configPath?: string): Promise<Config> {
30
37
  if (rawConfig.styleguide?.extends?.some(isNotString)) {
@@ -355,7 +362,7 @@ function getMergedRawStyleguideConfig(
355
362
  ) {
356
363
  const resultLint = {
357
364
  ...rootStyleguideConfig,
358
- ...apiStyleguideConfig,
365
+ ...pickDefined(apiStyleguideConfig),
359
366
  rules: { ...rootStyleguideConfig?.rules, ...apiStyleguideConfig?.rules },
360
367
  oas2Rules: { ...rootStyleguideConfig?.oas2Rules, ...apiStyleguideConfig?.oas2Rules },
361
368
  oas3_0Rules: { ...rootStyleguideConfig?.oas3_0Rules, ...apiStyleguideConfig?.oas3_0Rules },
@@ -408,26 +415,17 @@ function groupStyleguideAssertionRules({
408
415
  const transformedRules: Record<string, RuleConfig> = {};
409
416
 
410
417
  // Collect assertion rules
411
- const assertions = [];
418
+ const assertions: Assertion[] = [];
412
419
  for (const [ruleKey, rule] of Object.entries(rules)) {
413
420
  if (ruleKey.startsWith('assert/') && typeof rule === 'object' && rule !== null) {
414
- const assertion = rule;
421
+ const assertion = rule as RawAssertion;
422
+
415
423
  if (plugins) {
416
- for (const field of Object.keys(assertion)) {
417
- const [pluginId, fn] = field.split('/');
418
- if (!pluginId || !fn) continue;
419
- const plugin = plugins.find((plugin) => plugin.id === pluginId);
420
- if (!plugin) {
421
- throw Error(colorize.red(`Plugin ${colorize.blue(pluginId)} isn't found.`));
422
- }
423
- if (!plugin.assertions || !plugin.assertions[fn]) {
424
- throw Error(
425
- `Plugin ${colorize.red(
426
- pluginId
427
- )} doesn't export assertions function with name ${colorize.red(fn)}.`
428
- );
429
- }
430
- asserts[field] = buildAssertCustomFunction(plugin.assertions[fn]);
424
+ registerCustomAssertions(plugins, assertion);
425
+
426
+ // We may have custom assertion inside where block
427
+ for (const context of assertion.where || []) {
428
+ registerCustomAssertions(plugins, context);
431
429
  }
432
430
  }
433
431
  assertions.push({
@@ -445,3 +443,29 @@ function groupStyleguideAssertionRules({
445
443
 
446
444
  return transformedRules;
447
445
  }
446
+
447
+ function registerCustomAssertions(plugins: Plugin[], assertion: AssertionDefinition) {
448
+ for (const field of keysOf(assertion.assertions)) {
449
+ const [pluginId, fn] = field.split('/');
450
+
451
+ if (!pluginId || !fn) continue;
452
+
453
+ const plugin = plugins.find((plugin) => plugin.id === pluginId);
454
+
455
+ if (!plugin) {
456
+ throw Error(colorize.red(`Plugin ${colorize.blue(pluginId)} isn't found.`));
457
+ }
458
+
459
+ if (!plugin.assertions || !plugin.assertions[fn]) {
460
+ throw Error(
461
+ `Plugin ${colorize.red(
462
+ pluginId
463
+ )} doesn't export assertions function with name ${colorize.red(fn)}.`
464
+ );
465
+ }
466
+
467
+ (asserts as Asserts & { [name: string]: AssertionFn })[field] = buildAssertCustomFunction(
468
+ plugin.assertions[fn]
469
+ );
470
+ }
471
+ }
@@ -71,11 +71,8 @@ export async function loadConfig(
71
71
  } = {}
72
72
  ): Promise<Config> {
73
73
  const { configPath = findConfig(), customExtends, processRawConfig, files, region } = options;
74
- const config = await getConfig(configPath);
74
+ const config = await getConfig(configPath, processRawConfig);
75
75
  const rawConfig = { ...config, files: files ?? config.files, region: region ?? config.region };
76
- if (typeof processRawConfig === 'function') {
77
- await processRawConfig(rawConfig);
78
- }
79
76
 
80
77
  const redoclyClient = new RedoclyClient();
81
78
  const tokens = await redoclyClient.getTokens();
@@ -105,11 +102,17 @@ export function findConfig(dir?: string): string | undefined {
105
102
  return existingConfigFiles[0];
106
103
  }
107
104
 
108
- export async function getConfig(configPath: string | undefined = findConfig()): Promise<RawConfig> {
105
+ export async function getConfig(
106
+ configPath: string | undefined = findConfig(),
107
+ processRawConfig?: (rawConfig: RawConfig) => void | Promise<void>
108
+ ): Promise<RawConfig> {
109
109
  if (!configPath || !doesYamlFileExist(configPath)) return {};
110
110
  try {
111
111
  const rawConfig =
112
112
  (await loadYaml<RawConfig & DeprecatedInRawConfig & FlatRawConfig>(configPath)) || {};
113
+ if (typeof processRawConfig === 'function') {
114
+ await processRawConfig(rawConfig);
115
+ }
113
116
  return transformConfig(rawConfig);
114
117
  } catch (e) {
115
118
  throw new Error(`Error parsing config file at '${configPath}': ${e.message}`);
@@ -2,7 +2,6 @@ import type { PluginStyleguideConfig } from './types';
2
2
 
3
3
  export default {
4
4
  rules: {
5
- 'info-description': 'warn',
6
5
  'info-contact': 'off',
7
6
  'info-license': 'off',
8
7
  'info-license-url': 'off',
@@ -2,7 +2,6 @@ import type { PluginStyleguideConfig } from './types';
2
2
 
3
3
  export default {
4
4
  rules: {
5
- 'info-description': 'warn',
6
5
  'info-contact': 'off',
7
6
  'info-license': 'warn',
8
7
  'info-license-url': 'warn',
@@ -88,4 +88,41 @@ describe('Oas3 operation-2xx-response', () => {
88
88
 
89
89
  expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
90
90
  });
91
+
92
+ it('should report even if the responses are null', async () => {
93
+ const document = parseYamlToDocument(
94
+ outdent`
95
+ openapi: 3.0.0
96
+ paths:
97
+ '/test/':
98
+ put:
99
+ responses: null
100
+ `,
101
+ 'foobar.yaml'
102
+ );
103
+
104
+ const results = await lintDocument({
105
+ externalRefResolver: new BaseResolver(),
106
+ document,
107
+ config: await makeConfig({ 'operation-2xx-response': 'error' }),
108
+ });
109
+
110
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
111
+ Array [
112
+ Object {
113
+ "location": Array [
114
+ Object {
115
+ "pointer": "#/paths/~1test~1/put/responses",
116
+ "reportOnKey": true,
117
+ "source": "foobar.yaml",
118
+ },
119
+ ],
120
+ "message": "Operation must have at least one \`2XX\` response.",
121
+ "ruleId": "operation-2xx-response",
122
+ "severity": "error",
123
+ "suggest": Array [],
124
+ },
125
+ ]
126
+ `);
127
+ });
91
128
  });
@@ -127,4 +127,41 @@ describe('Oas3 operation-4xx-response', () => {
127
127
  ]
128
128
  `);
129
129
  });
130
+
131
+ it('should report even if the responses are null', async () => {
132
+ const document = parseYamlToDocument(
133
+ outdent`
134
+ openapi: 3.0.0
135
+ paths:
136
+ '/test/':
137
+ put:
138
+ responses: null
139
+ `,
140
+ 'foobar.yaml'
141
+ );
142
+
143
+ const results = await lintDocument({
144
+ externalRefResolver: new BaseResolver(),
145
+ document,
146
+ config: await makeConfig({ 'operation-2xx-response': 'error' }),
147
+ });
148
+
149
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
150
+ Array [
151
+ Object {
152
+ "location": Array [
153
+ Object {
154
+ "pointer": "#/paths/~1test~1/put/responses",
155
+ "reportOnKey": true,
156
+ "source": "foobar.yaml",
157
+ },
158
+ ],
159
+ "message": "Operation must have at least one \`2XX\` response.",
160
+ "ruleId": "operation-2xx-response",
161
+ "severity": "error",
162
+ "suggest": Array [],
163
+ },
164
+ ]
165
+ `);
166
+ });
130
167
  });
@@ -130,4 +130,73 @@ describe('Oas3 path-params-defined', () => {
130
130
  ]
131
131
  `);
132
132
  });
133
+
134
+ it('should fail cause POST has no parameters', async () => {
135
+ const document = parseYamlToDocument(
136
+ outdent`
137
+ openapi: 3.0.0
138
+ paths:
139
+ /pets/{a}:
140
+ get:
141
+ parameters:
142
+ - name: a
143
+ in: path
144
+ post:
145
+ description: without parameters
146
+ `,
147
+ 'foobar.yaml'
148
+ );
149
+
150
+ const results = await lintDocument({
151
+ externalRefResolver: new BaseResolver(),
152
+ document,
153
+ config: await makeConfig({ 'path-params-defined': 'error' }),
154
+ });
155
+
156
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
157
+ Array [
158
+ Object {
159
+ "location": Array [
160
+ Object {
161
+ "pointer": "#/paths/~1pets~1{a}/post/parameters",
162
+ "reportOnKey": true,
163
+ "source": "foobar.yaml",
164
+ },
165
+ ],
166
+ "message": "The operation does not define the path parameter \`{a}\` expected by path \`/pets/{a}\`.",
167
+ "ruleId": "path-params-defined",
168
+ "severity": "error",
169
+ "suggest": Array [],
170
+ },
171
+ ]
172
+ `);
173
+ });
174
+
175
+ it('should apply parameters for POST operation from path parameters', async () => {
176
+ const document = parseYamlToDocument(
177
+ outdent`
178
+ openapi: 3.0.0
179
+ paths:
180
+ /pets/{a}:
181
+ parameters:
182
+ - name: a
183
+ in: path
184
+ get:
185
+ parameters:
186
+ - name: a
187
+ in: path
188
+ post:
189
+ description: without parameters
190
+ `,
191
+ 'foobar.yaml'
192
+ );
193
+
194
+ const results = await lintDocument({
195
+ externalRefResolver: new BaseResolver(),
196
+ document,
197
+ config: await makeConfig({ 'path-params-defined': 'error' }),
198
+ });
199
+
200
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
201
+ });
133
202
  });
@@ -81,12 +81,12 @@ describe('Oas3 security-defined', () => {
81
81
  Object {
82
82
  "location": Array [
83
83
  Object {
84
- "pointer": "#/",
85
- "reportOnKey": false,
84
+ "pointer": "#/paths/~1pets/get",
85
+ "reportOnKey": true,
86
86
  "source": "foobar.yaml",
87
87
  },
88
88
  ],
89
- "message": "Every API should have security defined on the root level or for each operation.",
89
+ "message": "Every operation should have security defined on it or on the root level.",
90
90
  "ruleId": "security-defined",
91
91
  "severity": "error",
92
92
  "suggest": Array [],
@@ -133,12 +133,12 @@ describe('Oas3 security-defined', () => {
133
133
  Object {
134
134
  "location": Array [
135
135
  Object {
136
- "pointer": "#/",
137
- "reportOnKey": false,
136
+ "pointer": "#/paths/~1cats/get",
137
+ "reportOnKey": true,
138
138
  "source": "foobar.yaml",
139
139
  },
140
140
  ],
141
- "message": "Every API should have security defined on the root level or for each operation.",
141
+ "message": "Every operation should have security defined on it or on the root level.",
142
142
  "ruleId": "security-defined",
143
143
  "severity": "error",
144
144
  "suggest": Array [],
@@ -139,3 +139,128 @@ describe('Oas3 spec', () => {
139
139
  `);
140
140
  });
141
141
  });
142
+
143
+ describe('Oas3.1 spec', () => {
144
+ it('should report with "type can be one of the following only"', async () => {
145
+ const document = parseYamlToDocument(
146
+ outdent`
147
+ openapi: 3.1.0
148
+ info:
149
+ version: 1.0.0
150
+ title: Example.com
151
+ description: info,
152
+ license:
153
+ name: Apache 2.0
154
+ url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
155
+ components:
156
+ schemas:
157
+ TestSchema:
158
+ title: TestSchema
159
+ description: Property name's description
160
+ type: test
161
+ `
162
+ );
163
+
164
+ const results = await lintDocument({
165
+ externalRefResolver: new BaseResolver(),
166
+ document,
167
+ config: await makeConfig({ spec: 'error' }),
168
+ });
169
+
170
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
171
+ Array [
172
+ Object {
173
+ "from": undefined,
174
+ "location": Array [
175
+ Object {
176
+ "pointer": "#/components/schemas/TestSchema/type",
177
+ "reportOnKey": false,
178
+ "source": "",
179
+ },
180
+ ],
181
+ "message": "\`type\` can be one of the following only: \\"object\\", \\"array\\", \\"string\\", \\"number\\", \\"integer\\", \\"boolean\\", \\"null\\".",
182
+ "ruleId": "spec",
183
+ "severity": "error",
184
+ "suggest": Array [],
185
+ },
186
+ ]
187
+ `);
188
+ });
189
+
190
+ it('should report with unknown type in type`s list', async () => {
191
+ const document = parseYamlToDocument(
192
+ outdent`
193
+ openapi: 3.1.0
194
+ info:
195
+ version: 1.0.0
196
+ title: Example.com
197
+ description: info,
198
+ license:
199
+ name: Apache 2.0
200
+ url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
201
+ components:
202
+ schemas:
203
+ TestSchema:
204
+ title: TestSchema
205
+ description: Property name's description
206
+ type:
207
+ - string
208
+ - foo
209
+ `
210
+ );
211
+
212
+ const results = await lintDocument({
213
+ externalRefResolver: new BaseResolver(),
214
+ document,
215
+ config: await makeConfig({ spec: 'error' }),
216
+ });
217
+
218
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
219
+ Array [
220
+ Object {
221
+ "from": undefined,
222
+ "location": Array [
223
+ Object {
224
+ "pointer": "#/components/schemas/TestSchema/type/1",
225
+ "reportOnKey": false,
226
+ "source": "",
227
+ },
228
+ ],
229
+ "message": "\`type\` can be one of the following only: \\"object\\", \\"array\\", \\"string\\", \\"number\\", \\"integer\\", \\"boolean\\", \\"null\\".",
230
+ "ruleId": "spec",
231
+ "severity": "error",
232
+ "suggest": Array [],
233
+ },
234
+ ]
235
+ `);
236
+ });
237
+
238
+ it('should not report about unknown type', async () => {
239
+ const document = parseYamlToDocument(
240
+ outdent`
241
+ openapi: 3.1.0
242
+ info:
243
+ version: 1.0.0
244
+ title: Example.com
245
+ description: info,
246
+ license:
247
+ name: Apache 2.0
248
+ url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
249
+ components:
250
+ schemas:
251
+ TestSchema:
252
+ title: TestSchema
253
+ description: Property name's description
254
+ type: null
255
+ `
256
+ );
257
+
258
+ const results = await lintDocument({
259
+ externalRefResolver: new BaseResolver(),
260
+ document,
261
+ config: await makeConfig({ spec: 'error' }),
262
+ });
263
+
264
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
265
+ });
266
+ });
@@ -1,6 +1,6 @@
1
1
  import { Location } from '../../../../ref-utils';
2
2
  import { Source } from '../../../../resolve';
3
- import { asserts, buildAssertCustomFunction } from '../asserts';
3
+ import { Asserts, asserts, buildAssertCustomFunction } from '../asserts';
4
4
 
5
5
  let baseLocation = new Location(jest.fn() as any as Source, 'pointer');
6
6
 
@@ -674,9 +674,13 @@ describe('oas3 assertions', () => {
674
674
  }
675
675
  return [];
676
676
  });
677
- asserts['local/customFn'] = buildAssertCustomFunction(customFn);
677
+ asserts['local/customFn' as keyof Asserts] = buildAssertCustomFunction(customFn);
678
678
  expect(
679
- asserts['local/customFn'](Object.keys(fakeNode), { word: 'foo' }, baseLocation)
679
+ asserts['local/customFn' as keyof Asserts](
680
+ Object.keys(fakeNode),
681
+ { word: 'foo' },
682
+ baseLocation
683
+ )
680
684
  ).toEqual([
681
685
  {
682
686
  message: 'First value should be foo',
@@ -1,61 +1,82 @@
1
- import { Assertions } from '../.';
1
+ import { Assertion, Assertions } from '../.';
2
2
 
3
3
  const opts = {
4
4
  '0': {
5
- subject: 'Operation',
6
- property: 'summary',
5
+ subject: {
6
+ type: 'Operation',
7
+ property: 'summary',
8
+ },
7
9
  description: 'example warn text',
8
10
  severity: 'warn',
9
- pattern: '/example/',
11
+ assertions: { pattern: '/example/' },
10
12
  },
11
13
  '1': {
12
- subject: 'PathItem',
13
- context: [{ type: 'Operation', matchParentKeys: ['post'] }],
14
+ subject: {
15
+ type: 'PathItem',
16
+ },
17
+ where: [
18
+ {
19
+ subject: { type: 'Operation', filterInParentKeys: ['post'], property: 'responses' },
20
+ assertions: { defined: true },
21
+ },
22
+ ],
14
23
  description: 'example warn text',
15
24
  severity: 'warn',
16
- mutuallyExclusive: ['summary', 'security'],
25
+ assertions: { mutuallyExclusive: ['summary', 'security'] },
17
26
  },
18
27
  '2': {
19
- subject: ['PathItem'],
20
- context: [{ type: 'Operation' }],
21
- property: 'tags',
28
+ subject: { type: 'PathItem', property: 'tags' },
29
+ where: [
30
+ { subject: { type: 'Operation', property: 'responses' }, assertions: { defined: true } },
31
+ ],
22
32
  description: 'example warn text',
23
33
  severity: 'warn',
24
- sortOrder: 'desc',
34
+ assertions: { sortOrder: 'desc' },
25
35
  },
26
36
  '3': {
27
- subject: ['Foo'],
28
- context: [{ type: 'Bar' }, { type: 'Baz' }],
29
- property: 'test',
37
+ subject: { type: 'Foo', property: 'test' },
38
+ where: [
39
+ { subject: { type: 'Bar' }, assertions: {} },
40
+ { subject: { type: 'Baz' }, assertions: {} },
41
+ ],
30
42
  description: 'example warn text',
31
43
  severity: 'warn',
32
- sortOrder: 'desc',
44
+ assertions: { sortOrder: 'desc' },
33
45
  },
34
46
  };
35
47
 
36
48
  describe('Oas3 assertions', () => {
37
49
  it('should return the right visitor structure', () => {
38
- const visitors = Assertions(opts) as any;
50
+ const visitors = Assertions(opts as any);
39
51
  expect(visitors).toMatchInlineSnapshot(`
40
52
  Array [
41
53
  Object {
42
- "Operation": [Function],
54
+ "Operation": Object {
55
+ "enter": [Function],
56
+ },
43
57
  },
44
58
  Object {
45
59
  "Operation": Object {
46
- "PathItem": [Function],
60
+ "PathItem": Object {
61
+ "enter": [Function],
62
+ },
47
63
  "skip": [Function],
48
64
  },
49
65
  },
50
66
  Object {
51
67
  "Operation": Object {
52
- "PathItem": [Function],
68
+ "PathItem": Object {
69
+ "enter": [Function],
70
+ },
71
+ "skip": [Function],
53
72
  },
54
73
  },
55
74
  Object {
56
75
  "Bar": Object {
57
76
  "Baz": Object {
58
- "Foo": [Function],
77
+ "Foo": Object {
78
+ "enter": [Function],
79
+ },
59
80
  },
60
81
  },
61
82
  },