@redocly/openapi-core 1.31.3 → 1.32.0

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 (53) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/lib/bundle.js +5 -0
  3. package/lib/config/all.js +3 -0
  4. package/lib/config/builtIn.js +5 -0
  5. package/lib/config/config-resolvers.js +34 -6
  6. package/lib/config/config.d.ts +2 -2
  7. package/lib/config/config.js +16 -0
  8. package/lib/config/minimal.js +3 -0
  9. package/lib/config/recommended-strict.js +3 -0
  10. package/lib/config/recommended.js +3 -0
  11. package/lib/config/rules.d.ts +2 -2
  12. package/lib/config/spec.js +3 -0
  13. package/lib/config/types.d.ts +8 -2
  14. package/lib/config/utils.js +13 -1
  15. package/lib/decorators/overlay1/index.d.ts +1 -0
  16. package/lib/decorators/overlay1/index.js +4 -0
  17. package/lib/oas-types.d.ts +9 -4
  18. package/lib/oas-types.js +10 -0
  19. package/lib/rules/common/assertions/index.d.ts +2 -2
  20. package/lib/rules/common/struct.d.ts +2 -2
  21. package/lib/rules/overlay1/index.d.ts +3 -0
  22. package/lib/rules/overlay1/index.js +12 -0
  23. package/lib/types/oas3.js +1 -1
  24. package/lib/types/redocly-yaml.d.ts +2 -0
  25. package/lib/types/redocly-yaml.js +2 -0
  26. package/lib/visitors.d.ts +11 -0
  27. package/package.json +1 -1
  28. package/src/bundle.ts +5 -0
  29. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +10 -0
  30. package/src/config/__tests__/__snapshots__/config.test.ts.snap +24 -0
  31. package/src/config/__tests__/config.test.ts +11 -0
  32. package/src/config/all.ts +3 -0
  33. package/src/config/builtIn.ts +5 -0
  34. package/src/config/config-resolvers.ts +36 -6
  35. package/src/config/config.ts +20 -0
  36. package/src/config/minimal.ts +3 -0
  37. package/src/config/recommended-strict.ts +3 -0
  38. package/src/config/recommended.ts +3 -0
  39. package/src/config/rules.ts +9 -1
  40. package/src/config/spec.ts +3 -0
  41. package/src/config/types.ts +13 -1
  42. package/src/config/utils.ts +15 -0
  43. package/src/decorators/overlay1/index.ts +1 -0
  44. package/src/lint.ts +3 -0
  45. package/src/oas-types.ts +20 -0
  46. package/src/rules/common/assertions/index.ts +9 -2
  47. package/src/rules/common/struct.ts +16 -3
  48. package/src/rules/overlay1/__tests__/info-contact.test.ts +112 -0
  49. package/src/rules/overlay1/index.ts +14 -0
  50. package/src/types/oas3.ts +1 -1
  51. package/src/types/redocly-yaml.ts +5 -0
  52. package/src/visitors.ts +19 -0
  53. package/tsconfig.tsbuildinfo +1 -1
package/src/lint.ts CHANGED
@@ -21,6 +21,7 @@ import type {
21
21
  NestedVisitObject,
22
22
  Oas2Visitor,
23
23
  Oas3Visitor,
24
+ Overlay1Visitor,
24
25
  RuleInstanceConfig,
25
26
  } from './visitors';
26
27
  import type { CollectFn } from './utils';
@@ -154,6 +155,8 @@ export async function lintConfig(opts: {
154
155
  | Async3Visitor[]
155
156
  | Arazzo1Visitor
156
157
  | Arazzo1Visitor[]
158
+ | Overlay1Visitor
159
+ | Overlay1Visitor[]
157
160
  >;
158
161
  })[] = [
159
162
  {
package/src/oas-types.ts CHANGED
@@ -4,6 +4,7 @@ import { Oas3_1Types } from './types/oas3_1';
4
4
  import { AsyncApi2Types } from './types/asyncapi2';
5
5
  import { AsyncApi3Types } from './types/asyncapi3';
6
6
  import { Arazzo1Types } from './types/arazzo';
7
+ import { Overlay1Types } from './types/overlay';
7
8
  import { isPlainObject } from './utils';
8
9
  import { VERSION_PATTERN } from './typings/arazzo';
9
10
 
@@ -13,6 +14,7 @@ import type {
13
14
  BuiltInArazzo1RuleId,
14
15
  BuiltInOAS2RuleId,
15
16
  BuiltInOAS3RuleId,
17
+ BuiltInOverlay1RuleId,
16
18
  } from './types/redocly-yaml';
17
19
  import type {
18
20
  Oas3Rule,
@@ -25,6 +27,8 @@ import type {
25
27
  Async3Rule,
26
28
  Arazzo1Preprocessor,
27
29
  Arazzo1Rule,
30
+ Overlay1Preprocessor,
31
+ Overlay1Rule,
28
32
  } from './visitors';
29
33
 
30
34
  export enum SpecVersion {
@@ -34,6 +38,7 @@ export enum SpecVersion {
34
38
  Async2 = 'async2',
35
39
  Async3 = 'async3',
36
40
  Arazzo1 = 'arazzo1',
41
+ Overlay1 = 'overlay1',
37
42
  }
38
43
 
39
44
  export enum SpecMajorVersion {
@@ -42,6 +47,7 @@ export enum SpecMajorVersion {
42
47
  Async2 = 'async2',
43
48
  Async3 = 'async3',
44
49
  Arazzo1 = 'arazzo1',
50
+ Overlay1 = 'overlay1',
45
51
  }
46
52
 
47
53
  const typesMap = {
@@ -51,6 +57,7 @@ const typesMap = {
51
57
  [SpecVersion.Async2]: AsyncApi2Types,
52
58
  [SpecVersion.Async3]: AsyncApi3Types,
53
59
  [SpecVersion.Arazzo1]: Arazzo1Types,
60
+ [SpecVersion.Overlay1]: Overlay1Types,
54
61
  };
55
62
 
56
63
  export type RuleMap<Key extends string, RuleConfig, T> = Record<
@@ -83,17 +90,24 @@ export type Arazzo1RuleSet<T = undefined> = RuleMap<
83
90
  T
84
91
  >;
85
92
 
93
+ export type Overlay1RuleSet<T = undefined> = RuleMap<
94
+ BuiltInOverlay1RuleId | 'struct' | 'assertions',
95
+ Overlay1Rule,
96
+ T
97
+ >;
86
98
  export type Oas3PreprocessorsSet = Record<string, Oas3Preprocessor>;
87
99
  export type Oas2PreprocessorsSet = Record<string, Oas2Preprocessor>;
88
100
  export type Async2PreprocessorsSet = Record<string, Async2Preprocessor>;
89
101
  export type Async3PreprocessorsSet = Record<string, Async3Preprocessor>;
90
102
  export type Arazzo1PreprocessorsSet = Record<string, Arazzo1Preprocessor>;
103
+ export type Overlay1PreprocessorsSet = Record<string, Overlay1Preprocessor>;
91
104
 
92
105
  export type Oas3DecoratorsSet = Record<string, Oas3Preprocessor>;
93
106
  export type Oas2DecoratorsSet = Record<string, Oas2Preprocessor>;
94
107
  export type Async2DecoratorsSet = Record<string, Async2Preprocessor>;
95
108
  export type Async3DecoratorsSet = Record<string, Async3Preprocessor>;
96
109
  export type Arazzo1DecoratorsSet = Record<string, Arazzo1Preprocessor>;
110
+ export type Overlay1DecoratorsSet = Record<string, Overlay1Preprocessor>;
97
111
 
98
112
  export function detectSpec(root: unknown): SpecVersion {
99
113
  if (!isPlainObject(root)) {
@@ -136,6 +150,10 @@ export function detectSpec(root: unknown): SpecVersion {
136
150
  return SpecVersion.Arazzo1;
137
151
  }
138
152
 
153
+ if (typeof root.overlay === 'string' && VERSION_PATTERN.test(root.overlay)) {
154
+ return SpecVersion.Overlay1;
155
+ }
156
+
139
157
  throw new Error(`Unsupported specification`);
140
158
  }
141
159
 
@@ -148,6 +166,8 @@ export function getMajorSpecVersion(version: SpecVersion): SpecMajorVersion {
148
166
  return SpecMajorVersion.Async3;
149
167
  } else if (version === SpecVersion.Arazzo1) {
150
168
  return SpecMajorVersion.Arazzo1;
169
+ } else if (version === SpecVersion.Overlay1) {
170
+ return SpecMajorVersion.Overlay1;
151
171
  } else {
152
172
  return SpecMajorVersion.OAS3;
153
173
  }
@@ -8,6 +8,7 @@ import type {
8
8
  Async3Visitor,
9
9
  Oas2Visitor,
10
10
  Oas3Visitor,
11
+ Overlay1Visitor,
11
12
  } from '../../../visitors';
12
13
  import type { RuleSeverity } from '../../../config';
13
14
 
@@ -35,8 +36,14 @@ export type RawAssertion = AssertionDefinition & {
35
36
  export type Assertion = RawAssertion & { assertionId: string };
36
37
 
37
38
  export const Assertions = (opts: Record<string, Assertion>) => {
38
- const visitors: (Oas2Visitor | Oas3Visitor | Async2Visitor | Async3Visitor | Arazzo1Visitor)[] =
39
- [];
39
+ const visitors: (
40
+ | Oas2Visitor
41
+ | Oas3Visitor
42
+ | Async2Visitor
43
+ | Async3Visitor
44
+ | Arazzo1Visitor
45
+ | Overlay1Visitor
46
+ )[] = [];
40
47
 
41
48
  // As 'Assertions' has an array of asserts,
42
49
  // that array spreads into an 'opts' object on init rules phase here
@@ -4,9 +4,22 @@ import { isRef } from '../../ref-utils';
4
4
  import { isPlainObject } from '../../utils';
5
5
 
6
6
  import type { UserContext } from '../../walk';
7
- import type { Oas3Rule, Oas2Rule, Async2Rule, Async3Rule, Arazzo1Rule } from '../../visitors';
8
-
9
- export const Struct: Oas3Rule | Oas2Rule | Async2Rule | Async3Rule | Arazzo1Rule = () => {
7
+ import type {
8
+ Oas3Rule,
9
+ Oas2Rule,
10
+ Async2Rule,
11
+ Async3Rule,
12
+ Arazzo1Rule,
13
+ Overlay1Rule,
14
+ } from '../../visitors';
15
+
16
+ export const Struct:
17
+ | Oas3Rule
18
+ | Oas2Rule
19
+ | Async2Rule
20
+ | Async3Rule
21
+ | Arazzo1Rule
22
+ | Overlay1Rule = () => {
10
23
  return {
11
24
  any(
12
25
  node: any,
@@ -0,0 +1,112 @@
1
+ import { outdent } from 'outdent';
2
+ import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../../../__tests__/utils';
3
+ import { lintDocument } from '../../../lint';
4
+ import { BaseResolver } from '../../../resolve';
5
+
6
+ describe('Overlay 1.0 Description', () => {
7
+ it('should not report if the Contact Object is valid', async () => {
8
+ const document = parseYamlToDocument(
9
+ outdent`
10
+ overlay: 1.0.0
11
+ info:
12
+ title: Example Overlay 1 definition. Valid.
13
+ version: '1.0'
14
+ contact:
15
+ name: API Support
16
+ url: http://www.example.com/support
17
+ email: support@example.com
18
+ extends: 'openapi.yaml'
19
+ actions: []
20
+ `,
21
+ 'overlay.yaml'
22
+ );
23
+ const results = await lintDocument({
24
+ externalRefResolver: new BaseResolver(),
25
+ document,
26
+ config: await makeConfig({
27
+ rules: {
28
+ 'info-contact': { severity: 'error' },
29
+ },
30
+ }),
31
+ });
32
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
33
+ });
34
+
35
+ it('should report if the Contact Object is not defined', async () => {
36
+ const document = parseYamlToDocument(
37
+ outdent`
38
+ overlay: 1.0.0
39
+ info:
40
+ title: Example Overlay 1 definition. Invalid.
41
+ version: '1.0'
42
+ extends: 'openapi.yaml'
43
+ actions: []
44
+ `,
45
+ 'overlay.yaml'
46
+ );
47
+ const results = await lintDocument({
48
+ externalRefResolver: new BaseResolver(),
49
+ document,
50
+ config: await makeConfig({
51
+ rules: {
52
+ 'info-contact': { severity: 'error' },
53
+ },
54
+ }),
55
+ });
56
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
57
+ [
58
+ {
59
+ "location": [
60
+ {
61
+ "pointer": "#/info/contact",
62
+ "reportOnKey": true,
63
+ "source": "overlay.yaml",
64
+ },
65
+ ],
66
+ "message": "Info object should contain \`contact\` field.",
67
+ "ruleId": "info-contact",
68
+ "severity": "error",
69
+ "suggest": [],
70
+ },
71
+ ]
72
+ `);
73
+ });
74
+ it('should report if the Overlay Document is invalid', async () => {
75
+ const document = parseYamlToDocument(
76
+ outdent`
77
+ overlay: 1.0.0
78
+ info:
79
+ title: Example Overlay 1 definition. Invalid.
80
+ version: '1.0'
81
+ `,
82
+ 'overlay.yaml'
83
+ );
84
+ const results = await lintDocument({
85
+ externalRefResolver: new BaseResolver(),
86
+ document,
87
+ config: await makeConfig({
88
+ rules: {
89
+ struct: { severity: 'error' },
90
+ },
91
+ }),
92
+ });
93
+ expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
94
+ [
95
+ {
96
+ "from": undefined,
97
+ "location": [
98
+ {
99
+ "pointer": "#/",
100
+ "reportOnKey": true,
101
+ "source": "overlay.yaml",
102
+ },
103
+ ],
104
+ "message": "The field \`actions\` must be present on this level.",
105
+ "ruleId": "struct",
106
+ "severity": "error",
107
+ "suggest": [],
108
+ },
109
+ ]
110
+ `);
111
+ });
112
+ });
@@ -0,0 +1,14 @@
1
+ import { Assertions } from '../common/assertions';
2
+ import { InfoContact } from '../common/info-contact';
3
+ import { Struct } from '../common/struct';
4
+
5
+ import type { Overlay1RuleSet } from '../../oas-types';
6
+ import type { Overlay1Rule } from '../../visitors';
7
+
8
+ export const rules: Overlay1RuleSet<'built-in'> = {
9
+ 'info-contact': InfoContact as Overlay1Rule,
10
+ struct: Struct as Overlay1Rule,
11
+ assertions: Assertions as Overlay1Rule,
12
+ };
13
+
14
+ export const preprocessors = {};
package/src/types/oas3.ts CHANGED
@@ -332,7 +332,7 @@ const Schema: NodeType = {
332
332
  required: { type: 'array', items: { type: 'string' } },
333
333
  enum: { type: 'array' },
334
334
  type: {
335
- enum: ['object', 'array', 'string', 'number', 'integer', 'boolean', 'null'],
335
+ enum: ['object', 'array', 'string', 'number', 'integer', 'boolean'],
336
336
  },
337
337
  allOf: listOf('Schema'),
338
338
  anyOf: listOf('Schema'),
@@ -160,12 +160,17 @@ const builtInArazzo1Rules = [
160
160
 
161
161
  export type BuiltInArazzo1RuleId = typeof builtInArazzo1Rules[number];
162
162
 
163
+ const builtInOverlay1Rules = ['info-contact'] as const;
164
+
165
+ export type BuiltInOverlay1RuleId = typeof builtInOverlay1Rules[number];
166
+
163
167
  const builtInRules = [
164
168
  ...builtInOAS2Rules,
165
169
  ...builtInOAS3Rules,
166
170
  ...builtInAsync2Rules,
167
171
  ...builtInAsync3Rules,
168
172
  ...builtInArazzo1Rules,
173
+ ...builtInOverlay1Rules,
169
174
  'spec', // TODO: depricated in favor of struct
170
175
  'struct',
171
176
  ] as const;
package/src/visitors.ts CHANGED
@@ -70,6 +70,7 @@ import type {
70
70
  Step,
71
71
  Workflow,
72
72
  } from './typings/arazzo';
73
+ import type { Overlay1Definition } from './typings/overlay';
73
74
 
74
75
  export type SkipFunctionContext = Pick<
75
76
  UserContext,
@@ -259,6 +260,10 @@ type ArazzoFlatVisitor = {
259
260
  Workflows?: VisitFunctionOrObject<Workflow[]>;
260
261
  };
261
262
 
263
+ type Overlay1FlatVisitor = {
264
+ Root?: VisitFunctionOrObject<Overlay1Definition>;
265
+ };
266
+
262
267
  const legacyTypesMap = {
263
268
  Root: 'DefinitionRoot',
264
269
  ServerVariablesMap: 'ServerVariableMap',
@@ -308,6 +313,13 @@ type ArazzoNestedVisitor = {
308
313
  : ArazzoFlatVisitor[T] & NestedVisitor<ArazzoNestedVisitor>;
309
314
  };
310
315
 
316
+ type Overlay1NestedVisitor = {
317
+ // eslint-disable-next-line @typescript-eslint/ban-types
318
+ [T in keyof Overlay1FlatVisitor]: Overlay1FlatVisitor[T] extends Function
319
+ ? Overlay1FlatVisitor[T]
320
+ : Overlay1FlatVisitor[T] & NestedVisitor<Overlay1NestedVisitor>;
321
+ };
322
+
311
323
  export type Oas3Visitor = BaseVisitor &
312
324
  Oas3NestedVisitor &
313
325
  Record<string, VisitFunction<any> | NestedVisitObject<any, Oas3NestedVisitor>>;
@@ -328,6 +340,10 @@ export type Arazzo1Visitor = BaseVisitor &
328
340
  ArazzoNestedVisitor &
329
341
  Record<string, VisitFunction<any> | NestedVisitObject<any, ArazzoNestedVisitor>>;
330
342
 
343
+ export type Overlay1Visitor = BaseVisitor &
344
+ Overlay1NestedVisitor &
345
+ Record<string, VisitFunction<any> | NestedVisitObject<any, Overlay1NestedVisitor>>;
346
+
331
347
  export type NestedVisitor<T> = Exclude<T, 'any' | 'ref' | 'Root'>;
332
348
 
333
349
  export type NormalizedOasVisitors<T extends BaseVisitor> = {
@@ -352,16 +368,19 @@ export type Oas2Rule = (options: Record<string, any>) => Oas2Visitor | Oas2Visit
352
368
  export type Async2Rule = (options: Record<string, any>) => Async2Visitor | Async2Visitor[];
353
369
  export type Async3Rule = (options: Record<string, any>) => Async3Visitor | Async3Visitor[];
354
370
  export type Arazzo1Rule = (options: Record<string, any>) => Arazzo1Visitor | Arazzo1Visitor[];
371
+ export type Overlay1Rule = (options: Record<string, any>) => Overlay1Visitor | Overlay1Visitor[];
355
372
  export type Oas3Preprocessor = (options: Record<string, any>) => Oas3Visitor;
356
373
  export type Oas2Preprocessor = (options: Record<string, any>) => Oas2Visitor;
357
374
  export type Async2Preprocessor = (options: Record<string, any>) => Async2Visitor;
358
375
  export type Async3Preprocessor = (options: Record<string, any>) => Async3Visitor;
359
376
  export type Arazzo1Preprocessor = (options: Record<string, any>) => Arazzo1Visitor;
377
+ export type Overlay1Preprocessor = (options: Record<string, any>) => Overlay1Visitor;
360
378
  export type Oas3Decorator = (options: Record<string, any>) => Oas3Visitor;
361
379
  export type Oas2Decorator = (options: Record<string, any>) => Oas2Visitor;
362
380
  export type Async2Decorator = (options: Record<string, any>) => Async2Visitor;
363
381
  export type Async3Decorator = (options: Record<string, any>) => Async3Visitor;
364
382
  export type Arazzo1Decorator = (options: Record<string, any>) => Arazzo1Visitor;
383
+ export type Overlay1Decorator = (options: Record<string, any>) => Overlay1Visitor;
365
384
 
366
385
  // alias for the latest version supported
367
386
  // every time we update it - consider semver