@redocly/openapi-core 1.18.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/lib/benchmark/benches/lint-with-many-rules.bench.js +2 -2
- package/lib/benchmark/benches/lint-with-nested-rule.bench.js +2 -2
- package/lib/benchmark/benches/lint-with-no-rules.bench.js +2 -2
- package/lib/benchmark/benches/lint-with-top-level-rule-report.bench.js +2 -2
- package/lib/benchmark/benches/lint-with-top-level-rule.bench.js +2 -2
- package/lib/benchmark/benches/recommended-oas3.bench.js +2 -2
- package/lib/benchmark/benches/resolve-with-no-external.bench.js +2 -2
- package/lib/benchmark/utils.js +7 -4
- package/lib/bundle.d.ts +3 -3
- package/lib/bundle.js +128 -122
- package/lib/config/all.js +9 -0
- package/lib/config/builtIn.js +7 -1
- package/lib/config/config-resolvers.js +179 -138
- package/lib/config/config.d.ts +2 -2
- package/lib/config/config.js +53 -34
- package/lib/config/load.d.ts +1 -2
- package/lib/config/load.js +105 -117
- package/lib/config/minimal.js +9 -0
- package/lib/config/recommended-strict.js +9 -0
- package/lib/config/recommended.js +9 -0
- package/lib/config/rules.d.ts +3 -3
- package/lib/config/rules.js +1 -2
- package/lib/config/types.d.ts +9 -3
- package/lib/config/utils.js +70 -49
- package/lib/decorators/async3/index.d.ts +1 -0
- package/lib/decorators/async3/index.js +4 -0
- package/lib/decorators/common/filters/filter-helper.js +2 -3
- package/lib/decorators/common/filters/filter-in.js +1 -1
- package/lib/decorators/common/filters/filter-out.js +1 -1
- package/lib/decorators/common/info-override.js +1 -12
- package/lib/decorators/common/media-type-examples-override.js +8 -2
- package/lib/decorators/common/remove-x-internal.js +4 -5
- package/lib/decorators/oas2/remove-unused-components.js +1 -2
- package/lib/decorators/oas3/remove-unused-components.js +1 -2
- package/lib/env.d.ts +0 -1
- package/lib/env.js +1 -1
- package/lib/format/codeframes.js +10 -8
- package/lib/format/format.js +23 -15
- package/lib/index.d.ts +2 -1
- package/lib/index.js +6 -4
- package/lib/js-yaml/index.js +1 -1
- package/lib/lint.d.ts +2 -0
- package/lib/lint.js +92 -99
- package/lib/oas-types.d.ts +9 -5
- package/lib/oas-types.js +22 -12
- package/lib/redocly/domains.js +6 -6
- package/lib/redocly/index.js +60 -73
- package/lib/redocly/registry-api.js +64 -82
- package/lib/ref-utils.js +13 -13
- package/lib/resolve.js +186 -205
- package/lib/rules/ajv.js +10 -8
- package/lib/rules/async3/channels-kebab-case.d.ts +2 -0
- package/lib/rules/async3/channels-kebab-case.js +19 -0
- package/lib/rules/async3/index.d.ts +3 -0
- package/lib/rules/async3/index.js +22 -0
- package/lib/rules/async3/no-channel-trailing-slash.d.ts +2 -0
- package/lib/rules/async3/no-channel-trailing-slash.js +16 -0
- package/lib/rules/common/assertions/asserts.js +5 -5
- package/lib/rules/common/assertions/index.d.ts +5 -4
- package/lib/rules/common/assertions/utils.js +43 -28
- package/lib/rules/common/no-invalid-parameter-examples.js +1 -2
- package/lib/rules/common/no-invalid-schema-examples.js +1 -2
- package/lib/rules/common/no-required-schema-properties-undefined.js +1 -2
- package/lib/rules/common/operation-tag-defined.js +1 -2
- package/lib/rules/common/path-http-verbs-order.js +1 -1
- package/lib/rules/common/path-segment-plural.js +2 -1
- package/lib/rules/common/required-string-property-missing-min-length.js +2 -2
- package/lib/rules/common/response-contains-header.js +2 -2
- package/lib/rules/common/security-defined.js +3 -7
- package/lib/rules/common/spec.d.ts +2 -2
- package/lib/rules/common/spec.js +6 -7
- package/lib/rules/no-unresolved-refs.js +3 -4
- package/lib/rules/oas2/response-contains-property.js +1 -2
- package/lib/rules/oas3/array-parameter-serialization.js +1 -2
- package/lib/rules/oas3/component-name-unique.js +2 -4
- package/lib/rules/oas3/no-invalid-media-type-examples.js +1 -2
- package/lib/rules/oas3/no-server-variables-empty-enum.js +1 -2
- package/lib/rules/oas3/no-undefined-server-variable.js +2 -3
- package/lib/rules/oas3/no-unused-components.js +1 -2
- package/lib/rules/oas3/response-contains-property.js +1 -2
- package/lib/rules/utils.js +14 -12
- package/lib/types/arazzo.d.ts +1299 -73
- package/lib/types/arazzo.js +41 -36
- package/lib/types/asyncapi2.d.ts +17 -0
- package/lib/types/{asyncapi.js → asyncapi2.js} +71 -93
- package/lib/types/asyncapi3.d.ts +2 -0
- package/lib/types/asyncapi3.js +347 -0
- package/lib/types/index.js +19 -10
- package/lib/types/json-schema-adapter.js +4 -18
- package/lib/types/oas2.js +6 -6
- package/lib/types/oas3.js +10 -10
- package/lib/types/oas3_1.js +15 -9
- package/lib/types/redocly-yaml.d.ts +3 -1
- package/lib/types/redocly-yaml.js +131 -35
- package/lib/typings/arazzo.d.ts +28 -1
- package/lib/typings/asyncapi3.d.ts +53 -0
- package/lib/typings/asyncapi3.js +2 -0
- package/lib/utils.d.ts +12 -7
- package/lib/utils.js +91 -77
- package/lib/visitors.d.ts +11 -0
- package/lib/visitors.js +21 -8
- package/lib/walk.js +30 -23
- package/package.json +3 -3
- package/src/__tests__/bundle.test.ts +142 -0
- package/src/__tests__/lint.test.ts +0 -50
- package/src/bundle.ts +19 -6
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +22 -0
- package/src/config/__tests__/__snapshots__/config.test.ts.snap +24 -0
- package/src/config/__tests__/config.test.ts +11 -0
- package/src/config/all.ts +9 -0
- package/src/config/builtIn.ts +6 -0
- package/src/config/config-resolvers.ts +15 -2
- package/src/config/config.ts +24 -5
- package/src/config/load.ts +1 -2
- package/src/config/minimal.ts +9 -0
- package/src/config/recommended-strict.ts +9 -0
- package/src/config/recommended.ts +9 -0
- package/src/config/rules.ts +12 -4
- package/src/config/types.ts +15 -2
- package/src/config/utils.ts +15 -0
- package/src/decorators/async3/index.ts +1 -0
- package/src/decorators/common/remove-x-internal.ts +2 -2
- package/src/index.ts +2 -1
- package/src/lint.ts +26 -3
- package/src/oas-types.ts +31 -13
- package/src/rules/arazzo/index.ts +1 -1
- package/src/rules/async2/index.ts +5 -5
- package/src/rules/async3/__tests__/channels-kebab-case.test.ts +141 -0
- package/src/rules/async3/__tests__/no-channel-trailing-slash.test.ts +96 -0
- package/src/rules/async3/channels-kebab-case.ts +19 -0
- package/src/rules/async3/index.ts +23 -0
- package/src/rules/async3/no-channel-trailing-slash.ts +16 -0
- package/src/rules/common/__tests__/spec.test.ts +47 -0
- package/src/rules/common/assertions/index.ts +13 -4
- package/src/rules/common/no-invalid-schema-examples.ts +3 -2
- package/src/rules/common/path-segment-plural.ts +3 -2
- package/src/rules/common/spec.ts +2 -2
- package/src/rules/oas2/index.ts +4 -4
- package/src/rules/oas3/index.ts +39 -37
- package/src/types/arazzo.ts +28 -23
- package/src/types/{asyncapi.ts → asyncapi2.ts} +58 -76
- package/src/types/asyncapi3.ts +381 -0
- package/src/types/oas3_1.ts +3 -2
- package/src/types/redocly-yaml.ts +14 -0
- package/src/typings/arazzo.ts +41 -1
- package/src/typings/asyncapi3.ts +61 -0
- package/src/utils.ts +46 -11
- package/src/visitors.ts +18 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/types/asyncapi.d.ts +0 -2
package/lib/utils.js
CHANGED
|
@@ -1,20 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.
|
|
3
|
+
exports.stringifyYaml = exports.parseYaml = void 0;
|
|
4
|
+
exports.pushStack = pushStack;
|
|
5
|
+
exports.popStack = popStack;
|
|
6
|
+
exports.loadYaml = loadYaml;
|
|
7
|
+
exports.isDefined = isDefined;
|
|
8
|
+
exports.isPlainObject = isPlainObject;
|
|
9
|
+
exports.isEmptyObject = isEmptyObject;
|
|
10
|
+
exports.isEmptyArray = isEmptyArray;
|
|
11
|
+
exports.readFileFromUrl = readFileFromUrl;
|
|
12
|
+
exports.pickObjectProps = pickObjectProps;
|
|
13
|
+
exports.omitObjectProps = omitObjectProps;
|
|
14
|
+
exports.splitCamelCaseIntoWords = splitCamelCaseIntoWords;
|
|
15
|
+
exports.validateMimeType = validateMimeType;
|
|
16
|
+
exports.validateMimeTypeOAS3 = validateMimeTypeOAS3;
|
|
17
|
+
exports.readFileAsStringSync = readFileAsStringSync;
|
|
18
|
+
exports.yamlAndJsonSyncReader = yamlAndJsonSyncReader;
|
|
19
|
+
exports.isPathParameter = isPathParameter;
|
|
20
|
+
exports.slash = slash;
|
|
21
|
+
exports.isNotEmptyObject = isNotEmptyObject;
|
|
22
|
+
exports.isString = isString;
|
|
23
|
+
exports.isNotString = isNotString;
|
|
24
|
+
exports.assignExisting = assignExisting;
|
|
25
|
+
exports.getMatchingStatusCodeRange = getMatchingStatusCodeRange;
|
|
26
|
+
exports.isCustomRuleId = isCustomRuleId;
|
|
27
|
+
exports.doesYamlFileExist = doesYamlFileExist;
|
|
28
|
+
exports.showWarningForDeprecatedField = showWarningForDeprecatedField;
|
|
29
|
+
exports.showErrorForDeprecatedField = showErrorForDeprecatedField;
|
|
30
|
+
exports.isTruthy = isTruthy;
|
|
31
|
+
exports.identity = identity;
|
|
32
|
+
exports.keysOf = keysOf;
|
|
33
|
+
exports.pickDefined = pickDefined;
|
|
34
|
+
exports.nextTick = nextTick;
|
|
35
|
+
exports.pause = pause;
|
|
36
|
+
exports.getProxyAgent = getProxyAgent;
|
|
37
|
+
exports.dequal = dequal;
|
|
13
38
|
const fs = require("fs");
|
|
14
39
|
const path_1 = require("path");
|
|
15
40
|
const minimatch = require("minimatch");
|
|
16
41
|
const node_fetch_1 = require("node-fetch");
|
|
17
|
-
const pluralize = require("pluralize");
|
|
18
42
|
const js_yaml_1 = require("./js-yaml");
|
|
19
43
|
const env_1 = require("./env");
|
|
20
44
|
const logger_1 = require("./logger");
|
|
@@ -25,54 +49,41 @@ Object.defineProperty(exports, "stringifyYaml", { enumerable: true, get: functio
|
|
|
25
49
|
function pushStack(head, value) {
|
|
26
50
|
return { prev: head, value };
|
|
27
51
|
}
|
|
28
|
-
exports.pushStack = pushStack;
|
|
29
52
|
function popStack(head) {
|
|
30
|
-
|
|
31
|
-
return (_a = head === null || head === void 0 ? void 0 : head.prev) !== null && _a !== void 0 ? _a : null;
|
|
53
|
+
return head?.prev ?? null;
|
|
32
54
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return
|
|
36
|
-
const contents = yield fs.promises.readFile(filename, 'utf-8');
|
|
37
|
-
return (0, js_yaml_1.parseYaml)(contents);
|
|
38
|
-
});
|
|
55
|
+
async function loadYaml(filename) {
|
|
56
|
+
const contents = await fs.promises.readFile(filename, 'utf-8');
|
|
57
|
+
return (0, js_yaml_1.parseYaml)(contents);
|
|
39
58
|
}
|
|
40
|
-
exports.loadYaml = loadYaml;
|
|
41
59
|
function isDefined(x) {
|
|
42
60
|
return x !== undefined;
|
|
43
61
|
}
|
|
44
|
-
exports.isDefined = isDefined;
|
|
45
62
|
function isPlainObject(value) {
|
|
46
63
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
47
64
|
}
|
|
48
|
-
exports.isPlainObject = isPlainObject;
|
|
49
65
|
function isEmptyObject(value) {
|
|
50
66
|
return isPlainObject(value) && Object.keys(value).length === 0;
|
|
51
67
|
}
|
|
52
|
-
exports.isEmptyObject = isEmptyObject;
|
|
53
68
|
function isEmptyArray(value) {
|
|
54
69
|
return Array.isArray(value) && value.length === 0;
|
|
55
70
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
headers[header.name] =
|
|
63
|
-
header.envVariable !== undefined ? env_1.env[header.envVariable] || '' : header.value;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
const req = yield (config.customFetch || node_fetch_1.default)(url, {
|
|
67
|
-
headers: headers,
|
|
68
|
-
});
|
|
69
|
-
if (!req.ok) {
|
|
70
|
-
throw new Error(`Failed to load ${url}: ${req.status} ${req.statusText}`);
|
|
71
|
+
async function readFileFromUrl(url, config) {
|
|
72
|
+
const headers = {};
|
|
73
|
+
for (const header of config.headers) {
|
|
74
|
+
if (match(url, header.matches)) {
|
|
75
|
+
headers[header.name] =
|
|
76
|
+
header.envVariable !== undefined ? env_1.env[header.envVariable] || '' : header.value;
|
|
71
77
|
}
|
|
72
|
-
|
|
78
|
+
}
|
|
79
|
+
const req = await (config.customFetch || node_fetch_1.default)(url, {
|
|
80
|
+
headers: headers,
|
|
73
81
|
});
|
|
82
|
+
if (!req.ok) {
|
|
83
|
+
throw new Error(`Failed to load ${url}: ${req.status} ${req.statusText}`);
|
|
84
|
+
}
|
|
85
|
+
return { body: await req.text(), mimeType: req.headers.get('content-type') };
|
|
74
86
|
}
|
|
75
|
-
exports.readFileFromUrl = readFileFromUrl;
|
|
76
87
|
function match(url, pattern) {
|
|
77
88
|
if (!pattern.match(/^https?:\/\//)) {
|
|
78
89
|
// if pattern doesn't specify protocol directly, do not match against it
|
|
@@ -83,11 +94,9 @@ function match(url, pattern) {
|
|
|
83
94
|
function pickObjectProps(object, keys) {
|
|
84
95
|
return Object.fromEntries(keys.filter((key) => key in object).map((key) => [key, object[key]]));
|
|
85
96
|
}
|
|
86
|
-
exports.pickObjectProps = pickObjectProps;
|
|
87
97
|
function omitObjectProps(object, keys) {
|
|
88
98
|
return Object.fromEntries(Object.entries(object).filter(([key]) => !keys.includes(key)));
|
|
89
99
|
}
|
|
90
|
-
exports.omitObjectProps = omitObjectProps;
|
|
91
100
|
function splitCamelCaseIntoWords(str) {
|
|
92
101
|
const camel = str
|
|
93
102
|
.split(/(?:[-._])|([A-Z][a-z]+)/)
|
|
@@ -99,7 +108,6 @@ function splitCamelCaseIntoWords(str) {
|
|
|
99
108
|
.map((item) => item.toLocaleLowerCase());
|
|
100
109
|
return new Set([...camel, ...caps]);
|
|
101
110
|
}
|
|
102
|
-
exports.splitCamelCaseIntoWords = splitCamelCaseIntoWords;
|
|
103
111
|
function validateMimeType({ type, value }, { report, location }, allowedValues) {
|
|
104
112
|
const ruleType = type === 'consumes' ? 'request' : 'response';
|
|
105
113
|
if (!allowedValues)
|
|
@@ -115,7 +123,6 @@ function validateMimeType({ type, value }, { report, location }, allowedValues)
|
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
}
|
|
118
|
-
exports.validateMimeType = validateMimeType;
|
|
119
126
|
function validateMimeTypeOAS3({ type, value }, { report, location }, allowedValues) {
|
|
120
127
|
const ruleType = type === 'consumes' ? 'request' : 'response';
|
|
121
128
|
if (!allowedValues)
|
|
@@ -131,24 +138,16 @@ function validateMimeTypeOAS3({ type, value }, { report, location }, allowedValu
|
|
|
131
138
|
}
|
|
132
139
|
}
|
|
133
140
|
}
|
|
134
|
-
exports.validateMimeTypeOAS3 = validateMimeTypeOAS3;
|
|
135
|
-
function isSingular(path) {
|
|
136
|
-
return pluralize.isSingular(path);
|
|
137
|
-
}
|
|
138
|
-
exports.isSingular = isSingular;
|
|
139
141
|
function readFileAsStringSync(filePath) {
|
|
140
142
|
return fs.readFileSync(filePath, 'utf-8');
|
|
141
143
|
}
|
|
142
|
-
exports.readFileAsStringSync = readFileAsStringSync;
|
|
143
144
|
function yamlAndJsonSyncReader(filePath) {
|
|
144
145
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
145
146
|
return (0, js_yaml_1.parseYaml)(content);
|
|
146
147
|
}
|
|
147
|
-
exports.yamlAndJsonSyncReader = yamlAndJsonSyncReader;
|
|
148
148
|
function isPathParameter(pathSegment) {
|
|
149
149
|
return pathSegment.startsWith('{') && pathSegment.endsWith('}');
|
|
150
150
|
}
|
|
151
|
-
exports.isPathParameter = isPathParameter;
|
|
152
151
|
/**
|
|
153
152
|
* Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar
|
|
154
153
|
*/
|
|
@@ -159,20 +158,16 @@ function slash(path) {
|
|
|
159
158
|
}
|
|
160
159
|
return path.replace(/\\/g, '/');
|
|
161
160
|
}
|
|
162
|
-
exports.slash = slash;
|
|
163
161
|
function isNotEmptyObject(obj) {
|
|
164
162
|
return !!obj && Object.keys(obj).length > 0;
|
|
165
163
|
}
|
|
166
|
-
exports.isNotEmptyObject = isNotEmptyObject;
|
|
167
164
|
// TODO: use it everywhere
|
|
168
165
|
function isString(value) {
|
|
169
166
|
return typeof value === 'string';
|
|
170
167
|
}
|
|
171
|
-
exports.isString = isString;
|
|
172
168
|
function isNotString(value) {
|
|
173
169
|
return !isString(value);
|
|
174
170
|
}
|
|
175
|
-
exports.isNotString = isNotString;
|
|
176
171
|
function assignExisting(target, obj) {
|
|
177
172
|
for (const k of Object.keys(obj)) {
|
|
178
173
|
if (target.hasOwnProperty(k)) {
|
|
@@ -180,46 +175,36 @@ function assignExisting(target, obj) {
|
|
|
180
175
|
}
|
|
181
176
|
}
|
|
182
177
|
}
|
|
183
|
-
exports.assignExisting = assignExisting;
|
|
184
178
|
function getMatchingStatusCodeRange(code) {
|
|
185
179
|
return `${code}`.replace(/^(\d)\d\d$/, (_, firstDigit) => `${firstDigit}XX`);
|
|
186
180
|
}
|
|
187
|
-
exports.getMatchingStatusCodeRange = getMatchingStatusCodeRange;
|
|
188
181
|
function isCustomRuleId(id) {
|
|
189
182
|
return id.includes('/');
|
|
190
183
|
}
|
|
191
|
-
exports.isCustomRuleId = isCustomRuleId;
|
|
192
184
|
function doesYamlFileExist(filePath) {
|
|
193
|
-
var _a;
|
|
194
185
|
return (((0, path_1.extname)(filePath) === '.yaml' || (0, path_1.extname)(filePath) === '.yml') &&
|
|
195
|
-
|
|
186
|
+
fs?.hasOwnProperty?.('existsSync') &&
|
|
196
187
|
fs.existsSync(filePath));
|
|
197
188
|
}
|
|
198
|
-
exports.doesYamlFileExist = doesYamlFileExist;
|
|
199
189
|
function showWarningForDeprecatedField(deprecatedField, updatedField, updatedObject) {
|
|
200
190
|
logger_1.logger.warn(`The '${logger_1.colorize.red(deprecatedField)}' field is deprecated. ${updatedField
|
|
201
191
|
? `Use ${logger_1.colorize.green(getUpdatedFieldName(updatedField, updatedObject))} instead. `
|
|
202
192
|
: ''}Read more about this change: https://redocly.com/docs/api-registry/guides/migration-guide-config-file/#changed-properties\n`);
|
|
203
193
|
}
|
|
204
|
-
exports.showWarningForDeprecatedField = showWarningForDeprecatedField;
|
|
205
194
|
function showErrorForDeprecatedField(deprecatedField, updatedField, updatedObject) {
|
|
206
195
|
throw new Error(`Do not use '${deprecatedField}' field. ${updatedField ? `Use '${getUpdatedFieldName(updatedField, updatedObject)}' instead. ` : ''}\n`);
|
|
207
196
|
}
|
|
208
|
-
exports.showErrorForDeprecatedField = showErrorForDeprecatedField;
|
|
209
197
|
function isTruthy(value) {
|
|
210
198
|
return !!value;
|
|
211
199
|
}
|
|
212
|
-
exports.isTruthy = isTruthy;
|
|
213
200
|
function identity(value) {
|
|
214
201
|
return value;
|
|
215
202
|
}
|
|
216
|
-
exports.identity = identity;
|
|
217
203
|
function keysOf(obj) {
|
|
218
204
|
if (!obj)
|
|
219
205
|
return [];
|
|
220
206
|
return Object.keys(obj);
|
|
221
207
|
}
|
|
222
|
-
exports.keysOf = keysOf;
|
|
223
208
|
function pickDefined(obj) {
|
|
224
209
|
if (!obj)
|
|
225
210
|
return undefined;
|
|
@@ -231,19 +216,14 @@ function pickDefined(obj) {
|
|
|
231
216
|
}
|
|
232
217
|
return res;
|
|
233
218
|
}
|
|
234
|
-
exports.pickDefined = pickDefined;
|
|
235
219
|
function nextTick() {
|
|
236
|
-
new Promise((resolve) => {
|
|
220
|
+
return new Promise((resolve) => {
|
|
237
221
|
setTimeout(resolve);
|
|
238
222
|
});
|
|
239
223
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
243
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
244
|
-
});
|
|
224
|
+
async function pause(ms) {
|
|
225
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
245
226
|
}
|
|
246
|
-
exports.pause = pause;
|
|
247
227
|
function getUpdatedFieldName(updatedField, updatedObject) {
|
|
248
228
|
return `${typeof updatedObject !== 'undefined' ? `${updatedObject}.` : ''}${updatedField}`;
|
|
249
229
|
}
|
|
@@ -251,4 +231,38 @@ function getProxyAgent() {
|
|
|
251
231
|
const proxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
|
|
252
232
|
return proxy ? new https_proxy_agent_1.HttpsProxyAgent(proxy) : undefined;
|
|
253
233
|
}
|
|
254
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Checks if two objects are deeply equal.
|
|
236
|
+
* Borrowed the source code from https://github.com/lukeed/dequal.
|
|
237
|
+
*/
|
|
238
|
+
function dequal(foo, bar) {
|
|
239
|
+
let ctor, len;
|
|
240
|
+
if (foo === bar)
|
|
241
|
+
return true;
|
|
242
|
+
if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
|
|
243
|
+
if (ctor === Date)
|
|
244
|
+
return foo.getTime() === bar.getTime();
|
|
245
|
+
if (ctor === RegExp)
|
|
246
|
+
return foo.toString() === bar.toString();
|
|
247
|
+
if (ctor === Array) {
|
|
248
|
+
if ((len = foo.length) === bar.length) {
|
|
249
|
+
while (len-- && dequal(foo[len], bar[len]))
|
|
250
|
+
;
|
|
251
|
+
}
|
|
252
|
+
return len === -1;
|
|
253
|
+
}
|
|
254
|
+
if (!ctor || typeof foo === 'object') {
|
|
255
|
+
len = 0;
|
|
256
|
+
for (ctor in foo) {
|
|
257
|
+
if (Object.prototype.hasOwnProperty.call(foo, ctor) &&
|
|
258
|
+
++len &&
|
|
259
|
+
!Object.prototype.hasOwnProperty.call(bar, ctor))
|
|
260
|
+
return false;
|
|
261
|
+
if (!(ctor in bar) || !dequal(foo[ctor], bar[ctor]))
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
return Object.keys(bar).length === len;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return foo !== foo && bar !== bar;
|
|
268
|
+
}
|
package/lib/visitors.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { Location } from './ref-utils';
|
|
|
5
5
|
import type { Oas3Definition, Oas3ExternalDocs, Oas3Info, Oas3Contact, Oas3Components, Oas3License, Oas3Schema, Oas3Header, Oas3Parameter, Oas3Operation, Oas3PathItem, Oas3ServerVariable, Oas3Server, Oas3MediaType, Oas3Response, Oas3Example, Oas3RequestBody, Oas3Tag, OasRef, Oas3SecurityScheme, Oas3SecurityRequirement, Oas3Encoding, Oas3Link, Oas3Xml, Oas3Discriminator, Oas3Callback } from './typings/openapi';
|
|
6
6
|
import type { Oas2Definition, Oas2Tag, Oas2ExternalDocs, Oas2SecurityRequirement, Oas2Info, Oas2Contact, Oas2License, Oas2PathItem, Oas2Operation, Oas2Header, Oas2Response, Oas2Schema, Oas2Xml, Oas2Parameter, Oas2SecurityScheme } from './typings/swagger';
|
|
7
7
|
import type { Async2Definition } from './typings/asyncapi';
|
|
8
|
+
import type { Async3Definition } from './typings/asyncapi3';
|
|
8
9
|
import type { ArazzoDefinition } from './typings/arazzo';
|
|
9
10
|
export type SkipFunctionContext = Pick<UserContext, 'location' | 'rawNode' | 'resolve' | 'rawLocation'>;
|
|
10
11
|
export type VisitFunction<T> = (node: T, ctx: UserContext & {
|
|
@@ -140,6 +141,9 @@ type Oas2FlatVisitor = {
|
|
|
140
141
|
type Async2FlatVisitor = {
|
|
141
142
|
Root?: VisitFunctionOrObject<Async2Definition>;
|
|
142
143
|
};
|
|
144
|
+
type Async3FlatVisitor = {
|
|
145
|
+
Root?: VisitFunctionOrObject<Async3Definition>;
|
|
146
|
+
};
|
|
143
147
|
type ArazzoFlatVisitor = {
|
|
144
148
|
Root?: VisitFunctionOrObject<ArazzoDefinition>;
|
|
145
149
|
};
|
|
@@ -152,12 +156,16 @@ type Oas2NestedVisitor = {
|
|
|
152
156
|
type Async2NestedVisitor = {
|
|
153
157
|
[T in keyof Async2FlatVisitor]: Async2FlatVisitor[T] extends Function ? Async2FlatVisitor[T] : Async2FlatVisitor[T] & NestedVisitor<Async2NestedVisitor>;
|
|
154
158
|
};
|
|
159
|
+
type Async3NestedVisitor = {
|
|
160
|
+
[T in keyof Async3FlatVisitor]: Async3FlatVisitor[T] extends Function ? Async3FlatVisitor[T] : Async3FlatVisitor[T] & NestedVisitor<Async3NestedVisitor>;
|
|
161
|
+
};
|
|
155
162
|
type ArazzoNestedVisitor = {
|
|
156
163
|
[T in keyof ArazzoFlatVisitor]: ArazzoFlatVisitor[T] extends Function ? ArazzoFlatVisitor[T] : ArazzoFlatVisitor[T] & NestedVisitor<ArazzoNestedVisitor>;
|
|
157
164
|
};
|
|
158
165
|
export type Oas3Visitor = BaseVisitor & Oas3NestedVisitor & Record<string, VisitFunction<any> | NestedVisitObject<any, Oas3NestedVisitor>>;
|
|
159
166
|
export type Oas2Visitor = BaseVisitor & Oas2NestedVisitor & Record<string, VisitFunction<any> | NestedVisitObject<any, Oas2NestedVisitor>>;
|
|
160
167
|
export type Async2Visitor = BaseVisitor & Async2NestedVisitor & Record<string, VisitFunction<any> | NestedVisitObject<any, Async2NestedVisitor>>;
|
|
168
|
+
export type Async3Visitor = BaseVisitor & Async3NestedVisitor & Record<string, VisitFunction<any> | NestedVisitObject<any, Async3NestedVisitor>>;
|
|
161
169
|
export type ArazzoVisitor = BaseVisitor & ArazzoNestedVisitor & Record<string, VisitFunction<any> | NestedVisitObject<any, ArazzoNestedVisitor>>;
|
|
162
170
|
export type NestedVisitor<T> = Exclude<T, 'any' | 'ref' | 'Root'>;
|
|
163
171
|
export type NormalizedOasVisitors<T extends BaseVisitor> = {
|
|
@@ -178,14 +186,17 @@ export type NormalizedOasVisitors<T extends BaseVisitor> = {
|
|
|
178
186
|
export type Oas3Rule = (options: Record<string, any>) => Oas3Visitor | Oas3Visitor[];
|
|
179
187
|
export type Oas2Rule = (options: Record<string, any>) => Oas2Visitor | Oas2Visitor[];
|
|
180
188
|
export type Async2Rule = (options: Record<string, any>) => Async2Visitor | Async2Visitor[];
|
|
189
|
+
export type Async3Rule = (options: Record<string, any>) => Async3Visitor | Async3Visitor[];
|
|
181
190
|
export type ArazzoRule = (options: Record<string, any>) => ArazzoVisitor | ArazzoVisitor[];
|
|
182
191
|
export type Oas3Preprocessor = (options: Record<string, any>) => Oas3Visitor;
|
|
183
192
|
export type Oas2Preprocessor = (options: Record<string, any>) => Oas2Visitor;
|
|
184
193
|
export type Async2Preprocessor = (options: Record<string, any>) => Async2Visitor;
|
|
194
|
+
export type Async3Preprocessor = (options: Record<string, any>) => Async3Visitor;
|
|
185
195
|
export type ArazzoPreprocessor = (options: Record<string, any>) => ArazzoVisitor;
|
|
186
196
|
export type Oas3Decorator = (options: Record<string, any>) => Oas3Visitor;
|
|
187
197
|
export type Oas2Decorator = (options: Record<string, any>) => Oas2Visitor;
|
|
188
198
|
export type Async2Decorator = (options: Record<string, any>) => Async2Visitor;
|
|
199
|
+
export type Async3Decorator = (options: Record<string, any>) => Async3Visitor;
|
|
189
200
|
export type ArazzoDecorator = (options: Record<string, any>) => ArazzoVisitor;
|
|
190
201
|
export type OasRule = Oas3Rule;
|
|
191
202
|
export type OasPreprocessor = Oas3Preprocessor;
|
package/lib/visitors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.normalizeVisitors =
|
|
3
|
+
exports.normalizeVisitors = normalizeVisitors;
|
|
4
4
|
const types_1 = require("./types");
|
|
5
5
|
const legacyTypesMap = {
|
|
6
6
|
Root: 'DefinitionRoot',
|
|
@@ -81,11 +81,16 @@ function normalizeVisitors(visitorsConfig, types) {
|
|
|
81
81
|
enter: [],
|
|
82
82
|
leave: [],
|
|
83
83
|
};
|
|
84
|
-
normalizedVisitors[interType.name].enter.push(
|
|
84
|
+
normalizedVisitors[interType.name].enter.push({
|
|
85
|
+
...ruleConf,
|
|
86
|
+
visit: () => undefined,
|
|
87
|
+
depth: 0,
|
|
88
|
+
context: {
|
|
85
89
|
isSkippedLevel: true,
|
|
86
90
|
seen: new Set(),
|
|
87
91
|
parent: parentContext,
|
|
88
|
-
}
|
|
92
|
+
},
|
|
93
|
+
});
|
|
89
94
|
}
|
|
90
95
|
}
|
|
91
96
|
}
|
|
@@ -147,17 +152,25 @@ function normalizeVisitors(visitorsConfig, types) {
|
|
|
147
152
|
if (visitorEnter && typeof visitorEnter !== 'function') {
|
|
148
153
|
throw new Error('DEV: should be function');
|
|
149
154
|
}
|
|
150
|
-
normalizedTypeVisitor.enter.push(
|
|
151
|
-
|
|
155
|
+
normalizedTypeVisitor.enter.push({
|
|
156
|
+
...ruleConf,
|
|
157
|
+
visit: visitorEnter || (() => undefined),
|
|
158
|
+
skip: visitorSkip,
|
|
159
|
+
depth,
|
|
160
|
+
context,
|
|
161
|
+
});
|
|
152
162
|
}
|
|
153
163
|
if (visitorLeave) {
|
|
154
164
|
if (typeof visitorLeave !== 'function') {
|
|
155
165
|
throw new Error('DEV: should be function');
|
|
156
166
|
}
|
|
157
|
-
normalizedTypeVisitor.leave.push(
|
|
158
|
-
|
|
167
|
+
normalizedTypeVisitor.leave.push({
|
|
168
|
+
...ruleConf,
|
|
169
|
+
visit: visitorLeave,
|
|
170
|
+
depth,
|
|
171
|
+
context,
|
|
172
|
+
});
|
|
159
173
|
}
|
|
160
174
|
}
|
|
161
175
|
}
|
|
162
176
|
}
|
|
163
|
-
exports.normalizeVisitors = normalizeVisitors;
|
package/lib/walk.js
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.walkDocument =
|
|
3
|
+
exports.walkDocument = walkDocument;
|
|
4
4
|
const ref_utils_1 = require("./ref-utils");
|
|
5
5
|
const utils_1 = require("./utils");
|
|
6
6
|
const resolve_1 = require("./resolve");
|
|
7
7
|
const types_1 = require("./types");
|
|
8
8
|
function collectParents(ctx) {
|
|
9
|
-
var _a;
|
|
10
9
|
const parents = {};
|
|
11
10
|
while (ctx.parent) {
|
|
12
|
-
parents[ctx.parent.type.name] =
|
|
11
|
+
parents[ctx.parent.type.name] = ctx.parent.activatedOn?.value.node;
|
|
13
12
|
ctx = ctx.parent;
|
|
14
13
|
}
|
|
15
14
|
return parents;
|
|
16
15
|
}
|
|
17
16
|
function collectParentsLocations(ctx) {
|
|
18
|
-
var _a, _b;
|
|
19
17
|
const locations = {};
|
|
20
18
|
while (ctx.parent) {
|
|
21
|
-
if (
|
|
22
|
-
locations[ctx.parent.type.name] =
|
|
19
|
+
if (ctx.parent.activatedOn?.value.location) {
|
|
20
|
+
locations[ctx.parent.type.name] = ctx.parent.activatedOn?.value.location;
|
|
23
21
|
}
|
|
24
22
|
ctx = ctx.parent;
|
|
25
23
|
}
|
|
@@ -31,7 +29,6 @@ function walkDocument(opts) {
|
|
|
31
29
|
const ignoredNodes = new Set();
|
|
32
30
|
walkNode(document.parsed, rootType, new ref_utils_1.Location(document.source, '#/'), undefined, '');
|
|
33
31
|
function walkNode(node, type, location, parent, key) {
|
|
34
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
35
32
|
const resolve = (ref, from = currentLocation.source.absoluteRef) => {
|
|
36
33
|
if (!(0, ref_utils_1.isRef)(ref))
|
|
37
34
|
return { location, node: ref };
|
|
@@ -73,17 +70,17 @@ function walkDocument(opts) {
|
|
|
73
70
|
oasVersion: ctx.oasVersion,
|
|
74
71
|
getVisitorData: getVisitorDataFn.bind(undefined, ruleId),
|
|
75
72
|
}, { node: resolvedNode, location: resolvedLocation, error });
|
|
76
|
-
if (
|
|
77
|
-
ctx.refTypes.set(resolvedLocation
|
|
73
|
+
if (resolvedLocation?.source.absoluteRef && ctx.refTypes) {
|
|
74
|
+
ctx.refTypes.set(resolvedLocation?.source.absoluteRef, type);
|
|
78
75
|
}
|
|
79
76
|
}
|
|
80
77
|
}
|
|
81
78
|
if (resolvedNode !== undefined && resolvedLocation && type.name !== 'scalar') {
|
|
82
79
|
currentLocation = resolvedLocation;
|
|
83
|
-
const isNodeSeen =
|
|
80
|
+
const isNodeSeen = seenNodesPerType[type.name]?.has?.(resolvedNode);
|
|
84
81
|
let visitedBySome = false;
|
|
85
82
|
const anyEnterVisitors = normalizedVisitors.any.enter;
|
|
86
|
-
const currentEnterVisitors = anyEnterVisitors.concat(
|
|
83
|
+
const currentEnterVisitors = anyEnterVisitors.concat(normalizedVisitors[type.name]?.enter || []);
|
|
87
84
|
const activatedContexts = [];
|
|
88
85
|
for (const { context, visit, skip, ruleId, severity } of currentEnterVisitors) {
|
|
89
86
|
if (ignoredNodes.has(`${currentLocation.absolutePointer}${currentLocation.pointer}`))
|
|
@@ -101,9 +98,9 @@ function walkDocument(opts) {
|
|
|
101
98
|
else {
|
|
102
99
|
if ((context.parent && // if nested
|
|
103
100
|
context.parent.activatedOn &&
|
|
104
|
-
|
|
101
|
+
context.activatedOn?.value.withParentNode !== context.parent.activatedOn.value.node &&
|
|
105
102
|
// do not enter if visited by parent children (it works thanks because deeper visitors are sorted before)
|
|
106
|
-
|
|
103
|
+
context.parent.activatedOn.value.nextLevelTypeActivated?.value !== type) ||
|
|
107
104
|
(!context.parent && !isNodeSeen) // if top-level visit each node just once
|
|
108
105
|
) {
|
|
109
106
|
activatedContexts.push(context);
|
|
@@ -111,14 +108,15 @@ function walkDocument(opts) {
|
|
|
111
108
|
node: resolvedNode,
|
|
112
109
|
location: resolvedLocation,
|
|
113
110
|
nextLevelTypeActivated: null,
|
|
114
|
-
withParentNode:
|
|
115
|
-
skipped: (
|
|
116
|
-
|
|
111
|
+
withParentNode: context.parent?.activatedOn?.value.node,
|
|
112
|
+
skipped: (context.parent?.activatedOn?.value.skipped ||
|
|
113
|
+
skip?.(resolvedNode, key, {
|
|
117
114
|
location,
|
|
118
115
|
rawLocation,
|
|
119
116
|
resolve,
|
|
120
117
|
rawNode: node,
|
|
121
|
-
}))
|
|
118
|
+
})) ??
|
|
119
|
+
false,
|
|
122
120
|
};
|
|
123
121
|
context.activatedOn = (0, utils_1.pushStack)(context.activatedOn, activatedOn);
|
|
124
122
|
let ctx = context.parent;
|
|
@@ -180,7 +178,7 @@ function walkDocument(opts) {
|
|
|
180
178
|
propName.startsWith(type.extensionsPrefix)) {
|
|
181
179
|
propType = types_1.SpecExtension;
|
|
182
180
|
}
|
|
183
|
-
if (!(0, types_1.isNamedType)(propType) &&
|
|
181
|
+
if (!(0, types_1.isNamedType)(propType) && propType?.directResolveAs) {
|
|
184
182
|
propType = propType.directResolveAs;
|
|
185
183
|
value = { $ref: value };
|
|
186
184
|
}
|
|
@@ -195,7 +193,7 @@ function walkDocument(opts) {
|
|
|
195
193
|
}
|
|
196
194
|
}
|
|
197
195
|
const anyLeaveVisitors = normalizedVisitors.any.leave;
|
|
198
|
-
const currentLeaveVisitors = (
|
|
196
|
+
const currentLeaveVisitors = (normalizedVisitors[type.name]?.leave || []).concat(anyLeaveVisitors);
|
|
199
197
|
for (const context of activatedContexts.reverse()) {
|
|
200
198
|
if (context.isSkippedLevel) {
|
|
201
199
|
context.seen.delete(resolvedNode);
|
|
@@ -264,11 +262,21 @@ function walkDocument(opts) {
|
|
|
264
262
|
? Array.isArray(opts.location)
|
|
265
263
|
? opts.location
|
|
266
264
|
: [opts.location]
|
|
267
|
-
: [
|
|
268
|
-
const location = normalizedLocation.map((l) => (
|
|
265
|
+
: [{ ...currentLocation, reportOnKey: false }];
|
|
266
|
+
const location = normalizedLocation.map((l) => ({
|
|
267
|
+
...currentLocation,
|
|
268
|
+
reportOnKey: false,
|
|
269
|
+
...l,
|
|
270
|
+
}));
|
|
269
271
|
const ruleSeverity = opts.forceSeverity || severity;
|
|
270
272
|
if (ruleSeverity !== 'off') {
|
|
271
|
-
ctx.problems.push(
|
|
273
|
+
ctx.problems.push({
|
|
274
|
+
ruleId: opts.ruleId || ruleId,
|
|
275
|
+
severity: ruleSeverity,
|
|
276
|
+
...opts,
|
|
277
|
+
suggest: opts.suggest || [],
|
|
278
|
+
location,
|
|
279
|
+
});
|
|
272
280
|
}
|
|
273
281
|
}
|
|
274
282
|
function getVisitorDataFn(ruleId) {
|
|
@@ -277,4 +285,3 @@ function walkDocument(opts) {
|
|
|
277
285
|
}
|
|
278
286
|
}
|
|
279
287
|
}
|
|
280
|
-
exports.walkDocument = walkDocument;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/openapi-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@redocly/ajv": "^8.11.0",
|
|
39
|
-
"@redocly/config": "^0.
|
|
39
|
+
"@redocly/config": "^0.7.0",
|
|
40
40
|
"colorette": "^1.2.0",
|
|
41
41
|
"https-proxy-agent": "^7.0.4",
|
|
42
42
|
"js-levenshtein": "^1.1.6",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"@types/node-fetch": "^2.5.7",
|
|
57
57
|
"@types/pluralize": "^0.0.29",
|
|
58
58
|
"json-schema-to-ts": "^3.1.0",
|
|
59
|
-
"typescript": "
|
|
59
|
+
"typescript": "5.5.3"
|
|
60
60
|
}
|
|
61
61
|
}
|