@redocly/openapi-core 1.18.1 → 1.19.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 (139) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/lib/benchmark/benches/lint-with-many-rules.bench.js +2 -2
  3. package/lib/benchmark/benches/lint-with-nested-rule.bench.js +2 -2
  4. package/lib/benchmark/benches/lint-with-no-rules.bench.js +2 -2
  5. package/lib/benchmark/benches/lint-with-top-level-rule-report.bench.js +2 -2
  6. package/lib/benchmark/benches/lint-with-top-level-rule.bench.js +2 -2
  7. package/lib/benchmark/benches/recommended-oas3.bench.js +2 -2
  8. package/lib/benchmark/benches/resolve-with-no-external.bench.js +2 -2
  9. package/lib/benchmark/utils.js +7 -4
  10. package/lib/bundle.d.ts +2 -2
  11. package/lib/bundle.js +127 -120
  12. package/lib/config/all.js +9 -0
  13. package/lib/config/builtIn.js +7 -1
  14. package/lib/config/config-resolvers.js +179 -138
  15. package/lib/config/config.d.ts +2 -2
  16. package/lib/config/config.js +53 -34
  17. package/lib/config/load.js +105 -117
  18. package/lib/config/minimal.js +9 -0
  19. package/lib/config/recommended-strict.js +9 -0
  20. package/lib/config/recommended.js +9 -0
  21. package/lib/config/rules.d.ts +3 -3
  22. package/lib/config/rules.js +1 -2
  23. package/lib/config/types.d.ts +9 -3
  24. package/lib/config/utils.js +70 -49
  25. package/lib/decorators/async3/index.d.ts +1 -0
  26. package/lib/decorators/async3/index.js +4 -0
  27. package/lib/decorators/common/filters/filter-helper.js +2 -3
  28. package/lib/decorators/common/filters/filter-in.js +1 -1
  29. package/lib/decorators/common/filters/filter-out.js +1 -1
  30. package/lib/decorators/common/info-override.js +1 -12
  31. package/lib/decorators/common/media-type-examples-override.js +8 -2
  32. package/lib/decorators/common/remove-x-internal.js +4 -5
  33. package/lib/decorators/oas2/remove-unused-components.js +1 -2
  34. package/lib/decorators/oas3/remove-unused-components.js +1 -2
  35. package/lib/env.d.ts +0 -1
  36. package/lib/env.js +1 -1
  37. package/lib/format/codeframes.js +10 -8
  38. package/lib/format/format.js +23 -15
  39. package/lib/index.d.ts +2 -1
  40. package/lib/index.js +6 -4
  41. package/lib/js-yaml/index.js +1 -1
  42. package/lib/lint.d.ts +2 -0
  43. package/lib/lint.js +92 -99
  44. package/lib/oas-types.d.ts +9 -5
  45. package/lib/oas-types.js +22 -12
  46. package/lib/redocly/domains.js +6 -6
  47. package/lib/redocly/index.js +60 -73
  48. package/lib/redocly/registry-api.js +64 -82
  49. package/lib/ref-utils.js +13 -13
  50. package/lib/resolve.js +186 -205
  51. package/lib/rules/ajv.js +10 -8
  52. package/lib/rules/async3/channels-kebab-case.d.ts +2 -0
  53. package/lib/rules/async3/channels-kebab-case.js +19 -0
  54. package/lib/rules/async3/index.d.ts +3 -0
  55. package/lib/rules/async3/index.js +22 -0
  56. package/lib/rules/async3/no-channel-trailing-slash.d.ts +2 -0
  57. package/lib/rules/async3/no-channel-trailing-slash.js +16 -0
  58. package/lib/rules/common/assertions/asserts.js +5 -5
  59. package/lib/rules/common/assertions/index.d.ts +5 -4
  60. package/lib/rules/common/assertions/utils.js +43 -28
  61. package/lib/rules/common/no-invalid-parameter-examples.js +1 -2
  62. package/lib/rules/common/no-invalid-schema-examples.js +1 -2
  63. package/lib/rules/common/no-required-schema-properties-undefined.js +1 -2
  64. package/lib/rules/common/operation-tag-defined.js +1 -2
  65. package/lib/rules/common/path-http-verbs-order.js +1 -1
  66. package/lib/rules/common/required-string-property-missing-min-length.js +2 -2
  67. package/lib/rules/common/response-contains-header.js +2 -2
  68. package/lib/rules/common/security-defined.js +3 -7
  69. package/lib/rules/common/spec.d.ts +2 -2
  70. package/lib/rules/common/spec.js +6 -7
  71. package/lib/rules/no-unresolved-refs.js +3 -4
  72. package/lib/rules/oas2/response-contains-property.js +1 -2
  73. package/lib/rules/oas3/array-parameter-serialization.js +1 -2
  74. package/lib/rules/oas3/component-name-unique.js +2 -4
  75. package/lib/rules/oas3/no-invalid-media-type-examples.js +1 -2
  76. package/lib/rules/oas3/no-server-variables-empty-enum.js +1 -2
  77. package/lib/rules/oas3/no-undefined-server-variable.js +2 -3
  78. package/lib/rules/oas3/no-unused-components.js +1 -2
  79. package/lib/rules/oas3/response-contains-property.js +1 -2
  80. package/lib/rules/utils.js +14 -12
  81. package/lib/types/asyncapi2.d.ts +17 -0
  82. package/lib/types/{asyncapi.js → asyncapi2.js} +56 -52
  83. package/lib/types/asyncapi3.d.ts +2 -0
  84. package/lib/types/asyncapi3.js +347 -0
  85. package/lib/types/index.js +19 -10
  86. package/lib/types/json-schema-adapter.js +4 -18
  87. package/lib/types/oas2.js +6 -6
  88. package/lib/types/oas3.js +10 -10
  89. package/lib/types/oas3_1.js +14 -8
  90. package/lib/types/redocly-yaml.d.ts +3 -1
  91. package/lib/types/redocly-yaml.js +131 -35
  92. package/lib/typings/asyncapi3.d.ts +53 -0
  93. package/lib/typings/asyncapi3.js +2 -0
  94. package/lib/utils.d.ts +4 -3
  95. package/lib/utils.js +55 -72
  96. package/lib/visitors.d.ts +11 -0
  97. package/lib/visitors.js +21 -8
  98. package/lib/walk.js +30 -23
  99. package/package.json +2 -2
  100. package/src/__tests__/bundle.test.ts +142 -0
  101. package/src/bundle.ts +17 -3
  102. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +22 -0
  103. package/src/config/__tests__/__snapshots__/config.test.ts.snap +24 -0
  104. package/src/config/__tests__/config.test.ts +11 -0
  105. package/src/config/all.ts +9 -0
  106. package/src/config/builtIn.ts +6 -0
  107. package/src/config/config-resolvers.ts +15 -2
  108. package/src/config/config.ts +24 -5
  109. package/src/config/minimal.ts +9 -0
  110. package/src/config/recommended-strict.ts +9 -0
  111. package/src/config/recommended.ts +9 -0
  112. package/src/config/rules.ts +12 -4
  113. package/src/config/types.ts +15 -2
  114. package/src/config/utils.ts +15 -0
  115. package/src/decorators/async3/index.ts +1 -0
  116. package/src/decorators/common/remove-x-internal.ts +2 -2
  117. package/src/index.ts +2 -1
  118. package/src/lint.ts +26 -3
  119. package/src/oas-types.ts +31 -13
  120. package/src/rules/arazzo/index.ts +1 -1
  121. package/src/rules/async2/index.ts +5 -5
  122. package/src/rules/async3/__tests__/channels-kebab-case.test.ts +141 -0
  123. package/src/rules/async3/__tests__/no-channel-trailing-slash.test.ts +96 -0
  124. package/src/rules/async3/channels-kebab-case.ts +19 -0
  125. package/src/rules/async3/index.ts +23 -0
  126. package/src/rules/async3/no-channel-trailing-slash.ts +16 -0
  127. package/src/rules/common/assertions/index.ts +13 -4
  128. package/src/rules/common/spec.ts +2 -2
  129. package/src/rules/oas2/index.ts +4 -4
  130. package/src/rules/oas3/index.ts +39 -37
  131. package/src/types/{asyncapi.ts → asyncapi2.ts} +37 -34
  132. package/src/types/asyncapi3.ts +381 -0
  133. package/src/types/oas3_1.ts +2 -1
  134. package/src/types/redocly-yaml.ts +14 -0
  135. package/src/typings/asyncapi3.ts +61 -0
  136. package/src/utils.ts +5 -3
  137. package/src/visitors.ts +18 -0
  138. package/tsconfig.tsbuildinfo +1 -1
  139. package/lib/types/asyncapi.d.ts +0 -2
@@ -274,3 +274,145 @@ describe('bundleFromString', () => {
274
274
  expect(rest.source.body).toEqual(stringDocument);
275
275
  });
276
276
  });
277
+
278
+ describe('bundle async', () => {
279
+ it('should bundle async of version 2.x', async () => {
280
+ const testDocument = parseYamlToDocument(
281
+ outdent`
282
+ asyncapi: '2.6.0'
283
+ info:
284
+ title: Account Service
285
+ version: 1.0.0
286
+ description: This service is in charge of processing user signups
287
+ channels:
288
+ user/signedup:
289
+ subscribe:
290
+ message:
291
+ $ref: '#/components/messages/UserSignedUp'
292
+ components:
293
+ schemas:
294
+ UserSignedUp:
295
+ type: object
296
+ properties:
297
+ displayName:
298
+ type: string
299
+ description: Name of the user
300
+ messages:
301
+ UserSignedUp:
302
+ payload:
303
+ $ref: '#/components/schemas/UserSignedUp'
304
+ `,
305
+ ''
306
+ );
307
+
308
+ const config = await makeConfig({});
309
+
310
+ const {
311
+ bundle: { parsed },
312
+ problems,
313
+ } = await bundleDocument({
314
+ document: testDocument,
315
+ config: config,
316
+ externalRefResolver: new BaseResolver(),
317
+ dereference: true,
318
+ });
319
+
320
+ expect(problems).toHaveLength(0);
321
+ expect(parsed).toMatchInlineSnapshot(`
322
+ asyncapi: 2.6.0
323
+ info:
324
+ title: Account Service
325
+ version: 1.0.0
326
+ description: This service is in charge of processing user signups
327
+ channels:
328
+ user/signedup:
329
+ subscribe:
330
+ message:
331
+ payload: &ref_1
332
+ type: object
333
+ properties: &ref_0
334
+ displayName:
335
+ type: string
336
+ description: Name of the user
337
+ components:
338
+ schemas:
339
+ UserSignedUp:
340
+ type: object
341
+ properties: *ref_0
342
+ messages:
343
+ UserSignedUp:
344
+ payload: *ref_1
345
+
346
+ `);
347
+ });
348
+
349
+ it('should bundle async of version 3.0', async () => {
350
+ const testDocument = parseYamlToDocument(
351
+ outdent`
352
+ asyncapi: 3.0.0
353
+ info:
354
+ title: Account Service
355
+ version: 1.0.0
356
+ description: This service is in charge of processing user signups
357
+ operations:
358
+ sendUserSignedup:
359
+ action: send
360
+ messages:
361
+ - $ref: '#/components/messages/UserSignedUp'
362
+ components:
363
+ schemas:
364
+ UserSignedUp:
365
+ type: object
366
+ properties:
367
+ displayName:
368
+ type: string
369
+ description: Name of the user
370
+ messages:
371
+ UserSignedUp:
372
+ payload:
373
+ $ref: '#/components/schemas/UserSignedUp'
374
+ `,
375
+ ''
376
+ );
377
+
378
+ const config = await makeConfig({});
379
+
380
+ const {
381
+ bundle: { parsed },
382
+ problems,
383
+ } = await bundleDocument({
384
+ document: testDocument,
385
+ config: config,
386
+ externalRefResolver: new BaseResolver(),
387
+ dereference: true,
388
+ });
389
+
390
+ expect(problems).toHaveLength(0);
391
+ expect(parsed).toMatchInlineSnapshot(`
392
+ asyncapi: 3.0.0
393
+ info:
394
+ title: Account Service
395
+ version: 1.0.0
396
+ description: This service is in charge of processing user signups
397
+ operations:
398
+ sendUserSignedup:
399
+ action: send
400
+ messages:
401
+ - payload: &ref_1
402
+ type: object
403
+ properties: &ref_0
404
+ displayName:
405
+ type: string
406
+ description: Name of the user
407
+ components:
408
+ schemas:
409
+ UserSignedUp:
410
+ type: object
411
+ properties: *ref_0
412
+ messages:
413
+ UserSignedUp:
414
+ payload: *ref_1
415
+
416
+ `);
417
+ });
418
+ });
package/src/bundle.ts CHANGED
@@ -18,14 +18,13 @@ import { RemoveUnusedComponents as RemoveUnusedComponentsOas2 } from './decorato
18
18
  import { RemoveUnusedComponents as RemoveUnusedComponentsOas3 } from './decorators/oas3/remove-unused-components';
19
19
  import { ConfigTypes } from './types/redocly-yaml';
20
20
 
21
- import type { Oas3Rule, Oas3Visitor, Oas2Visitor } from './visitors';
21
+ import type { Oas3Visitor, Oas2Visitor } from './visitors';
22
22
  import type { NormalizedNodeType, NodeType } from './types';
23
23
  import type { WalkContext, UserContext, ResolveResult, NormalizedProblem } from './walk';
24
24
  import type { Config, StyleguideConfig } from './config';
25
25
  import type { OasRef } from './typings/openapi';
26
26
  import type { Document, ResolvedRefMap } from './resolve';
27
-
28
- export type Oas3RuleSet = Record<string, Oas3Rule>;
27
+ import type { CollectFn } from './utils';
29
28
 
30
29
  export enum OasVersion {
31
30
  Version2 = 'oas2',
@@ -84,6 +83,7 @@ export async function bundle(
84
83
  opts: {
85
84
  ref?: string;
86
85
  doc?: Document;
86
+ collectSpecData?: CollectFn;
87
87
  } & BundleOptions
88
88
  ) {
89
89
  const {
@@ -102,6 +102,7 @@ export async function bundle(
102
102
  if (document instanceof Error) {
103
103
  throw document;
104
104
  }
105
+ opts.collectSpecData?.(document.parsed);
105
106
 
106
107
  return bundleDocument({
107
108
  document,
@@ -292,6 +293,15 @@ export function mapTypeToComponent(typeName: string, version: SpecMajorVersion)
292
293
  default:
293
294
  return null;
294
295
  }
296
+ case SpecMajorVersion.Async3:
297
+ switch (typeName) {
298
+ case 'Schema':
299
+ return 'schemas';
300
+ case 'Parameter':
301
+ return 'parameters';
302
+ default:
303
+ return null;
304
+ }
295
305
  case SpecMajorVersion.Arazzo:
296
306
  switch (typeName) {
297
307
  case 'Root.x-parameters_items':
@@ -377,6 +387,8 @@ function makeBundleVisitor(
377
387
  components = root;
378
388
  } else if (version === SpecMajorVersion.Async2) {
379
389
  components = root.components = root.components || {};
390
+ } else if (version === SpecMajorVersion.Async3) {
391
+ components = root.components = root.components || {};
380
392
  } else if (version === SpecMajorVersion.Arazzo) {
381
393
  components = root.components = root.components || {};
382
394
  }
@@ -427,6 +439,8 @@ function makeBundleVisitor(
427
439
  components[componentType][name] = target.node;
428
440
  if (version === SpecMajorVersion.OAS3) {
429
441
  return `#/components/${componentType}/${name}`;
442
+ } else if (version === SpecMajorVersion.Async2 || version === SpecMajorVersion.Async3) {
443
+ return `#/components/${componentType}/${name}`;
430
444
  } else {
431
445
  return `#/${componentType}/${name}`;
432
446
  }
@@ -18,6 +18,17 @@ exports[`resolveConfig should ignore minimal from the root and read local file 1
18
18
  "tag-description": "warn",
19
19
  "tags-alphabetical": "off",
20
20
  },
21
+ "async3Decorators": {},
22
+ "async3Preprocessors": {},
23
+ "async3Rules": {
24
+ "channels-kebab-case": "off",
25
+ "info-contact": "off",
26
+ "no-channel-trailing-slash": "off",
27
+ "operation-operationId": "warn",
28
+ "spec": "error",
29
+ "tag-description": "warn",
30
+ "tags-alphabetical": "off",
31
+ },
21
32
  "decorators": {},
22
33
  "doNotResolveExamples": undefined,
23
34
  "oas2Decorators": {},
@@ -135,6 +146,17 @@ exports[`resolveStyleguideConfig should resolve extends with local file config w
135
146
  "tag-description": "warn",
136
147
  "tags-alphabetical": "off",
137
148
  },
149
+ "async3Decorators": {},
150
+ "async3Preprocessors": {},
151
+ "async3Rules": {
152
+ "channels-kebab-case": "off",
153
+ "info-contact": "off",
154
+ "no-channel-trailing-slash": "off",
155
+ "operation-operationId": "warn",
156
+ "spec": "error",
157
+ "tag-description": "warn",
158
+ "tags-alphabetical": "off",
159
+ },
138
160
  "decorators": {},
139
161
  "doNotResolveExamples": undefined,
140
162
  "oas2Decorators": {},
@@ -12,6 +12,11 @@ StyleguideConfig {
12
12
  "oas3_0": {},
13
13
  "oas3_1": {},
14
14
  },
15
+ "async3": {
16
+ "oas2": {},
17
+ "oas3_0": {},
18
+ "oas3_1": {},
19
+ },
15
20
  "oas2": {
16
21
  "oas2": {},
17
22
  "oas3_0": {},
@@ -51,6 +56,11 @@ StyleguideConfig {
51
56
  "oas3_0": {},
52
57
  "oas3_1": {},
53
58
  },
59
+ "async3": {
60
+ "oas2": {},
61
+ "oas3_0": {},
62
+ "oas3_1": {},
63
+ },
54
64
  "oas2": {
55
65
  "oas2": {},
56
66
  "oas3_0": {},
@@ -124,6 +134,20 @@ StyleguideConfig {
124
134
  "operation-summary": "error",
125
135
  },
126
136
  },
137
+ "async3": {
138
+ "oas2": {
139
+ "no-empty-servers": "error",
140
+ "operation-summary": "error",
141
+ },
142
+ "oas3_0": {
143
+ "no-empty-servers": "error",
144
+ "operation-summary": "error",
145
+ },
146
+ "oas3_1": {
147
+ "no-empty-servers": "error",
148
+ "operation-summary": "error",
149
+ },
150
+ },
127
151
  "oas2": {
128
152
  "oas2": {
129
153
  "no-empty-servers": "error",
@@ -119,6 +119,7 @@ describe('getMergedConfig', () => {
119
119
  "decorators": {
120
120
  "arazzo": {},
121
121
  "async2": {},
122
+ "async3": {},
122
123
  "oas2": {},
123
124
  "oas3_0": {},
124
125
  "oas3_1": {},
@@ -131,6 +132,7 @@ describe('getMergedConfig', () => {
131
132
  "preprocessors": {
132
133
  "arazzo": {},
133
134
  "async2": {},
135
+ "async3": {},
134
136
  "oas2": {},
135
137
  "oas3_0": {},
136
138
  "oas3_1": {},
@@ -148,6 +150,9 @@ describe('getMergedConfig', () => {
148
150
  "async2": {
149
151
  "operation-summary": "warn",
150
152
  },
153
+ "async3": {
154
+ "operation-summary": "warn",
155
+ },
151
156
  "oas2": {
152
157
  "operation-summary": "warn",
153
158
  },
@@ -227,6 +232,7 @@ describe('getMergedConfig', () => {
227
232
  "decorators": {
228
233
  "arazzo": {},
229
234
  "async2": {},
235
+ "async3": {},
230
236
  "oas2": {},
231
237
  "oas3_0": {},
232
238
  "oas3_1": {},
@@ -239,6 +245,7 @@ describe('getMergedConfig', () => {
239
245
  "preprocessors": {
240
246
  "arazzo": {},
241
247
  "async2": {},
248
+ "async3": {},
242
249
  "oas2": {},
243
250
  "oas3_0": {},
244
251
  "oas3_1": {},
@@ -259,6 +266,10 @@ describe('getMergedConfig', () => {
259
266
  "no-empty-servers": "error",
260
267
  "operation-summary": "error",
261
268
  },
269
+ "async3": {
270
+ "no-empty-servers": "error",
271
+ "operation-summary": "error",
272
+ },
262
273
  "oas2": {
263
274
  "no-empty-servers": "error",
264
275
  "operation-summary": "error",
package/src/config/all.ts CHANGED
@@ -114,6 +114,15 @@ const all: PluginStyleguideConfig<'built-in'> = {
114
114
  'channels-kebab-case': 'error',
115
115
  'no-channel-trailing-slash': 'error',
116
116
  },
117
+ async3Rules: {
118
+ spec: 'error',
119
+ 'info-contact': 'error',
120
+ 'operation-operationId': 'error',
121
+ 'tag-description': 'error',
122
+ 'tags-alphabetical': 'error',
123
+ 'channels-kebab-case': 'error',
124
+ 'no-channel-trailing-slash': 'error',
125
+ },
117
126
  arazzoRules: { spec: 'error' },
118
127
  };
119
128
 
@@ -5,14 +5,17 @@ import minimal from './minimal';
5
5
  import { rules as oas3Rules } from '../rules/oas3';
6
6
  import { rules as oas2Rules } from '../rules/oas2';
7
7
  import { rules as async2Rules } from '../rules/async2';
8
+ import { rules as async3Rules } from '../rules/async3';
8
9
  import { rules as arazzoRules } from '../rules/arazzo';
9
10
  import { preprocessors as oas3Preprocessors } from '../rules/oas3';
10
11
  import { preprocessors as oas2Preprocessors } from '../rules/oas2';
11
12
  import { preprocessors as async2Preprocessors } from '../rules/async2';
13
+ import { preprocessors as async3Preprocessors } from '../rules/async3';
12
14
  import { preprocessors as arazzoPreprocessors } from '../rules/arazzo';
13
15
  import { decorators as oas3Decorators } from '../decorators/oas3';
14
16
  import { decorators as oas2Decorators } from '../decorators/oas2';
15
17
  import { decorators as async2Decorators } from '../decorators/async2';
18
+ import { decorators as async3Decorators } from '../decorators/async3';
16
19
  import { decorators as arazzoDecorators } from '../decorators/arazzo';
17
20
 
18
21
  import type { CustomRulesConfig, StyleguideRawConfig, Plugin } from './types';
@@ -33,18 +36,21 @@ export const defaultPlugin: Plugin = {
33
36
  oas3: oas3Rules,
34
37
  oas2: oas2Rules,
35
38
  async2: async2Rules,
39
+ async3: async3Rules,
36
40
  arazzo: arazzoRules,
37
41
  } as CustomRulesConfig,
38
42
  preprocessors: {
39
43
  oas3: oas3Preprocessors,
40
44
  oas2: oas2Preprocessors,
41
45
  async2: async2Preprocessors,
46
+ async3: async3Preprocessors,
42
47
  arazzo: arazzoPreprocessors,
43
48
  },
44
49
  decorators: {
45
50
  oas3: oas3Decorators,
46
51
  oas2: oas2Decorators,
47
52
  async2: async2Decorators,
53
+ async3: async3Decorators,
48
54
  arazzo: arazzoDecorators,
49
55
  },
50
56
  configs: builtInConfigs,
@@ -181,7 +181,7 @@ export function resolvePlugins(
181
181
  if (pluginModule.rules) {
182
182
  if (!pluginModule.rules.oas3 && !pluginModule.rules.oas2 && !pluginModule.rules.async2) {
183
183
  throw new Error(
184
- `Plugin rules must have \`oas3\`, \`oas2\`, \`async2\`, or \`arazzo\` rules "${p}.`
184
+ `Plugin rules must have \`oas3\`, \`oas2\`, \`async2\`, \`async3\` or \`arazzo\` rules "${p}.`
185
185
  );
186
186
  }
187
187
  plugin.rules = {};
@@ -194,6 +194,9 @@ export function resolvePlugins(
194
194
  if (pluginModule.rules.async2) {
195
195
  plugin.rules.async2 = prefixRules(pluginModule.rules.async2, id);
196
196
  }
197
+ if (pluginModule.rules.async3) {
198
+ plugin.rules.async3 = prefixRules(pluginModule.rules.async3, id);
199
+ }
197
200
  if (pluginModule.rules.arazzo) {
198
201
  plugin.rules.arazzo = prefixRules(pluginModule.rules.arazzo, id);
199
202
  }
@@ -203,6 +206,7 @@ export function resolvePlugins(
203
206
  !pluginModule.preprocessors.oas3 &&
204
207
  !pluginModule.preprocessors.oas2 &&
205
208
  !pluginModule.preprocessors.async2 &&
209
+ !pluginModule.preprocessors.async3 &&
206
210
  !pluginModule.preprocessors.arazzo
207
211
  ) {
208
212
  throw new Error(
@@ -219,6 +223,9 @@ export function resolvePlugins(
219
223
  if (pluginModule.preprocessors.async2) {
220
224
  plugin.preprocessors.async2 = prefixRules(pluginModule.preprocessors.async2, id);
221
225
  }
226
+ if (pluginModule.preprocessors.async3) {
227
+ plugin.preprocessors.async3 = prefixRules(pluginModule.preprocessors.async3, id);
228
+ }
222
229
  if (pluginModule.preprocessors.arazzo) {
223
230
  plugin.preprocessors.arazzo = prefixRules(pluginModule.preprocessors.arazzo, id);
224
231
  }
@@ -229,10 +236,11 @@ export function resolvePlugins(
229
236
  !pluginModule.decorators.oas3 &&
230
237
  !pluginModule.decorators.oas2 &&
231
238
  !pluginModule.decorators.async2 &&
239
+ !pluginModule.decorators.async3 &&
232
240
  !pluginModule.decorators.arazzo
233
241
  ) {
234
242
  throw new Error(
235
- `Plugin \`decorators\` must have \`oas3\`, \`oas2\` or \`async2\` decorators "${p}.`
243
+ `Plugin \`decorators\` must have \`oas3\`, \`oas2\`, \`async2\` or \`async3\` decorators "${p}.`
236
244
  );
237
245
  }
238
246
  plugin.decorators = {};
@@ -245,6 +253,9 @@ export function resolvePlugins(
245
253
  if (pluginModule.decorators.async2) {
246
254
  plugin.decorators.async2 = prefixRules(pluginModule.decorators.async2, id);
247
255
  }
256
+ if (pluginModule.decorators.async3) {
257
+ plugin.decorators.async3 = prefixRules(pluginModule.decorators.async3, id);
258
+ }
248
259
  if (pluginModule.decorators.arazzo) {
249
260
  plugin.decorators.arazzo = prefixRules(pluginModule.decorators.arazzo, id);
250
261
  }
@@ -432,6 +443,8 @@ function getMergedRawStyleguideConfig(
432
443
  oas2Rules: { ...rootStyleguideConfig?.oas2Rules, ...apiStyleguideConfig?.oas2Rules },
433
444
  oas3_0Rules: { ...rootStyleguideConfig?.oas3_0Rules, ...apiStyleguideConfig?.oas3_0Rules },
434
445
  oas3_1Rules: { ...rootStyleguideConfig?.oas3_1Rules, ...apiStyleguideConfig?.oas3_1Rules },
446
+ async2Rules: { ...rootStyleguideConfig?.async2Rules, ...apiStyleguideConfig?.async2Rules },
447
+ async3Rules: { ...rootStyleguideConfig?.async3Rules, ...apiStyleguideConfig?.async3Rules },
435
448
  arazzoRules: { ...rootStyleguideConfig?.arazzoRules, ...apiStyleguideConfig?.arazzoRules },
436
449
  preprocessors: {
437
450
  ...rootStyleguideConfig?.preprocessors,
@@ -9,6 +9,7 @@ import {
9
9
  Oas2RuleSet,
10
10
  Oas3RuleSet,
11
11
  Async2RuleSet,
12
+ Async3RuleSet,
12
13
  ArazzoRuleSet,
13
14
  } from '../oas-types';
14
15
  import { isBrowser } from '../env';
@@ -72,6 +73,7 @@ export class StyleguideConfig {
72
73
  [SpecVersion.OAS3_0]: { ...rawConfig.rules, ...rawConfig.oas3_0Rules },
73
74
  [SpecVersion.OAS3_1]: { ...rawConfig.rules, ...rawConfig.oas3_1Rules },
74
75
  [SpecVersion.Async2]: { ...rawConfig.rules, ...rawConfig.async2Rules },
76
+ [SpecVersion.Async3]: { ...rawConfig.rules, ...rawConfig.async3Rules },
75
77
  [SpecVersion.Arazzo]: { ...rawConfig.arazzoRules },
76
78
  };
77
79
 
@@ -80,6 +82,7 @@ export class StyleguideConfig {
80
82
  [SpecVersion.OAS3_0]: { ...rawConfig.preprocessors, ...rawConfig.oas3_0Preprocessors },
81
83
  [SpecVersion.OAS3_1]: { ...rawConfig.preprocessors, ...rawConfig.oas3_1Preprocessors },
82
84
  [SpecVersion.Async2]: { ...rawConfig.preprocessors, ...rawConfig.async2Preprocessors },
85
+ [SpecVersion.Async3]: { ...rawConfig.preprocessors, ...rawConfig.async3Preprocessors },
83
86
  [SpecVersion.Arazzo]: { ...rawConfig.arazzoPreprocessors },
84
87
  };
85
88
 
@@ -88,6 +91,7 @@ export class StyleguideConfig {
88
91
  [SpecVersion.OAS3_0]: { ...rawConfig.decorators, ...rawConfig.oas3_0Decorators },
89
92
  [SpecVersion.OAS3_1]: { ...rawConfig.decorators, ...rawConfig.oas3_1Decorators },
90
93
  [SpecVersion.Async2]: { ...rawConfig.decorators, ...rawConfig.async2Decorators },
94
+ [SpecVersion.Async3]: { ...rawConfig.decorators, ...rawConfig.async3Decorators },
91
95
  [SpecVersion.Arazzo]: { ...rawConfig.arazzoDecorators },
92
96
  };
93
97
 
@@ -182,6 +186,10 @@ export class StyleguideConfig {
182
186
  if (!plugin.typeExtension.async2) continue;
183
187
  extendedTypes = plugin.typeExtension.async2(extendedTypes, version);
184
188
  break;
189
+ case SpecVersion.Async3:
190
+ if (!plugin.typeExtension.async3) continue;
191
+ extendedTypes = plugin.typeExtension.async3(extendedTypes, version);
192
+ break;
185
193
  case SpecVersion.Arazzo:
186
194
  if (!plugin.typeExtension.arazzo) continue;
187
195
  extendedTypes = plugin.typeExtension.arazzo(extendedTypes, version);
@@ -276,15 +284,26 @@ export class StyleguideConfig {
276
284
  return oas2Rules;
277
285
  case SpecMajorVersion.Async2:
278
286
  // eslint-disable-next-line no-case-declarations
279
- const asyncApiRules: Async2RuleSet[] = []; // default ruleset
287
+ const asyncApi2Rules: Async2RuleSet[] = []; // default ruleset
288
+ this.plugins.forEach(
289
+ (p) => p.preprocessors?.async2 && asyncApi2Rules.push(p.preprocessors.async2)
290
+ );
291
+ this.plugins.forEach((p) => p.rules?.async2 && asyncApi2Rules.push(p.rules.async2));
292
+ this.plugins.forEach(
293
+ (p) => p.decorators?.async2 && asyncApi2Rules.push(p.decorators.async2)
294
+ );
295
+ return asyncApi2Rules;
296
+ case SpecMajorVersion.Async3:
297
+ // eslint-disable-next-line no-case-declarations
298
+ const asyncApi3Rules: Async3RuleSet[] = []; // default ruleset
280
299
  this.plugins.forEach(
281
- (p) => p.preprocessors?.async2 && asyncApiRules.push(p.preprocessors.async2)
300
+ (p) => p.preprocessors?.async3 && asyncApi3Rules.push(p.preprocessors.async3)
282
301
  );
283
- this.plugins.forEach((p) => p.rules?.async2 && asyncApiRules.push(p.rules.async2));
302
+ this.plugins.forEach((p) => p.rules?.async3 && asyncApi3Rules.push(p.rules.async3));
284
303
  this.plugins.forEach(
285
- (p) => p.decorators?.async2 && asyncApiRules.push(p.decorators.async2)
304
+ (p) => p.decorators?.async3 && asyncApi3Rules.push(p.decorators.async3)
286
305
  );
287
- return asyncApiRules;
306
+ return asyncApi3Rules;
288
307
  case SpecMajorVersion.Arazzo:
289
308
  // eslint-disable-next-line no-case-declarations
290
309
  const arazzoRules: ArazzoRuleSet[] = []; // default ruleset
@@ -96,6 +96,15 @@ const minimal: PluginStyleguideConfig<'built-in'> = {
96
96
  'channels-kebab-case': 'off',
97
97
  'no-channel-trailing-slash': 'off',
98
98
  },
99
+ async3Rules: {
100
+ spec: 'error',
101
+ 'info-contact': 'off',
102
+ 'operation-operationId': 'warn',
103
+ 'tag-description': 'warn',
104
+ 'tags-alphabetical': 'off',
105
+ 'channels-kebab-case': 'off',
106
+ 'no-channel-trailing-slash': 'off',
107
+ },
99
108
  arazzoRules: {
100
109
  spec: 'error',
101
110
  },
@@ -96,6 +96,15 @@ const recommendedStrict: PluginStyleguideConfig<'built-in'> = {
96
96
  'channels-kebab-case': 'off',
97
97
  'no-channel-trailing-slash': 'off',
98
98
  },
99
+ async3Rules: {
100
+ spec: 'error',
101
+ 'info-contact': 'off',
102
+ 'operation-operationId': 'error',
103
+ 'tag-description': 'error',
104
+ 'tags-alphabetical': 'off',
105
+ 'channels-kebab-case': 'off',
106
+ 'no-channel-trailing-slash': 'off',
107
+ },
99
108
  arazzoRules: {
100
109
  spec: 'error',
101
110
  },
@@ -96,6 +96,15 @@ const recommended: PluginStyleguideConfig<'built-in'> = {
96
96
  'channels-kebab-case': 'off',
97
97
  'no-channel-trailing-slash': 'off',
98
98
  },
99
+ async3Rules: {
100
+ spec: 'error',
101
+ 'info-contact': 'off',
102
+ 'operation-operationId': 'warn',
103
+ 'tag-description': 'warn',
104
+ 'tags-alphabetical': 'off',
105
+ 'channels-kebab-case': 'off',
106
+ 'no-channel-trailing-slash': 'off',
107
+ },
99
108
  arazzoRules: {
100
109
  spec: 'error',
101
110
  },
@@ -1,6 +1,14 @@
1
- import { RuleSet, SpecVersion } from '../oas-types';
2
- import { StyleguideConfig } from './config';
3
1
  import { isDefined } from '../utils';
2
+
3
+ import type {
4
+ ArazzoRuleSet,
5
+ Async2RuleSet,
6
+ Async3RuleSet,
7
+ Oas2RuleSet,
8
+ Oas3RuleSet,
9
+ SpecVersion,
10
+ } from '../oas-types';
11
+ import type { StyleguideConfig } from './config';
4
12
  import type { ProblemSeverity } from '../walk';
5
13
 
6
14
  type InitializedRule = {
@@ -9,8 +17,8 @@ type InitializedRule = {
9
17
  visitor: any;
10
18
  };
11
19
 
12
- export function initRules<T extends Function, P extends RuleSet<T>>(
13
- rules: P[],
20
+ export function initRules(
21
+ rules: (Oas3RuleSet | Oas2RuleSet | Async2RuleSet | Async3RuleSet | ArazzoRuleSet)[],
14
22
  config: StyleguideConfig,
15
23
  type: 'rules' | 'preprocessors' | 'decorators',
16
24
  oasVersion: SpecVersion