@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.
Files changed (151) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/lib/benchmark/benches/lint-with-many-rules.bench.js +2 -2
  3. package/lib/benchmark/benches/lint-with-nested-rule.bench.js +2 -2
  4. package/lib/benchmark/benches/lint-with-no-rules.bench.js +2 -2
  5. package/lib/benchmark/benches/lint-with-top-level-rule-report.bench.js +2 -2
  6. package/lib/benchmark/benches/lint-with-top-level-rule.bench.js +2 -2
  7. package/lib/benchmark/benches/recommended-oas3.bench.js +2 -2
  8. package/lib/benchmark/benches/resolve-with-no-external.bench.js +2 -2
  9. package/lib/benchmark/utils.js +7 -4
  10. package/lib/bundle.d.ts +3 -3
  11. package/lib/bundle.js +128 -122
  12. package/lib/config/all.js +9 -0
  13. package/lib/config/builtIn.js +7 -1
  14. package/lib/config/config-resolvers.js +179 -138
  15. package/lib/config/config.d.ts +2 -2
  16. package/lib/config/config.js +53 -34
  17. package/lib/config/load.d.ts +1 -2
  18. package/lib/config/load.js +105 -117
  19. package/lib/config/minimal.js +9 -0
  20. package/lib/config/recommended-strict.js +9 -0
  21. package/lib/config/recommended.js +9 -0
  22. package/lib/config/rules.d.ts +3 -3
  23. package/lib/config/rules.js +1 -2
  24. package/lib/config/types.d.ts +9 -3
  25. package/lib/config/utils.js +70 -49
  26. package/lib/decorators/async3/index.d.ts +1 -0
  27. package/lib/decorators/async3/index.js +4 -0
  28. package/lib/decorators/common/filters/filter-helper.js +2 -3
  29. package/lib/decorators/common/filters/filter-in.js +1 -1
  30. package/lib/decorators/common/filters/filter-out.js +1 -1
  31. package/lib/decorators/common/info-override.js +1 -12
  32. package/lib/decorators/common/media-type-examples-override.js +8 -2
  33. package/lib/decorators/common/remove-x-internal.js +4 -5
  34. package/lib/decorators/oas2/remove-unused-components.js +1 -2
  35. package/lib/decorators/oas3/remove-unused-components.js +1 -2
  36. package/lib/env.d.ts +0 -1
  37. package/lib/env.js +1 -1
  38. package/lib/format/codeframes.js +10 -8
  39. package/lib/format/format.js +23 -15
  40. package/lib/index.d.ts +2 -1
  41. package/lib/index.js +6 -4
  42. package/lib/js-yaml/index.js +1 -1
  43. package/lib/lint.d.ts +2 -0
  44. package/lib/lint.js +92 -99
  45. package/lib/oas-types.d.ts +9 -5
  46. package/lib/oas-types.js +22 -12
  47. package/lib/redocly/domains.js +6 -6
  48. package/lib/redocly/index.js +60 -73
  49. package/lib/redocly/registry-api.js +64 -82
  50. package/lib/ref-utils.js +13 -13
  51. package/lib/resolve.js +186 -205
  52. package/lib/rules/ajv.js +10 -8
  53. package/lib/rules/async3/channels-kebab-case.d.ts +2 -0
  54. package/lib/rules/async3/channels-kebab-case.js +19 -0
  55. package/lib/rules/async3/index.d.ts +3 -0
  56. package/lib/rules/async3/index.js +22 -0
  57. package/lib/rules/async3/no-channel-trailing-slash.d.ts +2 -0
  58. package/lib/rules/async3/no-channel-trailing-slash.js +16 -0
  59. package/lib/rules/common/assertions/asserts.js +5 -5
  60. package/lib/rules/common/assertions/index.d.ts +5 -4
  61. package/lib/rules/common/assertions/utils.js +43 -28
  62. package/lib/rules/common/no-invalid-parameter-examples.js +1 -2
  63. package/lib/rules/common/no-invalid-schema-examples.js +1 -2
  64. package/lib/rules/common/no-required-schema-properties-undefined.js +1 -2
  65. package/lib/rules/common/operation-tag-defined.js +1 -2
  66. package/lib/rules/common/path-http-verbs-order.js +1 -1
  67. package/lib/rules/common/path-segment-plural.js +2 -1
  68. package/lib/rules/common/required-string-property-missing-min-length.js +2 -2
  69. package/lib/rules/common/response-contains-header.js +2 -2
  70. package/lib/rules/common/security-defined.js +3 -7
  71. package/lib/rules/common/spec.d.ts +2 -2
  72. package/lib/rules/common/spec.js +6 -7
  73. package/lib/rules/no-unresolved-refs.js +3 -4
  74. package/lib/rules/oas2/response-contains-property.js +1 -2
  75. package/lib/rules/oas3/array-parameter-serialization.js +1 -2
  76. package/lib/rules/oas3/component-name-unique.js +2 -4
  77. package/lib/rules/oas3/no-invalid-media-type-examples.js +1 -2
  78. package/lib/rules/oas3/no-server-variables-empty-enum.js +1 -2
  79. package/lib/rules/oas3/no-undefined-server-variable.js +2 -3
  80. package/lib/rules/oas3/no-unused-components.js +1 -2
  81. package/lib/rules/oas3/response-contains-property.js +1 -2
  82. package/lib/rules/utils.js +14 -12
  83. package/lib/types/arazzo.d.ts +1299 -73
  84. package/lib/types/arazzo.js +41 -36
  85. package/lib/types/asyncapi2.d.ts +17 -0
  86. package/lib/types/{asyncapi.js → asyncapi2.js} +71 -93
  87. package/lib/types/asyncapi3.d.ts +2 -0
  88. package/lib/types/asyncapi3.js +347 -0
  89. package/lib/types/index.js +19 -10
  90. package/lib/types/json-schema-adapter.js +4 -18
  91. package/lib/types/oas2.js +6 -6
  92. package/lib/types/oas3.js +10 -10
  93. package/lib/types/oas3_1.js +15 -9
  94. package/lib/types/redocly-yaml.d.ts +3 -1
  95. package/lib/types/redocly-yaml.js +131 -35
  96. package/lib/typings/arazzo.d.ts +28 -1
  97. package/lib/typings/asyncapi3.d.ts +53 -0
  98. package/lib/typings/asyncapi3.js +2 -0
  99. package/lib/utils.d.ts +12 -7
  100. package/lib/utils.js +91 -77
  101. package/lib/visitors.d.ts +11 -0
  102. package/lib/visitors.js +21 -8
  103. package/lib/walk.js +30 -23
  104. package/package.json +3 -3
  105. package/src/__tests__/bundle.test.ts +142 -0
  106. package/src/__tests__/lint.test.ts +0 -50
  107. package/src/bundle.ts +19 -6
  108. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +22 -0
  109. package/src/config/__tests__/__snapshots__/config.test.ts.snap +24 -0
  110. package/src/config/__tests__/config.test.ts +11 -0
  111. package/src/config/all.ts +9 -0
  112. package/src/config/builtIn.ts +6 -0
  113. package/src/config/config-resolvers.ts +15 -2
  114. package/src/config/config.ts +24 -5
  115. package/src/config/load.ts +1 -2
  116. package/src/config/minimal.ts +9 -0
  117. package/src/config/recommended-strict.ts +9 -0
  118. package/src/config/recommended.ts +9 -0
  119. package/src/config/rules.ts +12 -4
  120. package/src/config/types.ts +15 -2
  121. package/src/config/utils.ts +15 -0
  122. package/src/decorators/async3/index.ts +1 -0
  123. package/src/decorators/common/remove-x-internal.ts +2 -2
  124. package/src/index.ts +2 -1
  125. package/src/lint.ts +26 -3
  126. package/src/oas-types.ts +31 -13
  127. package/src/rules/arazzo/index.ts +1 -1
  128. package/src/rules/async2/index.ts +5 -5
  129. package/src/rules/async3/__tests__/channels-kebab-case.test.ts +141 -0
  130. package/src/rules/async3/__tests__/no-channel-trailing-slash.test.ts +96 -0
  131. package/src/rules/async3/channels-kebab-case.ts +19 -0
  132. package/src/rules/async3/index.ts +23 -0
  133. package/src/rules/async3/no-channel-trailing-slash.ts +16 -0
  134. package/src/rules/common/__tests__/spec.test.ts +47 -0
  135. package/src/rules/common/assertions/index.ts +13 -4
  136. package/src/rules/common/no-invalid-schema-examples.ts +3 -2
  137. package/src/rules/common/path-segment-plural.ts +3 -2
  138. package/src/rules/common/spec.ts +2 -2
  139. package/src/rules/oas2/index.ts +4 -4
  140. package/src/rules/oas3/index.ts +39 -37
  141. package/src/types/arazzo.ts +28 -23
  142. package/src/types/{asyncapi.ts → asyncapi2.ts} +58 -76
  143. package/src/types/asyncapi3.ts +381 -0
  144. package/src/types/oas3_1.ts +3 -2
  145. package/src/types/redocly-yaml.ts +14 -0
  146. package/src/typings/arazzo.ts +41 -1
  147. package/src/typings/asyncapi3.ts +61 -0
  148. package/src/utils.ts +46 -11
  149. package/src/visitors.ts +18 -0
  150. package/tsconfig.tsbuildinfo +1 -1
  151. 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.getProxyAgent = exports.pause = exports.nextTick = exports.pickDefined = exports.keysOf = exports.identity = exports.isTruthy = exports.showErrorForDeprecatedField = exports.showWarningForDeprecatedField = exports.doesYamlFileExist = exports.isCustomRuleId = exports.getMatchingStatusCodeRange = exports.assignExisting = exports.isNotString = exports.isString = exports.isNotEmptyObject = exports.slash = exports.isPathParameter = exports.yamlAndJsonSyncReader = exports.readFileAsStringSync = exports.isSingular = exports.validateMimeTypeOAS3 = exports.validateMimeType = exports.splitCamelCaseIntoWords = exports.omitObjectProps = exports.pickObjectProps = exports.readFileFromUrl = exports.isEmptyArray = exports.isEmptyObject = exports.isPlainObject = exports.isDefined = exports.loadYaml = exports.popStack = exports.pushStack = exports.stringifyYaml = exports.parseYaml = void 0;
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
- var _a;
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
- exports.popStack = popStack;
34
- function loadYaml(filename) {
35
- return __awaiter(this, void 0, void 0, function* () {
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
- exports.isEmptyArray = isEmptyArray;
57
- function readFileFromUrl(url, config) {
58
- return __awaiter(this, void 0, void 0, function* () {
59
- const headers = {};
60
- for (const header of config.headers) {
61
- if (match(url, header.matches)) {
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
- return { body: yield req.text(), mimeType: req.headers.get('content-type') };
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
- ((_a = fs === null || fs === void 0 ? void 0 : fs.hasOwnProperty) === null || _a === void 0 ? void 0 : _a.call(fs, 'existsSync')) &&
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
- exports.nextTick = nextTick;
241
- function pause(ms) {
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
- exports.getProxyAgent = getProxyAgent;
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 = void 0;
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(Object.assign(Object.assign({}, ruleConf), { visit: () => undefined, depth: 0, context: {
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(Object.assign(Object.assign({}, ruleConf), { visit: visitorEnter || (() => undefined), skip: visitorSkip, depth,
151
- context }));
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(Object.assign(Object.assign({}, ruleConf), { visit: visitorLeave, depth,
158
- context }));
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 = void 0;
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] = (_a = ctx.parent.activatedOn) === null || _a === void 0 ? void 0 : _a.value.node;
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 ((_a = ctx.parent.activatedOn) === null || _a === void 0 ? void 0 : _a.value.location) {
22
- locations[ctx.parent.type.name] = (_b = ctx.parent.activatedOn) === null || _b === void 0 ? void 0 : _b.value.location;
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 ((resolvedLocation === null || resolvedLocation === void 0 ? void 0 : resolvedLocation.source.absoluteRef) && ctx.refTypes) {
77
- ctx.refTypes.set(resolvedLocation === null || resolvedLocation === void 0 ? void 0 : resolvedLocation.source.absoluteRef, type);
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 = (_b = (_a = seenNodesPerType[type.name]) === null || _a === void 0 ? void 0 : _a.has) === null || _b === void 0 ? void 0 : _b.call(_a, resolvedNode);
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(((_c = normalizedVisitors[type.name]) === null || _c === void 0 ? void 0 : _c.enter) || []);
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
- ((_d = context.activatedOn) === null || _d === void 0 ? void 0 : _d.value.withParentNode) !== context.parent.activatedOn.value.node &&
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
- ((_e = context.parent.activatedOn.value.nextLevelTypeActivated) === null || _e === void 0 ? void 0 : _e.value) !== type) ||
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: (_g = (_f = context.parent) === null || _f === void 0 ? void 0 : _f.activatedOn) === null || _g === void 0 ? void 0 : _g.value.node,
115
- skipped: (_k = (((_j = (_h = context.parent) === null || _h === void 0 ? void 0 : _h.activatedOn) === null || _j === void 0 ? void 0 : _j.value.skipped) ||
116
- (skip === null || skip === void 0 ? void 0 : skip(resolvedNode, key, {
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
- })))) !== null && _k !== void 0 ? _k : false,
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) && (propType === null || propType === void 0 ? void 0 : propType.directResolveAs)) {
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 = (((_l = normalizedVisitors[type.name]) === null || _l === void 0 ? void 0 : _l.leave) || []).concat(anyLeaveVisitors);
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
- : [Object.assign(Object.assign({}, currentLocation), { reportOnKey: false })];
268
- const location = normalizedLocation.map((l) => (Object.assign(Object.assign(Object.assign({}, currentLocation), { reportOnKey: false }), 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(Object.assign(Object.assign({ ruleId: opts.ruleId || ruleId, severity: ruleSeverity }, opts), { suggest: opts.suggest || [], location }));
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.18.0",
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.6.2",
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": "^5.2.2"
59
+ "typescript": "5.5.3"
60
60
  }
61
61
  }