@redocly/openapi-core 1.18.0 → 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.
- package/CHANGELOG.md +20 -0
- package/lib/benchmark/benches/lint-with-many-rules.bench.js +2 -2
- package/lib/benchmark/benches/lint-with-nested-rule.bench.js +2 -2
- package/lib/benchmark/benches/lint-with-no-rules.bench.js +2 -2
- package/lib/benchmark/benches/lint-with-top-level-rule-report.bench.js +2 -2
- package/lib/benchmark/benches/lint-with-top-level-rule.bench.js +2 -2
- package/lib/benchmark/benches/recommended-oas3.bench.js +2 -2
- package/lib/benchmark/benches/resolve-with-no-external.bench.js +2 -2
- package/lib/benchmark/utils.js +7 -4
- package/lib/bundle.d.ts +3 -3
- package/lib/bundle.js +128 -122
- package/lib/config/all.js +9 -0
- package/lib/config/builtIn.js +7 -1
- package/lib/config/config-resolvers.js +179 -138
- package/lib/config/config.d.ts +2 -2
- package/lib/config/config.js +53 -34
- package/lib/config/load.d.ts +1 -2
- package/lib/config/load.js +105 -117
- package/lib/config/minimal.js +9 -0
- package/lib/config/recommended-strict.js +9 -0
- package/lib/config/recommended.js +9 -0
- package/lib/config/rules.d.ts +3 -3
- package/lib/config/rules.js +1 -2
- package/lib/config/types.d.ts +9 -3
- package/lib/config/utils.js +70 -49
- package/lib/decorators/async3/index.d.ts +1 -0
- package/lib/decorators/async3/index.js +4 -0
- package/lib/decorators/common/filters/filter-helper.js +2 -3
- package/lib/decorators/common/filters/filter-in.js +1 -1
- package/lib/decorators/common/filters/filter-out.js +1 -1
- package/lib/decorators/common/info-override.js +1 -12
- package/lib/decorators/common/media-type-examples-override.js +8 -2
- package/lib/decorators/common/remove-x-internal.js +4 -5
- package/lib/decorators/oas2/remove-unused-components.js +1 -2
- package/lib/decorators/oas3/remove-unused-components.js +1 -2
- package/lib/env.d.ts +0 -1
- package/lib/env.js +1 -1
- package/lib/format/codeframes.js +10 -8
- package/lib/format/format.js +23 -15
- package/lib/index.d.ts +2 -1
- package/lib/index.js +6 -4
- package/lib/js-yaml/index.js +1 -1
- package/lib/lint.d.ts +2 -0
- package/lib/lint.js +92 -99
- package/lib/oas-types.d.ts +9 -5
- package/lib/oas-types.js +22 -12
- package/lib/redocly/domains.js +6 -6
- package/lib/redocly/index.js +60 -73
- package/lib/redocly/registry-api.js +64 -82
- package/lib/ref-utils.js +13 -13
- package/lib/resolve.js +186 -205
- package/lib/rules/ajv.js +10 -8
- package/lib/rules/async3/channels-kebab-case.d.ts +2 -0
- package/lib/rules/async3/channels-kebab-case.js +19 -0
- package/lib/rules/async3/index.d.ts +3 -0
- package/lib/rules/async3/index.js +22 -0
- package/lib/rules/async3/no-channel-trailing-slash.d.ts +2 -0
- package/lib/rules/async3/no-channel-trailing-slash.js +16 -0
- package/lib/rules/common/assertions/asserts.js +5 -5
- package/lib/rules/common/assertions/index.d.ts +5 -4
- package/lib/rules/common/assertions/utils.js +43 -28
- package/lib/rules/common/no-invalid-parameter-examples.js +1 -2
- package/lib/rules/common/no-invalid-schema-examples.js +1 -2
- package/lib/rules/common/no-required-schema-properties-undefined.js +1 -2
- package/lib/rules/common/operation-tag-defined.js +1 -2
- package/lib/rules/common/path-http-verbs-order.js +1 -1
- package/lib/rules/common/path-segment-plural.js +2 -1
- package/lib/rules/common/required-string-property-missing-min-length.js +2 -2
- package/lib/rules/common/response-contains-header.js +2 -2
- package/lib/rules/common/security-defined.js +3 -7
- package/lib/rules/common/spec.d.ts +2 -2
- package/lib/rules/common/spec.js +6 -7
- package/lib/rules/no-unresolved-refs.js +3 -4
- package/lib/rules/oas2/response-contains-property.js +1 -2
- package/lib/rules/oas3/array-parameter-serialization.js +1 -2
- package/lib/rules/oas3/component-name-unique.js +2 -4
- package/lib/rules/oas3/no-invalid-media-type-examples.js +1 -2
- package/lib/rules/oas3/no-server-variables-empty-enum.js +1 -2
- package/lib/rules/oas3/no-undefined-server-variable.js +2 -3
- package/lib/rules/oas3/no-unused-components.js +1 -2
- package/lib/rules/oas3/response-contains-property.js +1 -2
- package/lib/rules/utils.js +14 -12
- package/lib/types/arazzo.d.ts +1299 -73
- package/lib/types/arazzo.js +41 -36
- package/lib/types/asyncapi2.d.ts +17 -0
- package/lib/types/{asyncapi.js → asyncapi2.js} +71 -93
- package/lib/types/asyncapi3.d.ts +2 -0
- package/lib/types/asyncapi3.js +347 -0
- package/lib/types/index.js +19 -10
- package/lib/types/json-schema-adapter.js +4 -18
- package/lib/types/oas2.js +6 -6
- package/lib/types/oas3.js +10 -10
- package/lib/types/oas3_1.js +15 -9
- package/lib/types/redocly-yaml.d.ts +3 -1
- package/lib/types/redocly-yaml.js +131 -35
- package/lib/typings/arazzo.d.ts +28 -1
- package/lib/typings/asyncapi3.d.ts +53 -0
- package/lib/typings/asyncapi3.js +2 -0
- package/lib/utils.d.ts +12 -7
- package/lib/utils.js +91 -77
- package/lib/visitors.d.ts +11 -0
- package/lib/visitors.js +21 -8
- package/lib/walk.js +30 -23
- package/package.json +3 -3
- package/src/__tests__/bundle.test.ts +142 -0
- package/src/__tests__/lint.test.ts +0 -50
- package/src/bundle.ts +19 -6
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +22 -0
- package/src/config/__tests__/__snapshots__/config.test.ts.snap +24 -0
- package/src/config/__tests__/config.test.ts +11 -0
- package/src/config/all.ts +9 -0
- package/src/config/builtIn.ts +6 -0
- package/src/config/config-resolvers.ts +15 -2
- package/src/config/config.ts +24 -5
- package/src/config/load.ts +1 -2
- package/src/config/minimal.ts +9 -0
- package/src/config/recommended-strict.ts +9 -0
- package/src/config/recommended.ts +9 -0
- package/src/config/rules.ts +12 -4
- package/src/config/types.ts +15 -2
- package/src/config/utils.ts +15 -0
- package/src/decorators/async3/index.ts +1 -0
- package/src/decorators/common/remove-x-internal.ts +2 -2
- package/src/index.ts +2 -1
- package/src/lint.ts +26 -3
- package/src/oas-types.ts +31 -13
- package/src/rules/arazzo/index.ts +1 -1
- package/src/rules/async2/index.ts +5 -5
- package/src/rules/async3/__tests__/channels-kebab-case.test.ts +141 -0
- package/src/rules/async3/__tests__/no-channel-trailing-slash.test.ts +96 -0
- package/src/rules/async3/channels-kebab-case.ts +19 -0
- package/src/rules/async3/index.ts +23 -0
- package/src/rules/async3/no-channel-trailing-slash.ts +16 -0
- package/src/rules/common/__tests__/spec.test.ts +47 -0
- package/src/rules/common/assertions/index.ts +13 -4
- package/src/rules/common/no-invalid-schema-examples.ts +3 -2
- package/src/rules/common/path-segment-plural.ts +3 -2
- package/src/rules/common/spec.ts +2 -2
- package/src/rules/oas2/index.ts +4 -4
- package/src/rules/oas3/index.ts +39 -37
- package/src/types/arazzo.ts +28 -23
- package/src/types/{asyncapi.ts → asyncapi2.ts} +58 -76
- package/src/types/asyncapi3.ts +381 -0
- package/src/types/oas3_1.ts +3 -2
- package/src/types/redocly-yaml.ts +14 -0
- package/src/typings/arazzo.ts +41 -1
- package/src/typings/asyncapi3.ts +61 -0
- package/src/utils.ts +46 -11
- package/src/visitors.ts +18 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/types/asyncapi.d.ts +0 -2
|
@@ -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
|
},
|
package/src/config/rules.ts
CHANGED
|
@@ -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
|
|
13
|
-
rules:
|
|
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
|
package/src/config/types.ts
CHANGED
|
@@ -11,6 +11,9 @@ import type {
|
|
|
11
11
|
Async2PreprocessorsSet,
|
|
12
12
|
Async2DecoratorsSet,
|
|
13
13
|
Async2RuleSet,
|
|
14
|
+
Async3PreprocessorsSet,
|
|
15
|
+
Async3DecoratorsSet,
|
|
16
|
+
Async3RuleSet,
|
|
14
17
|
ArazzoRuleSet,
|
|
15
18
|
ArazzoPreprocessorsSet,
|
|
16
19
|
ArazzoDecoratorsSet,
|
|
@@ -22,6 +25,7 @@ import { Location } from '../ref-utils';
|
|
|
22
25
|
import type { SkipFunctionContext } from '../visitors';
|
|
23
26
|
import {
|
|
24
27
|
BuiltInAsync2RuleId,
|
|
28
|
+
BuiltInAsync3RuleId,
|
|
25
29
|
BuiltInCommonOASRuleId,
|
|
26
30
|
BuiltInOAS2RuleId,
|
|
27
31
|
BuiltInOAS3RuleId,
|
|
@@ -59,6 +63,7 @@ export type StyleguideRawConfig<T = undefined> = {
|
|
|
59
63
|
oas3_0Rules?: RuleMap<BuiltInOAS3RuleId, RuleConfig, T>;
|
|
60
64
|
oas3_1Rules?: RuleMap<BuiltInOAS3RuleId, RuleConfig, T>;
|
|
61
65
|
async2Rules?: RuleMap<BuiltInAsync2RuleId, RuleConfig, T>;
|
|
66
|
+
async3Rules?: RuleMap<BuiltInAsync3RuleId, RuleConfig, T>;
|
|
62
67
|
arazzoRules?: RuleMap<BuiltInArazzoRuleId, RuleConfig, T>;
|
|
63
68
|
|
|
64
69
|
preprocessors?: Record<string, PreprocessorConfig>;
|
|
@@ -66,6 +71,7 @@ export type StyleguideRawConfig<T = undefined> = {
|
|
|
66
71
|
oas3_0Preprocessors?: Record<string, PreprocessorConfig>;
|
|
67
72
|
oas3_1Preprocessors?: Record<string, PreprocessorConfig>;
|
|
68
73
|
async2Preprocessors?: Record<string, PreprocessorConfig>;
|
|
74
|
+
async3Preprocessors?: Record<string, PreprocessorConfig>;
|
|
69
75
|
arazzoPreprocessors?: Record<string, PreprocessorConfig>;
|
|
70
76
|
|
|
71
77
|
decorators?: Record<string, DecoratorConfig>;
|
|
@@ -73,6 +79,7 @@ export type StyleguideRawConfig<T = undefined> = {
|
|
|
73
79
|
oas3_0Decorators?: Record<string, DecoratorConfig>;
|
|
74
80
|
oas3_1Decorators?: Record<string, DecoratorConfig>;
|
|
75
81
|
async2Decorators?: Record<string, DecoratorConfig>;
|
|
82
|
+
async3Decorators?: Record<string, DecoratorConfig>;
|
|
76
83
|
arazzoDecorators?: Record<string, DecoratorConfig>;
|
|
77
84
|
};
|
|
78
85
|
|
|
@@ -90,6 +97,7 @@ export type PreprocessorsConfig = {
|
|
|
90
97
|
oas3?: Oas3PreprocessorsSet;
|
|
91
98
|
oas2?: Oas2PreprocessorsSet;
|
|
92
99
|
async2?: Async2PreprocessorsSet;
|
|
100
|
+
async3?: Async3PreprocessorsSet;
|
|
93
101
|
arazzo?: ArazzoPreprocessorsSet;
|
|
94
102
|
};
|
|
95
103
|
|
|
@@ -97,6 +105,7 @@ export type DecoratorsConfig = {
|
|
|
97
105
|
oas3?: Oas3DecoratorsSet;
|
|
98
106
|
oas2?: Oas2DecoratorsSet;
|
|
99
107
|
async2?: Async2DecoratorsSet;
|
|
108
|
+
async3?: Async3DecoratorsSet;
|
|
100
109
|
arazzo?: ArazzoDecoratorsSet;
|
|
101
110
|
};
|
|
102
111
|
|
|
@@ -111,6 +120,7 @@ export type CustomRulesConfig = {
|
|
|
111
120
|
oas3?: Oas3RuleSet;
|
|
112
121
|
oas2?: Oas2RuleSet;
|
|
113
122
|
async2?: Async2RuleSet;
|
|
123
|
+
async3?: Async3RuleSet;
|
|
114
124
|
arazzo?: ArazzoRuleSet;
|
|
115
125
|
};
|
|
116
126
|
|
|
@@ -243,16 +253,19 @@ export type RulesFields =
|
|
|
243
253
|
| 'oas3_0Rules'
|
|
244
254
|
| 'oas3_1Rules'
|
|
245
255
|
| 'async2Rules'
|
|
256
|
+
| 'async3Rules'
|
|
246
257
|
| 'arazzoRules'
|
|
247
258
|
| 'preprocessors'
|
|
248
259
|
| 'oas2Preprocessors'
|
|
249
260
|
| 'oas3_0Preprocessors'
|
|
250
261
|
| 'oas3_1Preprocessors'
|
|
251
262
|
| 'async2Preprocessors'
|
|
263
|
+
| 'async3Preprocessors'
|
|
252
264
|
| 'arazzoPreprocessors'
|
|
253
265
|
| 'decorators'
|
|
254
266
|
| 'oas2Decorators'
|
|
255
267
|
| 'oas3_0Decorators'
|
|
256
268
|
| 'oas3_1Decorators'
|
|
257
|
-
| '
|
|
258
|
-
| '
|
|
269
|
+
| 'async2Decorators'
|
|
270
|
+
| 'async3Decorators'
|
|
271
|
+
| 'arazzoDecorators';
|
package/src/config/utils.ts
CHANGED
|
@@ -56,6 +56,7 @@ function extractFlatConfig<
|
|
|
56
56
|
oas3_0Rules,
|
|
57
57
|
oas3_1Rules,
|
|
58
58
|
async2Rules,
|
|
59
|
+
async3Rules,
|
|
59
60
|
arazzoRules,
|
|
60
61
|
|
|
61
62
|
preprocessors,
|
|
@@ -63,6 +64,7 @@ function extractFlatConfig<
|
|
|
63
64
|
oas3_0Preprocessors,
|
|
64
65
|
oas3_1Preprocessors,
|
|
65
66
|
async2Preprocessors,
|
|
67
|
+
async3Preprocessors,
|
|
66
68
|
arazzoPreprocessors,
|
|
67
69
|
|
|
68
70
|
decorators,
|
|
@@ -70,6 +72,7 @@ function extractFlatConfig<
|
|
|
70
72
|
oas3_0Decorators,
|
|
71
73
|
oas3_1Decorators,
|
|
72
74
|
async2Decorators,
|
|
75
|
+
async3Decorators,
|
|
73
76
|
arazzoDecorators,
|
|
74
77
|
|
|
75
78
|
...rawConfigRest
|
|
@@ -86,6 +89,7 @@ function extractFlatConfig<
|
|
|
86
89
|
oas3_0Rules,
|
|
87
90
|
oas3_1Rules,
|
|
88
91
|
async2Rules,
|
|
92
|
+
async3Rules,
|
|
89
93
|
arazzoRules,
|
|
90
94
|
|
|
91
95
|
preprocessors,
|
|
@@ -93,6 +97,7 @@ function extractFlatConfig<
|
|
|
93
97
|
oas3_0Preprocessors,
|
|
94
98
|
oas3_1Preprocessors,
|
|
95
99
|
async2Preprocessors,
|
|
100
|
+
async3Preprocessors,
|
|
96
101
|
arazzoPreprocessors,
|
|
97
102
|
|
|
98
103
|
decorators,
|
|
@@ -100,6 +105,7 @@ function extractFlatConfig<
|
|
|
100
105
|
oas3_0Decorators,
|
|
101
106
|
oas3_1Decorators,
|
|
102
107
|
async2Decorators,
|
|
108
|
+
async3Decorators,
|
|
103
109
|
arazzoDecorators,
|
|
104
110
|
|
|
105
111
|
doNotResolveExamples: rawConfigRest.resolve?.doNotResolveExamples,
|
|
@@ -158,6 +164,7 @@ export function mergeExtends(rulesConfList: ResolvedStyleguideConfig[]) {
|
|
|
158
164
|
oas3_0Rules: {},
|
|
159
165
|
oas3_1Rules: {},
|
|
160
166
|
async2Rules: {},
|
|
167
|
+
async3Rules: {},
|
|
161
168
|
arazzoRules: {},
|
|
162
169
|
|
|
163
170
|
preprocessors: {},
|
|
@@ -165,6 +172,7 @@ export function mergeExtends(rulesConfList: ResolvedStyleguideConfig[]) {
|
|
|
165
172
|
oas3_0Preprocessors: {},
|
|
166
173
|
oas3_1Preprocessors: {},
|
|
167
174
|
async2Preprocessors: {},
|
|
175
|
+
async3Preprocessors: {},
|
|
168
176
|
arazzoPreprocessors: {},
|
|
169
177
|
|
|
170
178
|
decorators: {},
|
|
@@ -172,6 +180,7 @@ export function mergeExtends(rulesConfList: ResolvedStyleguideConfig[]) {
|
|
|
172
180
|
oas3_0Decorators: {},
|
|
173
181
|
oas3_1Decorators: {},
|
|
174
182
|
async2Decorators: {},
|
|
183
|
+
async3Decorators: {},
|
|
175
184
|
arazzoDecorators: {},
|
|
176
185
|
|
|
177
186
|
plugins: [],
|
|
@@ -195,6 +204,8 @@ export function mergeExtends(rulesConfList: ResolvedStyleguideConfig[]) {
|
|
|
195
204
|
assignExisting(result.oas3_1Rules, rulesConf.rules || {});
|
|
196
205
|
Object.assign(result.async2Rules, rulesConf.async2Rules);
|
|
197
206
|
assignExisting(result.async2Rules, rulesConf.rules || {});
|
|
207
|
+
Object.assign(result.async3Rules, rulesConf.async3Rules);
|
|
208
|
+
assignExisting(result.async3Rules, rulesConf.rules || {});
|
|
198
209
|
Object.assign(result.arazzoRules, rulesConf.arazzoRules);
|
|
199
210
|
assignExisting(result.arazzoRules, rulesConf.rules || {});
|
|
200
211
|
|
|
@@ -207,6 +218,8 @@ export function mergeExtends(rulesConfList: ResolvedStyleguideConfig[]) {
|
|
|
207
218
|
assignExisting(result.oas3_1Preprocessors, rulesConf.preprocessors || {});
|
|
208
219
|
Object.assign(result.async2Preprocessors, rulesConf.async2Preprocessors);
|
|
209
220
|
assignExisting(result.async2Preprocessors, rulesConf.preprocessors || {});
|
|
221
|
+
Object.assign(result.async3Preprocessors, rulesConf.async3Preprocessors);
|
|
222
|
+
assignExisting(result.async3Preprocessors, rulesConf.preprocessors || {});
|
|
210
223
|
Object.assign(result.arazzoPreprocessors, rulesConf.arazzoPreprocessors);
|
|
211
224
|
assignExisting(result.arazzoPreprocessors, rulesConf.preprocessors || {});
|
|
212
225
|
|
|
@@ -219,6 +232,8 @@ export function mergeExtends(rulesConfList: ResolvedStyleguideConfig[]) {
|
|
|
219
232
|
assignExisting(result.oas3_1Decorators, rulesConf.decorators || {});
|
|
220
233
|
Object.assign(result.async2Decorators, rulesConf.async2Decorators);
|
|
221
234
|
assignExisting(result.async2Decorators, rulesConf.decorators || {});
|
|
235
|
+
Object.assign(result.async3Decorators, rulesConf.async3Decorators);
|
|
236
|
+
assignExisting(result.async3Decorators, rulesConf.decorators || {});
|
|
222
237
|
Object.assign(result.arazzoDecorators, rulesConf.arazzoDecorators);
|
|
223
238
|
assignExisting(result.arazzoDecorators, rulesConf.decorators || {});
|
|
224
239
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const decorators = {};
|
|
@@ -6,7 +6,7 @@ import { isRef } from '../../ref-utils';
|
|
|
6
6
|
const DEFAULT_INTERNAL_PROPERTY_NAME = 'x-internal';
|
|
7
7
|
|
|
8
8
|
export const RemoveXInternal: Oas3Decorator | Oas2Decorator = ({ internalFlagProperty }) => {
|
|
9
|
-
const hiddenTag = internalFlagProperty || DEFAULT_INTERNAL_PROPERTY_NAME;
|
|
9
|
+
const hiddenTag: string = internalFlagProperty || DEFAULT_INTERNAL_PROPERTY_NAME;
|
|
10
10
|
|
|
11
11
|
function removeInternal(node: any, ctx: UserContext) {
|
|
12
12
|
const { parent, key } = ctx;
|
|
@@ -31,7 +31,7 @@ export const RemoveXInternal: Oas3Decorator | Oas2Decorator = ({ internalFlagPro
|
|
|
31
31
|
for (const key of Object.keys(node)) {
|
|
32
32
|
node = node as any;
|
|
33
33
|
if (isRef(node[key])) {
|
|
34
|
-
const resolved = ctx.resolve(node[key]);
|
|
34
|
+
const resolved = ctx.resolve<any>(node[key]);
|
|
35
35
|
if (resolved.node?.[hiddenTag]) {
|
|
36
36
|
delete node[key];
|
|
37
37
|
didDelete = true;
|
package/src/index.ts
CHANGED
|
@@ -11,7 +11,8 @@ export { Oas3_1Types } from './types/oas3_1';
|
|
|
11
11
|
export { ArazzoTypes } from './types/arazzo';
|
|
12
12
|
export { Oas3Types } from './types/oas3';
|
|
13
13
|
export { Oas2Types } from './types/oas2';
|
|
14
|
-
export { AsyncApi2Types } from './types/
|
|
14
|
+
export { AsyncApi2Types } from './types/asyncapi2';
|
|
15
|
+
export { AsyncApi3Types } from './types/asyncapi3';
|
|
15
16
|
export { ConfigTypes } from './types/redocly-yaml';
|
|
16
17
|
export type {
|
|
17
18
|
Oas3Definition,
|
package/src/lint.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { rootRedoclyConfigSchema } from '@redocly/config';
|
|
1
2
|
import { BaseResolver, resolveDocument, makeDocumentFromString } from './resolve';
|
|
2
3
|
import { normalizeVisitors } from './visitors';
|
|
3
4
|
import { walkDocument } from './walk';
|
|
@@ -12,16 +13,26 @@ import { NoUnresolvedRefs } from './rules/no-unresolved-refs';
|
|
|
12
13
|
import type { Document, ResolvedRefMap } from './resolve';
|
|
13
14
|
import type { ProblemSeverity, WalkContext } from './walk';
|
|
14
15
|
import type { NodeType } from './types';
|
|
15
|
-
import type {
|
|
16
|
-
|
|
16
|
+
import type {
|
|
17
|
+
ArazzoVisitor,
|
|
18
|
+
Async2Visitor,
|
|
19
|
+
Async3Visitor,
|
|
20
|
+
NestedVisitObject,
|
|
21
|
+
Oas2Visitor,
|
|
22
|
+
Oas3Visitor,
|
|
23
|
+
RuleInstanceConfig,
|
|
24
|
+
} from './visitors';
|
|
25
|
+
import type { CollectFn } from './utils';
|
|
17
26
|
|
|
18
27
|
export async function lint(opts: {
|
|
19
28
|
ref: string;
|
|
20
29
|
config: Config;
|
|
21
30
|
externalRefResolver?: BaseResolver;
|
|
31
|
+
collectSpecData?: CollectFn;
|
|
22
32
|
}) {
|
|
23
33
|
const { ref, externalRefResolver = new BaseResolver(opts.config.resolve) } = opts;
|
|
24
34
|
const document = (await externalRefResolver.resolveDocument(null, ref, true)) as Document;
|
|
35
|
+
opts.collectSpecData?.(document.parsed);
|
|
25
36
|
|
|
26
37
|
return lintDocument({
|
|
27
38
|
document,
|
|
@@ -130,7 +141,19 @@ export async function lintConfig(opts: {
|
|
|
130
141
|
);
|
|
131
142
|
|
|
132
143
|
const rules: (RuleInstanceConfig & {
|
|
133
|
-
visitor: NestedVisitObject<
|
|
144
|
+
visitor: NestedVisitObject<
|
|
145
|
+
unknown,
|
|
146
|
+
| Oas3Visitor
|
|
147
|
+
| Oas3Visitor[]
|
|
148
|
+
| Oas2Visitor
|
|
149
|
+
| Oas2Visitor[]
|
|
150
|
+
| Async2Visitor
|
|
151
|
+
| Async2Visitor[]
|
|
152
|
+
| Async3Visitor
|
|
153
|
+
| Async3Visitor[]
|
|
154
|
+
| ArazzoVisitor
|
|
155
|
+
| ArazzoVisitor[]
|
|
156
|
+
>;
|
|
134
157
|
})[] = [
|
|
135
158
|
{
|
|
136
159
|
severity: severity || 'error',
|
package/src/oas-types.ts
CHANGED
|
@@ -1,33 +1,37 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type {
|
|
2
2
|
Oas3Rule,
|
|
3
3
|
Oas3Preprocessor,
|
|
4
4
|
Oas2Rule,
|
|
5
5
|
Oas2Preprocessor,
|
|
6
6
|
Async2Preprocessor,
|
|
7
7
|
Async2Rule,
|
|
8
|
+
Async3Preprocessor,
|
|
9
|
+
Async3Rule,
|
|
8
10
|
ArazzoPreprocessor,
|
|
9
11
|
ArazzoRule,
|
|
10
12
|
} from './visitors';
|
|
11
13
|
import { Oas2Types } from './types/oas2';
|
|
12
14
|
import { Oas3Types } from './types/oas3';
|
|
13
15
|
import { Oas3_1Types } from './types/oas3_1';
|
|
14
|
-
import { AsyncApi2Types } from './types/
|
|
16
|
+
import { AsyncApi2Types } from './types/asyncapi2';
|
|
17
|
+
import { AsyncApi3Types } from './types/asyncapi3';
|
|
15
18
|
import { ArazzoTypes } from './types/arazzo';
|
|
16
|
-
import {
|
|
19
|
+
import type {
|
|
17
20
|
BuiltInAsync2RuleId,
|
|
21
|
+
BuiltInAsync3RuleId,
|
|
18
22
|
BuiltInCommonOASRuleId,
|
|
19
23
|
BuiltInArazzoRuleId,
|
|
20
24
|
BuiltInOAS2RuleId,
|
|
21
25
|
BuiltInOAS3RuleId,
|
|
22
26
|
} from './types/redocly-yaml';
|
|
23
|
-
|
|
24
|
-
export type RuleSet<T> = Record<string, T>;
|
|
27
|
+
import { isPlainObject } from './utils';
|
|
25
28
|
|
|
26
29
|
export enum SpecVersion {
|
|
27
30
|
OAS2 = 'oas2',
|
|
28
31
|
OAS3_0 = 'oas3_0',
|
|
29
32
|
OAS3_1 = 'oas3_1',
|
|
30
|
-
Async2 = 'async2',
|
|
33
|
+
Async2 = 'async2',
|
|
34
|
+
Async3 = 'async3',
|
|
31
35
|
Arazzo = 'arazzo',
|
|
32
36
|
}
|
|
33
37
|
|
|
@@ -35,6 +39,7 @@ export enum SpecMajorVersion {
|
|
|
35
39
|
OAS2 = 'oas2',
|
|
36
40
|
OAS3 = 'oas3',
|
|
37
41
|
Async2 = 'async2',
|
|
42
|
+
Async3 = 'async3',
|
|
38
43
|
Arazzo = 'arazzo',
|
|
39
44
|
}
|
|
40
45
|
|
|
@@ -43,6 +48,7 @@ const typesMap = {
|
|
|
43
48
|
[SpecVersion.OAS3_0]: Oas3Types,
|
|
44
49
|
[SpecVersion.OAS3_1]: Oas3_1Types,
|
|
45
50
|
[SpecVersion.Async2]: AsyncApi2Types,
|
|
51
|
+
[SpecVersion.Async3]: AsyncApi3Types,
|
|
46
52
|
[SpecVersion.Arazzo]: ArazzoTypes,
|
|
47
53
|
};
|
|
48
54
|
|
|
@@ -65,6 +71,11 @@ export type Async2RuleSet<T = undefined> = RuleMap<
|
|
|
65
71
|
Async2Rule,
|
|
66
72
|
T
|
|
67
73
|
>;
|
|
74
|
+
export type Async3RuleSet<T = undefined> = RuleMap<
|
|
75
|
+
BuiltInAsync3RuleId | 'assertions',
|
|
76
|
+
Async3Rule,
|
|
77
|
+
T
|
|
78
|
+
>;
|
|
68
79
|
export type ArazzoRuleSet<T = undefined> = RuleMap<
|
|
69
80
|
BuiltInArazzoRuleId | 'assertions',
|
|
70
81
|
ArazzoRule,
|
|
@@ -74,15 +85,17 @@ export type ArazzoRuleSet<T = undefined> = RuleMap<
|
|
|
74
85
|
export type Oas3PreprocessorsSet = Record<string, Oas3Preprocessor>;
|
|
75
86
|
export type Oas2PreprocessorsSet = Record<string, Oas2Preprocessor>;
|
|
76
87
|
export type Async2PreprocessorsSet = Record<string, Async2Preprocessor>;
|
|
88
|
+
export type Async3PreprocessorsSet = Record<string, Async3Preprocessor>;
|
|
77
89
|
export type ArazzoPreprocessorsSet = Record<string, ArazzoPreprocessor>;
|
|
78
90
|
|
|
79
91
|
export type Oas3DecoratorsSet = Record<string, Oas3Preprocessor>;
|
|
80
92
|
export type Oas2DecoratorsSet = Record<string, Oas2Preprocessor>;
|
|
81
93
|
export type Async2DecoratorsSet = Record<string, Async2Preprocessor>;
|
|
94
|
+
export type Async3DecoratorsSet = Record<string, Async3Preprocessor>;
|
|
82
95
|
export type ArazzoDecoratorsSet = Record<string, ArazzoPreprocessor>;
|
|
83
96
|
|
|
84
|
-
export function detectSpec(root:
|
|
85
|
-
if (
|
|
97
|
+
export function detectSpec(root: unknown): SpecVersion {
|
|
98
|
+
if (!isPlainObject(root)) {
|
|
86
99
|
throw new Error(`Document must be JSON object, got ${typeof root}`);
|
|
87
100
|
}
|
|
88
101
|
|
|
@@ -90,11 +103,11 @@ export function detectSpec(root: any): SpecVersion {
|
|
|
90
103
|
throw new Error(`Invalid OpenAPI version: should be a string but got "${typeof root.openapi}"`);
|
|
91
104
|
}
|
|
92
105
|
|
|
93
|
-
if (root.openapi && root.openapi.startsWith('3.0')) {
|
|
106
|
+
if (typeof root.openapi === 'string' && root.openapi.startsWith('3.0')) {
|
|
94
107
|
return SpecVersion.OAS3_0;
|
|
95
108
|
}
|
|
96
109
|
|
|
97
|
-
if (root.openapi && root.openapi.startsWith('3.1')) {
|
|
110
|
+
if (typeof root.openapi === 'string' && root.openapi.startsWith('3.1')) {
|
|
98
111
|
return SpecVersion.OAS3_1;
|
|
99
112
|
}
|
|
100
113
|
|
|
@@ -102,20 +115,23 @@ export function detectSpec(root: any): SpecVersion {
|
|
|
102
115
|
return SpecVersion.OAS2;
|
|
103
116
|
}
|
|
104
117
|
|
|
105
|
-
// if not detected yet
|
|
106
118
|
if (root.openapi || root.swagger) {
|
|
107
119
|
throw new Error(`Unsupported OpenAPI version: ${root.openapi || root.swagger}`);
|
|
108
120
|
}
|
|
109
121
|
|
|
110
|
-
if (root.asyncapi && root.asyncapi.startsWith('2.')) {
|
|
122
|
+
if (typeof root.asyncapi === 'string' && root.asyncapi.startsWith('2.')) {
|
|
111
123
|
return SpecVersion.Async2;
|
|
112
124
|
}
|
|
113
125
|
|
|
126
|
+
if (typeof root.asyncapi === 'string' && root.asyncapi.startsWith('3.')) {
|
|
127
|
+
return SpecVersion.Async3;
|
|
128
|
+
}
|
|
129
|
+
|
|
114
130
|
if (root.asyncapi) {
|
|
115
131
|
throw new Error(`Unsupported AsyncAPI version: ${root.asyncapi}`);
|
|
116
132
|
}
|
|
117
133
|
|
|
118
|
-
if (root.arazzo && root.arazzo.startsWith('1.')) {
|
|
134
|
+
if (typeof root.arazzo === 'string' && root.arazzo.startsWith('1.')) {
|
|
119
135
|
return SpecVersion.Arazzo;
|
|
120
136
|
}
|
|
121
137
|
|
|
@@ -127,6 +143,8 @@ export function getMajorSpecVersion(version: SpecVersion): SpecMajorVersion {
|
|
|
127
143
|
return SpecMajorVersion.OAS2;
|
|
128
144
|
} else if (version === SpecVersion.Async2) {
|
|
129
145
|
return SpecMajorVersion.Async2;
|
|
146
|
+
} else if (version === SpecVersion.Async3) {
|
|
147
|
+
return SpecMajorVersion.Async3;
|
|
130
148
|
} else if (version === SpecVersion.Arazzo) {
|
|
131
149
|
return SpecMajorVersion.Arazzo;
|
|
132
150
|
} else {
|
|
@@ -11,13 +11,13 @@ import type { Async2RuleSet } from '../../oas-types';
|
|
|
11
11
|
|
|
12
12
|
export const rules: Async2RuleSet<'built-in'> = {
|
|
13
13
|
spec: Spec as Async2Rule,
|
|
14
|
-
assertions: Assertions,
|
|
15
|
-
'info-contact': InfoContact,
|
|
16
|
-
'operation-operationId': OperationOperationId,
|
|
14
|
+
assertions: Assertions as Async2Rule,
|
|
15
|
+
'info-contact': InfoContact as Async2Rule,
|
|
16
|
+
'operation-operationId': OperationOperationId as Async2Rule,
|
|
17
17
|
'channels-kebab-case': ChannelsKebabCase,
|
|
18
18
|
'no-channel-trailing-slash': NoChannelTrailingSlash,
|
|
19
|
-
'tag-description': TagDescription,
|
|
20
|
-
'tags-alphabetical': TagsAlphabetical,
|
|
19
|
+
'tag-description': TagDescription as Async2Rule,
|
|
20
|
+
'tags-alphabetical': TagsAlphabetical as Async2Rule,
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
export const preprocessors = {};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { outdent } from 'outdent';
|
|
2
|
+
import { lintDocument } from '../../../lint';
|
|
3
|
+
import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../../../__tests__/utils';
|
|
4
|
+
import { BaseResolver } from '../../../resolve';
|
|
5
|
+
|
|
6
|
+
describe('Async2 channels-kebab-case', () => {
|
|
7
|
+
it('should report on no kebab-case channel path', async () => {
|
|
8
|
+
const document = parseYamlToDocument(
|
|
9
|
+
outdent`
|
|
10
|
+
asyncapi: '3.0.0'
|
|
11
|
+
info:
|
|
12
|
+
title: Cool API
|
|
13
|
+
version: 1.0.0
|
|
14
|
+
channels:
|
|
15
|
+
channel1:
|
|
16
|
+
address: /NOT_A_KEBAB/
|
|
17
|
+
payload:
|
|
18
|
+
type: object
|
|
19
|
+
`,
|
|
20
|
+
'asyncapi.yaml'
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const results = await lintDocument({
|
|
24
|
+
externalRefResolver: new BaseResolver(),
|
|
25
|
+
document,
|
|
26
|
+
config: await makeConfig({ 'channels-kebab-case': 'error' }),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
30
|
+
[
|
|
31
|
+
{
|
|
32
|
+
"location": [
|
|
33
|
+
{
|
|
34
|
+
"pointer": "#/channels/channel1",
|
|
35
|
+
"reportOnKey": true,
|
|
36
|
+
"source": "asyncapi.yaml",
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
"message": "\`/NOT_A_KEBAB/\` does not use kebab-case.",
|
|
40
|
+
"ruleId": "channels-kebab-case",
|
|
41
|
+
"severity": "error",
|
|
42
|
+
"suggest": [],
|
|
43
|
+
},
|
|
44
|
+
]
|
|
45
|
+
`);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should report on snake_case in channel path', async () => {
|
|
49
|
+
const document = parseYamlToDocument(
|
|
50
|
+
outdent`
|
|
51
|
+
asyncapi: '3.0.0'
|
|
52
|
+
info:
|
|
53
|
+
title: Cool API
|
|
54
|
+
version: 1.0.0
|
|
55
|
+
channels:
|
|
56
|
+
channel1:
|
|
57
|
+
address: snake_kebab
|
|
58
|
+
payload:
|
|
59
|
+
type: object
|
|
60
|
+
`,
|
|
61
|
+
'asyncapi.yaml'
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const results = await lintDocument({
|
|
65
|
+
externalRefResolver: new BaseResolver(),
|
|
66
|
+
document,
|
|
67
|
+
config: await makeConfig({ 'channels-kebab-case': 'error' }),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
71
|
+
[
|
|
72
|
+
{
|
|
73
|
+
"location": [
|
|
74
|
+
{
|
|
75
|
+
"pointer": "#/channels/channel1",
|
|
76
|
+
"reportOnKey": true,
|
|
77
|
+
"source": "asyncapi.yaml",
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
"message": "\`snake_kebab\` does not use kebab-case.",
|
|
81
|
+
"ruleId": "channels-kebab-case",
|
|
82
|
+
"severity": "error",
|
|
83
|
+
"suggest": [],
|
|
84
|
+
},
|
|
85
|
+
]
|
|
86
|
+
`);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should allow trailing slash in channel path with "channels-kebab-case" rule', async () => {
|
|
90
|
+
const document = parseYamlToDocument(
|
|
91
|
+
outdent`
|
|
92
|
+
asyncapi: '3.0.0'
|
|
93
|
+
info:
|
|
94
|
+
title: Cool API
|
|
95
|
+
version: 1.0.0
|
|
96
|
+
channels:
|
|
97
|
+
channel1:
|
|
98
|
+
address: kebab/
|
|
99
|
+
payload:
|
|
100
|
+
type: object
|
|
101
|
+
`,
|
|
102
|
+
'asyncapi.yaml'
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const results = await lintDocument({
|
|
106
|
+
externalRefResolver: new BaseResolver(),
|
|
107
|
+
document,
|
|
108
|
+
config: await makeConfig({
|
|
109
|
+
'paths-kebab-case': 'error',
|
|
110
|
+
'no-path-trailing-slash': 'off',
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('words with hyphens are allowed with "channels-kebab-case" rule', async () => {
|
|
117
|
+
const document = parseYamlToDocument(
|
|
118
|
+
outdent`
|
|
119
|
+
asyncapi: '3.0.0'
|
|
120
|
+
info:
|
|
121
|
+
title: Cool API
|
|
122
|
+
version: 1.0.0
|
|
123
|
+
channels:
|
|
124
|
+
channel1:
|
|
125
|
+
address: kebab-with-longer-channel-path:/
|
|
126
|
+
payload:
|
|
127
|
+
type: object
|
|
128
|
+
`,
|
|
129
|
+
'asyncapi.yaml'
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const results = await lintDocument({
|
|
133
|
+
externalRefResolver: new BaseResolver(),
|
|
134
|
+
document,
|
|
135
|
+
config: await makeConfig({
|
|
136
|
+
'paths-kebab-case': 'error',
|
|
137
|
+
}),
|
|
138
|
+
});
|
|
139
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
|
|
140
|
+
});
|
|
141
|
+
});
|