@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
|
@@ -1,122 +1,154 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.regexFromString = exports.isOrdered = exports.getIntersectionLength = exports.buildSubjectVisitor = exports.buildVisitorObject = void 0;
|
|
3
|
+
exports.regexFromString = exports.isOrdered = exports.getIntersectionLength = exports.buildSubjectVisitor = exports.buildVisitorObject = exports.getAssertsToApply = void 0;
|
|
4
|
+
const asserts_1 = require("./asserts");
|
|
4
5
|
const logger_1 = require("../../../logger");
|
|
5
6
|
const ref_utils_1 = require("../../../ref-utils");
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const utils_1 = require("../../../utils");
|
|
8
|
+
const assertionMessageTemplates = {
|
|
9
|
+
problems: '{{problems}}',
|
|
10
|
+
};
|
|
11
|
+
function getPredicatesFromLocators(locators) {
|
|
12
|
+
const { filterInParentKeys, filterOutParentKeys, matchParentKeys } = locators;
|
|
13
|
+
const keyMatcher = matchParentKeys && regexFromString(matchParentKeys);
|
|
14
|
+
const matchKeysPredicate = keyMatcher && ((key) => keyMatcher.test(key.toString()));
|
|
15
|
+
const filterInPredicate = Array.isArray(filterInParentKeys) &&
|
|
16
|
+
((key) => filterInParentKeys.includes(key.toString()));
|
|
17
|
+
const filterOutPredicate = Array.isArray(filterOutParentKeys) &&
|
|
18
|
+
((key) => !filterOutParentKeys.includes(key.toString()));
|
|
19
|
+
return [matchKeysPredicate, filterInPredicate, filterOutPredicate].filter(utils_1.isTruthy);
|
|
20
|
+
}
|
|
21
|
+
function getAssertsToApply(assertion) {
|
|
22
|
+
const assertsToApply = utils_1.keysOf(asserts_1.asserts)
|
|
23
|
+
.filter((assertName) => assertion.assertions[assertName] !== undefined)
|
|
24
|
+
.map((assertName) => {
|
|
25
|
+
return {
|
|
26
|
+
name: assertName,
|
|
27
|
+
conditions: assertion.assertions[assertName],
|
|
28
|
+
runsOnKeys: asserts_1.runOnKeysSet.has(assertName),
|
|
29
|
+
runsOnValues: asserts_1.runOnValuesSet.has(assertName),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
const shouldRunOnKeys = assertsToApply.find((assert) => assert.runsOnKeys && !assert.runsOnValues);
|
|
33
|
+
const shouldRunOnValues = assertsToApply.find((assert) => assert.runsOnValues && !assert.runsOnKeys);
|
|
34
|
+
if (shouldRunOnValues && !assertion.subject.property) {
|
|
35
|
+
throw new Error(`${shouldRunOnValues.name} can't be used on all keys. Please provide a single property`);
|
|
36
|
+
}
|
|
37
|
+
if (shouldRunOnKeys && assertion.subject.property) {
|
|
38
|
+
throw new Error(`${shouldRunOnKeys.name} can't be used on a single property. Please use 'property'.`);
|
|
39
|
+
}
|
|
40
|
+
return assertsToApply;
|
|
41
|
+
}
|
|
42
|
+
exports.getAssertsToApply = getAssertsToApply;
|
|
43
|
+
function getAssertionProperties({ subject }) {
|
|
44
|
+
return (Array.isArray(subject.property) ? subject.property : [subject === null || subject === void 0 ? void 0 : subject.property]).filter(Boolean);
|
|
45
|
+
}
|
|
46
|
+
function applyAssertions(assertionDefinition, asserts, { rawLocation, rawNode, resolve, location, node }) {
|
|
47
|
+
var _a;
|
|
48
|
+
const properties = getAssertionProperties(assertionDefinition);
|
|
49
|
+
const assertResults = [];
|
|
50
|
+
for (const assert of asserts) {
|
|
51
|
+
const currentLocation = assert.name === 'ref' ? rawLocation : location;
|
|
52
|
+
if (properties.length) {
|
|
53
|
+
for (const property of properties) {
|
|
54
|
+
// we can have resolvable scalar so need to resolve value here.
|
|
55
|
+
const value = ref_utils_1.isRef(node[property]) ? (_a = resolve(node[property])) === null || _a === void 0 ? void 0 : _a.node : node[property];
|
|
56
|
+
assertResults.push(runAssertion({
|
|
57
|
+
values: value,
|
|
58
|
+
rawValues: rawNode[property],
|
|
59
|
+
assert,
|
|
60
|
+
location: currentLocation.child(property),
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const value = assert.name === 'ref' ? rawNode : Object.keys(node);
|
|
66
|
+
assertResults.push(runAssertion({
|
|
67
|
+
values: Object.keys(node),
|
|
68
|
+
rawValues: value,
|
|
69
|
+
assert,
|
|
70
|
+
location: currentLocation,
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return assertResults.flat();
|
|
75
|
+
}
|
|
76
|
+
function buildVisitorObject(assertion, subjectVisitor) {
|
|
77
|
+
var _a, _b;
|
|
78
|
+
const targetVisitorLocatorPredicates = getPredicatesFromLocators(assertion.subject);
|
|
79
|
+
const targetVisitorSkipFunction = targetVisitorLocatorPredicates.length
|
|
80
|
+
? (node, key) => !targetVisitorLocatorPredicates.every((predicate) => predicate(key))
|
|
81
|
+
: undefined;
|
|
82
|
+
const targetVisitor = {
|
|
83
|
+
[assertion.subject.type]: Object.assign({ enter: subjectVisitor }, (targetVisitorSkipFunction && { skip: targetVisitorSkipFunction })),
|
|
84
|
+
};
|
|
85
|
+
if (!Array.isArray(assertion.where)) {
|
|
86
|
+
return targetVisitor;
|
|
10
87
|
}
|
|
11
88
|
let currentVisitorLevel = {};
|
|
12
89
|
const visitor = currentVisitorLevel;
|
|
90
|
+
const context = assertion.where;
|
|
13
91
|
for (let index = 0; index < context.length; index++) {
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
// as a workaround for that we don't create separate visitor for the last element
|
|
18
|
-
// which is the same as subject;
|
|
19
|
-
// we will check includes/excludes it in the last visitor.
|
|
20
|
-
continue;
|
|
92
|
+
const assertionDefinitionNode = context[index];
|
|
93
|
+
if (!utils_1.isString((_a = assertionDefinitionNode.subject) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
94
|
+
throw new Error(`${assertion.assertionId} -> where -> [${index}]: 'type' (String) is required`);
|
|
21
95
|
}
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
96
|
+
const locatorPredicates = getPredicatesFromLocators(assertionDefinitionNode.subject);
|
|
97
|
+
const assertsToApply = getAssertsToApply(assertionDefinitionNode);
|
|
98
|
+
const skipFunction = (node, key, { location, rawLocation, resolve, rawNode }) => !locatorPredicates.every((predicate) => predicate(key)) ||
|
|
99
|
+
!!applyAssertions(assertionDefinitionNode, assertsToApply, {
|
|
100
|
+
location,
|
|
101
|
+
node,
|
|
102
|
+
rawLocation,
|
|
103
|
+
rawNode,
|
|
104
|
+
resolve,
|
|
105
|
+
}).length;
|
|
106
|
+
const nodeVisitor = Object.assign({}, ((locatorPredicates.length || assertsToApply.length) && { skip: skipFunction }));
|
|
107
|
+
if (assertionDefinitionNode.subject.type === assertion.subject.type &&
|
|
108
|
+
index === context.length - 1) {
|
|
109
|
+
// We have to merge the visitors if the last node inside the `where` is the same as the subject.
|
|
110
|
+
targetVisitor[assertion.subject.type] = Object.assign({ enter: subjectVisitor }, ((nodeVisitor.skip && { skip: nodeVisitor.skip }) ||
|
|
111
|
+
(targetVisitorSkipFunction && {
|
|
112
|
+
skip: (node, key, ctx // We may have locators defined on assertion level and on where level for the same node type
|
|
113
|
+
) => { var _a; return !!(((_a = nodeVisitor.skip) === null || _a === void 0 ? void 0 : _a.call(nodeVisitor, node, key, ctx)) || (targetVisitorSkipFunction === null || targetVisitorSkipFunction === void 0 ? void 0 : targetVisitorSkipFunction(node, key))); },
|
|
114
|
+
})));
|
|
38
115
|
}
|
|
39
116
|
else {
|
|
40
|
-
currentVisitorLevel[
|
|
117
|
+
currentVisitorLevel = currentVisitorLevel[(_b = assertionDefinitionNode.subject) === null || _b === void 0 ? void 0 : _b.type] =
|
|
118
|
+
nodeVisitor;
|
|
41
119
|
}
|
|
42
|
-
currentVisitorLevel = currentVisitorLevel[node.type];
|
|
43
120
|
}
|
|
44
|
-
currentVisitorLevel[subject] =
|
|
121
|
+
currentVisitorLevel[assertion.subject.type] = targetVisitor[assertion.subject.type];
|
|
45
122
|
return visitor;
|
|
46
123
|
}
|
|
47
124
|
exports.buildVisitorObject = buildVisitorObject;
|
|
48
|
-
function buildSubjectVisitor(assertId, assertion
|
|
49
|
-
return (node, { report, location, rawLocation,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const excludeParentKeys = lastContextNode.excludeParentKeys;
|
|
60
|
-
if (matchParentKeys && !matchParentKeys.includes(key)) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (excludeParentKeys && excludeParentKeys.includes(key)) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
if (properties) {
|
|
69
|
-
properties = Array.isArray(properties) ? properties : [properties];
|
|
70
|
-
}
|
|
71
|
-
const defaultMessage = `${logger_1.colorize.blue(assertId)} failed because the ${logger_1.colorize.blue(assertion.subject)}${logger_1.colorize.blue(properties ? ` ${properties.join(', ')}` : '')} didn't meet the assertions: {{problems}}`;
|
|
72
|
-
const assertResults = [];
|
|
73
|
-
for (const assert of asserts) {
|
|
74
|
-
const currentLocation = assert.name === 'ref' ? rawLocation : location;
|
|
75
|
-
if (properties) {
|
|
76
|
-
for (const property of properties) {
|
|
77
|
-
// we can have resolvable scalar so need to resolve value here.
|
|
78
|
-
const value = ref_utils_1.isRef(node[property]) ? (_a = resolve(node[property])) === null || _a === void 0 ? void 0 : _a.node : node[property];
|
|
79
|
-
assertResults.push(runAssertion({
|
|
80
|
-
values: value,
|
|
81
|
-
rawValues: rawNode[property],
|
|
82
|
-
assert,
|
|
83
|
-
location: currentLocation.child(property),
|
|
84
|
-
}));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
const value = assert.name === 'ref' ? rawNode : Object.keys(node);
|
|
89
|
-
assertResults.push(runAssertion({
|
|
90
|
-
values: Object.keys(node),
|
|
91
|
-
rawValues: value,
|
|
92
|
-
assert,
|
|
93
|
-
location: currentLocation,
|
|
94
|
-
}));
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
const problems = assertResults.flat();
|
|
125
|
+
function buildSubjectVisitor(assertId, assertion) {
|
|
126
|
+
return (node, { report, location, rawLocation, resolve, rawNode }) => {
|
|
127
|
+
const properties = getAssertionProperties(assertion);
|
|
128
|
+
const defaultMessage = `${logger_1.colorize.blue(assertId)} failed because the ${logger_1.colorize.blue(assertion.subject.type)} ${logger_1.colorize.blue(properties.join(', '))} didn't meet the assertions: ${assertionMessageTemplates.problems}`.replace(/ +/g, ' ');
|
|
129
|
+
const problems = applyAssertions(assertion, getAssertsToApply(assertion), {
|
|
130
|
+
rawLocation,
|
|
131
|
+
rawNode,
|
|
132
|
+
resolve,
|
|
133
|
+
location,
|
|
134
|
+
node,
|
|
135
|
+
});
|
|
98
136
|
if (problems.length) {
|
|
99
137
|
const message = assertion.message || defaultMessage;
|
|
100
|
-
|
|
101
|
-
message
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
138
|
+
for (const problem of problems) {
|
|
139
|
+
const problemMessage = problem.message ? problem.message : defaultMessage;
|
|
140
|
+
report({
|
|
141
|
+
message: message.replace(assertionMessageTemplates.problems, problemMessage),
|
|
142
|
+
location: problem.location || location,
|
|
143
|
+
forceSeverity: assertion.severity || 'error',
|
|
144
|
+
suggest: assertion.suggest || [],
|
|
145
|
+
ruleId: assertId,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
107
148
|
}
|
|
108
149
|
};
|
|
109
150
|
}
|
|
110
151
|
exports.buildSubjectVisitor = buildSubjectVisitor;
|
|
111
|
-
function getProblemsLocation(problems) {
|
|
112
|
-
return problems.length ? problems[0].location : undefined;
|
|
113
|
-
}
|
|
114
|
-
function getProblemsMessage(problems) {
|
|
115
|
-
var _a;
|
|
116
|
-
return problems.length === 1
|
|
117
|
-
? (_a = problems[0].message) !== null && _a !== void 0 ? _a : ''
|
|
118
|
-
: problems.map((problem) => { var _a; return `\n- ${(_a = problem.message) !== null && _a !== void 0 ? _a : ''}`; }).join('');
|
|
119
|
-
}
|
|
120
152
|
function getIntersectionLength(keys, properties) {
|
|
121
153
|
const props = new Set(properties);
|
|
122
154
|
let count = 0;
|
package/lib/rules/common/spec.js
CHANGED
|
@@ -142,6 +142,12 @@ const OasSpec = () => {
|
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
+
if (propName === 'nullable' && !node.type) {
|
|
146
|
+
report({
|
|
147
|
+
message: 'The `type` field must be defined when the `nullable` field is used.',
|
|
148
|
+
location: location.child([propName]),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
145
151
|
}
|
|
146
152
|
},
|
|
147
153
|
};
|
package/lib/rules/oas2/index.js
CHANGED
|
@@ -4,7 +4,6 @@ exports.preprocessors = exports.rules = void 0;
|
|
|
4
4
|
const spec_1 = require("../common/spec");
|
|
5
5
|
const no_invalid_schema_examples_1 = require("../common/no-invalid-schema-examples");
|
|
6
6
|
const no_invalid_parameter_examples_1 = require("../common/no-invalid-parameter-examples");
|
|
7
|
-
const info_description_1 = require("../common/info-description");
|
|
8
7
|
const info_contact_1 = require("../common/info-contact");
|
|
9
8
|
const info_license_1 = require("../common/info-license");
|
|
10
9
|
const info_license_url_1 = require("../common/info-license-url");
|
|
@@ -46,7 +45,6 @@ exports.rules = {
|
|
|
46
45
|
spec: spec_1.OasSpec,
|
|
47
46
|
'no-invalid-schema-examples': no_invalid_schema_examples_1.NoInvalidSchemaExamples,
|
|
48
47
|
'no-invalid-parameter-examples': no_invalid_parameter_examples_1.NoInvalidParameterExamples,
|
|
49
|
-
'info-description': info_description_1.InfoDescription,
|
|
50
48
|
'info-contact': info_contact_1.InfoContact,
|
|
51
49
|
'info-license': info_license_1.InfoLicense,
|
|
52
50
|
'info-license-url': info_license_url_1.InfoLicenseUrl,
|
package/lib/rules/oas3/index.js
CHANGED
|
@@ -17,7 +17,6 @@ const operation_operationId_url_safe_1 = require("../common/operation-operationI
|
|
|
17
17
|
const tags_alphabetical_1 = require("../common/tags-alphabetical");
|
|
18
18
|
const no_server_example_com_1 = require("./no-server-example.com");
|
|
19
19
|
const no_server_trailing_slash_1 = require("./no-server-trailing-slash");
|
|
20
|
-
const info_description_1 = require("../common/info-description");
|
|
21
20
|
const tag_description_1 = require("../common/tag-description");
|
|
22
21
|
const info_contact_1 = require("../common/info-contact");
|
|
23
22
|
const info_license_1 = require("../common/info-license");
|
|
@@ -54,7 +53,6 @@ const spec_components_invalid_map_name_1 = require("./spec-components-invalid-ma
|
|
|
54
53
|
const operation_4xx_problem_details_rfc7807_1 = require("./operation-4xx-problem-details-rfc7807");
|
|
55
54
|
exports.rules = {
|
|
56
55
|
spec: spec_1.OasSpec,
|
|
57
|
-
'info-description': info_description_1.InfoDescription,
|
|
58
56
|
'info-contact': info_contact_1.InfoContact,
|
|
59
57
|
'info-license': info_license_1.InfoLicense,
|
|
60
58
|
'info-license-url': info_license_url_1.InfoLicenseUrl,
|
package/lib/rules/utils.js
CHANGED
|
@@ -101,6 +101,9 @@ function validateExample(example, schema, dataLoc, { resolve, location, report }
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
catch (e) {
|
|
104
|
+
if (e.message === 'discriminator: requires oneOf or anyOf composite keyword') {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
104
107
|
report({
|
|
105
108
|
message: `Example validation errored: ${e.message}.`,
|
|
106
109
|
location: location.child('schema'),
|
package/lib/types/oas2.js
CHANGED
|
@@ -17,8 +17,8 @@ const Root = {
|
|
|
17
17
|
parameters: 'NamedParameters',
|
|
18
18
|
responses: 'NamedResponses',
|
|
19
19
|
securityDefinitions: 'NamedSecuritySchemes',
|
|
20
|
-
security:
|
|
21
|
-
tags:
|
|
20
|
+
security: 'SecurityRequirementList',
|
|
21
|
+
tags: 'TagList',
|
|
22
22
|
externalDocs: 'ExternalDocs',
|
|
23
23
|
},
|
|
24
24
|
required: ['swagger', 'paths', 'info'],
|
|
@@ -55,7 +55,7 @@ const Paths = {
|
|
|
55
55
|
const PathItem = {
|
|
56
56
|
properties: {
|
|
57
57
|
$ref: { type: 'string' },
|
|
58
|
-
parameters:
|
|
58
|
+
parameters: 'ParameterList',
|
|
59
59
|
get: 'Operation',
|
|
60
60
|
put: 'Operation',
|
|
61
61
|
post: 'Operation',
|
|
@@ -74,13 +74,13 @@ const Operation = {
|
|
|
74
74
|
operationId: { type: 'string' },
|
|
75
75
|
consumes: { type: 'array', items: { type: 'string' } },
|
|
76
76
|
produces: { type: 'array', items: { type: 'string' } },
|
|
77
|
-
parameters:
|
|
77
|
+
parameters: 'ParameterList',
|
|
78
78
|
responses: 'Responses',
|
|
79
79
|
schemes: { type: 'array', items: { type: 'string' } },
|
|
80
80
|
deprecated: { type: 'boolean' },
|
|
81
|
-
security:
|
|
82
|
-
'x-codeSamples':
|
|
83
|
-
'x-code-samples':
|
|
81
|
+
security: 'SecurityRequirementList',
|
|
82
|
+
'x-codeSamples': 'XCodeSampleList',
|
|
83
|
+
'x-code-samples': 'XCodeSampleList',
|
|
84
84
|
'x-hideTryItPanel': { type: 'boolean' },
|
|
85
85
|
},
|
|
86
86
|
required: ['responses'],
|
|
@@ -354,8 +354,10 @@ const SecurityRequirement = {
|
|
|
354
354
|
exports.Oas2Types = {
|
|
355
355
|
Root,
|
|
356
356
|
Tag,
|
|
357
|
+
TagList: _1.listOf('Tag'),
|
|
357
358
|
ExternalDocs,
|
|
358
359
|
SecurityRequirement,
|
|
360
|
+
SecurityRequirementList: _1.listOf('SecurityRequirement'),
|
|
359
361
|
Info,
|
|
360
362
|
Contact,
|
|
361
363
|
License,
|
|
@@ -363,6 +365,7 @@ exports.Oas2Types = {
|
|
|
363
365
|
PathItem,
|
|
364
366
|
Parameter,
|
|
365
367
|
ParameterItems,
|
|
368
|
+
ParameterList: _1.listOf('Parameter'),
|
|
366
369
|
Operation,
|
|
367
370
|
Examples,
|
|
368
371
|
Header,
|
|
@@ -377,4 +380,5 @@ exports.Oas2Types = {
|
|
|
377
380
|
NamedSecuritySchemes: _1.mapOf('SecurityScheme'),
|
|
378
381
|
SecurityScheme,
|
|
379
382
|
XCodeSample,
|
|
383
|
+
XCodeSampleList: _1.listOf('XCodeSample'),
|
|
380
384
|
};
|
package/lib/types/oas3.js
CHANGED
|
@@ -8,9 +8,9 @@ const Root = {
|
|
|
8
8
|
properties: {
|
|
9
9
|
openapi: null,
|
|
10
10
|
info: 'Info',
|
|
11
|
-
servers:
|
|
12
|
-
security:
|
|
13
|
-
tags:
|
|
11
|
+
servers: 'ServerList',
|
|
12
|
+
security: 'SecurityRequirementList',
|
|
13
|
+
tags: 'TagList',
|
|
14
14
|
externalDocs: 'ExternalDocs',
|
|
15
15
|
paths: 'Paths',
|
|
16
16
|
components: 'Components',
|
|
@@ -92,8 +92,8 @@ const WebhooksMap = {
|
|
|
92
92
|
const PathItem = {
|
|
93
93
|
properties: {
|
|
94
94
|
$ref: { type: 'string' },
|
|
95
|
-
servers:
|
|
96
|
-
parameters:
|
|
95
|
+
servers: 'ServerList',
|
|
96
|
+
parameters: 'ParameterList',
|
|
97
97
|
summary: { type: 'string' },
|
|
98
98
|
description: { type: 'string' },
|
|
99
99
|
get: 'Operation',
|
|
@@ -137,15 +137,15 @@ const Operation = {
|
|
|
137
137
|
description: { type: 'string' },
|
|
138
138
|
externalDocs: 'ExternalDocs',
|
|
139
139
|
operationId: { type: 'string' },
|
|
140
|
-
parameters:
|
|
141
|
-
security:
|
|
142
|
-
servers:
|
|
140
|
+
parameters: 'ParameterList',
|
|
141
|
+
security: 'SecurityRequirementList',
|
|
142
|
+
servers: 'ServerList',
|
|
143
143
|
requestBody: 'RequestBody',
|
|
144
144
|
responses: 'Responses',
|
|
145
145
|
deprecated: { type: 'boolean' },
|
|
146
146
|
callbacks: 'CallbacksMap',
|
|
147
|
-
'x-codeSamples':
|
|
148
|
-
'x-code-samples':
|
|
147
|
+
'x-codeSamples': 'XCodeSampleList',
|
|
148
|
+
'x-code-samples': 'XCodeSampleList',
|
|
149
149
|
'x-hideTryItPanel': { type: 'boolean' },
|
|
150
150
|
},
|
|
151
151
|
required: ['responses'],
|
|
@@ -430,17 +430,21 @@ const SecurityScheme = {
|
|
|
430
430
|
exports.Oas3Types = {
|
|
431
431
|
Root,
|
|
432
432
|
Tag,
|
|
433
|
+
TagList: _1.listOf('Tag'),
|
|
433
434
|
ExternalDocs,
|
|
434
435
|
Server,
|
|
436
|
+
ServerList: _1.listOf('Server'),
|
|
435
437
|
ServerVariable,
|
|
436
438
|
ServerVariablesMap: _1.mapOf('ServerVariable'),
|
|
437
439
|
SecurityRequirement,
|
|
440
|
+
SecurityRequirementList: _1.listOf('SecurityRequirement'),
|
|
438
441
|
Info,
|
|
439
442
|
Contact,
|
|
440
443
|
License,
|
|
441
444
|
Paths,
|
|
442
445
|
PathItem,
|
|
443
446
|
Parameter,
|
|
447
|
+
ParameterList: _1.listOf('Parameter'),
|
|
444
448
|
Operation,
|
|
445
449
|
Callback: _1.mapOf('PathItem'),
|
|
446
450
|
CallbacksMap: _1.mapOf('Callback'),
|
|
@@ -479,5 +483,6 @@ exports.Oas3Types = {
|
|
|
479
483
|
OAuth2Flows,
|
|
480
484
|
SecurityScheme,
|
|
481
485
|
XCodeSample,
|
|
486
|
+
XCodeSampleList: _1.listOf('XCodeSample'),
|
|
482
487
|
WebhooksMap,
|
|
483
488
|
};
|
package/lib/types/oas3_1.js
CHANGED
|
@@ -5,7 +5,6 @@ const _1 = require(".");
|
|
|
5
5
|
const utils_1 = require("../utils");
|
|
6
6
|
const builtInRulesList = [
|
|
7
7
|
'spec',
|
|
8
|
-
'info-description',
|
|
9
8
|
'info-contact',
|
|
10
9
|
'info-license',
|
|
11
10
|
'info-license-url',
|
|
@@ -60,17 +59,21 @@ const builtInRulesList = [
|
|
|
60
59
|
const nodeTypesList = [
|
|
61
60
|
'Root',
|
|
62
61
|
'Tag',
|
|
62
|
+
'TagList',
|
|
63
63
|
'ExternalDocs',
|
|
64
64
|
'Server',
|
|
65
|
+
'ServerList',
|
|
65
66
|
'ServerVariable',
|
|
66
67
|
'ServerVariablesMap',
|
|
67
68
|
'SecurityRequirement',
|
|
69
|
+
'SecurityRequirementList',
|
|
68
70
|
'Info',
|
|
69
71
|
'Contact',
|
|
70
72
|
'License',
|
|
71
73
|
'Paths',
|
|
72
74
|
'PathItem',
|
|
73
75
|
'Parameter',
|
|
76
|
+
'ParameterList',
|
|
74
77
|
'Operation',
|
|
75
78
|
'Callback',
|
|
76
79
|
'CallbacksMap',
|
|
@@ -109,6 +112,7 @@ const nodeTypesList = [
|
|
|
109
112
|
'OAuth2Flows',
|
|
110
113
|
'SecurityScheme',
|
|
111
114
|
'XCodeSample',
|
|
115
|
+
'XCodeSampleList',
|
|
112
116
|
'WebhooksMap',
|
|
113
117
|
];
|
|
114
118
|
const ConfigStyleguide = {
|
|
@@ -140,11 +144,7 @@ const RootConfigStyleguide = {
|
|
|
140
144
|
} }, ConfigStyleguide.properties),
|
|
141
145
|
};
|
|
142
146
|
const ConfigRoot = {
|
|
143
|
-
properties: Object.assign(Object.assign({ organization: { type: 'string' }, apis: 'ConfigApis',
|
|
144
|
-
type: 'object',
|
|
145
|
-
properties: {},
|
|
146
|
-
additionalProperties: { properties: { type: 'string' } },
|
|
147
|
-
} }, RootConfigStyleguide.properties), { styleguide: 'RootConfigStyleguide', lint: 'RootConfigStyleguide', 'features.openapi': 'ConfigReferenceDocs', referenceDocs: 'ConfigReferenceDocs', 'features.mockServer': 'ConfigMockServer', region: { enum: ['us', 'eu'] }, resolve: {
|
|
147
|
+
properties: Object.assign(Object.assign({ organization: { type: 'string' }, apis: 'ConfigApis' }, RootConfigStyleguide.properties), { 'features.openapi': 'ConfigReferenceDocs', 'features.mockServer': 'ConfigMockServer', region: { enum: ['us', 'eu'] }, resolve: {
|
|
148
148
|
properties: {
|
|
149
149
|
http: 'ConfigHTTP',
|
|
150
150
|
doNotResolveExamples: { type: 'boolean' },
|
|
@@ -209,16 +209,9 @@ const ObjectRule = {
|
|
|
209
209
|
additionalProperties: {},
|
|
210
210
|
required: ['severity'],
|
|
211
211
|
};
|
|
212
|
-
const
|
|
212
|
+
const AssertionDefinitionSubject = {
|
|
213
213
|
properties: {
|
|
214
|
-
|
|
215
|
-
if (Array.isArray(value)) {
|
|
216
|
-
return { type: 'array', items: { enum: nodeTypesList } };
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
return { enum: nodeTypesList };
|
|
220
|
-
}
|
|
221
|
-
},
|
|
214
|
+
type: { enum: nodeTypesList },
|
|
222
215
|
property: (value) => {
|
|
223
216
|
if (Array.isArray(value)) {
|
|
224
217
|
return { type: 'array', items: { type: 'string' } };
|
|
@@ -230,10 +223,14 @@ const Assert = {
|
|
|
230
223
|
return { type: 'string' };
|
|
231
224
|
}
|
|
232
225
|
},
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
226
|
+
filterInParentKeys: { type: 'array', items: { type: 'string' } },
|
|
227
|
+
filterOutParentKeys: { type: 'array', items: { type: 'string' } },
|
|
228
|
+
matchParentKeys: { type: 'string' },
|
|
229
|
+
},
|
|
230
|
+
required: ['type'],
|
|
231
|
+
};
|
|
232
|
+
const AssertionDefinitionAssertions = {
|
|
233
|
+
properties: {
|
|
237
234
|
enum: { type: 'array', items: { type: 'string' } },
|
|
238
235
|
pattern: { type: 'string' },
|
|
239
236
|
casing: {
|
|
@@ -253,26 +250,49 @@ const Assert = {
|
|
|
253
250
|
requireAny: { type: 'array', items: { type: 'string' } },
|
|
254
251
|
disallowed: { type: 'array', items: { type: 'string' } },
|
|
255
252
|
defined: { type: 'boolean' },
|
|
256
|
-
undefined: { type: 'boolean' },
|
|
253
|
+
// undefined: { type: 'boolean' }, // TODO: Remove `undefined` assertion from codebase overall
|
|
257
254
|
nonEmpty: { type: 'boolean' },
|
|
258
255
|
minLength: { type: 'integer' },
|
|
259
256
|
maxLength: { type: 'integer' },
|
|
260
257
|
ref: (value) => typeof value === 'string' ? { type: 'string' } : { type: 'boolean' },
|
|
258
|
+
const: (value) => {
|
|
259
|
+
if (typeof value === 'string') {
|
|
260
|
+
return { type: 'string' };
|
|
261
|
+
}
|
|
262
|
+
if (typeof value === 'number') {
|
|
263
|
+
return { type: 'number' };
|
|
264
|
+
}
|
|
265
|
+
if (typeof value === 'boolean') {
|
|
266
|
+
return { type: 'boolean' };
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
},
|
|
261
272
|
},
|
|
262
273
|
additionalProperties: (_value, key) => {
|
|
263
274
|
if (/^\w+\/\w+$/.test(key))
|
|
264
275
|
return { type: 'object' };
|
|
265
276
|
return;
|
|
266
277
|
},
|
|
267
|
-
required: ['subject'],
|
|
268
278
|
};
|
|
269
|
-
const
|
|
279
|
+
const AssertDefinition = {
|
|
270
280
|
properties: {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
excludeParentKeys: { type: 'array', items: { type: 'string' } },
|
|
281
|
+
subject: 'AssertionDefinitionSubject',
|
|
282
|
+
assertions: 'AssertionDefinitionAssertions',
|
|
274
283
|
},
|
|
275
|
-
required: ['
|
|
284
|
+
required: ['subject', 'assertions'],
|
|
285
|
+
};
|
|
286
|
+
const Assert = {
|
|
287
|
+
properties: {
|
|
288
|
+
subject: 'AssertionDefinitionSubject',
|
|
289
|
+
assertions: 'AssertionDefinitionAssertions',
|
|
290
|
+
where: _1.listOf('AssertDefinition'),
|
|
291
|
+
message: { type: 'string' },
|
|
292
|
+
suggest: { type: 'array', items: { type: 'string' } },
|
|
293
|
+
severity: { enum: ['error', 'warn', 'off'] },
|
|
294
|
+
},
|
|
295
|
+
required: ['subject', 'assertions'],
|
|
276
296
|
};
|
|
277
297
|
const ConfigLanguage = {
|
|
278
298
|
properties: {
|
|
@@ -792,7 +812,7 @@ exports.ConfigTypes = {
|
|
|
792
812
|
ConfigSidebarLinks,
|
|
793
813
|
CommonConfigSidebarLinks,
|
|
794
814
|
ConfigTheme,
|
|
795
|
-
|
|
815
|
+
AssertDefinition,
|
|
796
816
|
ThemeColors,
|
|
797
817
|
CommonThemeColors,
|
|
798
818
|
BorderThemeColors,
|
|
@@ -839,4 +859,6 @@ exports.ConfigTypes = {
|
|
|
839
859
|
Sidebar,
|
|
840
860
|
Heading,
|
|
841
861
|
Typography,
|
|
862
|
+
AssertionDefinitionAssertions,
|
|
863
|
+
AssertionDefinitionSubject,
|
|
842
864
|
};
|
package/lib/utils.d.ts
CHANGED
|
@@ -46,4 +46,6 @@ export declare function showErrorForDeprecatedField(deprecatedField: string, upd
|
|
|
46
46
|
export declare type Falsy = undefined | null | false | '' | 0;
|
|
47
47
|
export declare function isTruthy<Truthy>(value: Truthy | Falsy): value is Truthy;
|
|
48
48
|
export declare function identity<T>(value: T): T;
|
|
49
|
+
export declare function keysOf<T>(obj: T): (keyof T)[];
|
|
49
50
|
export declare function pickDefined<T extends Record<string, unknown>>(obj?: T): Record<string, unknown> | undefined;
|
|
51
|
+
export declare function nextTick(): void;
|