@redocly/openapi-core 1.0.0-beta.111 → 1.0.0-beta.113

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 (78) hide show
  1. package/lib/config/all.js +0 -1
  2. package/lib/config/config-resolvers.js +22 -18
  3. package/lib/config/config.d.ts +4 -10
  4. package/lib/config/config.js +1 -1
  5. package/lib/config/load.d.ts +1 -1
  6. package/lib/config/load.js +10 -10
  7. package/lib/config/minimal.js +0 -1
  8. package/lib/config/recommended.js +0 -1
  9. package/lib/config/rules.d.ts +6 -3
  10. package/lib/config/rules.js +3 -2
  11. package/lib/config/types.d.ts +3 -0
  12. package/lib/ref-utils.d.ts +1 -0
  13. package/lib/ref-utils.js +5 -1
  14. package/lib/resolve.js +19 -0
  15. package/lib/rules/common/assertions/asserts.d.ts +22 -5
  16. package/lib/rules/common/assertions/asserts.js +25 -0
  17. package/lib/rules/common/assertions/index.d.ts +27 -2
  18. package/lib/rules/common/assertions/index.js +6 -29
  19. package/lib/rules/common/assertions/utils.d.ts +7 -14
  20. package/lib/rules/common/assertions/utils.js +129 -97
  21. package/lib/rules/common/spec.js +6 -0
  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/utils.js +3 -0
  26. package/lib/types/oas2.js +11 -7
  27. package/lib/types/oas3.js +15 -10
  28. package/lib/types/oas3_1.js +1 -0
  29. package/lib/types/redocly-yaml.js +49 -27
  30. package/lib/utils.d.ts +2 -0
  31. package/lib/utils.js +13 -1
  32. package/lib/visitors.d.ts +2 -1
  33. package/lib/visitors.js +1 -0
  34. package/lib/walk.js +7 -1
  35. package/package.json +1 -1
  36. package/src/__tests__/bundle.test.ts +46 -0
  37. package/src/__tests__/lint.test.ts +24 -5
  38. package/src/benchmark/benches/rebilly.yaml +36 -28
  39. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +1 -3
  40. package/src/config/__tests__/config-resolvers.test.ts +6 -7
  41. package/src/config/__tests__/fixtures/load-redocly.yaml +2 -0
  42. package/src/config/__tests__/fixtures/resolve-config/local-config-with-custom-function.yaml +6 -5
  43. package/src/config/__tests__/fixtures/resolve-config/local-config-with-wrong-custom-function.yaml +0 -1
  44. package/src/config/__tests__/load.test.ts +4 -1
  45. package/src/config/all.ts +0 -1
  46. package/src/config/config-resolvers.ts +44 -31
  47. package/src/config/config.ts +6 -5
  48. package/src/config/load.ts +19 -9
  49. package/src/config/minimal.ts +0 -1
  50. package/src/config/recommended.ts +0 -1
  51. package/src/config/rules.ts +11 -3
  52. package/src/config/types.ts +2 -0
  53. package/src/ref-utils.ts +4 -0
  54. package/src/resolve.ts +25 -3
  55. package/src/rules/common/__tests__/spec.test.ts +170 -0
  56. package/src/rules/common/assertions/__tests__/asserts.test.ts +7 -3
  57. package/src/rules/common/assertions/__tests__/index.test.ts +41 -20
  58. package/src/rules/common/assertions/__tests__/utils.test.ts +43 -17
  59. package/src/rules/common/assertions/asserts.ts +60 -8
  60. package/src/rules/common/assertions/index.ts +36 -46
  61. package/src/rules/common/assertions/utils.ts +204 -127
  62. package/src/rules/common/spec.ts +7 -0
  63. package/src/rules/oas2/index.ts +0 -2
  64. package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +32 -0
  65. package/src/rules/oas3/index.ts +0 -2
  66. package/src/rules/utils.ts +4 -0
  67. package/src/types/oas2.ts +11 -7
  68. package/src/types/oas3.ts +15 -10
  69. package/src/types/oas3_1.ts +1 -0
  70. package/src/types/redocly-yaml.ts +49 -29
  71. package/src/utils.ts +11 -0
  72. package/src/visitors.ts +7 -1
  73. package/src/walk.ts +8 -1
  74. package/tsconfig.tsbuildinfo +1 -1
  75. package/lib/rules/common/info-description.d.ts +0 -2
  76. package/lib/rules/common/info-description.js +0 -12
  77. package/src/rules/common/__tests__/info-description.test.ts +0 -102
  78. package/src/rules/common/info-description.ts +0 -10
@@ -15,18 +15,21 @@ async function addConfigMetadata({
15
15
  customExtends,
16
16
  configPath,
17
17
  tokens,
18
+ files,
19
+ region,
18
20
  }: {
19
21
  rawConfig: RawConfig;
20
22
  customExtends?: string[];
21
23
  configPath?: string;
22
24
  tokens?: RegionalTokenWithValidity[];
25
+ files?: string[];
26
+ region?: Region;
23
27
  }): Promise<Config> {
24
28
  if (customExtends !== undefined) {
25
29
  rawConfig.styleguide = rawConfig.styleguide || {};
26
30
  rawConfig.styleguide.extends = customExtends;
27
31
  } else if (isEmptyObject(rawConfig)) {
28
- // TODO: check if we can add recommended here. add message here?
29
- // rawConfig.styleguide = { extends: ['recommended'], recommendedFallback: true };
32
+ rawConfig.styleguide = { extends: ['recommended'], recommendedFallback: true };
30
33
  }
31
34
 
32
35
  if (tokens?.length) {
@@ -58,7 +61,10 @@ async function addConfigMetadata({
58
61
  }
59
62
  }
60
63
 
61
- return resolveConfig(rawConfig, configPath);
64
+ return resolveConfig(
65
+ { ...rawConfig, files: files ?? rawConfig.files, region: region ?? rawConfig.region },
66
+ configPath
67
+ );
62
68
  }
63
69
 
64
70
  export async function loadConfig(
@@ -71,11 +77,7 @@ export async function loadConfig(
71
77
  } = {}
72
78
  ): Promise<Config> {
73
79
  const { configPath = findConfig(), customExtends, processRawConfig, files, region } = options;
74
- const config = await getConfig(configPath);
75
- const rawConfig = { ...config, files: files ?? config.files, region: region ?? config.region };
76
- if (typeof processRawConfig === 'function') {
77
- await processRawConfig(rawConfig);
78
- }
80
+ const rawConfig = await getConfig(configPath, processRawConfig);
79
81
 
80
82
  const redoclyClient = new RedoclyClient();
81
83
  const tokens = await redoclyClient.getTokens();
@@ -85,6 +87,8 @@ export async function loadConfig(
85
87
  customExtends,
86
88
  configPath,
87
89
  tokens,
90
+ files,
91
+ region,
88
92
  });
89
93
  }
90
94
 
@@ -105,11 +109,17 @@ export function findConfig(dir?: string): string | undefined {
105
109
  return existingConfigFiles[0];
106
110
  }
107
111
 
108
- export async function getConfig(configPath: string | undefined = findConfig()): Promise<RawConfig> {
112
+ export async function getConfig(
113
+ configPath: string | undefined = findConfig(),
114
+ processRawConfig?: (rawConfig: RawConfig) => void | Promise<void>
115
+ ): Promise<RawConfig> {
109
116
  if (!configPath || !doesYamlFileExist(configPath)) return {};
110
117
  try {
111
118
  const rawConfig =
112
119
  (await loadYaml<RawConfig & DeprecatedInRawConfig & FlatRawConfig>(configPath)) || {};
120
+ if (typeof processRawConfig === 'function') {
121
+ await processRawConfig(rawConfig);
122
+ }
113
123
  return transformConfig(rawConfig);
114
124
  } catch (e) {
115
125
  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',
@@ -1,13 +1,20 @@
1
1
  import { RuleSet, OasVersion } from '../oas-types';
2
2
  import { StyleguideConfig } from './config';
3
3
  import { isDefined } from '../utils';
4
+ import type { ProblemSeverity } from '../walk';
5
+
6
+ type InitializedRule = {
7
+ severity: ProblemSeverity;
8
+ ruleId: string;
9
+ visitor: any;
10
+ };
4
11
 
5
12
  export function initRules<T extends Function, P extends RuleSet<T>>(
6
13
  rules: P[],
7
14
  config: StyleguideConfig,
8
15
  type: 'rules' | 'preprocessors' | 'decorators',
9
16
  oasVersion: OasVersion
10
- ) {
17
+ ): InitializedRule[] {
11
18
  return rules
12
19
  .flatMap((ruleset) =>
13
20
  Object.keys(ruleset).map((ruleId) => {
@@ -23,19 +30,20 @@ export function initRules<T extends Function, P extends RuleSet<T>>(
23
30
  if (ruleSettings.severity === 'off') {
24
31
  return undefined;
25
32
  }
33
+ const severity: ProblemSeverity = ruleSettings.severity;
26
34
 
27
35
  const visitors = rule(ruleSettings);
28
36
 
29
37
  if (Array.isArray(visitors)) {
30
38
  return visitors.map((visitor: any) => ({
31
- severity: ruleSettings.severity,
39
+ severity,
32
40
  ruleId,
33
41
  visitor: visitor,
34
42
  }));
35
43
  }
36
44
 
37
45
  return {
38
- severity: ruleSettings.severity,
46
+ severity,
39
47
  ruleId,
40
48
  visitor: visitors, // note: actually it is only one visitor object
41
49
  };
@@ -14,6 +14,8 @@ import { Location } from '../ref-utils';
14
14
 
15
15
  export type RuleSeverity = ProblemSeverity | 'off';
16
16
 
17
+ export type RuleSettings = { severity: RuleSeverity };
18
+
17
19
  export type PreprocessorSeverity = RuleSeverity | 'on';
18
20
 
19
21
  export type RuleConfig =
package/src/ref-utils.ts CHANGED
@@ -79,3 +79,7 @@ export function isMappingRef(mapping: string) {
79
79
  mapping.indexOf('/') > -1
80
80
  );
81
81
  }
82
+
83
+ export function isAnchor(ref: string) {
84
+ return /^#[A-Za-z][A-Za-z0-9\-_:.]*$/.test(ref);
85
+ }
package/src/resolve.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { OasRef } from './typings/openapi';
4
- import { isRef, joinPointer, escapePointer, parseRef, isAbsoluteUrl } from './ref-utils';
4
+ import { isRef, joinPointer, escapePointer, parseRef, isAbsoluteUrl, isAnchor } from './ref-utils';
5
5
  import type { YAMLNode, LoadOptions } from 'yaml-ast-parser';
6
6
  import { NormalizedNodeType, isNamedType } from './types';
7
- import { readFileFromUrl, parseYaml } from './utils';
7
+ import { readFileFromUrl, parseYaml, nextTick } from './utils';
8
8
  import { ResolveConfig } from './config/types';
9
9
 
10
10
  export type CollectedRefs = Map<string /* absoluteFilePath */, Document>;
@@ -237,6 +237,7 @@ export async function resolveDocument(opts: {
237
237
  type: any
238
238
  ) {
239
239
  const rootNodeDocAbsoluteRef = rootNodeDocument.source.absoluteRef;
240
+ const anchorRefsMap: Map<string, any> = new Map();
240
241
 
241
242
  walk(rootNode, type, rootNodeDocAbsoluteRef + rootNodePointer);
242
243
 
@@ -252,6 +253,11 @@ export async function resolveDocument(opts: {
252
253
 
253
254
  seedNodes.add(nodeId);
254
255
 
256
+ const [_, anchor] = Object.entries(node).find(([key]) => key === '$anchor') || [];
257
+ if (anchor) {
258
+ anchorRefsMap.set(`#${anchor}`, node);
259
+ }
260
+
255
261
  if (Array.isArray(node)) {
256
262
  const itemsType = type.items;
257
263
  // we continue resolving unknown types, but stop early on known scalars
@@ -313,6 +319,22 @@ export async function resolveDocument(opts: {
313
319
  if (hasRef(refStack.prev, ref)) {
314
320
  throw new Error('Self-referencing circular pointer');
315
321
  }
322
+
323
+ if (isAnchor(ref.$ref)) {
324
+ // Wait for all anchors in the document to be collected firstly.
325
+ await nextTick();
326
+ const resolvedRef: ResolvedRef = {
327
+ resolved: true,
328
+ isRemote: false,
329
+ node: anchorRefsMap.get(ref.$ref),
330
+ document,
331
+ nodePointer: ref.$ref,
332
+ };
333
+ const refId = makeRefId(document.source.absoluteRef, ref.$ref);
334
+ resolvedRefMap.set(refId, resolvedRef);
335
+ return resolvedRef;
336
+ }
337
+
316
338
  const { uri, pointer } = parseRef(ref.$ref);
317
339
  const isRemote = uri !== null;
318
340
  let targetDoc: Document;
@@ -336,7 +358,7 @@ export async function resolveDocument(opts: {
336
358
  }
337
359
 
338
360
  let resolvedRef: ResolvedRef = {
339
- resolved: true as const,
361
+ resolved: true,
340
362
  document: targetDoc,
341
363
  isRemote,
342
364
  node: document.parsed,
@@ -138,6 +138,176 @@ describe('Oas3 spec', () => {
138
138
  ]
139
139
  `);
140
140
  });
141
+
142
+ it('should report on nullable without type', async () => {
143
+ const document = parseYamlToDocument(
144
+ outdent`
145
+ openapi: 3.0.0
146
+ components:
147
+ requestBodies:
148
+ TestRequestBody:
149
+ content:
150
+ application/json:
151
+ schema:
152
+ nullable: true
153
+ `,
154
+ 'foobar.yaml'
155
+ );
156
+
157
+ const results = await lintDocument({
158
+ externalRefResolver: new BaseResolver(),
159
+ document,
160
+ config: await makeConfig({ spec: 'error' }),
161
+ });
162
+
163
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
164
+ Array [
165
+ Object {
166
+ "from": undefined,
167
+ "location": Array [
168
+ Object {
169
+ "pointer": "#/",
170
+ "reportOnKey": true,
171
+ "source": "foobar.yaml",
172
+ },
173
+ ],
174
+ "message": "The field \`paths\` must be present on this level.",
175
+ "ruleId": "spec",
176
+ "severity": "error",
177
+ "suggest": Array [],
178
+ },
179
+ Object {
180
+ "from": undefined,
181
+ "location": Array [
182
+ Object {
183
+ "pointer": "#/",
184
+ "reportOnKey": true,
185
+ "source": "foobar.yaml",
186
+ },
187
+ ],
188
+ "message": "The field \`info\` must be present on this level.",
189
+ "ruleId": "spec",
190
+ "severity": "error",
191
+ "suggest": Array [],
192
+ },
193
+ Object {
194
+ "location": Array [
195
+ Object {
196
+ "pointer": "#/components/requestBodies/TestRequestBody/content/application~1json/schema/nullable",
197
+ "reportOnKey": false,
198
+ "source": "foobar.yaml",
199
+ },
200
+ ],
201
+ "message": "The \`type\` field must be defined when the \`nullable\` field is used.",
202
+ "ruleId": "spec",
203
+ "severity": "error",
204
+ "suggest": Array [],
205
+ },
206
+ ]
207
+ `);
208
+ });
209
+
210
+ it('should report on nullable with type defined in allOf', async () => {
211
+ const document = parseYamlToDocument(
212
+ outdent`
213
+ openapi: 3.0.0
214
+ components:
215
+ requestBodies:
216
+ TestRequestBody:
217
+ content:
218
+ application/json:
219
+ schema:
220
+ nullable: true
221
+ allOf:
222
+ - $ref: "#/components/requestBodies/TestSchema"
223
+ schemas:
224
+ TestSchema:
225
+ title: TestSchema
226
+ type: object
227
+ `,
228
+ 'foobar.yaml'
229
+ );
230
+
231
+ const results = await lintDocument({
232
+ externalRefResolver: new BaseResolver(),
233
+ document,
234
+ config: await makeConfig({ spec: 'error' }),
235
+ });
236
+
237
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
238
+ Array [
239
+ Object {
240
+ "from": undefined,
241
+ "location": Array [
242
+ Object {
243
+ "pointer": "#/",
244
+ "reportOnKey": true,
245
+ "source": "foobar.yaml",
246
+ },
247
+ ],
248
+ "message": "The field \`paths\` must be present on this level.",
249
+ "ruleId": "spec",
250
+ "severity": "error",
251
+ "suggest": Array [],
252
+ },
253
+ Object {
254
+ "from": undefined,
255
+ "location": Array [
256
+ Object {
257
+ "pointer": "#/",
258
+ "reportOnKey": true,
259
+ "source": "foobar.yaml",
260
+ },
261
+ ],
262
+ "message": "The field \`info\` must be present on this level.",
263
+ "ruleId": "spec",
264
+ "severity": "error",
265
+ "suggest": Array [],
266
+ },
267
+ Object {
268
+ "location": Array [
269
+ Object {
270
+ "pointer": "#/components/requestBodies/TestRequestBody/content/application~1json/schema/nullable",
271
+ "reportOnKey": false,
272
+ "source": "foobar.yaml",
273
+ },
274
+ ],
275
+ "message": "The \`type\` field must be defined when the \`nullable\` field is used.",
276
+ "ruleId": "spec",
277
+ "severity": "error",
278
+ "suggest": Array [],
279
+ },
280
+ Object {
281
+ "from": undefined,
282
+ "location": Array [
283
+ Object {
284
+ "pointer": "#/components/requestBodies/schemas",
285
+ "reportOnKey": true,
286
+ "source": "foobar.yaml",
287
+ },
288
+ ],
289
+ "message": "The field \`content\` must be present on this level.",
290
+ "ruleId": "spec",
291
+ "severity": "error",
292
+ "suggest": Array [],
293
+ },
294
+ Object {
295
+ "from": undefined,
296
+ "location": Array [
297
+ Object {
298
+ "pointer": "#/components/requestBodies/schemas/TestSchema",
299
+ "reportOnKey": true,
300
+ "source": "foobar.yaml",
301
+ },
302
+ ],
303
+ "message": "Property \`TestSchema\` is not expected here.",
304
+ "ruleId": "spec",
305
+ "severity": "error",
306
+ "suggest": Array [],
307
+ },
308
+ ]
309
+ `);
310
+ });
141
311
  });
142
312
 
143
313
  describe('Oas3.1 spec', () => {
@@ -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
  },
@@ -1,3 +1,4 @@
1
+ import { Assertion, AssertionDefinition } from '..';
1
2
  import { isOrdered, buildVisitorObject, getIntersectionLength } from '../utils';
2
3
 
3
4
  describe('Oas3 assertions', () => {
@@ -25,29 +26,43 @@ describe('Oas3 assertions', () => {
25
26
 
26
27
  describe('buildVisitorObject', () => {
27
28
  it('should return a consistent visitor structure', () => {
28
- const context = [
29
+ const where: AssertionDefinition[] = [
29
30
  {
30
- type: 'Foo',
31
- matchParentKeys: ['test'],
31
+ subject: {
32
+ type: 'Foo',
33
+ filterInParentKeys: ['test'],
34
+ },
35
+ assertions: {},
32
36
  },
33
37
  {
34
- type: 'Bar',
35
- matchParentKeys: ['test'],
38
+ subject: {
39
+ type: 'Bar',
40
+ filterInParentKeys: ['test'],
41
+ },
42
+ assertions: {},
36
43
  },
37
44
  {
38
- type: 'Roof',
39
- matchParentKeys: ['test'],
45
+ subject: {
46
+ type: 'Roof',
47
+ filterInParentKeys: ['test'],
48
+ },
49
+ assertions: {},
40
50
  },
41
- ];
51
+ ] as AssertionDefinition[];
42
52
 
43
- const visitors = buildVisitorObject('Bar', context, () => {}) as any;
53
+ const visitors = buildVisitorObject(
54
+ { subject: { type: 'Bar' }, where, assertions: {} } as Assertion,
55
+ () => {}
56
+ );
44
57
 
45
58
  expect(visitors).toMatchInlineSnapshot(`
46
59
  Object {
47
60
  "Foo": Object {
48
61
  "Bar": Object {
49
62
  "Roof": Object {
50
- "Bar": [Function],
63
+ "Bar": Object {
64
+ "enter": [Function],
65
+ },
51
66
  "skip": [Function],
52
67
  },
53
68
  "skip": [Function],
@@ -59,24 +74,35 @@ describe('Oas3 assertions', () => {
59
74
  });
60
75
 
61
76
  it('should return the right visitor structure', () => {
62
- const context = [
77
+ const where = [
63
78
  {
64
- type: 'Operation',
65
- matchParentKeys: ['put'],
79
+ subject: {
80
+ type: 'Operation',
81
+ filterInParentKeys: ['put'],
82
+ },
83
+ assertions: {},
66
84
  },
67
85
  {
68
- type: 'Responses',
69
- matchParentKeys: [201, 200],
86
+ subject: {
87
+ type: 'Responses',
88
+ filterInParentKeys: [201, 200],
89
+ },
90
+ assertions: {},
70
91
  },
71
92
  ];
72
93
 
73
- const visitors = buildVisitorObject('MediaTypesMap', context, () => {}) as any;
94
+ const visitors = buildVisitorObject(
95
+ { subject: { type: 'MediaTypesMap' }, where, assertions: {} } as Assertion,
96
+ () => {}
97
+ );
74
98
 
75
99
  expect(visitors).toMatchInlineSnapshot(`
76
100
  Object {
77
101
  "Operation": Object {
78
102
  "Responses": Object {
79
- "MediaTypesMap": [Function],
103
+ "MediaTypesMap": Object {
104
+ "enter": [Function],
105
+ },
80
106
  "skip": [Function],
81
107
  },
82
108
  "skip": [Function],