@redocly/openapi-core 1.23.0 → 1.24.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 +13 -0
- package/lib/config/all.js +3 -0
- package/lib/config/config.js +4 -1
- package/lib/config/minimal.js +3 -0
- package/lib/config/recommended-strict.js +3 -0
- package/lib/config/recommended.js +3 -0
- package/lib/rules/arazzo/criteria-unique.d.ts +2 -0
- package/lib/rules/arazzo/criteria-unique.js +65 -0
- package/lib/rules/arazzo/index.js +6 -0
- package/lib/rules/spot/no-actions-type-end.d.ts +2 -0
- package/lib/rules/spot/no-actions-type-end.js +28 -0
- package/lib/rules/spot/no-criteria-xpath.d.ts +2 -0
- package/lib/rules/spot/no-criteria-xpath.js +21 -0
- package/lib/types/arazzo.js +1 -1
- package/lib/types/redocly-yaml.d.ts +1 -1
- package/lib/types/redocly-yaml.js +3 -0
- package/package.json +2 -2
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +6 -0
- package/src/config/all.ts +3 -0
- package/src/config/config.ts +4 -1
- package/src/config/minimal.ts +3 -0
- package/src/config/recommended-strict.ts +3 -0
- package/src/config/recommended.ts +3 -0
- package/src/rules/arazzo/__tests__/criteria-unique.test.ts +161 -0
- package/src/rules/arazzo/__tests__/no-actions-type-end.test.ts +122 -0
- package/src/rules/arazzo/__tests__/no-criteria-xpath.test.ts +127 -0
- package/src/rules/arazzo/criteria-unique.ts +63 -0
- package/src/rules/arazzo/index.ts +6 -0
- package/src/rules/spot/no-actions-type-end.ts +27 -0
- package/src/rules/spot/no-criteria-xpath.ts +20 -0
- package/src/types/arazzo.ts +1 -1
- package/src/types/redocly-yaml.ts +3 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,127 @@
|
|
|
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('Arazzo no-criteria-xpath', () => {
|
|
7
|
+
const document = parseYamlToDocument(
|
|
8
|
+
outdent`
|
|
9
|
+
arazzo: '1.0.0'
|
|
10
|
+
info:
|
|
11
|
+
title: Cool API
|
|
12
|
+
version: 1.0.0
|
|
13
|
+
description: A cool API
|
|
14
|
+
sourceDescriptions:
|
|
15
|
+
- name: museum-api
|
|
16
|
+
type: openapi
|
|
17
|
+
url: openapi.yaml
|
|
18
|
+
workflows:
|
|
19
|
+
- workflowId: get-museum-hours
|
|
20
|
+
description: This workflow demonstrates how to get the museum opening hours and buy tickets.
|
|
21
|
+
parameters:
|
|
22
|
+
- in: header
|
|
23
|
+
name: Authorization
|
|
24
|
+
value: Basic Og==
|
|
25
|
+
steps:
|
|
26
|
+
- stepId: create-event
|
|
27
|
+
description: >-
|
|
28
|
+
Create a new special event.
|
|
29
|
+
operationPath: $sourceDescriptions.museum-api#/paths/~1special-events/post
|
|
30
|
+
requestBody:
|
|
31
|
+
payload:
|
|
32
|
+
name: 'Mermaid Treasure Identification and Analysis'
|
|
33
|
+
location: 'Under the seaaa 🦀 🎶 🌊.'
|
|
34
|
+
eventDescription: 'Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.'
|
|
35
|
+
dates:
|
|
36
|
+
- '2023-09-05'
|
|
37
|
+
- '2023-09-08'
|
|
38
|
+
price: 0
|
|
39
|
+
successCriteria:
|
|
40
|
+
- condition: $statusCode == 201
|
|
41
|
+
- context: $response.body
|
|
42
|
+
condition: $.name == 'Mermaid Treasure Identification and Analysis'
|
|
43
|
+
type:
|
|
44
|
+
type: jsonpath
|
|
45
|
+
version: draft-goessner-dispatch-jsonpath-00
|
|
46
|
+
- context: $response.body
|
|
47
|
+
condition: $.name == 'Orca Identification and Analysis'
|
|
48
|
+
type: xpath
|
|
49
|
+
- context: $response.body
|
|
50
|
+
condition: $.name == 'Mermaid Treasure Identification and Analysis'
|
|
51
|
+
type:
|
|
52
|
+
type: xpath
|
|
53
|
+
version: xpath-30
|
|
54
|
+
outputs:
|
|
55
|
+
createdEventId: $response.body.eventId
|
|
56
|
+
name: $response.body.name
|
|
57
|
+
- workflowId: get-museum-hours-2
|
|
58
|
+
description: This workflow demonstrates how to get the museum opening hours and buy tickets.
|
|
59
|
+
parameters:
|
|
60
|
+
- in: header
|
|
61
|
+
name: Authorization
|
|
62
|
+
value: Basic Og==
|
|
63
|
+
steps:
|
|
64
|
+
- stepId: get-museum-hours
|
|
65
|
+
description: >-
|
|
66
|
+
Get museum hours by resolving request details with getMuseumHours operationId from openapi.yaml description.
|
|
67
|
+
operationId: museum-api.getMuseumHours
|
|
68
|
+
successCriteria:
|
|
69
|
+
- condition: $statusCode == 200
|
|
70
|
+
`,
|
|
71
|
+
'arazzo.yaml'
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
it('should report when the `xpath` criteria exists', async () => {
|
|
75
|
+
const results = await lintDocument({
|
|
76
|
+
externalRefResolver: new BaseResolver(),
|
|
77
|
+
document,
|
|
78
|
+
config: await makeConfig({
|
|
79
|
+
rules: {},
|
|
80
|
+
arazzoRules: { 'no-criteria-xpath': 'error' },
|
|
81
|
+
}),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
85
|
+
[
|
|
86
|
+
{
|
|
87
|
+
"location": [
|
|
88
|
+
{
|
|
89
|
+
"pointer": "#/workflows/0/steps/0/successCriteria/2/type",
|
|
90
|
+
"reportOnKey": false,
|
|
91
|
+
"source": "arazzo.yaml",
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
"message": "The \`xpath\` type criteria is not supported by Spot.",
|
|
95
|
+
"ruleId": "no-criteria-xpath",
|
|
96
|
+
"severity": "error",
|
|
97
|
+
"suggest": [],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"location": [
|
|
101
|
+
{
|
|
102
|
+
"pointer": "#/workflows/0/steps/0/successCriteria/3/type",
|
|
103
|
+
"reportOnKey": false,
|
|
104
|
+
"source": "arazzo.yaml",
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
"message": "The \`xpath\` type criteria is not supported by Spot.",
|
|
108
|
+
"ruleId": "no-criteria-xpath",
|
|
109
|
+
"severity": "error",
|
|
110
|
+
"suggest": [],
|
|
111
|
+
},
|
|
112
|
+
]
|
|
113
|
+
`);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should not report when the `xpath` criteria exists', async () => {
|
|
117
|
+
const results = await lintDocument({
|
|
118
|
+
externalRefResolver: new BaseResolver(),
|
|
119
|
+
document,
|
|
120
|
+
config: await makeConfig({
|
|
121
|
+
rules: {},
|
|
122
|
+
}),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ArazzoRule } from '../../visitors';
|
|
2
|
+
import type { UserContext } from '../../walk';
|
|
3
|
+
|
|
4
|
+
export const CriteriaUnique: ArazzoRule = () => {
|
|
5
|
+
return {
|
|
6
|
+
FailureActionObject: {
|
|
7
|
+
enter(action, { report, location }: UserContext) {
|
|
8
|
+
const criterias = action.criteria;
|
|
9
|
+
const seen = new Set<string>();
|
|
10
|
+
for (const criteria of criterias) {
|
|
11
|
+
const key = JSON.stringify(criteria);
|
|
12
|
+
if (seen.has(key)) {
|
|
13
|
+
report({
|
|
14
|
+
message: 'The FailureAction criteria items must be unique.',
|
|
15
|
+
location: location.child(['criteria', criterias.indexOf(criteria)]),
|
|
16
|
+
});
|
|
17
|
+
} else {
|
|
18
|
+
seen.add(key);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
SuccessActionObject: {
|
|
24
|
+
enter(action, { report, location }: UserContext) {
|
|
25
|
+
const criterias = action.criteria;
|
|
26
|
+
const seen = new Set<string>();
|
|
27
|
+
for (const criteria of criterias) {
|
|
28
|
+
const key = JSON.stringify(criteria);
|
|
29
|
+
if (seen.has(key)) {
|
|
30
|
+
report({
|
|
31
|
+
message: 'The SuccessAction criteria items must be unique.',
|
|
32
|
+
location: location.child(['criteria', criterias.indexOf(criteria)]),
|
|
33
|
+
});
|
|
34
|
+
} else {
|
|
35
|
+
seen.add(key);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
Step: {
|
|
41
|
+
enter(step, { report, location }: UserContext) {
|
|
42
|
+
if (!step.successCriteria) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const successCriterias = step.successCriteria;
|
|
47
|
+
const seen = new Set<string>();
|
|
48
|
+
|
|
49
|
+
for (const criteria of successCriterias) {
|
|
50
|
+
const key = JSON.stringify(criteria);
|
|
51
|
+
if (seen.has(key)) {
|
|
52
|
+
report({
|
|
53
|
+
message: 'The Step SuccessCriteria items must be unique.',
|
|
54
|
+
location: location.child(['successCriteria', successCriterias.indexOf(criteria)]),
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
seen.add(key);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
};
|
|
@@ -11,6 +11,9 @@ import { ParametersUnique } from './parameters-unique';
|
|
|
11
11
|
import { StepOnSuccessUnique } from './step-onSuccess-unique';
|
|
12
12
|
import { StepOnFailureUnique } from './step-onFailure-unique';
|
|
13
13
|
import { RequestBodyReplacementsUnique } from './requestBody-replacements-unique';
|
|
14
|
+
import { NoCriteriaXpath } from '../spot/no-criteria-xpath';
|
|
15
|
+
import { NoActionsTypeEnd } from '../spot/no-actions-type-end';
|
|
16
|
+
import { CriteriaUnique } from './criteria-unique';
|
|
14
17
|
|
|
15
18
|
import type { ArazzoRule } from '../../visitors';
|
|
16
19
|
import type { ArazzoRuleSet } from '../../oas-types';
|
|
@@ -29,6 +32,9 @@ export const rules: ArazzoRuleSet<'built-in'> = {
|
|
|
29
32
|
'step-onSuccess-unique': StepOnSuccessUnique as ArazzoRule,
|
|
30
33
|
'step-onFailure-unique': StepOnFailureUnique as ArazzoRule,
|
|
31
34
|
'requestBody-replacements-unique': RequestBodyReplacementsUnique as ArazzoRule,
|
|
35
|
+
'no-criteria-xpath': NoCriteriaXpath as ArazzoRule,
|
|
36
|
+
'no-actions-type-end': NoActionsTypeEnd as ArazzoRule,
|
|
37
|
+
'criteria-unique': CriteriaUnique as ArazzoRule,
|
|
32
38
|
};
|
|
33
39
|
|
|
34
40
|
export const preprocessors = {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ArazzoRule } from '../../visitors';
|
|
2
|
+
import type { UserContext } from '../../walk';
|
|
3
|
+
|
|
4
|
+
export const NoActionsTypeEnd: ArazzoRule = () => {
|
|
5
|
+
return {
|
|
6
|
+
FailureActionObject: {
|
|
7
|
+
enter(action, { report, location }: UserContext) {
|
|
8
|
+
if (action.type === 'end') {
|
|
9
|
+
report({
|
|
10
|
+
message: 'The `end` type action is not supported by Spot.',
|
|
11
|
+
location: location.child(['type']),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
SuccessActionObject: {
|
|
17
|
+
enter(action, { report, location }: UserContext) {
|
|
18
|
+
if (action.type === 'end') {
|
|
19
|
+
report({
|
|
20
|
+
message: 'The `end` type action is not supported by Spot.',
|
|
21
|
+
location: location.child(['type']),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ArazzoRule } from '../../visitors';
|
|
2
|
+
import type { UserContext } from '../../walk';
|
|
3
|
+
|
|
4
|
+
export const NoCriteriaXpath: ArazzoRule = () => {
|
|
5
|
+
return {
|
|
6
|
+
CriterionObject: {
|
|
7
|
+
enter(criteria, { report, location }: UserContext) {
|
|
8
|
+
if (!criteria.type) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (criteria?.type?.type === 'xpath' || criteria?.type === 'xpath') {
|
|
12
|
+
report({
|
|
13
|
+
message: 'The `xpath` type criteria is not supported by Spot.',
|
|
14
|
+
location: location.child(['type']),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
};
|
package/src/types/arazzo.ts
CHANGED
|
@@ -205,7 +205,7 @@ const CriterionObject: NodeType = {
|
|
|
205
205
|
return undefined;
|
|
206
206
|
} else if (typeof value === 'string') {
|
|
207
207
|
return { enum: ['regex', 'jsonpath', 'simple', 'xpath'] };
|
|
208
|
-
} else if (value
|
|
208
|
+
} else if (value?.type === 'jsonpath') {
|
|
209
209
|
return 'JSONPathCriterion';
|
|
210
210
|
} else {
|
|
211
211
|
return 'XPathCriterion';
|
|
@@ -122,6 +122,9 @@ const builtInArazzoRules = [
|
|
|
122
122
|
'step-onSuccess-unique',
|
|
123
123
|
'step-onFailure-unique',
|
|
124
124
|
'requestBody-replacements-unique',
|
|
125
|
+
'no-criteria-xpath',
|
|
126
|
+
'no-actions-type-end',
|
|
127
|
+
'criteria-unique',
|
|
125
128
|
] as const;
|
|
126
129
|
|
|
127
130
|
export type BuiltInArazzoRuleId = typeof builtInArazzoRules[number];
|