@redocly/openapi-core 1.0.0-beta.111 → 1.0.0-beta.113
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/lib/config/all.js +0 -1
- package/lib/config/config-resolvers.js +22 -18
- package/lib/config/config.d.ts +4 -10
- package/lib/config/config.js +1 -1
- package/lib/config/load.d.ts +1 -1
- package/lib/config/load.js +10 -10
- package/lib/config/minimal.js +0 -1
- package/lib/config/recommended.js +0 -1
- package/lib/config/rules.d.ts +6 -3
- package/lib/config/rules.js +3 -2
- package/lib/config/types.d.ts +3 -0
- package/lib/ref-utils.d.ts +1 -0
- package/lib/ref-utils.js +5 -1
- package/lib/resolve.js +19 -0
- package/lib/rules/common/assertions/asserts.d.ts +22 -5
- package/lib/rules/common/assertions/asserts.js +25 -0
- package/lib/rules/common/assertions/index.d.ts +27 -2
- package/lib/rules/common/assertions/index.js +6 -29
- package/lib/rules/common/assertions/utils.d.ts +7 -14
- package/lib/rules/common/assertions/utils.js +129 -97
- package/lib/rules/common/spec.js +6 -0
- package/lib/rules/oas2/index.d.ts +0 -1
- package/lib/rules/oas2/index.js +0 -2
- package/lib/rules/oas3/index.js +0 -2
- package/lib/rules/utils.js +3 -0
- package/lib/types/oas2.js +11 -7
- package/lib/types/oas3.js +15 -10
- package/lib/types/oas3_1.js +1 -0
- package/lib/types/redocly-yaml.js +49 -27
- package/lib/utils.d.ts +2 -0
- package/lib/utils.js +13 -1
- package/lib/visitors.d.ts +2 -1
- package/lib/visitors.js +1 -0
- package/lib/walk.js +7 -1
- package/package.json +1 -1
- package/src/__tests__/bundle.test.ts +46 -0
- package/src/__tests__/lint.test.ts +24 -5
- package/src/benchmark/benches/rebilly.yaml +36 -28
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +1 -3
- package/src/config/__tests__/config-resolvers.test.ts +6 -7
- package/src/config/__tests__/fixtures/load-redocly.yaml +2 -0
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-custom-function.yaml +6 -5
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-wrong-custom-function.yaml +0 -1
- package/src/config/__tests__/load.test.ts +4 -1
- package/src/config/all.ts +0 -1
- package/src/config/config-resolvers.ts +44 -31
- package/src/config/config.ts +6 -5
- package/src/config/load.ts +19 -9
- package/src/config/minimal.ts +0 -1
- package/src/config/recommended.ts +0 -1
- package/src/config/rules.ts +11 -3
- package/src/config/types.ts +2 -0
- package/src/ref-utils.ts +4 -0
- package/src/resolve.ts +25 -3
- package/src/rules/common/__tests__/spec.test.ts +170 -0
- package/src/rules/common/assertions/__tests__/asserts.test.ts +7 -3
- package/src/rules/common/assertions/__tests__/index.test.ts +41 -20
- package/src/rules/common/assertions/__tests__/utils.test.ts +43 -17
- package/src/rules/common/assertions/asserts.ts +60 -8
- package/src/rules/common/assertions/index.ts +36 -46
- package/src/rules/common/assertions/utils.ts +204 -127
- package/src/rules/common/spec.ts +7 -0
- package/src/rules/oas2/index.ts +0 -2
- package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +32 -0
- package/src/rules/oas3/index.ts +0 -2
- package/src/rules/utils.ts +4 -0
- package/src/types/oas2.ts +11 -7
- package/src/types/oas3.ts +15 -10
- package/src/types/oas3_1.ts +1 -0
- package/src/types/redocly-yaml.ts +49 -29
- package/src/utils.ts +11 -0
- package/src/visitors.ts +7 -1
- package/src/walk.ts +8 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/rules/common/info-description.d.ts +0 -2
- package/lib/rules/common/info-description.js +0 -12
- package/src/rules/common/__tests__/info-description.test.ts +0 -102
- package/src/rules/common/info-description.ts +0 -10
package/src/config/load.ts
CHANGED
|
@@ -15,18 +15,21 @@ async function addConfigMetadata({
|
|
|
15
15
|
customExtends,
|
|
16
16
|
configPath,
|
|
17
17
|
tokens,
|
|
18
|
+
files,
|
|
19
|
+
region,
|
|
18
20
|
}: {
|
|
19
21
|
rawConfig: RawConfig;
|
|
20
22
|
customExtends?: string[];
|
|
21
23
|
configPath?: string;
|
|
22
24
|
tokens?: RegionalTokenWithValidity[];
|
|
25
|
+
files?: string[];
|
|
26
|
+
region?: Region;
|
|
23
27
|
}): Promise<Config> {
|
|
24
28
|
if (customExtends !== undefined) {
|
|
25
29
|
rawConfig.styleguide = rawConfig.styleguide || {};
|
|
26
30
|
rawConfig.styleguide.extends = customExtends;
|
|
27
31
|
} else if (isEmptyObject(rawConfig)) {
|
|
28
|
-
|
|
29
|
-
// rawConfig.styleguide = { extends: ['recommended'], recommendedFallback: true };
|
|
32
|
+
rawConfig.styleguide = { extends: ['recommended'], recommendedFallback: true };
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
if (tokens?.length) {
|
|
@@ -58,7 +61,10 @@ async function addConfigMetadata({
|
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
|
|
61
|
-
return resolveConfig(
|
|
64
|
+
return resolveConfig(
|
|
65
|
+
{ ...rawConfig, files: files ?? rawConfig.files, region: region ?? rawConfig.region },
|
|
66
|
+
configPath
|
|
67
|
+
);
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
export async function loadConfig(
|
|
@@ -71,11 +77,7 @@ export async function loadConfig(
|
|
|
71
77
|
} = {}
|
|
72
78
|
): Promise<Config> {
|
|
73
79
|
const { configPath = findConfig(), customExtends, processRawConfig, files, region } = options;
|
|
74
|
-
const
|
|
75
|
-
const rawConfig = { ...config, files: files ?? config.files, region: region ?? config.region };
|
|
76
|
-
if (typeof processRawConfig === 'function') {
|
|
77
|
-
await processRawConfig(rawConfig);
|
|
78
|
-
}
|
|
80
|
+
const rawConfig = await getConfig(configPath, processRawConfig);
|
|
79
81
|
|
|
80
82
|
const redoclyClient = new RedoclyClient();
|
|
81
83
|
const tokens = await redoclyClient.getTokens();
|
|
@@ -85,6 +87,8 @@ export async function loadConfig(
|
|
|
85
87
|
customExtends,
|
|
86
88
|
configPath,
|
|
87
89
|
tokens,
|
|
90
|
+
files,
|
|
91
|
+
region,
|
|
88
92
|
});
|
|
89
93
|
}
|
|
90
94
|
|
|
@@ -105,11 +109,17 @@ export function findConfig(dir?: string): string | undefined {
|
|
|
105
109
|
return existingConfigFiles[0];
|
|
106
110
|
}
|
|
107
111
|
|
|
108
|
-
export async function getConfig(
|
|
112
|
+
export async function getConfig(
|
|
113
|
+
configPath: string | undefined = findConfig(),
|
|
114
|
+
processRawConfig?: (rawConfig: RawConfig) => void | Promise<void>
|
|
115
|
+
): Promise<RawConfig> {
|
|
109
116
|
if (!configPath || !doesYamlFileExist(configPath)) return {};
|
|
110
117
|
try {
|
|
111
118
|
const rawConfig =
|
|
112
119
|
(await loadYaml<RawConfig & DeprecatedInRawConfig & FlatRawConfig>(configPath)) || {};
|
|
120
|
+
if (typeof processRawConfig === 'function') {
|
|
121
|
+
await processRawConfig(rawConfig);
|
|
122
|
+
}
|
|
113
123
|
return transformConfig(rawConfig);
|
|
114
124
|
} catch (e) {
|
|
115
125
|
throw new Error(`Error parsing config file at '${configPath}': ${e.message}`);
|
package/src/config/minimal.ts
CHANGED
package/src/config/rules.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { RuleSet, OasVersion } from '../oas-types';
|
|
2
2
|
import { StyleguideConfig } from './config';
|
|
3
3
|
import { isDefined } from '../utils';
|
|
4
|
+
import type { ProblemSeverity } from '../walk';
|
|
5
|
+
|
|
6
|
+
type InitializedRule = {
|
|
7
|
+
severity: ProblemSeverity;
|
|
8
|
+
ruleId: string;
|
|
9
|
+
visitor: any;
|
|
10
|
+
};
|
|
4
11
|
|
|
5
12
|
export function initRules<T extends Function, P extends RuleSet<T>>(
|
|
6
13
|
rules: P[],
|
|
7
14
|
config: StyleguideConfig,
|
|
8
15
|
type: 'rules' | 'preprocessors' | 'decorators',
|
|
9
16
|
oasVersion: OasVersion
|
|
10
|
-
) {
|
|
17
|
+
): InitializedRule[] {
|
|
11
18
|
return rules
|
|
12
19
|
.flatMap((ruleset) =>
|
|
13
20
|
Object.keys(ruleset).map((ruleId) => {
|
|
@@ -23,19 +30,20 @@ export function initRules<T extends Function, P extends RuleSet<T>>(
|
|
|
23
30
|
if (ruleSettings.severity === 'off') {
|
|
24
31
|
return undefined;
|
|
25
32
|
}
|
|
33
|
+
const severity: ProblemSeverity = ruleSettings.severity;
|
|
26
34
|
|
|
27
35
|
const visitors = rule(ruleSettings);
|
|
28
36
|
|
|
29
37
|
if (Array.isArray(visitors)) {
|
|
30
38
|
return visitors.map((visitor: any) => ({
|
|
31
|
-
severity
|
|
39
|
+
severity,
|
|
32
40
|
ruleId,
|
|
33
41
|
visitor: visitor,
|
|
34
42
|
}));
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
return {
|
|
38
|
-
severity
|
|
46
|
+
severity,
|
|
39
47
|
ruleId,
|
|
40
48
|
visitor: visitors, // note: actually it is only one visitor object
|
|
41
49
|
};
|
package/src/config/types.ts
CHANGED
package/src/ref-utils.ts
CHANGED
package/src/resolve.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { OasRef } from './typings/openapi';
|
|
4
|
-
import { isRef, joinPointer, escapePointer, parseRef, isAbsoluteUrl } from './ref-utils';
|
|
4
|
+
import { isRef, joinPointer, escapePointer, parseRef, isAbsoluteUrl, isAnchor } from './ref-utils';
|
|
5
5
|
import type { YAMLNode, LoadOptions } from 'yaml-ast-parser';
|
|
6
6
|
import { NormalizedNodeType, isNamedType } from './types';
|
|
7
|
-
import { readFileFromUrl, parseYaml } from './utils';
|
|
7
|
+
import { readFileFromUrl, parseYaml, nextTick } from './utils';
|
|
8
8
|
import { ResolveConfig } from './config/types';
|
|
9
9
|
|
|
10
10
|
export type CollectedRefs = Map<string /* absoluteFilePath */, Document>;
|
|
@@ -237,6 +237,7 @@ export async function resolveDocument(opts: {
|
|
|
237
237
|
type: any
|
|
238
238
|
) {
|
|
239
239
|
const rootNodeDocAbsoluteRef = rootNodeDocument.source.absoluteRef;
|
|
240
|
+
const anchorRefsMap: Map<string, any> = new Map();
|
|
240
241
|
|
|
241
242
|
walk(rootNode, type, rootNodeDocAbsoluteRef + rootNodePointer);
|
|
242
243
|
|
|
@@ -252,6 +253,11 @@ export async function resolveDocument(opts: {
|
|
|
252
253
|
|
|
253
254
|
seedNodes.add(nodeId);
|
|
254
255
|
|
|
256
|
+
const [_, anchor] = Object.entries(node).find(([key]) => key === '$anchor') || [];
|
|
257
|
+
if (anchor) {
|
|
258
|
+
anchorRefsMap.set(`#${anchor}`, node);
|
|
259
|
+
}
|
|
260
|
+
|
|
255
261
|
if (Array.isArray(node)) {
|
|
256
262
|
const itemsType = type.items;
|
|
257
263
|
// we continue resolving unknown types, but stop early on known scalars
|
|
@@ -313,6 +319,22 @@ export async function resolveDocument(opts: {
|
|
|
313
319
|
if (hasRef(refStack.prev, ref)) {
|
|
314
320
|
throw new Error('Self-referencing circular pointer');
|
|
315
321
|
}
|
|
322
|
+
|
|
323
|
+
if (isAnchor(ref.$ref)) {
|
|
324
|
+
// Wait for all anchors in the document to be collected firstly.
|
|
325
|
+
await nextTick();
|
|
326
|
+
const resolvedRef: ResolvedRef = {
|
|
327
|
+
resolved: true,
|
|
328
|
+
isRemote: false,
|
|
329
|
+
node: anchorRefsMap.get(ref.$ref),
|
|
330
|
+
document,
|
|
331
|
+
nodePointer: ref.$ref,
|
|
332
|
+
};
|
|
333
|
+
const refId = makeRefId(document.source.absoluteRef, ref.$ref);
|
|
334
|
+
resolvedRefMap.set(refId, resolvedRef);
|
|
335
|
+
return resolvedRef;
|
|
336
|
+
}
|
|
337
|
+
|
|
316
338
|
const { uri, pointer } = parseRef(ref.$ref);
|
|
317
339
|
const isRemote = uri !== null;
|
|
318
340
|
let targetDoc: Document;
|
|
@@ -336,7 +358,7 @@ export async function resolveDocument(opts: {
|
|
|
336
358
|
}
|
|
337
359
|
|
|
338
360
|
let resolvedRef: ResolvedRef = {
|
|
339
|
-
resolved: true
|
|
361
|
+
resolved: true,
|
|
340
362
|
document: targetDoc,
|
|
341
363
|
isRemote,
|
|
342
364
|
node: document.parsed,
|
|
@@ -138,6 +138,176 @@ describe('Oas3 spec', () => {
|
|
|
138
138
|
]
|
|
139
139
|
`);
|
|
140
140
|
});
|
|
141
|
+
|
|
142
|
+
it('should report on nullable without type', async () => {
|
|
143
|
+
const document = parseYamlToDocument(
|
|
144
|
+
outdent`
|
|
145
|
+
openapi: 3.0.0
|
|
146
|
+
components:
|
|
147
|
+
requestBodies:
|
|
148
|
+
TestRequestBody:
|
|
149
|
+
content:
|
|
150
|
+
application/json:
|
|
151
|
+
schema:
|
|
152
|
+
nullable: true
|
|
153
|
+
`,
|
|
154
|
+
'foobar.yaml'
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const results = await lintDocument({
|
|
158
|
+
externalRefResolver: new BaseResolver(),
|
|
159
|
+
document,
|
|
160
|
+
config: await makeConfig({ spec: 'error' }),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
164
|
+
Array [
|
|
165
|
+
Object {
|
|
166
|
+
"from": undefined,
|
|
167
|
+
"location": Array [
|
|
168
|
+
Object {
|
|
169
|
+
"pointer": "#/",
|
|
170
|
+
"reportOnKey": true,
|
|
171
|
+
"source": "foobar.yaml",
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
"message": "The field \`paths\` must be present on this level.",
|
|
175
|
+
"ruleId": "spec",
|
|
176
|
+
"severity": "error",
|
|
177
|
+
"suggest": Array [],
|
|
178
|
+
},
|
|
179
|
+
Object {
|
|
180
|
+
"from": undefined,
|
|
181
|
+
"location": Array [
|
|
182
|
+
Object {
|
|
183
|
+
"pointer": "#/",
|
|
184
|
+
"reportOnKey": true,
|
|
185
|
+
"source": "foobar.yaml",
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
"message": "The field \`info\` must be present on this level.",
|
|
189
|
+
"ruleId": "spec",
|
|
190
|
+
"severity": "error",
|
|
191
|
+
"suggest": Array [],
|
|
192
|
+
},
|
|
193
|
+
Object {
|
|
194
|
+
"location": Array [
|
|
195
|
+
Object {
|
|
196
|
+
"pointer": "#/components/requestBodies/TestRequestBody/content/application~1json/schema/nullable",
|
|
197
|
+
"reportOnKey": false,
|
|
198
|
+
"source": "foobar.yaml",
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
"message": "The \`type\` field must be defined when the \`nullable\` field is used.",
|
|
202
|
+
"ruleId": "spec",
|
|
203
|
+
"severity": "error",
|
|
204
|
+
"suggest": Array [],
|
|
205
|
+
},
|
|
206
|
+
]
|
|
207
|
+
`);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should report on nullable with type defined in allOf', async () => {
|
|
211
|
+
const document = parseYamlToDocument(
|
|
212
|
+
outdent`
|
|
213
|
+
openapi: 3.0.0
|
|
214
|
+
components:
|
|
215
|
+
requestBodies:
|
|
216
|
+
TestRequestBody:
|
|
217
|
+
content:
|
|
218
|
+
application/json:
|
|
219
|
+
schema:
|
|
220
|
+
nullable: true
|
|
221
|
+
allOf:
|
|
222
|
+
- $ref: "#/components/requestBodies/TestSchema"
|
|
223
|
+
schemas:
|
|
224
|
+
TestSchema:
|
|
225
|
+
title: TestSchema
|
|
226
|
+
type: object
|
|
227
|
+
`,
|
|
228
|
+
'foobar.yaml'
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const results = await lintDocument({
|
|
232
|
+
externalRefResolver: new BaseResolver(),
|
|
233
|
+
document,
|
|
234
|
+
config: await makeConfig({ spec: 'error' }),
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
238
|
+
Array [
|
|
239
|
+
Object {
|
|
240
|
+
"from": undefined,
|
|
241
|
+
"location": Array [
|
|
242
|
+
Object {
|
|
243
|
+
"pointer": "#/",
|
|
244
|
+
"reportOnKey": true,
|
|
245
|
+
"source": "foobar.yaml",
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
"message": "The field \`paths\` must be present on this level.",
|
|
249
|
+
"ruleId": "spec",
|
|
250
|
+
"severity": "error",
|
|
251
|
+
"suggest": Array [],
|
|
252
|
+
},
|
|
253
|
+
Object {
|
|
254
|
+
"from": undefined,
|
|
255
|
+
"location": Array [
|
|
256
|
+
Object {
|
|
257
|
+
"pointer": "#/",
|
|
258
|
+
"reportOnKey": true,
|
|
259
|
+
"source": "foobar.yaml",
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
"message": "The field \`info\` must be present on this level.",
|
|
263
|
+
"ruleId": "spec",
|
|
264
|
+
"severity": "error",
|
|
265
|
+
"suggest": Array [],
|
|
266
|
+
},
|
|
267
|
+
Object {
|
|
268
|
+
"location": Array [
|
|
269
|
+
Object {
|
|
270
|
+
"pointer": "#/components/requestBodies/TestRequestBody/content/application~1json/schema/nullable",
|
|
271
|
+
"reportOnKey": false,
|
|
272
|
+
"source": "foobar.yaml",
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
"message": "The \`type\` field must be defined when the \`nullable\` field is used.",
|
|
276
|
+
"ruleId": "spec",
|
|
277
|
+
"severity": "error",
|
|
278
|
+
"suggest": Array [],
|
|
279
|
+
},
|
|
280
|
+
Object {
|
|
281
|
+
"from": undefined,
|
|
282
|
+
"location": Array [
|
|
283
|
+
Object {
|
|
284
|
+
"pointer": "#/components/requestBodies/schemas",
|
|
285
|
+
"reportOnKey": true,
|
|
286
|
+
"source": "foobar.yaml",
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
"message": "The field \`content\` must be present on this level.",
|
|
290
|
+
"ruleId": "spec",
|
|
291
|
+
"severity": "error",
|
|
292
|
+
"suggest": Array [],
|
|
293
|
+
},
|
|
294
|
+
Object {
|
|
295
|
+
"from": undefined,
|
|
296
|
+
"location": Array [
|
|
297
|
+
Object {
|
|
298
|
+
"pointer": "#/components/requestBodies/schemas/TestSchema",
|
|
299
|
+
"reportOnKey": true,
|
|
300
|
+
"source": "foobar.yaml",
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
"message": "Property \`TestSchema\` is not expected here.",
|
|
304
|
+
"ruleId": "spec",
|
|
305
|
+
"severity": "error",
|
|
306
|
+
"suggest": Array [],
|
|
307
|
+
},
|
|
308
|
+
]
|
|
309
|
+
`);
|
|
310
|
+
});
|
|
141
311
|
});
|
|
142
312
|
|
|
143
313
|
describe('Oas3.1 spec', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Location } from '../../../../ref-utils';
|
|
2
2
|
import { Source } from '../../../../resolve';
|
|
3
|
-
import { asserts, buildAssertCustomFunction } from '../asserts';
|
|
3
|
+
import { Asserts, asserts, buildAssertCustomFunction } from '../asserts';
|
|
4
4
|
|
|
5
5
|
let baseLocation = new Location(jest.fn() as any as Source, 'pointer');
|
|
6
6
|
|
|
@@ -674,9 +674,13 @@ describe('oas3 assertions', () => {
|
|
|
674
674
|
}
|
|
675
675
|
return [];
|
|
676
676
|
});
|
|
677
|
-
asserts['local/customFn'] = buildAssertCustomFunction(customFn);
|
|
677
|
+
asserts['local/customFn' as keyof Asserts] = buildAssertCustomFunction(customFn);
|
|
678
678
|
expect(
|
|
679
|
-
asserts['local/customFn'
|
|
679
|
+
asserts['local/customFn' as keyof Asserts](
|
|
680
|
+
Object.keys(fakeNode),
|
|
681
|
+
{ word: 'foo' },
|
|
682
|
+
baseLocation
|
|
683
|
+
)
|
|
680
684
|
).toEqual([
|
|
681
685
|
{
|
|
682
686
|
message: 'First value should be foo',
|
|
@@ -1,61 +1,82 @@
|
|
|
1
|
-
import { Assertions } from '../.';
|
|
1
|
+
import { Assertion, Assertions } from '../.';
|
|
2
2
|
|
|
3
3
|
const opts = {
|
|
4
4
|
'0': {
|
|
5
|
-
subject:
|
|
6
|
-
|
|
5
|
+
subject: {
|
|
6
|
+
type: 'Operation',
|
|
7
|
+
property: 'summary',
|
|
8
|
+
},
|
|
7
9
|
description: 'example warn text',
|
|
8
10
|
severity: 'warn',
|
|
9
|
-
pattern: '/example/',
|
|
11
|
+
assertions: { pattern: '/example/' },
|
|
10
12
|
},
|
|
11
13
|
'1': {
|
|
12
|
-
subject:
|
|
13
|
-
|
|
14
|
+
subject: {
|
|
15
|
+
type: 'PathItem',
|
|
16
|
+
},
|
|
17
|
+
where: [
|
|
18
|
+
{
|
|
19
|
+
subject: { type: 'Operation', filterInParentKeys: ['post'], property: 'responses' },
|
|
20
|
+
assertions: { defined: true },
|
|
21
|
+
},
|
|
22
|
+
],
|
|
14
23
|
description: 'example warn text',
|
|
15
24
|
severity: 'warn',
|
|
16
|
-
mutuallyExclusive: ['summary', 'security'],
|
|
25
|
+
assertions: { mutuallyExclusive: ['summary', 'security'] },
|
|
17
26
|
},
|
|
18
27
|
'2': {
|
|
19
|
-
subject:
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
subject: { type: 'PathItem', property: 'tags' },
|
|
29
|
+
where: [
|
|
30
|
+
{ subject: { type: 'Operation', property: 'responses' }, assertions: { defined: true } },
|
|
31
|
+
],
|
|
22
32
|
description: 'example warn text',
|
|
23
33
|
severity: 'warn',
|
|
24
|
-
sortOrder: 'desc',
|
|
34
|
+
assertions: { sortOrder: 'desc' },
|
|
25
35
|
},
|
|
26
36
|
'3': {
|
|
27
|
-
subject:
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
subject: { type: 'Foo', property: 'test' },
|
|
38
|
+
where: [
|
|
39
|
+
{ subject: { type: 'Bar' }, assertions: {} },
|
|
40
|
+
{ subject: { type: 'Baz' }, assertions: {} },
|
|
41
|
+
],
|
|
30
42
|
description: 'example warn text',
|
|
31
43
|
severity: 'warn',
|
|
32
|
-
sortOrder: 'desc',
|
|
44
|
+
assertions: { sortOrder: 'desc' },
|
|
33
45
|
},
|
|
34
46
|
};
|
|
35
47
|
|
|
36
48
|
describe('Oas3 assertions', () => {
|
|
37
49
|
it('should return the right visitor structure', () => {
|
|
38
|
-
const visitors = Assertions(opts
|
|
50
|
+
const visitors = Assertions(opts as any);
|
|
39
51
|
expect(visitors).toMatchInlineSnapshot(`
|
|
40
52
|
Array [
|
|
41
53
|
Object {
|
|
42
|
-
"Operation":
|
|
54
|
+
"Operation": Object {
|
|
55
|
+
"enter": [Function],
|
|
56
|
+
},
|
|
43
57
|
},
|
|
44
58
|
Object {
|
|
45
59
|
"Operation": Object {
|
|
46
|
-
"PathItem":
|
|
60
|
+
"PathItem": Object {
|
|
61
|
+
"enter": [Function],
|
|
62
|
+
},
|
|
47
63
|
"skip": [Function],
|
|
48
64
|
},
|
|
49
65
|
},
|
|
50
66
|
Object {
|
|
51
67
|
"Operation": Object {
|
|
52
|
-
"PathItem":
|
|
68
|
+
"PathItem": Object {
|
|
69
|
+
"enter": [Function],
|
|
70
|
+
},
|
|
71
|
+
"skip": [Function],
|
|
53
72
|
},
|
|
54
73
|
},
|
|
55
74
|
Object {
|
|
56
75
|
"Bar": Object {
|
|
57
76
|
"Baz": Object {
|
|
58
|
-
"Foo":
|
|
77
|
+
"Foo": Object {
|
|
78
|
+
"enter": [Function],
|
|
79
|
+
},
|
|
59
80
|
},
|
|
60
81
|
},
|
|
61
82
|
},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Assertion, AssertionDefinition } from '..';
|
|
1
2
|
import { isOrdered, buildVisitorObject, getIntersectionLength } from '../utils';
|
|
2
3
|
|
|
3
4
|
describe('Oas3 assertions', () => {
|
|
@@ -25,29 +26,43 @@ describe('Oas3 assertions', () => {
|
|
|
25
26
|
|
|
26
27
|
describe('buildVisitorObject', () => {
|
|
27
28
|
it('should return a consistent visitor structure', () => {
|
|
28
|
-
const
|
|
29
|
+
const where: AssertionDefinition[] = [
|
|
29
30
|
{
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
subject: {
|
|
32
|
+
type: 'Foo',
|
|
33
|
+
filterInParentKeys: ['test'],
|
|
34
|
+
},
|
|
35
|
+
assertions: {},
|
|
32
36
|
},
|
|
33
37
|
{
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
subject: {
|
|
39
|
+
type: 'Bar',
|
|
40
|
+
filterInParentKeys: ['test'],
|
|
41
|
+
},
|
|
42
|
+
assertions: {},
|
|
36
43
|
},
|
|
37
44
|
{
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
subject: {
|
|
46
|
+
type: 'Roof',
|
|
47
|
+
filterInParentKeys: ['test'],
|
|
48
|
+
},
|
|
49
|
+
assertions: {},
|
|
40
50
|
},
|
|
41
|
-
];
|
|
51
|
+
] as AssertionDefinition[];
|
|
42
52
|
|
|
43
|
-
const visitors = buildVisitorObject(
|
|
53
|
+
const visitors = buildVisitorObject(
|
|
54
|
+
{ subject: { type: 'Bar' }, where, assertions: {} } as Assertion,
|
|
55
|
+
() => {}
|
|
56
|
+
);
|
|
44
57
|
|
|
45
58
|
expect(visitors).toMatchInlineSnapshot(`
|
|
46
59
|
Object {
|
|
47
60
|
"Foo": Object {
|
|
48
61
|
"Bar": Object {
|
|
49
62
|
"Roof": Object {
|
|
50
|
-
"Bar":
|
|
63
|
+
"Bar": Object {
|
|
64
|
+
"enter": [Function],
|
|
65
|
+
},
|
|
51
66
|
"skip": [Function],
|
|
52
67
|
},
|
|
53
68
|
"skip": [Function],
|
|
@@ -59,24 +74,35 @@ describe('Oas3 assertions', () => {
|
|
|
59
74
|
});
|
|
60
75
|
|
|
61
76
|
it('should return the right visitor structure', () => {
|
|
62
|
-
const
|
|
77
|
+
const where = [
|
|
63
78
|
{
|
|
64
|
-
|
|
65
|
-
|
|
79
|
+
subject: {
|
|
80
|
+
type: 'Operation',
|
|
81
|
+
filterInParentKeys: ['put'],
|
|
82
|
+
},
|
|
83
|
+
assertions: {},
|
|
66
84
|
},
|
|
67
85
|
{
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
subject: {
|
|
87
|
+
type: 'Responses',
|
|
88
|
+
filterInParentKeys: [201, 200],
|
|
89
|
+
},
|
|
90
|
+
assertions: {},
|
|
70
91
|
},
|
|
71
92
|
];
|
|
72
93
|
|
|
73
|
-
const visitors = buildVisitorObject(
|
|
94
|
+
const visitors = buildVisitorObject(
|
|
95
|
+
{ subject: { type: 'MediaTypesMap' }, where, assertions: {} } as Assertion,
|
|
96
|
+
() => {}
|
|
97
|
+
);
|
|
74
98
|
|
|
75
99
|
expect(visitors).toMatchInlineSnapshot(`
|
|
76
100
|
Object {
|
|
77
101
|
"Operation": Object {
|
|
78
102
|
"Responses": Object {
|
|
79
|
-
"MediaTypesMap":
|
|
103
|
+
"MediaTypesMap": Object {
|
|
104
|
+
"enter": [Function],
|
|
105
|
+
},
|
|
80
106
|
"skip": [Function],
|
|
81
107
|
},
|
|
82
108
|
"skip": [Function],
|