@redocly/openapi-core 1.26.0 → 1.27.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 +17 -0
- package/lib/config/all.js +2 -4
- package/lib/config/config-resolvers.d.ts +3 -1
- package/lib/config/config-resolvers.js +7 -5
- package/lib/config/minimal.js +1 -3
- package/lib/config/recommended-strict.js +2 -4
- package/lib/config/recommended.js +2 -4
- package/lib/config/rules.js +3 -0
- package/lib/config/spec.js +2 -4
- package/lib/config/types.d.ts +2 -3
- package/lib/rules/arazzo/index.js +2 -6
- package/lib/rules/spot/spot-supported-versions.d.ts +2 -0
- package/lib/rules/spot/{version-enum.js → spot-supported-versions.js} +3 -3
- package/lib/types/redocly-yaml.d.ts +1 -1
- package/lib/types/redocly-yaml.js +1 -3
- package/lib/visitors.d.ts +3 -0
- package/lib/visitors.js +2 -2
- package/lib/walk.js +14 -11
- package/package.json +1 -3
- package/src/__tests__/walk.test.ts +51 -0
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +4 -8
- package/src/config/all.ts +2 -4
- package/src/config/config-resolvers.ts +28 -36
- package/src/config/minimal.ts +1 -3
- package/src/config/recommended-strict.ts +2 -4
- package/src/config/recommended.ts +2 -4
- package/src/config/rules.ts +3 -1
- package/src/config/spec.ts +2 -4
- package/src/config/types.ts +2 -6
- package/src/rules/arazzo/__tests__/{version-enum.test.ts → spot-supported-versions.test.ts} +3 -3
- package/src/rules/arazzo/index.ts +2 -6
- package/src/rules/spot/{version-enum.ts → spot-supported-versions.ts} +1 -1
- package/src/types/redocly-yaml.ts +1 -3
- package/src/visitors.ts +5 -2
- package/src/walk.ts +20 -11
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/rules/spot/no-actions-type-end.d.ts +0 -2
- package/lib/rules/spot/no-actions-type-end.js +0 -28
- package/lib/rules/spot/parameters-not-in-body.d.ts +0 -2
- package/lib/rules/spot/parameters-not-in-body.js +0 -18
- package/lib/rules/spot/version-enum.d.ts +0 -2
- package/src/rules/arazzo/__tests__/no-actions-type-end.test.ts +0 -121
- package/src/rules/arazzo/__tests__/parameters-not-in-body.test.ts +0 -73
- package/src/rules/spot/no-actions-type-end.ts +0 -27
- package/src/rules/spot/parameters-not-in-body.ts +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @redocly/openapi-core
|
|
2
2
|
|
|
3
|
+
## 1.27.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added the ability to override default problem messages for built-in rules.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated Spot validation rules.
|
|
12
|
+
|
|
13
|
+
## 1.26.1
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Removed the `no-actions-type-end` Spot rule.
|
|
18
|
+
- Removed unused lodash.isequal dependency.
|
|
19
|
+
|
|
3
20
|
## 1.26.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
package/lib/config/all.js
CHANGED
|
@@ -210,9 +210,7 @@ const all = {
|
|
|
210
210
|
},
|
|
211
211
|
arazzo1Rules: {
|
|
212
212
|
'criteria-unique': 'error',
|
|
213
|
-
'no-criteria-xpath': '
|
|
214
|
-
'no-actions-type-end': 'error',
|
|
215
|
-
'parameters-not-in-body': 'error',
|
|
213
|
+
'no-criteria-xpath': 'off',
|
|
216
214
|
'parameters-unique': 'error',
|
|
217
215
|
'requestBody-replacements-unique': 'error',
|
|
218
216
|
'sourceDescription-type': 'error',
|
|
@@ -221,7 +219,7 @@ const all = {
|
|
|
221
219
|
'stepId-unique': 'error',
|
|
222
220
|
'sourceDescription-name-unique': 'error',
|
|
223
221
|
'sourceDescriptions-not-empty': 'error',
|
|
224
|
-
'
|
|
222
|
+
'spot-supported-versions': 'off',
|
|
225
223
|
'workflowId-unique': 'error',
|
|
226
224
|
'workflow-dependsOn': 'error',
|
|
227
225
|
},
|
|
@@ -24,5 +24,7 @@ export declare function resolveStyleguideConfig(opts: {
|
|
|
24
24
|
styleguideConfig?: StyleguideRawConfig;
|
|
25
25
|
configPath?: string;
|
|
26
26
|
resolver?: BaseResolver;
|
|
27
|
-
|
|
27
|
+
parentConfigPaths?: string[];
|
|
28
|
+
extendPaths?: string[];
|
|
29
|
+
}): Promise<ResolvedStyleguideConfig>;
|
|
28
30
|
export declare function resolvePreset(presetName: string, plugins: Plugin[]): ResolvedStyleguideConfig;
|
|
@@ -257,7 +257,7 @@ async function resolveApis({ rawConfig, configPath = '', resolver, }) {
|
|
|
257
257
|
}
|
|
258
258
|
return resolvedApis;
|
|
259
259
|
}
|
|
260
|
-
async function resolveAndMergeNestedStyleguideConfig({ styleguideConfig, configPath = '', resolver = new resolve_1.BaseResolver(),
|
|
260
|
+
async function resolveAndMergeNestedStyleguideConfig({ styleguideConfig, configPath = '', resolver = new resolve_1.BaseResolver(), parentConfigPaths = [], extendPaths = [], }) {
|
|
261
261
|
if (parentConfigPaths.includes(configPath)) {
|
|
262
262
|
throw new Error(`Circular dependency in config file: "${configPath}"`);
|
|
263
263
|
}
|
|
@@ -284,8 +284,10 @@ async function resolveAndMergeNestedStyleguideConfig({ styleguideConfig, configP
|
|
|
284
284
|
return await resolveAndMergeNestedStyleguideConfig({
|
|
285
285
|
styleguideConfig: extendedStyleguideConfig,
|
|
286
286
|
configPath: pathItem,
|
|
287
|
-
resolver
|
|
288
|
-
|
|
287
|
+
resolver,
|
|
288
|
+
parentConfigPaths: [...parentConfigPaths, resolvedConfigPath],
|
|
289
|
+
extendPaths,
|
|
290
|
+
});
|
|
289
291
|
}) || []);
|
|
290
292
|
const { plugins: mergedPlugins = [], ...styleguide } = (0, utils_2.mergeExtends)([
|
|
291
293
|
...extendConfigs,
|
|
@@ -305,8 +307,8 @@ async function resolveAndMergeNestedStyleguideConfig({ styleguideConfig, configP
|
|
|
305
307
|
doNotResolveExamples: styleguideConfig?.doNotResolveExamples,
|
|
306
308
|
};
|
|
307
309
|
}
|
|
308
|
-
async function resolveStyleguideConfig(opts
|
|
309
|
-
const resolvedStyleguideConfig = await resolveAndMergeNestedStyleguideConfig(opts
|
|
310
|
+
async function resolveStyleguideConfig(opts) {
|
|
311
|
+
const resolvedStyleguideConfig = await resolveAndMergeNestedStyleguideConfig(opts);
|
|
310
312
|
return {
|
|
311
313
|
...resolvedStyleguideConfig,
|
|
312
314
|
rules: resolvedStyleguideConfig.rules && groupStyleguideAssertionRules(resolvedStyleguideConfig),
|
package/lib/config/minimal.js
CHANGED
|
@@ -187,8 +187,6 @@ const minimal = {
|
|
|
187
187
|
arazzo1Rules: {
|
|
188
188
|
'criteria-unique': 'off',
|
|
189
189
|
'no-criteria-xpath': 'off',
|
|
190
|
-
'no-actions-type-end': 'off',
|
|
191
|
-
'parameters-not-in-body': 'off',
|
|
192
190
|
'parameters-unique': 'off',
|
|
193
191
|
'requestBody-replacements-unique': 'off',
|
|
194
192
|
'sourceDescription-type': 'off',
|
|
@@ -197,7 +195,7 @@ const minimal = {
|
|
|
197
195
|
'step-onFailure-unique': 'off',
|
|
198
196
|
'stepId-unique': 'error',
|
|
199
197
|
'sourceDescription-name-unique': 'off',
|
|
200
|
-
'
|
|
198
|
+
'spot-supported-versions': 'off',
|
|
201
199
|
'workflowId-unique': 'error',
|
|
202
200
|
'workflow-dependsOn': 'off',
|
|
203
201
|
},
|
|
@@ -186,9 +186,7 @@ const recommendedStrict = {
|
|
|
186
186
|
},
|
|
187
187
|
arazzo1Rules: {
|
|
188
188
|
'criteria-unique': 'error',
|
|
189
|
-
'no-criteria-xpath': '
|
|
190
|
-
'no-actions-type-end': 'error',
|
|
191
|
-
'parameters-not-in-body': 'error',
|
|
189
|
+
'no-criteria-xpath': 'off',
|
|
192
190
|
'parameters-unique': 'error',
|
|
193
191
|
'requestBody-replacements-unique': 'error',
|
|
194
192
|
'sourceDescription-type': 'error',
|
|
@@ -197,7 +195,7 @@ const recommendedStrict = {
|
|
|
197
195
|
'stepId-unique': 'error',
|
|
198
196
|
'sourceDescription-name-unique': 'error',
|
|
199
197
|
'sourceDescriptions-not-empty': 'error',
|
|
200
|
-
'
|
|
198
|
+
'spot-supported-versions': 'off',
|
|
201
199
|
'workflowId-unique': 'error',
|
|
202
200
|
'workflow-dependsOn': 'error',
|
|
203
201
|
},
|
|
@@ -186,9 +186,7 @@ const recommended = {
|
|
|
186
186
|
},
|
|
187
187
|
arazzo1Rules: {
|
|
188
188
|
'criteria-unique': 'warn',
|
|
189
|
-
'no-criteria-xpath': '
|
|
190
|
-
'no-actions-type-end': 'warn',
|
|
191
|
-
'parameters-not-in-body': 'warn',
|
|
189
|
+
'no-criteria-xpath': 'off',
|
|
192
190
|
'parameters-unique': 'error',
|
|
193
191
|
'requestBody-replacements-unique': 'warn',
|
|
194
192
|
'sourceDescription-type': 'error',
|
|
@@ -197,7 +195,7 @@ const recommended = {
|
|
|
197
195
|
'stepId-unique': 'error',
|
|
198
196
|
'sourceDescription-name-unique': 'error',
|
|
199
197
|
'sourceDescriptions-not-empty': 'error',
|
|
200
|
-
'
|
|
198
|
+
'spot-supported-versions': 'off',
|
|
201
199
|
'workflowId-unique': 'error',
|
|
202
200
|
'workflow-dependsOn': 'error',
|
|
203
201
|
},
|
package/lib/config/rules.js
CHANGED
|
@@ -15,16 +15,19 @@ function initRules(rules, config, type, oasVersion) {
|
|
|
15
15
|
return undefined;
|
|
16
16
|
}
|
|
17
17
|
const severity = ruleSettings.severity;
|
|
18
|
+
const message = ruleSettings.message;
|
|
18
19
|
const visitors = rule(ruleSettings);
|
|
19
20
|
if (Array.isArray(visitors)) {
|
|
20
21
|
return visitors.map((visitor) => ({
|
|
21
22
|
severity,
|
|
22
23
|
ruleId,
|
|
24
|
+
message,
|
|
23
25
|
visitor: visitor,
|
|
24
26
|
}));
|
|
25
27
|
}
|
|
26
28
|
return {
|
|
27
29
|
severity,
|
|
30
|
+
message,
|
|
28
31
|
ruleId,
|
|
29
32
|
visitor: visitors, // note: actually it is only one visitor object
|
|
30
33
|
};
|
package/lib/config/spec.js
CHANGED
|
@@ -11,9 +11,8 @@ const spec = {
|
|
|
11
11
|
async2Rules: {},
|
|
12
12
|
async3Rules: {},
|
|
13
13
|
arazzo1Rules: {
|
|
14
|
-
'parameters-not-in-body': 'error',
|
|
15
14
|
'sourceDescription-type': 'error',
|
|
16
|
-
'
|
|
15
|
+
'spot-supported-versions': 'off',
|
|
17
16
|
'workflowId-unique': 'error',
|
|
18
17
|
'stepId-unique': 'error',
|
|
19
18
|
'sourceDescription-name-unique': 'error',
|
|
@@ -23,8 +22,7 @@ const spec = {
|
|
|
23
22
|
'step-onSuccess-unique': 'error',
|
|
24
23
|
'step-onFailure-unique': 'error',
|
|
25
24
|
'requestBody-replacements-unique': 'error',
|
|
26
|
-
'no-criteria-xpath': '
|
|
27
|
-
'no-actions-type-end': 'error',
|
|
25
|
+
'no-criteria-xpath': 'off',
|
|
28
26
|
'criteria-unique': 'error',
|
|
29
27
|
},
|
|
30
28
|
};
|
package/lib/config/types.d.ts
CHANGED
|
@@ -7,11 +7,10 @@ import type { JSONSchema } from 'json-schema-to-ts';
|
|
|
7
7
|
export type RuleSeverity = ProblemSeverity | 'off';
|
|
8
8
|
export type RuleSettings = {
|
|
9
9
|
severity: RuleSeverity;
|
|
10
|
+
message?: string;
|
|
10
11
|
};
|
|
11
12
|
export type PreprocessorSeverity = RuleSeverity | 'on';
|
|
12
|
-
export type RuleConfig = RuleSeverity | (
|
|
13
|
-
severity?: ProblemSeverity;
|
|
14
|
-
} & Record<string, any>);
|
|
13
|
+
export type RuleConfig = RuleSeverity | (Partial<RuleSettings> & Record<string, any>);
|
|
15
14
|
export type PreprocessorConfig = PreprocessorSeverity | ({
|
|
16
15
|
severity?: ProblemSeverity;
|
|
17
16
|
} & Record<string, any>);
|
|
@@ -3,10 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.preprocessors = exports.rules = void 0;
|
|
4
4
|
const struct_1 = require("../common/struct");
|
|
5
5
|
const assertions_1 = require("../common/assertions");
|
|
6
|
-
const parameters_not_in_body_1 = require("../spot/parameters-not-in-body");
|
|
7
6
|
const sourceDescription_type_1 = require("../arazzo/sourceDescription-type");
|
|
8
7
|
const sourceDescriptions_not_empty_1 = require("./sourceDescriptions-not-empty");
|
|
9
|
-
const
|
|
8
|
+
const spot_supported_versions_1 = require("../spot/spot-supported-versions");
|
|
10
9
|
const workflowId_unique_1 = require("./workflowId-unique");
|
|
11
10
|
const stepId_unique_1 = require("./stepId-unique");
|
|
12
11
|
const sourceDescriptions_name_unique_1 = require("./sourceDescriptions-name-unique");
|
|
@@ -16,14 +15,12 @@ const step_onSuccess_unique_1 = require("./step-onSuccess-unique");
|
|
|
16
15
|
const step_onFailure_unique_1 = require("./step-onFailure-unique");
|
|
17
16
|
const requestBody_replacements_unique_1 = require("./requestBody-replacements-unique");
|
|
18
17
|
const no_criteria_xpath_1 = require("../spot/no-criteria-xpath");
|
|
19
|
-
const no_actions_type_end_1 = require("../spot/no-actions-type-end");
|
|
20
18
|
const criteria_unique_1 = require("./criteria-unique");
|
|
21
19
|
exports.rules = {
|
|
22
20
|
struct: struct_1.Struct,
|
|
23
21
|
assertions: assertions_1.Assertions,
|
|
24
|
-
'parameters-not-in-body': parameters_not_in_body_1.ParametersNotInBody,
|
|
25
22
|
'sourceDescription-type': sourceDescription_type_1.SourceDescriptionType,
|
|
26
|
-
'
|
|
23
|
+
'spot-supported-versions': spot_supported_versions_1.SpotSupportedVersions,
|
|
27
24
|
'workflowId-unique': workflowId_unique_1.WorkflowIdUnique,
|
|
28
25
|
'stepId-unique': stepId_unique_1.StepIdUnique,
|
|
29
26
|
'sourceDescription-name-unique': sourceDescriptions_name_unique_1.SourceDescriptionsNameUnique,
|
|
@@ -34,7 +31,6 @@ exports.rules = {
|
|
|
34
31
|
'step-onFailure-unique': step_onFailure_unique_1.StepOnFailureUnique,
|
|
35
32
|
'requestBody-replacements-unique': requestBody_replacements_unique_1.RequestBodyReplacementsUnique,
|
|
36
33
|
'no-criteria-xpath': no_criteria_xpath_1.NoCriteriaXpath,
|
|
37
|
-
'no-actions-type-end': no_actions_type_end_1.NoActionsTypeEnd,
|
|
38
34
|
'criteria-unique': criteria_unique_1.CriteriaUnique,
|
|
39
35
|
};
|
|
40
36
|
exports.preprocessors = {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.SpotSupportedVersions = void 0;
|
|
4
4
|
const arazzo_1 = require("../../typings/arazzo");
|
|
5
5
|
const utils_1 = require("../../utils");
|
|
6
|
-
const
|
|
6
|
+
const SpotSupportedVersions = () => {
|
|
7
7
|
const supportedVersions = arazzo_1.ARAZZO_VERSIONS_SUPPORTED_BY_SPOT.join(', ');
|
|
8
8
|
return {
|
|
9
9
|
Root: {
|
|
@@ -18,4 +18,4 @@ const VersionEnum = () => {
|
|
|
18
18
|
},
|
|
19
19
|
};
|
|
20
20
|
};
|
|
21
|
-
exports.
|
|
21
|
+
exports.SpotSupportedVersions = SpotSupportedVersions;
|
|
@@ -9,7 +9,7 @@ declare const builtInAsync2Rules: readonly ["info-contact", "info-license-strict
|
|
|
9
9
|
declare const builtInAsync3Rules: readonly ["info-contact", "info-license-strict", "operation-operationId", "tag-description", "tags-alphabetical", "channels-kebab-case", "no-channel-trailing-slash"];
|
|
10
10
|
export type BuiltInAsync2RuleId = typeof builtInAsync2Rules[number];
|
|
11
11
|
export type BuiltInAsync3RuleId = typeof builtInAsync3Rules[number];
|
|
12
|
-
declare const builtInArazzo1Rules: readonly ["
|
|
12
|
+
declare const builtInArazzo1Rules: readonly ["sourceDescription-type", "workflowId-unique", "stepId-unique", "sourceDescription-name-unique", "sourceDescriptions-not-empty", "workflow-dependsOn", "parameters-unique", "step-onSuccess-unique", "step-onFailure-unique", "spot-supported-versions", "requestBody-replacements-unique", "no-criteria-xpath", "criteria-unique"];
|
|
13
13
|
export type BuiltInArazzo1RuleId = typeof builtInArazzo1Rules[number];
|
|
14
14
|
declare const oas2NodeTypesList: readonly ["Root", "Tag", "TagList", "ExternalDocs", "SecurityRequirement", "SecurityRequirementList", "Info", "Contact", "License", "Paths", "PathItem", "Parameter", "ParameterList", "ParameterItems", "Operation", "Example", "ExamplesMap", "Examples", "Header", "Responses", "Response", "Schema", "Xml", "SchemaProperties", "NamedSchemas", "NamedResponses", "NamedParameters", "NamedSecuritySchemes", "SecurityScheme", "TagGroup", "TagGroups", "EnumDescriptions", "Logo", "XCodeSample", "XCodeSampleList", "XServer", "XServerList"];
|
|
15
15
|
export type Oas2NodeType = typeof oas2NodeTypesList[number];
|
|
@@ -128,9 +128,7 @@ const builtInAsync3Rules = [
|
|
|
128
128
|
'no-channel-trailing-slash',
|
|
129
129
|
];
|
|
130
130
|
const builtInArazzo1Rules = [
|
|
131
|
-
'parameters-not-in-body',
|
|
132
131
|
'sourceDescription-type',
|
|
133
|
-
'version-enum',
|
|
134
132
|
'workflowId-unique',
|
|
135
133
|
'stepId-unique',
|
|
136
134
|
'sourceDescription-name-unique',
|
|
@@ -139,9 +137,9 @@ const builtInArazzo1Rules = [
|
|
|
139
137
|
'parameters-unique',
|
|
140
138
|
'step-onSuccess-unique',
|
|
141
139
|
'step-onFailure-unique',
|
|
140
|
+
'spot-supported-versions',
|
|
142
141
|
'requestBody-replacements-unique',
|
|
143
142
|
'no-criteria-xpath',
|
|
144
|
-
'no-actions-type-end',
|
|
145
143
|
'criteria-unique',
|
|
146
144
|
];
|
|
147
145
|
const builtInRules = [
|
package/lib/visitors.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ type VisitFunctionOrObject<T> = VisitFunction<T> | VisitObject<T>;
|
|
|
23
23
|
export type VisitorNode<T> = {
|
|
24
24
|
ruleId: string;
|
|
25
25
|
severity: ProblemSeverity;
|
|
26
|
+
message?: string;
|
|
26
27
|
context: VisitorLevelContext | VisitorSkippedLevelContext;
|
|
27
28
|
depth: number;
|
|
28
29
|
visit: VisitFunction<T>;
|
|
@@ -31,6 +32,7 @@ export type VisitorNode<T> = {
|
|
|
31
32
|
type VisitorRefNode = {
|
|
32
33
|
ruleId: string;
|
|
33
34
|
severity: ProblemSeverity;
|
|
35
|
+
message?: string;
|
|
34
36
|
context: VisitorLevelContext;
|
|
35
37
|
depth: number;
|
|
36
38
|
visit: VisitRefFunction;
|
|
@@ -219,6 +221,7 @@ export type OasDecorator = Oas3Decorator;
|
|
|
219
221
|
export type RuleInstanceConfig = {
|
|
220
222
|
ruleId: string;
|
|
221
223
|
severity: ProblemSeverity;
|
|
224
|
+
message?: string;
|
|
222
225
|
};
|
|
223
226
|
export declare function normalizeVisitors<T extends BaseVisitor>(visitorsConfig: (RuleInstanceConfig & {
|
|
224
227
|
visitor: NestedVisitObject<unknown, T>;
|
package/lib/visitors.js
CHANGED
|
@@ -31,8 +31,8 @@ function normalizeVisitors(visitorsConfig, types) {
|
|
|
31
31
|
enter: [],
|
|
32
32
|
leave: [],
|
|
33
33
|
};
|
|
34
|
-
for (const { ruleId, severity, visitor } of visitorsConfig) {
|
|
35
|
-
normalizeVisitorLevel({ ruleId, severity }, visitor, null);
|
|
34
|
+
for (const { ruleId, severity, message, visitor } of visitorsConfig) {
|
|
35
|
+
normalizeVisitorLevel({ ruleId, severity, message }, visitor, null);
|
|
36
36
|
}
|
|
37
37
|
for (const v of Object.keys(normalizedVisitors)) {
|
|
38
38
|
normalizedVisitors[v].enter.sort((a, b) => b.depth - a.depth);
|
package/lib/walk.js
CHANGED
|
@@ -54,9 +54,9 @@ function walkDocument(opts) {
|
|
|
54
54
|
const enteredContexts = new Set();
|
|
55
55
|
if ((0, ref_utils_1.isRef)(node)) {
|
|
56
56
|
const refEnterVisitors = normalizedVisitors.ref.enter;
|
|
57
|
-
for (const { visit: visitor, ruleId, severity, context } of refEnterVisitors) {
|
|
57
|
+
for (const { visit: visitor, ruleId, severity, message, context } of refEnterVisitors) {
|
|
58
58
|
enteredContexts.add(context);
|
|
59
|
-
const report = reportFn.bind(undefined, ruleId, severity);
|
|
59
|
+
const report = reportFn.bind(undefined, ruleId, severity, message);
|
|
60
60
|
visitor(node, {
|
|
61
61
|
report,
|
|
62
62
|
resolve,
|
|
@@ -82,7 +82,7 @@ function walkDocument(opts) {
|
|
|
82
82
|
const anyEnterVisitors = normalizedVisitors.any.enter;
|
|
83
83
|
const currentEnterVisitors = anyEnterVisitors.concat(normalizedVisitors[type.name]?.enter || []);
|
|
84
84
|
const activatedContexts = [];
|
|
85
|
-
for (const { context, visit, skip, ruleId, severity } of currentEnterVisitors) {
|
|
85
|
+
for (const { context, visit, skip, ruleId, severity, message } of currentEnterVisitors) {
|
|
86
86
|
if (ignoredNodes.has(`${currentLocation.absolutePointer}${currentLocation.pointer}`))
|
|
87
87
|
break;
|
|
88
88
|
if (context.isSkippedLevel) {
|
|
@@ -127,7 +127,7 @@ function walkDocument(opts) {
|
|
|
127
127
|
if (!activatedOn.skipped) {
|
|
128
128
|
visitedBySome = true;
|
|
129
129
|
enteredContexts.add(context);
|
|
130
|
-
visitWithContext(visit, resolvedNode, node, context, ruleId, severity);
|
|
130
|
+
visitWithContext(visit, resolvedNode, node, context, ruleId, severity, message);
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
}
|
|
@@ -209,18 +209,18 @@ function walkDocument(opts) {
|
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
|
-
for (const { context, visit, ruleId, severity } of currentLeaveVisitors) {
|
|
212
|
+
for (const { context, visit, ruleId, severity, message } of currentLeaveVisitors) {
|
|
213
213
|
if (!context.isSkippedLevel && enteredContexts.has(context)) {
|
|
214
|
-
visitWithContext(visit, resolvedNode, node, context, ruleId, severity);
|
|
214
|
+
visitWithContext(visit, resolvedNode, node, context, ruleId, severity, message);
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
currentLocation = location;
|
|
219
219
|
if ((0, ref_utils_1.isRef)(node)) {
|
|
220
220
|
const refLeaveVisitors = normalizedVisitors.ref.leave;
|
|
221
|
-
for (const { visit: visitor, ruleId, severity, context } of refLeaveVisitors) {
|
|
221
|
+
for (const { visit: visitor, ruleId, severity, context, message } of refLeaveVisitors) {
|
|
222
222
|
if (enteredContexts.has(context)) {
|
|
223
|
-
const report = reportFn.bind(undefined, ruleId, severity);
|
|
223
|
+
const report = reportFn.bind(undefined, ruleId, severity, message);
|
|
224
224
|
visitor(node, {
|
|
225
225
|
report,
|
|
226
226
|
resolve,
|
|
@@ -238,8 +238,8 @@ function walkDocument(opts) {
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
// returns true ignores all the next visitors on the specific node
|
|
241
|
-
function visitWithContext(visit, resolvedNode, node, context, ruleId, severity) {
|
|
242
|
-
const report = reportFn.bind(undefined, ruleId, severity);
|
|
241
|
+
function visitWithContext(visit, resolvedNode, node, context, ruleId, severity, customMessage) {
|
|
242
|
+
const report = reportFn.bind(undefined, ruleId, severity, customMessage);
|
|
243
243
|
visit(resolvedNode, {
|
|
244
244
|
report,
|
|
245
245
|
resolve,
|
|
@@ -257,7 +257,7 @@ function walkDocument(opts) {
|
|
|
257
257
|
getVisitorData: getVisitorDataFn.bind(undefined, ruleId),
|
|
258
258
|
}, collectParents(context), context);
|
|
259
259
|
}
|
|
260
|
-
function reportFn(ruleId, severity, opts) {
|
|
260
|
+
function reportFn(ruleId, severity, customMessage, opts) {
|
|
261
261
|
const normalizedLocation = opts.location
|
|
262
262
|
? Array.isArray(opts.location)
|
|
263
263
|
? opts.location
|
|
@@ -274,6 +274,9 @@ function walkDocument(opts) {
|
|
|
274
274
|
ruleId: opts.ruleId || ruleId,
|
|
275
275
|
severity: ruleSeverity,
|
|
276
276
|
...opts,
|
|
277
|
+
message: customMessage
|
|
278
|
+
? customMessage.replace('{{message}}', opts.message)
|
|
279
|
+
: opts.message,
|
|
277
280
|
suggest: opts.suggest || [],
|
|
278
281
|
location,
|
|
279
282
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/openapi-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -41,7 +41,6 @@
|
|
|
41
41
|
"https-proxy-agent": "^7.0.4",
|
|
42
42
|
"js-levenshtein": "^1.1.6",
|
|
43
43
|
"js-yaml": "^4.1.0",
|
|
44
|
-
"lodash.isequal": "^4.5.0",
|
|
45
44
|
"minimatch": "^5.0.1",
|
|
46
45
|
"node-fetch": "^2.6.1",
|
|
47
46
|
"pluralize": "^8.0.0",
|
|
@@ -50,7 +49,6 @@
|
|
|
50
49
|
"devDependencies": {
|
|
51
50
|
"@types/js-levenshtein": "^1.1.0",
|
|
52
51
|
"@types/js-yaml": "^4.0.3",
|
|
53
|
-
"@types/lodash.isequal": "^4.5.5",
|
|
54
52
|
"@types/minimatch": "^3.0.5",
|
|
55
53
|
"@types/node": "^20.11.5",
|
|
56
54
|
"@types/node-fetch": "^2.5.7",
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { BaseResolver, Document } from '../resolve';
|
|
13
13
|
import { listOf } from '../types';
|
|
14
14
|
import { Oas3RuleSet } from '../oas-types';
|
|
15
|
+
import { createConfig } from '../config';
|
|
15
16
|
|
|
16
17
|
describe('walk order', () => {
|
|
17
18
|
it('should run visitors', async () => {
|
|
@@ -1338,6 +1339,56 @@ describe('context.report', () => {
|
|
|
1338
1339
|
]
|
|
1339
1340
|
`);
|
|
1340
1341
|
});
|
|
1342
|
+
|
|
1343
|
+
it('should report errors with custom messages', async () => {
|
|
1344
|
+
const document = parseYamlToDocument(
|
|
1345
|
+
outdent`
|
|
1346
|
+
openapi: 3.0.0
|
|
1347
|
+
info:
|
|
1348
|
+
license: {}
|
|
1349
|
+
paths: {}
|
|
1350
|
+
`,
|
|
1351
|
+
'foobar.yaml'
|
|
1352
|
+
);
|
|
1353
|
+
|
|
1354
|
+
const config = await createConfig(`
|
|
1355
|
+
rules:
|
|
1356
|
+
info-contact:
|
|
1357
|
+
message: "MY ERR DESCRIPTION: {{message}}"
|
|
1358
|
+
severity: "error"
|
|
1359
|
+
`);
|
|
1360
|
+
|
|
1361
|
+
const results = await lintDocument({
|
|
1362
|
+
externalRefResolver: new BaseResolver(),
|
|
1363
|
+
document,
|
|
1364
|
+
config: config.styleguide,
|
|
1365
|
+
});
|
|
1366
|
+
|
|
1367
|
+
expect(results).toMatchInlineSnapshot(`
|
|
1368
|
+
[
|
|
1369
|
+
{
|
|
1370
|
+
"location": [
|
|
1371
|
+
{
|
|
1372
|
+
"pointer": "#/info/contact",
|
|
1373
|
+
"reportOnKey": true,
|
|
1374
|
+
"source": Source {
|
|
1375
|
+
"absoluteRef": "foobar.yaml",
|
|
1376
|
+
"body": "openapi: 3.0.0
|
|
1377
|
+
info:
|
|
1378
|
+
license: {}
|
|
1379
|
+
paths: {}",
|
|
1380
|
+
"mimeType": undefined,
|
|
1381
|
+
},
|
|
1382
|
+
},
|
|
1383
|
+
],
|
|
1384
|
+
"message": "MY ERR DESCRIPTION: Info object should contain \`contact\` field.",
|
|
1385
|
+
"ruleId": "info-contact",
|
|
1386
|
+
"severity": "error",
|
|
1387
|
+
"suggest": [],
|
|
1388
|
+
},
|
|
1389
|
+
]
|
|
1390
|
+
`);
|
|
1391
|
+
});
|
|
1341
1392
|
});
|
|
1342
1393
|
|
|
1343
1394
|
describe('context.resolve', () => {
|
|
@@ -6,18 +6,16 @@ exports[`resolveConfig should ignore minimal from the root and read local file 1
|
|
|
6
6
|
"arazzo1Preprocessors": {},
|
|
7
7
|
"arazzo1Rules": {
|
|
8
8
|
"criteria-unique": "warn",
|
|
9
|
-
"no-
|
|
10
|
-
"no-criteria-xpath": "warn",
|
|
11
|
-
"parameters-not-in-body": "warn",
|
|
9
|
+
"no-criteria-xpath": "off",
|
|
12
10
|
"parameters-unique": "error",
|
|
13
11
|
"requestBody-replacements-unique": "warn",
|
|
14
12
|
"sourceDescription-name-unique": "error",
|
|
15
13
|
"sourceDescription-type": "error",
|
|
16
14
|
"sourceDescriptions-not-empty": "error",
|
|
15
|
+
"spot-supported-versions": "off",
|
|
17
16
|
"step-onFailure-unique": "warn",
|
|
18
17
|
"step-onSuccess-unique": "warn",
|
|
19
18
|
"stepId-unique": "error",
|
|
20
|
-
"version-enum": "warn",
|
|
21
19
|
"workflow-dependsOn": "error",
|
|
22
20
|
"workflowId-unique": "error",
|
|
23
21
|
},
|
|
@@ -234,18 +232,16 @@ exports[`resolveStyleguideConfig should resolve extends with local file config w
|
|
|
234
232
|
"arazzo1Preprocessors": {},
|
|
235
233
|
"arazzo1Rules": {
|
|
236
234
|
"criteria-unique": "warn",
|
|
237
|
-
"no-
|
|
238
|
-
"no-criteria-xpath": "warn",
|
|
239
|
-
"parameters-not-in-body": "warn",
|
|
235
|
+
"no-criteria-xpath": "off",
|
|
240
236
|
"parameters-unique": "error",
|
|
241
237
|
"requestBody-replacements-unique": "warn",
|
|
242
238
|
"sourceDescription-name-unique": "error",
|
|
243
239
|
"sourceDescription-type": "error",
|
|
244
240
|
"sourceDescriptions-not-empty": "error",
|
|
241
|
+
"spot-supported-versions": "off",
|
|
245
242
|
"step-onFailure-unique": "warn",
|
|
246
243
|
"step-onSuccess-unique": "warn",
|
|
247
244
|
"stepId-unique": "error",
|
|
248
|
-
"version-enum": "warn",
|
|
249
245
|
"workflow-dependsOn": "error",
|
|
250
246
|
"workflowId-unique": "error",
|
|
251
247
|
},
|
package/src/config/all.ts
CHANGED
|
@@ -210,9 +210,7 @@ const all: PluginStyleguideConfig<'built-in'> = {
|
|
|
210
210
|
},
|
|
211
211
|
arazzo1Rules: {
|
|
212
212
|
'criteria-unique': 'error',
|
|
213
|
-
'no-criteria-xpath': '
|
|
214
|
-
'no-actions-type-end': 'error',
|
|
215
|
-
'parameters-not-in-body': 'error',
|
|
213
|
+
'no-criteria-xpath': 'off',
|
|
216
214
|
'parameters-unique': 'error',
|
|
217
215
|
'requestBody-replacements-unique': 'error',
|
|
218
216
|
'sourceDescription-type': 'error',
|
|
@@ -221,7 +219,7 @@ const all: PluginStyleguideConfig<'built-in'> = {
|
|
|
221
219
|
'stepId-unique': 'error',
|
|
222
220
|
'sourceDescription-name-unique': 'error',
|
|
223
221
|
'sourceDescriptions-not-empty': 'error',
|
|
224
|
-
'
|
|
222
|
+
'spot-supported-versions': 'off',
|
|
225
223
|
'workflowId-unique': 'error',
|
|
226
224
|
'workflow-dependsOn': 'error',
|
|
227
225
|
},
|
|
@@ -370,19 +370,19 @@ export async function resolveApis({
|
|
|
370
370
|
return resolvedApis;
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
-
async function resolveAndMergeNestedStyleguideConfig(
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
parentConfigPaths
|
|
384
|
-
extendPaths
|
|
385
|
-
): Promise<ResolvedStyleguideConfig> {
|
|
373
|
+
async function resolveAndMergeNestedStyleguideConfig({
|
|
374
|
+
styleguideConfig,
|
|
375
|
+
configPath = '',
|
|
376
|
+
resolver = new BaseResolver(),
|
|
377
|
+
parentConfigPaths = [],
|
|
378
|
+
extendPaths = [],
|
|
379
|
+
}: {
|
|
380
|
+
styleguideConfig?: StyleguideRawConfig;
|
|
381
|
+
configPath?: string;
|
|
382
|
+
resolver?: BaseResolver;
|
|
383
|
+
parentConfigPaths?: string[];
|
|
384
|
+
extendPaths?: string[];
|
|
385
|
+
}): Promise<ResolvedStyleguideConfig> {
|
|
386
386
|
if (parentConfigPaths.includes(configPath)) {
|
|
387
387
|
throw new Error(`Circular dependency in config file: "${configPath}"`);
|
|
388
388
|
}
|
|
@@ -414,15 +414,13 @@ async function resolveAndMergeNestedStyleguideConfig(
|
|
|
414
414
|
? new URL(presetItem, configPath).href
|
|
415
415
|
: path.resolve(path.dirname(configPath), presetItem);
|
|
416
416
|
const extendedStyleguideConfig = await loadExtendStyleguideConfig(pathItem, resolver);
|
|
417
|
-
return await resolveAndMergeNestedStyleguideConfig(
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
extendPaths
|
|
425
|
-
);
|
|
417
|
+
return await resolveAndMergeNestedStyleguideConfig({
|
|
418
|
+
styleguideConfig: extendedStyleguideConfig,
|
|
419
|
+
configPath: pathItem,
|
|
420
|
+
resolver,
|
|
421
|
+
parentConfigPaths: [...parentConfigPaths, resolvedConfigPath],
|
|
422
|
+
extendPaths,
|
|
423
|
+
});
|
|
426
424
|
}) || []
|
|
427
425
|
);
|
|
428
426
|
|
|
@@ -446,20 +444,14 @@ async function resolveAndMergeNestedStyleguideConfig(
|
|
|
446
444
|
};
|
|
447
445
|
}
|
|
448
446
|
|
|
449
|
-
export async function resolveStyleguideConfig(
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
): Promise<ResolvedStyleguideConfig> {
|
|
458
|
-
const resolvedStyleguideConfig = await resolveAndMergeNestedStyleguideConfig(
|
|
459
|
-
opts,
|
|
460
|
-
parentConfigPaths,
|
|
461
|
-
extendPaths
|
|
462
|
-
);
|
|
447
|
+
export async function resolveStyleguideConfig(opts: {
|
|
448
|
+
styleguideConfig?: StyleguideRawConfig;
|
|
449
|
+
configPath?: string;
|
|
450
|
+
resolver?: BaseResolver;
|
|
451
|
+
parentConfigPaths?: string[];
|
|
452
|
+
extendPaths?: string[];
|
|
453
|
+
}): Promise<ResolvedStyleguideConfig> {
|
|
454
|
+
const resolvedStyleguideConfig = await resolveAndMergeNestedStyleguideConfig(opts);
|
|
463
455
|
|
|
464
456
|
return {
|
|
465
457
|
...resolvedStyleguideConfig,
|