@redocly/openapi-core 1.0.0-beta.106 → 1.0.0-beta.109
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/benchmark/benches/lint-with-top-level-rule-report.bench.js +0 -1
- package/lib/benchmark/benches/resolve-with-no-external.bench.js +1 -1
- package/lib/bundle.d.ts +1 -1
- package/lib/bundle.js +9 -6
- package/lib/config/all.js +5 -3
- package/lib/config/config-resolvers.js +32 -14
- package/lib/config/config.d.ts +3 -5
- package/lib/config/config.js +7 -4
- package/lib/config/load.d.ts +7 -0
- package/lib/config/load.js +14 -6
- package/lib/config/minimal.js +7 -4
- package/lib/config/recommended.js +7 -4
- package/lib/config/rules.d.ts +1 -1
- package/lib/config/rules.js +1 -1
- package/lib/config/types.d.ts +7 -0
- package/lib/config/utils.d.ts +2 -2
- package/lib/config/utils.js +49 -11
- package/lib/decorators/common/registry-dependencies.js +2 -2
- package/lib/env.d.ts +3 -0
- package/lib/env.js +8 -0
- package/lib/format/codeframes.js +16 -10
- package/lib/format/format.d.ts +1 -1
- package/lib/format/format.js +49 -26
- package/lib/index.d.ts +5 -5
- package/lib/index.js +3 -1
- package/lib/js-yaml/index.js +1 -0
- package/lib/lint.js +2 -2
- package/lib/logger.d.ts +10 -0
- package/lib/logger.js +31 -0
- package/lib/output.d.ts +3 -0
- package/lib/output.js +9 -0
- package/lib/redocly/index.js +10 -9
- package/lib/redocly/registry-api-types.d.ts +28 -30
- package/lib/redocly/registry-api.d.ts +3 -3
- package/lib/redocly/registry-api.js +7 -1
- package/lib/ref-utils.js +2 -1
- package/lib/resolve.d.ts +1 -1
- package/lib/resolve.js +4 -2
- package/lib/rules/ajv.d.ts +1 -1
- package/lib/rules/ajv.js +7 -7
- package/lib/rules/common/assertions/asserts.js +4 -4
- package/lib/rules/common/assertions/index.js +1 -1
- package/lib/rules/common/no-ambiguous-paths.js +1 -1
- package/lib/rules/common/no-identical-paths.js +1 -1
- package/lib/rules/common/no-invalid-parameter-examples.js +3 -3
- package/lib/rules/common/no-invalid-schema-examples.js +3 -3
- package/lib/rules/common/operation-2xx-response.js +1 -1
- package/lib/rules/common/operation-4xx-response.js +1 -1
- package/lib/rules/common/operation-operationId.js +1 -1
- package/lib/rules/common/operation-tag-defined.js +1 -1
- package/lib/rules/common/path-not-include-query.js +1 -1
- package/lib/rules/common/security-defined.d.ts +2 -0
- package/lib/rules/common/{operation-security-defined.js → security-defined.js} +19 -5
- package/lib/rules/common/spec.js +14 -3
- package/lib/rules/common/tags-alphabetical.js +1 -1
- package/lib/rules/oas2/index.d.ts +1 -1
- package/lib/rules/oas2/index.js +2 -2
- package/lib/rules/oas2/remove-unused-components.js +3 -3
- package/lib/rules/oas2/request-mime-type.js +1 -1
- package/lib/rules/oas2/response-mime-type.js +1 -1
- package/lib/rules/oas3/index.js +8 -4
- package/lib/rules/oas3/no-empty-servers.js +1 -1
- package/lib/rules/oas3/no-invalid-media-type-examples.js +2 -2
- package/lib/rules/oas3/no-server-variables-empty-enum.d.ts +2 -0
- package/lib/rules/oas3/{no-servers-empty-enum.js → no-server-variables-empty-enum.js} +5 -5
- package/lib/rules/oas3/no-unused-components.js +2 -2
- package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.d.ts +5 -0
- package/lib/rules/oas3/operation-4xx-problem-details-rfc7807.js +36 -0
- package/lib/rules/oas3/remove-unused-components.js +4 -4
- package/lib/rules/oas3/request-mime-type.js +1 -1
- package/lib/rules/oas3/response-mime-type.js +1 -1
- package/lib/rules/oas3/spec-components-invalid-map-name.d.ts +2 -0
- package/lib/rules/oas3/spec-components-invalid-map-name.js +46 -0
- package/lib/rules/other/stats.d.ts +2 -2
- package/lib/rules/other/stats.js +2 -2
- package/lib/rules/utils.d.ts +3 -2
- package/lib/rules/utils.js +16 -4
- package/lib/types/oas2.js +5 -5
- package/lib/types/oas3.js +27 -20
- package/lib/types/oas3_1.js +3 -3
- package/lib/types/redocly-yaml.js +47 -56
- package/lib/utils.d.ts +6 -1
- package/lib/utils.js +24 -7
- package/lib/visitors.d.ts +12 -12
- package/lib/visitors.js +15 -3
- package/lib/walk.d.ts +2 -1
- package/lib/walk.js +6 -3
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/bundle.test.ts.snap +3 -3
- package/src/__tests__/fixtures/extension.js +3 -3
- package/src/__tests__/format.test.ts +76 -0
- package/src/__tests__/lint.test.ts +106 -131
- package/src/__tests__/logger-browser.test.ts +53 -0
- package/src/__tests__/logger.test.ts +47 -0
- package/src/__tests__/output-browser.test.ts +18 -0
- package/src/__tests__/output.test.ts +15 -0
- package/src/__tests__/resolve-http.test.ts +1 -1
- package/src/__tests__/resolve.test.ts +9 -9
- package/src/__tests__/utils-browser.test.ts +11 -0
- package/src/__tests__/utils.test.ts +7 -0
- package/src/__tests__/walk.test.ts +78 -10
- package/src/benchmark/benches/lint-with-top-level-rule-report.bench.ts +0 -1
- package/src/benchmark/benches/resolve-with-no-external.bench.ts +1 -1
- package/src/bundle.ts +10 -7
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +12 -6
- package/src/config/__tests__/config.test.ts +35 -0
- package/src/config/__tests__/fixtures/plugin-config.yaml +2 -3
- package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +11 -12
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-circular.yaml +7 -8
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +18 -19
- package/src/config/__tests__/fixtures/resolve-config/local-config.yaml +9 -10
- package/src/config/__tests__/fixtures/resolve-remote-configs/nested-remote-config.yaml +3 -4
- package/src/config/__tests__/fixtures/resolve-remote-configs/remote-config.yaml +4 -5
- package/src/config/__tests__/load.test.ts +76 -1
- package/src/config/__tests__/utils.test.ts +64 -4
- package/src/config/all.ts +5 -3
- package/src/config/config-resolvers.ts +45 -19
- package/src/config/config.ts +10 -8
- package/src/config/load.ts +31 -7
- package/src/config/minimal.ts +7 -4
- package/src/config/recommended.ts +7 -4
- package/src/config/rules.ts +2 -2
- package/src/config/types.ts +11 -0
- package/src/config/utils.ts +115 -25
- package/src/decorators/common/registry-dependencies.ts +2 -2
- package/src/env.ts +5 -0
- package/src/format/codeframes.ts +15 -9
- package/src/format/format.ts +59 -34
- package/src/index.ts +6 -4
- package/src/js-yaml/index.ts +1 -0
- package/src/lint.ts +2 -2
- package/src/logger.ts +34 -0
- package/src/output.ts +7 -0
- package/src/redocly/index.ts +7 -4
- package/src/redocly/registry-api-types.ts +27 -29
- package/src/redocly/registry-api.ts +18 -7
- package/src/ref-utils.ts +2 -1
- package/src/resolve.ts +7 -5
- package/src/rules/__tests__/utils.test.ts +39 -1
- package/src/rules/ajv.ts +7 -7
- package/src/rules/common/__tests__/no-enum-type-mismatch.test.ts +1 -0
- package/src/rules/common/__tests__/operation-2xx-response.test.ts +1 -1
- package/src/rules/common/__tests__/operation-4xx-response.test.ts +26 -3
- package/src/rules/common/__tests__/security-defined.test.ts +175 -0
- package/src/rules/common/__tests__/spec.test.ts +79 -0
- package/src/rules/common/assertions/__tests__/utils.test.ts +2 -2
- package/src/rules/common/assertions/asserts.ts +4 -4
- package/src/rules/common/assertions/index.ts +1 -1
- package/src/rules/common/no-ambiguous-paths.ts +1 -1
- package/src/rules/common/no-identical-paths.ts +1 -1
- package/src/rules/common/no-invalid-parameter-examples.ts +4 -4
- package/src/rules/common/no-invalid-schema-examples.ts +4 -4
- package/src/rules/common/operation-2xx-response.ts +1 -1
- package/src/rules/common/operation-4xx-response.ts +1 -1
- package/src/rules/common/operation-operationId.ts +1 -1
- package/src/rules/common/operation-tag-defined.ts +1 -1
- package/src/rules/common/path-not-include-query.ts +1 -1
- package/src/rules/common/{operation-security-defined.ts → security-defined.ts} +20 -5
- package/src/rules/common/spec.ts +17 -3
- package/src/rules/common/tags-alphabetical.ts +1 -1
- package/src/rules/oas2/index.ts +2 -2
- package/src/rules/oas2/remove-unused-components.ts +3 -3
- package/src/rules/oas2/request-mime-type.ts +1 -1
- package/src/rules/oas2/response-mime-type.ts +1 -1
- package/src/rules/oas3/__tests__/no-empty-enum-servers.com.test.ts +16 -16
- package/src/rules/oas3/__tests__/no-invalid-media-type-examples.test.ts +5 -5
- package/src/rules/oas3/__tests__/operation-4xx-problem-details-rfc7807.test.ts +145 -0
- package/src/rules/oas3/__tests__/spec/spec.test.ts +10 -0
- package/src/rules/oas3/__tests__/spec-components-invalid-map-name.test.ts +217 -0
- package/src/rules/oas3/index.ts +8 -4
- package/src/rules/oas3/no-empty-servers.ts +1 -1
- package/src/rules/oas3/no-invalid-media-type-examples.ts +3 -3
- package/src/rules/oas3/{no-servers-empty-enum.ts → no-server-variables-empty-enum.ts} +3 -3
- package/src/rules/oas3/no-unused-components.ts +2 -2
- package/src/rules/oas3/operation-4xx-problem-details-rfc7807.ts +36 -0
- package/src/rules/oas3/remove-unused-components.ts +5 -5
- package/src/rules/oas3/request-mime-type.ts +1 -1
- package/src/rules/oas3/response-mime-type.ts +1 -1
- package/src/rules/oas3/spec-components-invalid-map-name.ts +53 -0
- package/src/rules/other/stats.ts +2 -2
- package/src/rules/utils.ts +17 -3
- package/src/types/index.ts +2 -2
- package/src/types/oas2.ts +5 -5
- package/src/types/oas3.ts +27 -20
- package/src/types/oas3_1.ts +3 -3
- package/src/types/redocly-yaml.ts +53 -41
- package/src/utils.ts +31 -4
- package/src/visitors.ts +34 -18
- package/src/walk.ts +15 -11
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/rules/common/operation-security-defined.d.ts +0 -2
- package/lib/rules/oas3/no-servers-empty-enum.d.ts +0 -2
- package/src/rules/common/__tests__/operation-security-defined.test.ts +0 -69
|
@@ -16,7 +16,7 @@ import { Oas3RuleSet } from '../oas-types';
|
|
|
16
16
|
describe('walk order', () => {
|
|
17
17
|
it('should run visitors', async () => {
|
|
18
18
|
const visitors = {
|
|
19
|
-
|
|
19
|
+
Root: {
|
|
20
20
|
enter: jest.fn(),
|
|
21
21
|
leave: jest.fn(),
|
|
22
22
|
},
|
|
@@ -63,6 +63,74 @@ describe('walk order', () => {
|
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
+
it('should run legacy visitors', async () => {
|
|
67
|
+
const visitors = {
|
|
68
|
+
DefinitionRoot: {
|
|
69
|
+
enter: jest.fn(),
|
|
70
|
+
leave: jest.fn(),
|
|
71
|
+
},
|
|
72
|
+
PathMap: {
|
|
73
|
+
enter: jest.fn(),
|
|
74
|
+
leave: jest.fn(),
|
|
75
|
+
},
|
|
76
|
+
ServerVariableMap: {
|
|
77
|
+
enter: jest.fn(),
|
|
78
|
+
leave: jest.fn(),
|
|
79
|
+
},
|
|
80
|
+
MediaTypeMap: {
|
|
81
|
+
enter: jest.fn(),
|
|
82
|
+
leave: jest.fn(),
|
|
83
|
+
},
|
|
84
|
+
ExampleMap: {
|
|
85
|
+
enter: jest.fn(),
|
|
86
|
+
leave: jest.fn(),
|
|
87
|
+
},
|
|
88
|
+
HeaderMap: {
|
|
89
|
+
enter: jest.fn(),
|
|
90
|
+
leave: jest.fn(),
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const testRuleSet: Oas3RuleSet = {
|
|
95
|
+
test: jest.fn(() => {
|
|
96
|
+
return visitors;
|
|
97
|
+
}),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const document = parseYamlToDocument(
|
|
101
|
+
outdent`
|
|
102
|
+
openapi: 3.0.0
|
|
103
|
+
servers:
|
|
104
|
+
- url: http://{test}.url
|
|
105
|
+
variables:
|
|
106
|
+
test: test
|
|
107
|
+
paths:
|
|
108
|
+
/test-path:
|
|
109
|
+
get:
|
|
110
|
+
responses:
|
|
111
|
+
200:
|
|
112
|
+
headers: {}
|
|
113
|
+
content:
|
|
114
|
+
application/json:
|
|
115
|
+
schema: {}
|
|
116
|
+
examples: {}
|
|
117
|
+
`,
|
|
118
|
+
''
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
await lintDocument({
|
|
122
|
+
externalRefResolver: new BaseResolver(),
|
|
123
|
+
document,
|
|
124
|
+
config: makeConfigForRuleset(testRuleSet),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(testRuleSet.test).toBeCalledTimes(1);
|
|
128
|
+
for (const fns of Object.values(visitors)) {
|
|
129
|
+
expect(fns.enter).toBeCalled();
|
|
130
|
+
expect(fns.leave).toBeCalled();
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
66
134
|
it('should run nested visitors correctly', async () => {
|
|
67
135
|
const calls: string[] = [];
|
|
68
136
|
|
|
@@ -1046,8 +1114,8 @@ describe('walk order', () => {
|
|
|
1046
1114
|
|
|
1047
1115
|
expect(calls).toMatchInlineSnapshot(`
|
|
1048
1116
|
Array [
|
|
1049
|
-
"enter
|
|
1050
|
-
"enter
|
|
1117
|
+
"enter Root",
|
|
1118
|
+
"enter PathsMap",
|
|
1051
1119
|
"enter PathItem",
|
|
1052
1120
|
"enter ParameterList",
|
|
1053
1121
|
"enter Parameter",
|
|
@@ -1066,7 +1134,7 @@ describe('walk order', () => {
|
|
|
1066
1134
|
"leave ParameterList",
|
|
1067
1135
|
"leave Operation",
|
|
1068
1136
|
"leave PathItem",
|
|
1069
|
-
"leave
|
|
1137
|
+
"leave PathsMap",
|
|
1070
1138
|
"enter Components",
|
|
1071
1139
|
"enter NamedParameters",
|
|
1072
1140
|
"leave NamedParameters",
|
|
@@ -1075,7 +1143,7 @@ describe('walk order', () => {
|
|
|
1075
1143
|
"leave Schema",
|
|
1076
1144
|
"leave NamedSchemas",
|
|
1077
1145
|
"leave Components",
|
|
1078
|
-
"leave
|
|
1146
|
+
"leave Root",
|
|
1079
1147
|
]
|
|
1080
1148
|
`);
|
|
1081
1149
|
});
|
|
@@ -1378,10 +1446,10 @@ describe('type extensions', () => {
|
|
|
1378
1446
|
parameters: listOf('Parameter'),
|
|
1379
1447
|
},
|
|
1380
1448
|
},
|
|
1381
|
-
|
|
1382
|
-
...types.
|
|
1449
|
+
Root: {
|
|
1450
|
+
...types.Root,
|
|
1383
1451
|
properties: {
|
|
1384
|
-
...types.
|
|
1452
|
+
...types.Root.properties,
|
|
1385
1453
|
'x-webhooks': 'XWebHooks',
|
|
1386
1454
|
},
|
|
1387
1455
|
},
|
|
@@ -1393,7 +1461,7 @@ describe('type extensions', () => {
|
|
|
1393
1461
|
|
|
1394
1462
|
expect(calls).toMatchInlineSnapshot(`
|
|
1395
1463
|
Array [
|
|
1396
|
-
"enter
|
|
1464
|
+
"enter Root",
|
|
1397
1465
|
"enter XWebHooks",
|
|
1398
1466
|
"enter hook test",
|
|
1399
1467
|
"enter ParameterList",
|
|
@@ -1402,7 +1470,7 @@ describe('type extensions', () => {
|
|
|
1402
1470
|
"leave ParameterList",
|
|
1403
1471
|
"leave hook test",
|
|
1404
1472
|
"leave XWebHooks",
|
|
1405
|
-
"leave
|
|
1473
|
+
"leave Root",
|
|
1406
1474
|
]
|
|
1407
1475
|
`);
|
|
1408
1476
|
});
|
package/src/bundle.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { detectOpenAPI, openAPIMajor, OasMajorVersion } from './oas-types';
|
|
|
10
10
|
import { isAbsoluteUrl, isRef, Location, refBaseName } from './ref-utils';
|
|
11
11
|
import { initRules } from './config/rules';
|
|
12
12
|
import { reportUnresolvedRef } from './rules/no-unresolved-refs';
|
|
13
|
-
import { isPlainObject } from './utils';
|
|
13
|
+
import { isPlainObject, isTruthy } from './utils';
|
|
14
14
|
import { OasRef } from './typings/openapi';
|
|
15
15
|
import { isRedoclyRegistryURL } from './redocly';
|
|
16
16
|
import { RemoveUnusedComponents as RemoveUnusedComponentsOas2 } from './rules/oas2/remove-unused-components';
|
|
@@ -122,7 +122,7 @@ export async function bundleDocument(opts: {
|
|
|
122
122
|
|
|
123
123
|
const resolvedRefMap = await resolveDocument({
|
|
124
124
|
rootDocument: document,
|
|
125
|
-
rootType: types.
|
|
125
|
+
rootType: types.Root,
|
|
126
126
|
externalRefResolver,
|
|
127
127
|
});
|
|
128
128
|
|
|
@@ -148,7 +148,7 @@ export async function bundleDocument(opts: {
|
|
|
148
148
|
|
|
149
149
|
walkDocument({
|
|
150
150
|
document,
|
|
151
|
-
rootType: types.
|
|
151
|
+
rootType: types.Root as NormalizedNodeType,
|
|
152
152
|
normalizedVisitors: bundleVisitor,
|
|
153
153
|
resolvedRefMap,
|
|
154
154
|
ctx,
|
|
@@ -158,7 +158,7 @@ export async function bundleDocument(opts: {
|
|
|
158
158
|
bundle: document,
|
|
159
159
|
problems: ctx.problems.map((problem) => config.addProblemToIgnore(problem)),
|
|
160
160
|
fileDependencies: externalRefResolver.getFiles(),
|
|
161
|
-
rootType: types.
|
|
161
|
+
rootType: types.Root,
|
|
162
162
|
refTypes: ctx.refTypes,
|
|
163
163
|
visitorsData: ctx.visitorsData,
|
|
164
164
|
};
|
|
@@ -254,7 +254,7 @@ function makeBundleVisitor(
|
|
|
254
254
|
}
|
|
255
255
|
},
|
|
256
256
|
},
|
|
257
|
-
|
|
257
|
+
Root: {
|
|
258
258
|
enter(root: any) {
|
|
259
259
|
if (version === OasMajorVersion.Version3) {
|
|
260
260
|
components = root.components = root.components || {};
|
|
@@ -302,9 +302,12 @@ function makeBundleVisitor(
|
|
|
302
302
|
if (!isPlainObject(resolved.node)) {
|
|
303
303
|
ctx.parent[ctx.key] = resolved.node;
|
|
304
304
|
} else {
|
|
305
|
+
// TODO: why $ref isn't optional in OasRef?
|
|
306
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
305
307
|
// @ts-ignore
|
|
306
308
|
delete ref.$ref;
|
|
307
|
-
Object.assign(
|
|
309
|
+
const obj = Object.assign({}, resolved.node, ref);
|
|
310
|
+
Object.assign(ref, obj); // assign ref itself again so ref fields take precedence
|
|
308
311
|
}
|
|
309
312
|
}
|
|
310
313
|
|
|
@@ -348,7 +351,7 @@ function makeBundleVisitor(
|
|
|
348
351
|
|
|
349
352
|
let name = '';
|
|
350
353
|
|
|
351
|
-
const refParts = pointer.slice(2).split('/').filter(
|
|
354
|
+
const refParts = pointer.slice(2).split('/').filter(isTruthy); // slice(2) removes "#/"
|
|
352
355
|
while (refParts.length > 0) {
|
|
353
356
|
name = refParts.pop() + (name ? `-${name}` : '');
|
|
354
357
|
if (
|
|
@@ -15,20 +15,23 @@ Object {
|
|
|
15
15
|
"no-invalid-media-type-examples": "error",
|
|
16
16
|
"no-server-example.com": "warn",
|
|
17
17
|
"no-server-trailing-slash": "error",
|
|
18
|
-
"no-
|
|
18
|
+
"no-server-variables-empty-enum": "error",
|
|
19
19
|
"no-undefined-server-variable": "error",
|
|
20
20
|
"no-unused-components": "warn",
|
|
21
|
+
"spec-components-invalid-map-name": "error",
|
|
21
22
|
},
|
|
22
23
|
"oas3_1Decorators": Object {},
|
|
23
24
|
"oas3_1Preprocessors": Object {},
|
|
24
25
|
"oas3_1Rules": Object {
|
|
25
26
|
"no-empty-servers": "error",
|
|
26
27
|
"no-example-value-and-externalValue": "error",
|
|
28
|
+
"no-invalid-media-type-examples": "error",
|
|
27
29
|
"no-server-example.com": "warn",
|
|
28
30
|
"no-server-trailing-slash": "error",
|
|
29
|
-
"no-
|
|
31
|
+
"no-server-variables-empty-enum": "error",
|
|
30
32
|
"no-undefined-server-variable": "error",
|
|
31
33
|
"no-unused-components": "warn",
|
|
34
|
+
"spec-components-invalid-map-name": "error",
|
|
32
35
|
},
|
|
33
36
|
"preprocessors": Object {},
|
|
34
37
|
"recommendedFallback": false,
|
|
@@ -53,7 +56,6 @@ Object {
|
|
|
53
56
|
"operation-operationId-unique": "error",
|
|
54
57
|
"operation-operationId-url-safe": "error",
|
|
55
58
|
"operation-parameters-unique": "error",
|
|
56
|
-
"operation-security-defined": "error",
|
|
57
59
|
"operation-singular-tag": "off",
|
|
58
60
|
"operation-summary": "error",
|
|
59
61
|
"operation-tag-defined": "off",
|
|
@@ -63,6 +65,7 @@ Object {
|
|
|
63
65
|
"path-not-include-query": "error",
|
|
64
66
|
"path-parameters-defined": "error",
|
|
65
67
|
"paths-kebab-case": "off",
|
|
68
|
+
"security-defined": "error",
|
|
66
69
|
"spec": "error",
|
|
67
70
|
"tag-description": "warn",
|
|
68
71
|
"tags-alphabetical": "off",
|
|
@@ -85,20 +88,23 @@ Object {
|
|
|
85
88
|
"no-invalid-media-type-examples": "warn",
|
|
86
89
|
"no-server-example.com": "warn",
|
|
87
90
|
"no-server-trailing-slash": "error",
|
|
88
|
-
"no-
|
|
91
|
+
"no-server-variables-empty-enum": "error",
|
|
89
92
|
"no-undefined-server-variable": "error",
|
|
90
93
|
"no-unused-components": "warn",
|
|
94
|
+
"spec-components-invalid-map-name": "error",
|
|
91
95
|
},
|
|
92
96
|
"oas3_1Decorators": Object {},
|
|
93
97
|
"oas3_1Preprocessors": Object {},
|
|
94
98
|
"oas3_1Rules": Object {
|
|
95
99
|
"no-empty-servers": "error",
|
|
96
100
|
"no-example-value-and-externalValue": "error",
|
|
101
|
+
"no-invalid-media-type-examples": "warn",
|
|
97
102
|
"no-server-example.com": "warn",
|
|
98
103
|
"no-server-trailing-slash": "error",
|
|
99
|
-
"no-
|
|
104
|
+
"no-server-variables-empty-enum": "error",
|
|
100
105
|
"no-undefined-server-variable": "error",
|
|
101
106
|
"no-unused-components": "warn",
|
|
107
|
+
"spec-components-invalid-map-name": "error",
|
|
102
108
|
},
|
|
103
109
|
"preprocessors": Object {},
|
|
104
110
|
"recommendedFallback": undefined,
|
|
@@ -140,7 +146,6 @@ Object {
|
|
|
140
146
|
"operation-operationId-unique": "error",
|
|
141
147
|
"operation-operationId-url-safe": "error",
|
|
142
148
|
"operation-parameters-unique": "error",
|
|
143
|
-
"operation-security-defined": "error",
|
|
144
149
|
"operation-singular-tag": "off",
|
|
145
150
|
"operation-summary": "error",
|
|
146
151
|
"operation-tag-defined": "off",
|
|
@@ -149,6 +154,7 @@ Object {
|
|
|
149
154
|
"path-not-include-query": "error",
|
|
150
155
|
"path-parameters-defined": "error",
|
|
151
156
|
"paths-kebab-case": "off",
|
|
157
|
+
"security-defined": "error",
|
|
152
158
|
"spec": "error",
|
|
153
159
|
"tag-description": "warn",
|
|
154
160
|
"tags-alphabetical": "off",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OasVersion } from '../../oas-types';
|
|
1
2
|
import { Config, StyleguideConfig } from '../config';
|
|
2
3
|
import { getMergedConfig } from '../utils';
|
|
3
4
|
|
|
@@ -242,3 +243,37 @@ describe('getMergedConfig', () => {
|
|
|
242
243
|
`);
|
|
243
244
|
});
|
|
244
245
|
});
|
|
246
|
+
|
|
247
|
+
describe('StyleguideConfig.extendTypes', () => {
|
|
248
|
+
let oas3 = jest.fn();
|
|
249
|
+
let oas2 = jest.fn();
|
|
250
|
+
let testRawConfigStyleguide = {
|
|
251
|
+
plugins: [
|
|
252
|
+
{
|
|
253
|
+
id: 'test-types-plugin',
|
|
254
|
+
typeExtension: {
|
|
255
|
+
oas3,
|
|
256
|
+
oas2,
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
};
|
|
261
|
+
it('should call only oas3 types extension', () => {
|
|
262
|
+
const styleguideConfig = new StyleguideConfig(testRawConfigStyleguide);
|
|
263
|
+
styleguideConfig.extendTypes({}, OasVersion.Version3_0);
|
|
264
|
+
expect(oas3).toHaveBeenCalledTimes(1);
|
|
265
|
+
expect(oas2).toHaveBeenCalledTimes(0);
|
|
266
|
+
});
|
|
267
|
+
it('should call only oas2 types extension', () => {
|
|
268
|
+
const styleguideConfig = new StyleguideConfig(testRawConfigStyleguide);
|
|
269
|
+
styleguideConfig.extendTypes({}, OasVersion.Version2);
|
|
270
|
+
expect(oas3).toHaveBeenCalledTimes(0);
|
|
271
|
+
expect(oas2).toHaveBeenCalledTimes(1);
|
|
272
|
+
});
|
|
273
|
+
it('should throw error if for oas version different from 2 and 3', () => {
|
|
274
|
+
const styleguideConfig = new StyleguideConfig(testRawConfigStyleguide);
|
|
275
|
+
expect(() => styleguideConfig.extendTypes({}, 'something else' as OasVersion)).toThrowError(
|
|
276
|
+
'Not implemented'
|
|
277
|
+
);
|
|
278
|
+
});
|
|
279
|
+
});
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
- './plugin.js'
|
|
1
|
+
plugins:
|
|
2
|
+
- './plugin.js'
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- test-plugin-nested/all
|
|
1
|
+
plugins:
|
|
2
|
+
- plugin.js
|
|
3
|
+
rules:
|
|
4
|
+
operation-2xx-response: error
|
|
5
|
+
assert/path-item-get-defined:
|
|
6
|
+
subject: PathItem
|
|
7
|
+
property: get
|
|
8
|
+
message: Every path item must have a GET operation.
|
|
9
|
+
defined: true
|
|
10
|
+
extends:
|
|
11
|
+
- test-plugin-nested/all
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
operation-2xx-response: off
|
|
1
|
+
extends:
|
|
2
|
+
- local-config-with-circular.yaml
|
|
3
|
+
rules:
|
|
4
|
+
no-invalid-media-type-examples: error
|
|
5
|
+
operation-description: error
|
|
6
|
+
path-http-verbs-order: error
|
|
7
|
+
operation-2xx-response: off
|
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- test-plugin/all
|
|
1
|
+
rules:
|
|
2
|
+
no-invalid-media-type-examples: warn
|
|
3
|
+
operation-4xx-response: off
|
|
4
|
+
assert/tag-description:
|
|
5
|
+
subject: Tag
|
|
6
|
+
property: description
|
|
7
|
+
message: Tag description must be at least 13 characters and end with a full stop.
|
|
8
|
+
severity: error
|
|
9
|
+
minLength: 13
|
|
10
|
+
pattern: /\.$/
|
|
11
|
+
plugins:
|
|
12
|
+
- plugin.js
|
|
13
|
+
- api/plugin.js
|
|
14
|
+
extends:
|
|
15
|
+
- recommended
|
|
16
|
+
- api/nested-config.yaml
|
|
17
|
+
- test-plugin-nested/all
|
|
18
|
+
- test-plugin/all
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
operation-2xx-response: off
|
|
1
|
+
plugins:
|
|
2
|
+
- plugin.js
|
|
3
|
+
extends:
|
|
4
|
+
- test-plugin/all
|
|
5
|
+
rules:
|
|
6
|
+
no-invalid-media-type-examples: error
|
|
7
|
+
operation-description: error
|
|
8
|
+
path-http-verbs-order: error
|
|
9
|
+
operation-2xx-response: off
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
operation-4xx-response: error
|
|
1
|
+
rules:
|
|
2
|
+
operation-2xx-response: off
|
|
3
|
+
operation-4xx-response: error
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
operation-2xx-response: error
|
|
1
|
+
extends:
|
|
2
|
+
- nested-remote-config.yaml
|
|
3
|
+
rules:
|
|
4
|
+
operation-2xx-response: error
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { loadConfig, findConfig, getConfig } from '../load';
|
|
1
|
+
import { loadConfig, findConfig, getConfig, createConfig } from '../load';
|
|
2
2
|
import { RedoclyClient } from '../../redocly';
|
|
3
|
+
import { RuleConfig, FlatRawConfig } from './../types';
|
|
4
|
+
import { Config } from '../config';
|
|
3
5
|
|
|
4
6
|
const fs = require('fs');
|
|
5
7
|
const path = require('path');
|
|
@@ -87,3 +89,76 @@ describe('getConfig', () => {
|
|
|
87
89
|
expect(getConfig()).toEqual(Promise.resolve({}));
|
|
88
90
|
});
|
|
89
91
|
});
|
|
92
|
+
|
|
93
|
+
describe('createConfig', () => {
|
|
94
|
+
it('should create config from string', async () => {
|
|
95
|
+
const config = await createConfig(`
|
|
96
|
+
extends:
|
|
97
|
+
- recommended
|
|
98
|
+
rules:
|
|
99
|
+
info-license: off
|
|
100
|
+
`);
|
|
101
|
+
|
|
102
|
+
verifyExtendedConfig(config, {
|
|
103
|
+
extendsRuleSet: 'recommended',
|
|
104
|
+
overridesRules: { 'info-license': 'off' },
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should create config from object', async () => {
|
|
109
|
+
const rawConfig: FlatRawConfig = {
|
|
110
|
+
extends: ['minimal'],
|
|
111
|
+
rules: {
|
|
112
|
+
'info-license': 'off',
|
|
113
|
+
'tag-description': 'off',
|
|
114
|
+
'operation-2xx-response': 'off',
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
const config = await createConfig(rawConfig);
|
|
118
|
+
|
|
119
|
+
verifyExtendedConfig(config, {
|
|
120
|
+
extendsRuleSet: 'minimal',
|
|
121
|
+
overridesRules: rawConfig.rules as Record<string, RuleConfig>,
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
function verifyExtendedConfig(
|
|
127
|
+
config: Config,
|
|
128
|
+
{
|
|
129
|
+
extendsRuleSet,
|
|
130
|
+
overridesRules,
|
|
131
|
+
}: { extendsRuleSet: string; overridesRules: Record<string, RuleConfig> }
|
|
132
|
+
) {
|
|
133
|
+
const defaultPlugin = config.styleguide.plugins.find((plugin) => plugin.id === '');
|
|
134
|
+
expect(defaultPlugin).toBeDefined();
|
|
135
|
+
|
|
136
|
+
const recommendedRules = defaultPlugin?.configs?.[extendsRuleSet];
|
|
137
|
+
expect(recommendedRules).toBeDefined();
|
|
138
|
+
|
|
139
|
+
verifyOasRules(config.styleguide.rules.oas2, overridesRules, recommendedRules?.rules || {});
|
|
140
|
+
verifyOasRules(
|
|
141
|
+
config.styleguide.rules.oas3_0,
|
|
142
|
+
overridesRules,
|
|
143
|
+
Object.assign({}, recommendedRules?.rules, recommendedRules?.oas3_0Rules)
|
|
144
|
+
);
|
|
145
|
+
verifyOasRules(
|
|
146
|
+
config.styleguide.rules.oas3_1,
|
|
147
|
+
overridesRules,
|
|
148
|
+
Object.assign({}, recommendedRules?.rules, recommendedRules?.oas3_1Rules)
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function verifyOasRules(
|
|
153
|
+
finalRuleset: Record<string, RuleConfig>,
|
|
154
|
+
overridesRules: Record<string, RuleConfig>,
|
|
155
|
+
defaultRuleset: Record<string, RuleConfig>
|
|
156
|
+
) {
|
|
157
|
+
Object.entries(finalRuleset).forEach(([ruleName, ruleValue]) => {
|
|
158
|
+
if (ruleName in overridesRules) {
|
|
159
|
+
expect(ruleValue).toBe(overridesRules[ruleName]);
|
|
160
|
+
} else {
|
|
161
|
+
expect(ruleValue).toBe(defaultRuleset[ruleName]);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DeprecatedInRawConfig, RawConfig } from '../types';
|
|
1
|
+
import { DeprecatedInRawConfig, RawConfig, FlatRawConfig } from '../types';
|
|
2
2
|
import * as utils from '../utils';
|
|
3
3
|
|
|
4
4
|
const makeTestRawConfig = (
|
|
@@ -22,8 +22,54 @@ const makeTestRawConfig = (
|
|
|
22
22
|
},
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
+
const rawTestConfig: RawConfig = {
|
|
26
|
+
apis: {
|
|
27
|
+
'test@v1': {
|
|
28
|
+
root: 'root.yaml',
|
|
29
|
+
styleguide: {
|
|
30
|
+
extends: ['recommended'],
|
|
31
|
+
rules: { 'operation-2xx-response': 'error' },
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
styleguide: {
|
|
36
|
+
plugins: ['test-plugin'],
|
|
37
|
+
extends: ['minimal'],
|
|
38
|
+
rules: { 'operation-4xx-response': 'warn' },
|
|
39
|
+
doNotResolveExamples: true,
|
|
40
|
+
},
|
|
41
|
+
resolve: {
|
|
42
|
+
http: { headers: [{ matches: '*', name: 'all', envVariable: 'all' }] },
|
|
43
|
+
},
|
|
44
|
+
'features.openapi': {
|
|
45
|
+
disableSidebar: true,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const flatTestConfig: FlatRawConfig = {
|
|
50
|
+
apis: {
|
|
51
|
+
'test@v1': {
|
|
52
|
+
root: 'root.yaml',
|
|
53
|
+
extends: ['recommended'],
|
|
54
|
+
rules: { 'operation-2xx-response': 'error' },
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
plugins: ['test-plugin'],
|
|
58
|
+
extends: ['minimal'],
|
|
59
|
+
rules: {
|
|
60
|
+
'operation-4xx-response': 'warn',
|
|
61
|
+
},
|
|
62
|
+
resolve: {
|
|
63
|
+
http: { headers: [{ matches: '*', name: 'all', envVariable: 'all' }] },
|
|
64
|
+
doNotResolveExamples: true,
|
|
65
|
+
},
|
|
66
|
+
'features.openapi': {
|
|
67
|
+
disableSidebar: true,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
25
71
|
describe('transformConfig', () => {
|
|
26
|
-
it('should work for
|
|
72
|
+
it('should work for the `styleguide` syntax', () => {
|
|
27
73
|
const transformedRawConfig: RawConfig = utils.transformConfig(
|
|
28
74
|
makeTestRawConfig('styleguide', 'styleguide')
|
|
29
75
|
);
|
|
@@ -73,11 +119,25 @@ describe('transformConfig', () => {
|
|
|
73
119
|
}
|
|
74
120
|
`);
|
|
75
121
|
});
|
|
76
|
-
it('should throw an error if both
|
|
122
|
+
it('should throw an error if both `styleguide` and `lint` syntaxes used together', () => {
|
|
77
123
|
const testRawConfig = makeTestRawConfig('styleguide', 'lint');
|
|
78
124
|
testRawConfig.apiDefinitions = { legacyApiDefinition: 'file.yaml' };
|
|
79
125
|
expect(() => utils.transformConfig(testRawConfig)).toThrowError(
|
|
80
|
-
`Do not use 'apiDefinitions' field. Use 'apis' instead
|
|
126
|
+
`Do not use 'apiDefinitions' field. Use 'apis' instead. `
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
it('should transform flatten config into styleguide', () => {
|
|
130
|
+
expect(utils.transformConfig(flatTestConfig)).toEqual({
|
|
131
|
+
...rawTestConfig,
|
|
132
|
+
resolve: { ...rawTestConfig.resolve, doNotResolveExamples: true },
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
it('should transform styleguide config into styleguide identically', () => {
|
|
136
|
+
expect(utils.transformConfig(rawTestConfig)).toEqual(rawTestConfig);
|
|
137
|
+
});
|
|
138
|
+
it('should fail when there is a mixed config', () => {
|
|
139
|
+
expect(() => utils.transformConfig({ ...rawTestConfig, extends: ['recommended'] })).toThrow(
|
|
140
|
+
`Do not use 'lint', 'styleguide' and flat syntax together. \nSee more about the configuration in the docs: https://redocly.com/docs/cli/configuration/ \n`
|
|
81
141
|
);
|
|
82
142
|
});
|
|
83
143
|
});
|