@redocly/openapi-core 1.0.0-beta.64 → 1.0.0-beta.68
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/__tests__/__snapshots__/bundle.test.ts.snap +126 -0
- package/__tests__/bundle.test.ts +53 -1
- package/__tests__/fixtures/refs/definitions.yaml +3 -0
- package/__tests__/fixtures/refs/external-request-body.yaml +13 -0
- package/__tests__/fixtures/refs/externalref.yaml +35 -0
- package/__tests__/fixtures/refs/hosted.yaml +35 -0
- package/__tests__/fixtures/refs/rename.yaml +1 -0
- package/__tests__/fixtures/refs/requestBody.yaml +9 -0
- package/__tests__/fixtures/refs/simple.yaml +1 -0
- package/__tests__/fixtures/refs/vendor.schema.yaml +20 -0
- package/lib/bundle.js +16 -4
- package/lib/config/all.js +9 -1
- package/lib/config/config.js +1 -1
- package/lib/config/minimal.js +1 -0
- package/lib/config/recommended.js +1 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +2 -1
- package/lib/ref-utils.js +1 -2
- package/lib/rules/builtin.d.ts +6 -0
- package/lib/rules/common/info-description-override.d.ts +2 -0
- package/lib/rules/common/info-description-override.js +24 -0
- package/lib/rules/common/info-license-url.js +1 -0
- package/lib/rules/common/no-http-verbs-in-paths.d.ts +2 -0
- package/lib/rules/common/no-http-verbs-in-paths.js +33 -0
- package/lib/rules/common/operation-4xx-response.d.ts +2 -0
- package/lib/rules/common/operation-4xx-response.js +17 -0
- package/lib/rules/common/operation-description-override.d.ts +2 -0
- package/lib/rules/common/operation-description-override.js +29 -0
- package/lib/rules/common/path-excludes-patterns.d.ts +2 -0
- package/lib/rules/common/path-excludes-patterns.js +22 -0
- package/lib/rules/common/path-segment-plural.d.ts +2 -0
- package/lib/rules/common/path-segment-plural.js +32 -0
- package/lib/rules/common/tag-description-override.d.ts +2 -0
- package/lib/rules/common/tag-description-override.js +25 -0
- package/lib/rules/oas2/index.d.ts +9 -0
- package/lib/rules/oas2/index.js +18 -0
- package/lib/rules/oas2/request-mime-type.d.ts +2 -0
- package/lib/rules/oas2/request-mime-type.js +17 -0
- package/lib/rules/oas2/response-mime-type.d.ts +2 -0
- package/lib/rules/oas2/response-mime-type.js +17 -0
- package/lib/rules/oas3/index.d.ts +3 -0
- package/lib/rules/oas3/index.js +19 -1
- package/lib/rules/oas3/no-server-trailing-slash.js +1 -1
- package/lib/rules/oas3/request-mime-type.d.ts +2 -0
- package/lib/rules/oas3/request-mime-type.js +31 -0
- package/lib/rules/oas3/response-mime-type.d.ts +2 -0
- package/lib/rules/oas3/response-mime-type.js +31 -0
- package/lib/types/oas3_1.js +6 -0
- package/lib/utils.d.ts +11 -0
- package/lib/utils.js +69 -1
- package/package.json +4 -2
- package/src/__tests__/utils.test.ts +19 -1
- package/src/bundle.ts +26 -6
- package/src/config/all.ts +9 -1
- package/src/config/config.ts +2 -2
- package/src/config/minimal.ts +1 -0
- package/src/config/recommended.ts +1 -0
- package/src/index.ts +1 -1
- package/src/ref-utils.ts +1 -3
- package/src/rules/common/__tests__/info-license.test.ts +1 -1
- package/src/rules/common/__tests__/operation-4xx-response.test.ts +108 -0
- package/src/rules/common/info-description-override.ts +24 -0
- package/src/rules/common/info-license-url.ts +1 -0
- package/src/rules/common/no-http-verbs-in-paths.ts +36 -0
- package/src/rules/common/operation-4xx-response.ts +17 -0
- package/src/rules/common/operation-description-override.ts +30 -0
- package/src/rules/common/path-excludes-patterns.ts +23 -0
- package/src/rules/common/path-segment-plural.ts +31 -0
- package/src/rules/common/tag-description-override.ts +25 -0
- package/src/rules/oas2/index.ts +18 -0
- package/src/rules/oas2/request-mime-type.ts +17 -0
- package/src/rules/oas2/response-mime-type.ts +17 -0
- package/src/rules/oas3/__tests__/no-server-trailing-slash.test.ts +19 -0
- package/src/rules/oas3/index.ts +20 -3
- package/src/rules/oas3/no-server-trailing-slash.ts +1 -1
- package/src/rules/oas3/request-mime-type.ts +31 -0
- package/src/rules/oas3/response-mime-type.ts +31 -0
- package/src/rules/utils.ts +1 -1
- package/src/types/oas3_1.ts +7 -0
- package/src/utils.ts +79 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -99,3 +99,129 @@ components:
|
|
|
99
99
|
name: shared-a
|
|
100
100
|
|
|
101
101
|
`;
|
|
102
|
+
|
|
103
|
+
exports[`bundle should not place referened schema inline when component in question is not of type "schemas" 1`] = `
|
|
104
|
+
openapi: 3.0.0
|
|
105
|
+
paths:
|
|
106
|
+
/pet:
|
|
107
|
+
post:
|
|
108
|
+
requestBody:
|
|
109
|
+
content:
|
|
110
|
+
application/json:
|
|
111
|
+
schema:
|
|
112
|
+
$ref: '#/components/schemas/requestBody'
|
|
113
|
+
components:
|
|
114
|
+
schemas:
|
|
115
|
+
requestBody:
|
|
116
|
+
content:
|
|
117
|
+
application/json:
|
|
118
|
+
schema:
|
|
119
|
+
type: object
|
|
120
|
+
properties:
|
|
121
|
+
a:
|
|
122
|
+
type: string
|
|
123
|
+
b:
|
|
124
|
+
type: number
|
|
125
|
+
|
|
126
|
+
`;
|
|
127
|
+
|
|
128
|
+
exports[`bundle should place referenced schema inline when referenced schema name resolves to original schema name 1`] = `
|
|
129
|
+
openapi: 3.1.0
|
|
130
|
+
info:
|
|
131
|
+
title: My API
|
|
132
|
+
description: It ain't so wonderful, but at least it's mine.
|
|
133
|
+
version: '1.0'
|
|
134
|
+
contact:
|
|
135
|
+
email: me@theintenet.com
|
|
136
|
+
name: me
|
|
137
|
+
paths:
|
|
138
|
+
/test:
|
|
139
|
+
get:
|
|
140
|
+
summary: test
|
|
141
|
+
responses:
|
|
142
|
+
'200':
|
|
143
|
+
description: test
|
|
144
|
+
content:
|
|
145
|
+
application/json:
|
|
146
|
+
schema:
|
|
147
|
+
$ref: '#/components/schemas/vendor'
|
|
148
|
+
components:
|
|
149
|
+
schemas:
|
|
150
|
+
vendor:
|
|
151
|
+
title: vendor
|
|
152
|
+
type: object
|
|
153
|
+
description: Vendors
|
|
154
|
+
properties:
|
|
155
|
+
key:
|
|
156
|
+
type: string
|
|
157
|
+
description: System-assigned key for the vendor.
|
|
158
|
+
readOnly: true
|
|
159
|
+
id:
|
|
160
|
+
type: string
|
|
161
|
+
description: >
|
|
162
|
+
Unique identifier of the vendor.
|
|
163
|
+
|
|
164
|
+
You must specify a unique vendor ID when creating a vendor unless
|
|
165
|
+
document sequencing is configured, in which case the ID is
|
|
166
|
+
auto-generated.
|
|
167
|
+
name:
|
|
168
|
+
type: string
|
|
169
|
+
description: Name of the vendor.
|
|
170
|
+
isOneTimeUse:
|
|
171
|
+
type: boolean
|
|
172
|
+
description: One-time use
|
|
173
|
+
default: false
|
|
174
|
+
myvendor:
|
|
175
|
+
$ref: '#/components/schemas/vendor'
|
|
176
|
+
simple:
|
|
177
|
+
type: string
|
|
178
|
+
A:
|
|
179
|
+
type: string
|
|
180
|
+
test:
|
|
181
|
+
$ref: '#/components/schemas/rename-2'
|
|
182
|
+
rename:
|
|
183
|
+
type: string
|
|
184
|
+
rename-2:
|
|
185
|
+
type: number
|
|
186
|
+
|
|
187
|
+
`;
|
|
188
|
+
|
|
189
|
+
exports[`bundle should pull hosted schema 1`] = `
|
|
190
|
+
openapi: 3.0.3
|
|
191
|
+
info:
|
|
192
|
+
title: bugtest
|
|
193
|
+
version: '1.0'
|
|
194
|
+
description: Demo
|
|
195
|
+
license:
|
|
196
|
+
name: DEMO
|
|
197
|
+
url: https://demo.com
|
|
198
|
+
servers:
|
|
199
|
+
- url: http://demo.com/api
|
|
200
|
+
paths:
|
|
201
|
+
/customer:
|
|
202
|
+
summary: Customer scope
|
|
203
|
+
get:
|
|
204
|
+
summary: Get demo no refs
|
|
205
|
+
operationId: GetCustomer
|
|
206
|
+
description: Returns Demo No Refs
|
|
207
|
+
responses:
|
|
208
|
+
'200':
|
|
209
|
+
description: Demo No Refs
|
|
210
|
+
content:
|
|
211
|
+
application/json:
|
|
212
|
+
schema:
|
|
213
|
+
$ref: '#/components/schemas/Customer'
|
|
214
|
+
components:
|
|
215
|
+
schemas:
|
|
216
|
+
Customer:
|
|
217
|
+
type: object
|
|
218
|
+
properties:
|
|
219
|
+
customerName:
|
|
220
|
+
type: string
|
|
221
|
+
accounts:
|
|
222
|
+
type: array
|
|
223
|
+
items:
|
|
224
|
+
$ref: '#/components/schemas/someexternal'
|
|
225
|
+
someexternal: External schema content
|
|
226
|
+
|
|
227
|
+
`;
|
package/__tests__/bundle.test.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { BaseResolver } from '../src/resolve';
|
|
|
10
10
|
describe('bundle', () => {
|
|
11
11
|
expect.addSnapshotSerializer(yamlSerializer);
|
|
12
12
|
|
|
13
|
-
const testDocument =
|
|
13
|
+
const testDocument = parseYamlToDocument(
|
|
14
14
|
outdent`
|
|
15
15
|
openapi: 3.0.0
|
|
16
16
|
paths:
|
|
@@ -77,4 +77,56 @@ describe('bundle', () => {
|
|
|
77
77
|
expect(problems).toHaveLength(0);
|
|
78
78
|
expect(res.parsed).toMatchSnapshot();
|
|
79
79
|
});
|
|
80
|
+
|
|
81
|
+
it('should place referenced schema inline when referenced schema name resolves to original schema name', async () => {
|
|
82
|
+
const { bundle: res, problems } = await bundle({
|
|
83
|
+
config: new Config({}),
|
|
84
|
+
ref: path.join(__dirname, 'fixtures/refs/externalref.yaml'),
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
expect(problems).toHaveLength(0);
|
|
88
|
+
expect(res.parsed).toMatchSnapshot();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should not place referened schema inline when component in question is not of type "schemas"', async () => {
|
|
92
|
+
const { bundle: res, problems } = await bundle({
|
|
93
|
+
config: new Config({}),
|
|
94
|
+
ref: path.join(__dirname, 'fixtures/refs/external-request-body.yaml'),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(problems).toHaveLength(0);
|
|
98
|
+
expect(res.parsed).toMatchSnapshot();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should pull hosted schema', async () => {
|
|
102
|
+
const fetchMock = jest.fn(
|
|
103
|
+
() => Promise.resolve({
|
|
104
|
+
ok: true,
|
|
105
|
+
text: () => 'External schema content',
|
|
106
|
+
headers: {
|
|
107
|
+
get: () => ''
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const { bundle: res, problems } = await bundle({
|
|
113
|
+
config: new Config({}),
|
|
114
|
+
externalRefResolver: new BaseResolver({
|
|
115
|
+
http: {
|
|
116
|
+
customFetch: fetchMock,
|
|
117
|
+
headers: []
|
|
118
|
+
}
|
|
119
|
+
}),
|
|
120
|
+
ref: path.join(__dirname, 'fixtures/refs/hosted.yaml')
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(problems).toHaveLength(0);
|
|
124
|
+
expect(fetchMock).toHaveBeenCalledWith(
|
|
125
|
+
"https://someexternal.schema",
|
|
126
|
+
{
|
|
127
|
+
headers: {}
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
expect(res.parsed).toMatchSnapshot();
|
|
131
|
+
})
|
|
80
132
|
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
openapi: 3.1.0
|
|
2
|
+
info:
|
|
3
|
+
title: My API
|
|
4
|
+
description: It ain't so wonderful, but at least it's mine.
|
|
5
|
+
version: '1.0'
|
|
6
|
+
contact:
|
|
7
|
+
email: me@theintenet.com
|
|
8
|
+
name: me
|
|
9
|
+
paths:
|
|
10
|
+
/test:
|
|
11
|
+
get:
|
|
12
|
+
summary: 'test'
|
|
13
|
+
responses:
|
|
14
|
+
200:
|
|
15
|
+
description: test
|
|
16
|
+
content:
|
|
17
|
+
application/json:
|
|
18
|
+
schema:
|
|
19
|
+
$ref: ./vendor.schema.yaml
|
|
20
|
+
components:
|
|
21
|
+
schemas:
|
|
22
|
+
vendor:
|
|
23
|
+
$ref: ./vendor.schema.yaml
|
|
24
|
+
myvendor:
|
|
25
|
+
$ref: ./vendor.schema.yaml
|
|
26
|
+
simple:
|
|
27
|
+
$ref: ./simple.yaml
|
|
28
|
+
A:
|
|
29
|
+
$ref: ./definitions.yaml#/$defs/A
|
|
30
|
+
test:
|
|
31
|
+
$ref: ./rename.yaml
|
|
32
|
+
rename:
|
|
33
|
+
type: string
|
|
34
|
+
rename-2:
|
|
35
|
+
$ref: ./rename.yaml
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
openapi: "3.0.3"
|
|
2
|
+
info:
|
|
3
|
+
title: bugtest
|
|
4
|
+
version: "1.0"
|
|
5
|
+
description: Demo
|
|
6
|
+
license:
|
|
7
|
+
name: DEMO
|
|
8
|
+
url: https://demo.com
|
|
9
|
+
servers:
|
|
10
|
+
- url: http://demo.com/api
|
|
11
|
+
paths:
|
|
12
|
+
/customer:
|
|
13
|
+
summary: "Customer scope"
|
|
14
|
+
get:
|
|
15
|
+
summary: "Get demo no refs"
|
|
16
|
+
operationId: GetCustomer
|
|
17
|
+
description: "Returns Demo No Refs"
|
|
18
|
+
responses:
|
|
19
|
+
200:
|
|
20
|
+
description: Demo No Refs
|
|
21
|
+
content:
|
|
22
|
+
application/json:
|
|
23
|
+
schema:
|
|
24
|
+
$ref: "#/components/schemas/Customer"
|
|
25
|
+
components:
|
|
26
|
+
schemas:
|
|
27
|
+
Customer:
|
|
28
|
+
type: object
|
|
29
|
+
properties:
|
|
30
|
+
customerName:
|
|
31
|
+
type: string
|
|
32
|
+
accounts:
|
|
33
|
+
type: array
|
|
34
|
+
items:
|
|
35
|
+
$ref: "https://someexternal.schema"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
type: number
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
type: string
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
title: vendor
|
|
2
|
+
type: object
|
|
3
|
+
description: Vendors
|
|
4
|
+
properties:
|
|
5
|
+
key:
|
|
6
|
+
type: string
|
|
7
|
+
description: System-assigned key for the vendor.
|
|
8
|
+
readOnly: true
|
|
9
|
+
id:
|
|
10
|
+
type: string
|
|
11
|
+
description: |
|
|
12
|
+
Unique identifier of the vendor.
|
|
13
|
+
You must specify a unique vendor ID when creating a vendor unless document sequencing is configured, in which case the ID is auto-generated.
|
|
14
|
+
name:
|
|
15
|
+
type: string
|
|
16
|
+
description: Name of the vendor.
|
|
17
|
+
isOneTimeUse:
|
|
18
|
+
type: boolean
|
|
19
|
+
description: One-time use
|
|
20
|
+
default: false
|
package/lib/bundle.js
CHANGED
|
@@ -49,7 +49,11 @@ function bundleDocument(opts) {
|
|
|
49
49
|
const oasVersion = oas_types_1.detectOpenAPI(document.parsed);
|
|
50
50
|
const oasMajorVersion = oas_types_1.openAPIMajor(oasVersion);
|
|
51
51
|
const rules = config.getRulesForOasVersion(oasMajorVersion);
|
|
52
|
-
const types = types_1.normalizeTypes(config.extendTypes((customTypes !== null && customTypes !== void 0 ? customTypes : oasMajorVersion === oas_types_1.OasMajorVersion.Version3)
|
|
52
|
+
const types = types_1.normalizeTypes(config.extendTypes((customTypes !== null && customTypes !== void 0 ? customTypes : oasMajorVersion === oas_types_1.OasMajorVersion.Version3)
|
|
53
|
+
? oasVersion === OasVersion.Version3_1
|
|
54
|
+
? oas3_1_1.Oas3_1Types
|
|
55
|
+
: oas3_1.Oas3Types
|
|
56
|
+
: oas2_1.Oas2Types, oasVersion), config);
|
|
53
57
|
const preprocessors = rules_1.initRules(rules, config, 'preprocessors', oasVersion);
|
|
54
58
|
const decorators = rules_1.initRules(rules, config, 'decorators', oasVersion);
|
|
55
59
|
const ctx = {
|
|
@@ -210,6 +214,14 @@ function makeBundleVisitor(version, dereference, rootDocument) {
|
|
|
210
214
|
return `#/${componentType}/${name}`;
|
|
211
215
|
}
|
|
212
216
|
}
|
|
217
|
+
function isEqualOrEqualRef(node, target, ctx) {
|
|
218
|
+
var _a;
|
|
219
|
+
if (ref_utils_1.isRef(node) &&
|
|
220
|
+
((_a = ctx.resolve(node).location) === null || _a === void 0 ? void 0 : _a.absolutePointer) === target.location.absolutePointer) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
return isEqual(node, target.node);
|
|
224
|
+
}
|
|
213
225
|
function getComponentName(target, componentType, ctx) {
|
|
214
226
|
const [fileRef, pointer] = [target.location.source.absoluteRef, target.location.pointer];
|
|
215
227
|
const componentsGroup = components[componentType];
|
|
@@ -219,17 +231,17 @@ function makeBundleVisitor(version, dereference, rootDocument) {
|
|
|
219
231
|
name = refParts.pop() + (name ? `-${name}` : '');
|
|
220
232
|
if (!componentsGroup ||
|
|
221
233
|
!componentsGroup[name] ||
|
|
222
|
-
|
|
234
|
+
isEqualOrEqualRef(componentsGroup[name], target, ctx)) {
|
|
223
235
|
return name;
|
|
224
236
|
}
|
|
225
237
|
}
|
|
226
238
|
name = ref_utils_1.refBaseName(fileRef) + (name ? `_${name}` : '');
|
|
227
|
-
if (!componentsGroup[name] ||
|
|
239
|
+
if (!componentsGroup[name] || isEqualOrEqualRef(componentsGroup[name], target, ctx)) {
|
|
228
240
|
return name;
|
|
229
241
|
}
|
|
230
242
|
const prevName = name;
|
|
231
243
|
let serialId = 2;
|
|
232
|
-
while (componentsGroup[name] && !
|
|
244
|
+
while (componentsGroup[name] && !isEqualOrEqualRef(componentsGroup[name], target, ctx)) {
|
|
233
245
|
name = `${prevName}-${serialId}`;
|
|
234
246
|
serialId++;
|
|
235
247
|
}
|
package/lib/config/all.js
CHANGED
|
@@ -12,11 +12,13 @@ exports.default = {
|
|
|
12
12
|
'no-identical-paths': 'error',
|
|
13
13
|
'no-ambiguous-paths': 'error',
|
|
14
14
|
'no-path-trailing-slash': 'error',
|
|
15
|
+
'path-segment-plural': 'error',
|
|
15
16
|
'path-declaration-must-exist': 'error',
|
|
16
17
|
'path-not-include-query': 'error',
|
|
17
18
|
'path-parameters-defined': 'error',
|
|
18
19
|
'operation-description': 'error',
|
|
19
20
|
'operation-2xx-response': 'error',
|
|
21
|
+
'operation-4xx-response': 'error',
|
|
20
22
|
'operation-operationId': 'error',
|
|
21
23
|
'operation-summary': 'error',
|
|
22
24
|
'operation-operationId-unique': 'error',
|
|
@@ -29,6 +31,12 @@ exports.default = {
|
|
|
29
31
|
'no-enum-type-mismatch': 'error',
|
|
30
32
|
'boolean-parameter-prefixes': 'error',
|
|
31
33
|
'paths-kebab-case': 'error',
|
|
34
|
+
'no-http-verbs-in-paths': 'error',
|
|
35
|
+
'path-excludes-patterns': {
|
|
36
|
+
severity: 'error',
|
|
37
|
+
patterns: [],
|
|
38
|
+
},
|
|
39
|
+
'request-mime-type': 'error',
|
|
32
40
|
spec: 'error',
|
|
33
41
|
},
|
|
34
42
|
oas3_0Rules: {
|
|
@@ -49,5 +57,5 @@ exports.default = {
|
|
|
49
57
|
'no-unused-components': 'error',
|
|
50
58
|
'no-undefined-server-variable': 'error',
|
|
51
59
|
'no-servers-empty-enum': 'error',
|
|
52
|
-
}
|
|
60
|
+
},
|
|
53
61
|
};
|
package/lib/config/config.js
CHANGED
|
@@ -73,7 +73,7 @@ class LintConfig {
|
|
|
73
73
|
const ignoreFile = path.join(dir, exports.IGNORE_FILE);
|
|
74
74
|
const mapped = {};
|
|
75
75
|
for (const absFileName of Object.keys(this.ignore)) {
|
|
76
|
-
const ignoredRules = (mapped[path.relative(dir, absFileName)] = this.ignore[absFileName]);
|
|
76
|
+
const ignoredRules = (mapped[utils_1.slash(path.relative(dir, absFileName))] = this.ignore[absFileName]);
|
|
77
77
|
for (const ruleId of Object.keys(ignoredRules)) {
|
|
78
78
|
ignoredRules[ruleId] = Array.from(ignoredRules[ruleId]);
|
|
79
79
|
}
|
package/lib/config/minimal.js
CHANGED
|
@@ -17,6 +17,7 @@ exports.default = {
|
|
|
17
17
|
'path-parameters-defined': 'warn',
|
|
18
18
|
'operation-description': 'off',
|
|
19
19
|
'operation-2xx-response': 'warn',
|
|
20
|
+
'operation-4xx-response': 'off',
|
|
20
21
|
'operation-operationId': 'warn',
|
|
21
22
|
'operation-summary': 'warn',
|
|
22
23
|
'operation-operationId-unique': 'warn',
|
|
@@ -17,6 +17,7 @@ exports.default = {
|
|
|
17
17
|
'path-parameters-defined': 'error',
|
|
18
18
|
'operation-description': 'off',
|
|
19
19
|
'operation-2xx-response': 'warn',
|
|
20
|
+
'operation-4xx-response': 'warn',
|
|
20
21
|
'operation-operationId': 'warn',
|
|
21
22
|
'operation-summary': 'error',
|
|
22
23
|
'operation-operationId-unique': 'error',
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.bundleDocument = exports.bundle = exports.lintConfig = exports.lintFromString = exports.lintDocument = exports.validate = exports.lint = exports.getTotals = exports.formatProblems = exports.getLineColLocation = exports.getAstNodeByPointer = exports.walkDocument = exports.normalizeVisitors = exports.OasVersion = exports.openAPIMajor = exports.OasMajorVersion = exports.detectOpenAPI = exports.unescapePointer = exports.stringifyYaml = exports.parseYaml = exports.makeDocumentFromString = exports.YamlParseError = exports.ResolveError = exports.resolveDocument = exports.BaseResolver = exports.Source = exports.RedoclyClient = exports.loadConfig = exports.IGNORE_FILE = exports.LintConfig = exports.Config = exports.Stats = exports.normalizeTypes = exports.ConfigTypes = exports.Oas2Types = exports.Oas3Types = exports.Oas3_1Types = exports.readFileFromUrl = void 0;
|
|
3
|
+
exports.bundleDocument = exports.bundle = exports.lintConfig = exports.lintFromString = exports.lintDocument = exports.validate = exports.lint = exports.getTotals = exports.formatProblems = exports.getLineColLocation = exports.getAstNodeByPointer = exports.walkDocument = exports.normalizeVisitors = exports.OasVersion = exports.openAPIMajor = exports.OasMajorVersion = exports.detectOpenAPI = exports.unescapePointer = exports.stringifyYaml = exports.parseYaml = exports.makeDocumentFromString = exports.YamlParseError = exports.ResolveError = exports.resolveDocument = exports.BaseResolver = exports.Source = exports.RedoclyClient = exports.loadConfig = exports.IGNORE_FILE = exports.LintConfig = exports.Config = exports.Stats = exports.normalizeTypes = exports.ConfigTypes = exports.Oas2Types = exports.Oas3Types = exports.Oas3_1Types = exports.slash = exports.readFileFromUrl = void 0;
|
|
4
4
|
var utils_1 = require("./utils");
|
|
5
5
|
Object.defineProperty(exports, "readFileFromUrl", { enumerable: true, get: function () { return utils_1.readFileFromUrl; } });
|
|
6
|
+
Object.defineProperty(exports, "slash", { enumerable: true, get: function () { return utils_1.slash; } });
|
|
6
7
|
var oas3_1_1 = require("./types/oas3_1");
|
|
7
8
|
Object.defineProperty(exports, "Oas3_1Types", { enumerable: true, get: function () { return oas3_1_1.Oas3_1Types; } });
|
|
8
9
|
var oas3_1 = require("./types/oas3");
|
package/lib/ref-utils.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isMappingRef = exports.isAbsoluteUrl = exports.refBaseName = exports.pointerBaseName = exports.parsePointer = exports.parseRef = exports.escapePointer = exports.unescapePointer = exports.Location = exports.isRef = exports.joinPointer = void 0;
|
|
4
|
-
const path_1 = require("path");
|
|
5
4
|
function joinPointer(base, key) {
|
|
6
5
|
if (base === '')
|
|
7
6
|
base = '#/';
|
|
@@ -56,7 +55,7 @@ function pointerBaseName(pointer) {
|
|
|
56
55
|
}
|
|
57
56
|
exports.pointerBaseName = pointerBaseName;
|
|
58
57
|
function refBaseName(ref) {
|
|
59
|
-
const parts = ref.split(
|
|
58
|
+
const parts = ref.split(/[\/\\]/); // split by '\' and '/'
|
|
60
59
|
return parts[parts.length - 1].split('.')[0];
|
|
61
60
|
}
|
|
62
61
|
exports.refBaseName = refBaseName;
|
package/lib/rules/builtin.d.ts
CHANGED
|
@@ -7,8 +7,14 @@ export declare const preprocessors: {
|
|
|
7
7
|
export declare const decorators: {
|
|
8
8
|
oas3: {
|
|
9
9
|
'registry-dependencies': import("../visitors").Oas3Decorator;
|
|
10
|
+
'operation-description-override': import("../visitors").Oas3Decorator;
|
|
11
|
+
'tag-description-override': import("../visitors").Oas3Decorator;
|
|
12
|
+
'info-description-override': import("../visitors").Oas3Decorator;
|
|
10
13
|
};
|
|
11
14
|
oas2: {
|
|
12
15
|
'registry-dependencies': import("../visitors").Oas2Decorator;
|
|
16
|
+
'operation-description-override': import("../visitors").Oas2Decorator;
|
|
17
|
+
'tag-description-override': import("../visitors").Oas2Decorator;
|
|
18
|
+
'info-description-override': import("../visitors").Oas2Decorator;
|
|
13
19
|
};
|
|
14
20
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InfoDescriptionOverride = void 0;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const InfoDescriptionOverride = ({ filePath }) => {
|
|
6
|
+
return {
|
|
7
|
+
Info: {
|
|
8
|
+
leave(info, { report, location }) {
|
|
9
|
+
if (!filePath)
|
|
10
|
+
throw new Error(`Parameter "filePath" is not provided for "info-description-override" rule`);
|
|
11
|
+
try {
|
|
12
|
+
info.description = utils_1.readFileAsStringSync(filePath);
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
report({
|
|
16
|
+
message: `Failed to read markdown override file for "info.description".\n${e.message}`,
|
|
17
|
+
location: location.child('description'),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
exports.InfoDescriptionOverride = InfoDescriptionOverride;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NoHttpVerbsInPaths = void 0;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const httpMethods = ['get', 'head', 'post', 'put', 'patch', 'delete', 'options', 'trace'];
|
|
6
|
+
const NoHttpVerbsInPaths = ({ splitIntoWords }) => {
|
|
7
|
+
return {
|
|
8
|
+
PathItem(_path, { key, report, location }) {
|
|
9
|
+
const pathKey = key.toString();
|
|
10
|
+
if (!pathKey.startsWith('/'))
|
|
11
|
+
return;
|
|
12
|
+
const pathSegments = pathKey.split('/');
|
|
13
|
+
for (const pathSegment of pathSegments) {
|
|
14
|
+
if (!pathSegment || utils_1.isPathParameter(pathSegment))
|
|
15
|
+
continue;
|
|
16
|
+
const isHttpMethodIncluded = (method) => {
|
|
17
|
+
return splitIntoWords
|
|
18
|
+
? utils_1.splitCamelCaseIntoWords(pathSegment).has(method)
|
|
19
|
+
: pathSegment.toLocaleLowerCase().includes(method);
|
|
20
|
+
};
|
|
21
|
+
for (const method of httpMethods) {
|
|
22
|
+
if (isHttpMethodIncluded(method)) {
|
|
23
|
+
report({
|
|
24
|
+
message: `path \`${pathKey}\` should not contain http verb ${method}`,
|
|
25
|
+
location: location.key(),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
exports.NoHttpVerbsInPaths = NoHttpVerbsInPaths;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Operation4xxResponse = void 0;
|
|
4
|
+
const Operation4xxResponse = () => {
|
|
5
|
+
return {
|
|
6
|
+
ResponsesMap(responses, { report }) {
|
|
7
|
+
const codes = Object.keys(responses);
|
|
8
|
+
if (!codes.some((code) => /4[Xx0-9]{2}/.test(code))) {
|
|
9
|
+
report({
|
|
10
|
+
message: 'Operation must have at least one `4xx` response.',
|
|
11
|
+
location: { reportOnKey: true },
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
exports.Operation4xxResponse = Operation4xxResponse;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OperationDescriptionOverride = void 0;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const OperationDescriptionOverride = ({ operationIds }) => {
|
|
6
|
+
return {
|
|
7
|
+
Operation: {
|
|
8
|
+
leave(operation, { report, location }) {
|
|
9
|
+
if (!operation.operationId)
|
|
10
|
+
return;
|
|
11
|
+
if (!operationIds)
|
|
12
|
+
throw new Error(`Parameter "operationIds" is not provided for "operation-description-override" rule`);
|
|
13
|
+
const operationId = operation.operationId;
|
|
14
|
+
if (operationIds[operationId]) {
|
|
15
|
+
try {
|
|
16
|
+
operation.description = utils_1.readFileAsStringSync(operationIds[operationId]);
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
report({
|
|
20
|
+
message: `Failed to read markdown override file for operation "${operationId}".\n${e.message}`,
|
|
21
|
+
location: location.child('operationId').key(),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
exports.OperationDescriptionOverride = OperationDescriptionOverride;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PathExcludesPatterns = void 0;
|
|
4
|
+
const PathExcludesPatterns = ({ patterns }) => {
|
|
5
|
+
return {
|
|
6
|
+
PathItem(_path, { report, key, location }) {
|
|
7
|
+
if (!patterns)
|
|
8
|
+
throw new Error(`Parameter "patterns" is not provided for "path-excludes-patterns" rule`);
|
|
9
|
+
const pathKey = key.toString();
|
|
10
|
+
if (pathKey.startsWith('/')) {
|
|
11
|
+
const matches = patterns.filter((pattern) => pathKey.match(pattern));
|
|
12
|
+
for (const match of matches) {
|
|
13
|
+
report({
|
|
14
|
+
message: `path \`${pathKey}\` should not match regex pattern: \`${match}\``,
|
|
15
|
+
location: location.key(),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
exports.PathExcludesPatterns = PathExcludesPatterns;
|