@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/resolve.js CHANGED
@@ -1,15 +1,9 @@
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.resolveDocument = exports.BaseResolver = exports.makeDocumentFromString = exports.makeRefId = exports.YamlParseError = exports.ResolveError = exports.Source = void 0;
3
+ exports.BaseResolver = exports.YamlParseError = exports.ResolveError = exports.Source = void 0;
4
+ exports.makeRefId = makeRefId;
5
+ exports.makeDocumentFromString = makeDocumentFromString;
6
+ exports.resolveDocument = resolveDocument;
13
7
  const fs = require("fs");
14
8
  const path = require("path");
15
9
  const ref_utils_1 = require("./ref-utils");
@@ -23,9 +17,8 @@ class Source {
23
17
  }
24
18
  // pass safeLoad as argument to separate it from browser bundle
25
19
  getAst(safeLoad) {
26
- var _a;
27
20
  if (this._ast === undefined) {
28
- this._ast = (_a = safeLoad(this.body, { filename: this.absoluteRef })) !== null && _a !== void 0 ? _a : undefined;
21
+ this._ast = safeLoad(this.body, { filename: this.absoluteRef }) ?? undefined;
29
22
  // fix ast representation of file with newlines only
30
23
  if (this._ast &&
31
24
  this._ast.kind === 0 && // KIND.scalar = 0
@@ -71,7 +64,6 @@ exports.YamlParseError = YamlParseError;
71
64
  function makeRefId(absoluteRef, pointer) {
72
65
  return absoluteRef + '::' + pointer;
73
66
  }
74
- exports.makeRefId = makeRefId;
75
67
  function makeDocumentFromString(sourceString, absoluteRef) {
76
68
  const source = new Source(absoluteRef, sourceString);
77
69
  try {
@@ -84,7 +76,6 @@ function makeDocumentFromString(sourceString, absoluteRef) {
84
76
  throw new YamlParseError(e, source);
85
77
  }
86
78
  }
87
- exports.makeDocumentFromString = makeDocumentFromString;
88
79
  class BaseResolver {
89
80
  constructor(config = { http: { headers: [] } }) {
90
81
  this.config = config;
@@ -102,33 +93,30 @@ class BaseResolver {
102
93
  }
103
94
  return path.resolve(base ? path.dirname(base) : process.cwd(), ref);
104
95
  }
105
- loadExternalRef(absoluteRef) {
106
- return __awaiter(this, void 0, void 0, function* () {
107
- try {
108
- if ((0, ref_utils_1.isAbsoluteUrl)(absoluteRef)) {
109
- const { body, mimeType } = yield (0, utils_1.readFileFromUrl)(absoluteRef, this.config.http);
110
- return new Source(absoluteRef, body, mimeType);
111
- }
112
- else {
113
- if (fs.lstatSync(absoluteRef).isDirectory()) {
114
- throw new Error(`Expected a file but received a folder at ${absoluteRef}`);
115
- }
116
- const content = yield fs.promises.readFile(absoluteRef, 'utf-8');
117
- // In some cases file have \r\n line delimeters like on windows, we should skip it.
118
- return new Source(absoluteRef, content.replace(/\r\n/g, '\n'));
119
- }
96
+ async loadExternalRef(absoluteRef) {
97
+ try {
98
+ if ((0, ref_utils_1.isAbsoluteUrl)(absoluteRef)) {
99
+ const { body, mimeType } = await (0, utils_1.readFileFromUrl)(absoluteRef, this.config.http);
100
+ return new Source(absoluteRef, body, mimeType);
120
101
  }
121
- catch (error) {
122
- error.message = error.message.replace(', lstat', '');
123
- throw new ResolveError(error);
102
+ else {
103
+ if (fs.lstatSync(absoluteRef).isDirectory()) {
104
+ throw new Error(`Expected a file but received a folder at ${absoluteRef}`);
105
+ }
106
+ const content = await fs.promises.readFile(absoluteRef, 'utf-8');
107
+ // In some cases file have \r\n line delimeters like on windows, we should skip it.
108
+ return new Source(absoluteRef, content.replace(/\r\n/g, '\n'));
124
109
  }
125
- });
110
+ }
111
+ catch (error) {
112
+ error.message = error.message.replace(', lstat', '');
113
+ throw new ResolveError(error);
114
+ }
126
115
  }
127
116
  parseDocument(source, isRoot = false) {
128
- var _a;
129
117
  const ext = source.absoluteRef.substr(source.absoluteRef.lastIndexOf('.'));
130
118
  if (!['.json', '.json', '.yml', '.yaml'].includes(ext) &&
131
- !((_a = source.mimeType) === null || _a === void 0 ? void 0 : _a.match(/(json|yaml|openapi)/)) &&
119
+ !source.mimeType?.match(/(json|yaml|openapi)/) &&
132
120
  !isRoot // always parse root
133
121
  ) {
134
122
  return { source, parsed: source.body };
@@ -143,19 +131,17 @@ class BaseResolver {
143
131
  throw new YamlParseError(e, source);
144
132
  }
145
133
  }
146
- resolveDocument(base, ref, isRoot = false) {
147
- return __awaiter(this, void 0, void 0, function* () {
148
- const absoluteRef = this.resolveExternalRef(base, ref);
149
- const cachedDocument = this.cache.get(absoluteRef);
150
- if (cachedDocument) {
151
- return cachedDocument;
152
- }
153
- const doc = this.loadExternalRef(absoluteRef).then((source) => {
154
- return this.parseDocument(source, isRoot);
155
- });
156
- this.cache.set(absoluteRef, doc);
157
- return doc;
134
+ async resolveDocument(base, ref, isRoot = false) {
135
+ const absoluteRef = this.resolveExternalRef(base, ref);
136
+ const cachedDocument = this.cache.get(absoluteRef);
137
+ if (cachedDocument) {
138
+ return cachedDocument;
139
+ }
140
+ const doc = this.loadExternalRef(absoluteRef).then((source) => {
141
+ return this.parseDocument(source, isRoot);
158
142
  });
143
+ this.cache.set(absoluteRef, doc);
144
+ return doc;
159
145
  }
160
146
  }
161
147
  exports.BaseResolver = BaseResolver;
@@ -176,174 +162,169 @@ function hasRef(head, node) {
176
162
  }
177
163
  const unknownType = { name: 'unknown', properties: {} };
178
164
  const resolvableScalarType = { name: 'scalar', properties: {} };
179
- function resolveDocument(opts) {
180
- return __awaiter(this, void 0, void 0, function* () {
181
- const { rootDocument, externalRefResolver, rootType } = opts;
182
- const resolvedRefMap = new Map();
183
- const seedNodes = new Set(); // format "${type}::${absoluteRef}${pointer}"
184
- const resolvePromises = [];
185
- resolveRefsInParallel(rootDocument.parsed, rootDocument, '#/', rootType);
186
- let resolved;
187
- do {
188
- resolved = yield Promise.all(resolvePromises);
189
- } while (resolvePromises.length !== resolved.length);
190
- return resolvedRefMap;
191
- function resolveRefsInParallel(rootNode, rootNodeDocument, rootNodePointer, type) {
192
- const rootNodeDocAbsoluteRef = rootNodeDocument.source.absoluteRef;
193
- const anchorRefsMap = new Map();
194
- walk(rootNode, type, rootNodeDocAbsoluteRef + rootNodePointer);
195
- function walk(node, type, nodeAbsoluteRef) {
196
- if (typeof node !== 'object' || node === null) {
197
- return;
198
- }
199
- const nodeId = `${type.name}::${nodeAbsoluteRef}`;
200
- if (seedNodes.has(nodeId)) {
165
+ async function resolveDocument(opts) {
166
+ const { rootDocument, externalRefResolver, rootType } = opts;
167
+ const resolvedRefMap = new Map();
168
+ const seedNodes = new Set(); // format "${type}::${absoluteRef}${pointer}"
169
+ const resolvePromises = [];
170
+ resolveRefsInParallel(rootDocument.parsed, rootDocument, '#/', rootType);
171
+ let resolved;
172
+ do {
173
+ resolved = await Promise.all(resolvePromises);
174
+ } while (resolvePromises.length !== resolved.length);
175
+ return resolvedRefMap;
176
+ function resolveRefsInParallel(rootNode, rootNodeDocument, rootNodePointer, type) {
177
+ const rootNodeDocAbsoluteRef = rootNodeDocument.source.absoluteRef;
178
+ const anchorRefsMap = new Map();
179
+ walk(rootNode, type, rootNodeDocAbsoluteRef + rootNodePointer);
180
+ function walk(node, type, nodeAbsoluteRef) {
181
+ if (typeof node !== 'object' || node === null) {
182
+ return;
183
+ }
184
+ const nodeId = `${type.name}::${nodeAbsoluteRef}`;
185
+ if (seedNodes.has(nodeId)) {
186
+ return;
187
+ }
188
+ seedNodes.add(nodeId);
189
+ const [_, anchor] = Object.entries(node).find(([key]) => key === '$anchor') || [];
190
+ if (anchor) {
191
+ anchorRefsMap.set(`#${anchor}`, node);
192
+ }
193
+ if (Array.isArray(node)) {
194
+ const itemsType = type.items;
195
+ // we continue resolving unknown types, but stop early on known scalars
196
+ if (itemsType === undefined && type !== unknownType && type !== types_1.SpecExtension) {
201
197
  return;
202
198
  }
203
- seedNodes.add(nodeId);
204
- const [_, anchor] = Object.entries(node).find(([key]) => key === '$anchor') || [];
205
- if (anchor) {
206
- anchorRefsMap.set(`#${anchor}`, node);
207
- }
208
- if (Array.isArray(node)) {
209
- const itemsType = type.items;
199
+ const isTypeAFunction = typeof itemsType === 'function';
200
+ for (let i = 0; i < node.length; i++) {
201
+ const itemType = isTypeAFunction
202
+ ? itemsType(node[i], (0, ref_utils_1.joinPointer)(nodeAbsoluteRef, i))
203
+ : itemsType;
210
204
  // we continue resolving unknown types, but stop early on known scalars
211
- if (itemsType === undefined && type !== unknownType && type !== types_1.SpecExtension) {
212
- return;
213
- }
214
- const isTypeAFunction = typeof itemsType === 'function';
215
- for (let i = 0; i < node.length; i++) {
216
- const itemType = isTypeAFunction
217
- ? itemsType(node[i], (0, ref_utils_1.joinPointer)(nodeAbsoluteRef, i))
218
- : itemsType;
219
- // we continue resolving unknown types, but stop early on known scalars
220
- if (itemType === undefined && type !== unknownType && type !== types_1.SpecExtension) {
221
- continue;
222
- }
223
- walk(node[i], (0, types_1.isNamedType)(itemType) ? itemType : unknownType, (0, ref_utils_1.joinPointer)(nodeAbsoluteRef, i));
224
- }
225
- return;
226
- }
227
- for (const propName of Object.keys(node)) {
228
- let propValue = node[propName];
229
- let propType = type.properties[propName];
230
- if (propType === undefined)
231
- propType = type.additionalProperties;
232
- if (typeof propType === 'function')
233
- propType = propType(propValue, propName);
234
- if (propType === undefined)
235
- propType = unknownType;
236
- if (type.extensionsPrefix &&
237
- propName.startsWith(type.extensionsPrefix) &&
238
- propType === unknownType) {
239
- propType = types_1.SpecExtension;
240
- }
241
- if (!(0, types_1.isNamedType)(propType) && (propType === null || propType === void 0 ? void 0 : propType.directResolveAs)) {
242
- propType = propType.directResolveAs;
243
- propValue = { $ref: propValue };
244
- }
245
- if (propType && propType.name === undefined && propType.resolvable !== false) {
246
- propType = resolvableScalarType;
247
- }
248
- if (!(0, types_1.isNamedType)(propType) || typeof propValue !== 'object') {
205
+ if (itemType === undefined && type !== unknownType && type !== types_1.SpecExtension) {
249
206
  continue;
250
207
  }
251
- walk(propValue, propType, (0, ref_utils_1.joinPointer)(nodeAbsoluteRef, (0, ref_utils_1.escapePointer)(propName)));
208
+ walk(node[i], (0, types_1.isNamedType)(itemType) ? itemType : unknownType, (0, ref_utils_1.joinPointer)(nodeAbsoluteRef, i));
209
+ }
210
+ return;
211
+ }
212
+ for (const propName of Object.keys(node)) {
213
+ let propValue = node[propName];
214
+ let propType = type.properties[propName];
215
+ if (propType === undefined)
216
+ propType = type.additionalProperties;
217
+ if (typeof propType === 'function')
218
+ propType = propType(propValue, propName);
219
+ if (propType === undefined)
220
+ propType = unknownType;
221
+ if (type.extensionsPrefix &&
222
+ propName.startsWith(type.extensionsPrefix) &&
223
+ propType === unknownType) {
224
+ propType = types_1.SpecExtension;
252
225
  }
253
- if ((0, ref_utils_1.isRef)(node)) {
254
- const promise = followRef(rootNodeDocument, node, {
255
- prev: null,
256
- node,
257
- }).then((resolvedRef) => {
258
- if (resolvedRef.resolved) {
259
- resolveRefsInParallel(resolvedRef.node, resolvedRef.document, resolvedRef.nodePointer, type);
260
- }
261
- });
262
- resolvePromises.push(promise);
226
+ if (!(0, types_1.isNamedType)(propType) && propType?.directResolveAs) {
227
+ propType = propType.directResolveAs;
228
+ propValue = { $ref: propValue };
263
229
  }
230
+ if (propType && propType.name === undefined && propType.resolvable !== false) {
231
+ propType = resolvableScalarType;
232
+ }
233
+ if (!(0, types_1.isNamedType)(propType) || typeof propValue !== 'object') {
234
+ continue;
235
+ }
236
+ walk(propValue, propType, (0, ref_utils_1.joinPointer)(nodeAbsoluteRef, (0, ref_utils_1.escapePointer)(propName)));
264
237
  }
265
- function followRef(document, ref, refStack) {
266
- return __awaiter(this, void 0, void 0, function* () {
267
- if (hasRef(refStack.prev, ref)) {
268
- throw new Error('Self-referencing circular pointer');
269
- }
270
- if ((0, ref_utils_1.isAnchor)(ref.$ref)) {
271
- // Wait for all anchors in the document to be collected firstly.
272
- yield (0, utils_1.nextTick)();
273
- const resolvedRef = {
274
- resolved: true,
275
- isRemote: false,
276
- node: anchorRefsMap.get(ref.$ref),
277
- document,
278
- nodePointer: ref.$ref,
279
- };
280
- const refId = makeRefId(document.source.absoluteRef, ref.$ref);
281
- resolvedRefMap.set(refId, resolvedRef);
282
- return resolvedRef;
283
- }
284
- const { uri, pointer } = (0, ref_utils_1.parseRef)(ref.$ref);
285
- const isRemote = uri !== null;
286
- let targetDoc;
287
- try {
288
- targetDoc = isRemote
289
- ? (yield externalRefResolver.resolveDocument(document.source.absoluteRef, uri))
290
- : document;
238
+ if ((0, ref_utils_1.isRef)(node)) {
239
+ const promise = followRef(rootNodeDocument, node, {
240
+ prev: null,
241
+ node,
242
+ }).then((resolvedRef) => {
243
+ if (resolvedRef.resolved) {
244
+ resolveRefsInParallel(resolvedRef.node, resolvedRef.document, resolvedRef.nodePointer, type);
291
245
  }
292
- catch (error) {
293
- const resolvedRef = {
294
- resolved: false,
295
- isRemote,
296
- document: undefined,
297
- error: error,
298
- };
299
- const refId = makeRefId(document.source.absoluteRef, ref.$ref);
300
- resolvedRefMap.set(refId, resolvedRef);
301
- return resolvedRef;
302
- }
303
- let resolvedRef = {
304
- resolved: true,
305
- document: targetDoc,
306
- isRemote,
307
- node: document.parsed,
308
- nodePointer: '#/',
309
- };
310
- let target = targetDoc.parsed;
311
- const segments = pointer;
312
- for (const segment of segments) {
313
- if (typeof target !== 'object') {
314
- target = undefined;
315
- break;
316
- }
317
- else if (target[segment] !== undefined) {
318
- target = target[segment];
319
- resolvedRef.nodePointer = (0, ref_utils_1.joinPointer)(resolvedRef.nodePointer, (0, ref_utils_1.escapePointer)(segment));
320
- }
321
- else if ((0, ref_utils_1.isRef)(target)) {
322
- resolvedRef = yield followRef(targetDoc, target, pushRef(refStack, target));
323
- targetDoc = resolvedRef.document || targetDoc;
324
- if (typeof resolvedRef.node !== 'object') {
325
- target = undefined;
326
- break;
327
- }
328
- target = resolvedRef.node[segment];
329
- resolvedRef.nodePointer = (0, ref_utils_1.joinPointer)(resolvedRef.nodePointer, (0, ref_utils_1.escapePointer)(segment));
330
- }
331
- else {
332
- target = undefined;
333
- break;
334
- }
335
- }
336
- resolvedRef.node = target;
337
- resolvedRef.document = targetDoc;
338
- const refId = makeRefId(document.source.absoluteRef, ref.$ref);
339
- if (resolvedRef.document && (0, ref_utils_1.isRef)(target)) {
340
- resolvedRef = yield followRef(resolvedRef.document, target, pushRef(refStack, target));
341
- }
342
- resolvedRefMap.set(refId, resolvedRef);
343
- return Object.assign({}, resolvedRef);
344
246
  });
247
+ resolvePromises.push(promise);
345
248
  }
346
249
  }
347
- });
250
+ async function followRef(document, ref, refStack) {
251
+ if (hasRef(refStack.prev, ref)) {
252
+ throw new Error('Self-referencing circular pointer');
253
+ }
254
+ if ((0, ref_utils_1.isAnchor)(ref.$ref)) {
255
+ // Wait for all anchors in the document to be collected firstly.
256
+ await (0, utils_1.nextTick)();
257
+ const resolvedRef = {
258
+ resolved: true,
259
+ isRemote: false,
260
+ node: anchorRefsMap.get(ref.$ref),
261
+ document,
262
+ nodePointer: ref.$ref,
263
+ };
264
+ const refId = makeRefId(document.source.absoluteRef, ref.$ref);
265
+ resolvedRefMap.set(refId, resolvedRef);
266
+ return resolvedRef;
267
+ }
268
+ const { uri, pointer } = (0, ref_utils_1.parseRef)(ref.$ref);
269
+ const isRemote = uri !== null;
270
+ let targetDoc;
271
+ try {
272
+ targetDoc = isRemote
273
+ ? (await externalRefResolver.resolveDocument(document.source.absoluteRef, uri))
274
+ : document;
275
+ }
276
+ catch (error) {
277
+ const resolvedRef = {
278
+ resolved: false,
279
+ isRemote,
280
+ document: undefined,
281
+ error: error,
282
+ };
283
+ const refId = makeRefId(document.source.absoluteRef, ref.$ref);
284
+ resolvedRefMap.set(refId, resolvedRef);
285
+ return resolvedRef;
286
+ }
287
+ let resolvedRef = {
288
+ resolved: true,
289
+ document: targetDoc,
290
+ isRemote,
291
+ node: document.parsed,
292
+ nodePointer: '#/',
293
+ };
294
+ let target = targetDoc.parsed;
295
+ const segments = pointer;
296
+ for (const segment of segments) {
297
+ if (typeof target !== 'object') {
298
+ target = undefined;
299
+ break;
300
+ }
301
+ else if (target[segment] !== undefined) {
302
+ target = target[segment];
303
+ resolvedRef.nodePointer = (0, ref_utils_1.joinPointer)(resolvedRef.nodePointer, (0, ref_utils_1.escapePointer)(segment));
304
+ }
305
+ else if ((0, ref_utils_1.isRef)(target)) {
306
+ resolvedRef = await followRef(targetDoc, target, pushRef(refStack, target));
307
+ targetDoc = resolvedRef.document || targetDoc;
308
+ if (typeof resolvedRef.node !== 'object') {
309
+ target = undefined;
310
+ break;
311
+ }
312
+ target = resolvedRef.node[segment];
313
+ resolvedRef.nodePointer = (0, ref_utils_1.joinPointer)(resolvedRef.nodePointer, (0, ref_utils_1.escapePointer)(segment));
314
+ }
315
+ else {
316
+ target = undefined;
317
+ break;
318
+ }
319
+ }
320
+ resolvedRef.node = target;
321
+ resolvedRef.document = targetDoc;
322
+ const refId = makeRefId(document.source.absoluteRef, ref.$ref);
323
+ if (resolvedRef.document && (0, ref_utils_1.isRef)(target)) {
324
+ resolvedRef = await followRef(resolvedRef.document, target, pushRef(refStack, target));
325
+ }
326
+ resolvedRefMap.set(refId, resolvedRef);
327
+ return { ...resolvedRef };
328
+ }
329
+ }
348
330
  }
349
- exports.resolveDocument = resolveDocument;
package/lib/rules/ajv.js CHANGED
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateJsonSchema = exports.releaseAjvInstance = void 0;
3
+ exports.releaseAjvInstance = releaseAjvInstance;
4
+ exports.validateJsonSchema = validateJsonSchema;
4
5
  const _2020_1 = require("@redocly/ajv/dist/2020");
5
6
  const ref_utils_1 = require("../ref-utils");
6
7
  let ajvInstance = null;
7
8
  function releaseAjvInstance() {
8
9
  ajvInstance = null;
9
10
  }
10
- exports.releaseAjvInstance = releaseAjvInstance;
11
11
  function getAjv(resolve, allowAdditionalProperties) {
12
12
  if (!ajvInstance) {
13
13
  ajvInstance = new _2020_1.default({
@@ -19,13 +19,13 @@ function getAjv(resolve, allowAdditionalProperties) {
19
19
  validateSchema: false,
20
20
  discriminator: true,
21
21
  allowUnionTypes: true,
22
- validateFormats: false,
22
+ validateFormats: false, // TODO: fix it
23
23
  defaultUnevaluatedProperties: allowAdditionalProperties,
24
24
  loadSchemaSync(base, $ref, $id) {
25
25
  const resolvedRef = resolve({ $ref }, base.split('#')[0]);
26
26
  if (!resolvedRef || !resolvedRef.location)
27
27
  return false;
28
- return Object.assign({ $id: resolvedRef.location.source.absoluteRef + '#' + $id }, resolvedRef.node);
28
+ return { $id: resolvedRef.location.source.absoluteRef + '#' + $id, ...resolvedRef.node };
29
29
  },
30
30
  logger: false,
31
31
  });
@@ -35,7 +35,7 @@ function getAjv(resolve, allowAdditionalProperties) {
35
35
  function getAjvValidator(schema, loc, resolve, allowAdditionalProperties) {
36
36
  const ajv = getAjv(resolve, allowAdditionalProperties);
37
37
  if (!ajv.getSchema(loc.absolutePointer)) {
38
- ajv.addSchema(Object.assign({ $id: loc.absolutePointer }, schema), loc.absolutePointer);
38
+ ajv.addSchema({ $id: loc.absolutePointer, ...schema }, loc.absolutePointer);
39
39
  }
40
40
  return ajv.getSchema(loc.absolutePointer);
41
41
  }
@@ -73,8 +73,10 @@ function validateJsonSchema(data, schema, schemaLoc, instancePath, resolve, allo
73
73
  message = `${message} \`${property}\``;
74
74
  error.instancePath += '/' + (0, ref_utils_1.escapePointer)(property);
75
75
  }
76
- return Object.assign(Object.assign({}, error), { message,
77
- suggest });
76
+ return {
77
+ ...error,
78
+ message,
79
+ suggest,
80
+ };
78
81
  }
79
82
  }
80
- exports.validateJsonSchema = validateJsonSchema;
@@ -0,0 +1,2 @@
1
+ import { Async3Rule } from '../../visitors';
2
+ export declare const ChannelsKebabCase: Async3Rule;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChannelsKebabCase = void 0;
4
+ const ChannelsKebabCase = () => {
5
+ return {
6
+ Channel(channel, { report }) {
7
+ const segments = (channel.address || '')
8
+ .split(/[/.:]/) // split on / or : as likely channel namespacers
9
+ .filter((s) => s !== ''); // filter out empty segments
10
+ if (!segments.every((segment) => /^{.+}$/.test(segment) || /^[a-z0-9-.]+$/.test(segment))) {
11
+ report({
12
+ message: `\`${channel.address}\` does not use kebab-case.`,
13
+ location: { reportOnKey: true },
14
+ });
15
+ }
16
+ },
17
+ };
18
+ };
19
+ exports.ChannelsKebabCase = ChannelsKebabCase;
@@ -0,0 +1,3 @@
1
+ import type { Async3RuleSet } from '../../oas-types';
2
+ export declare const rules: Async3RuleSet<'built-in'>;
3
+ export declare const preprocessors: {};
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.preprocessors = exports.rules = void 0;
4
+ const assertions_1 = require("../common/assertions");
5
+ const spec_1 = require("../common/spec");
6
+ const info_contact_1 = require("../common/info-contact");
7
+ const operation_operationId_1 = require("../common/operation-operationId");
8
+ const tag_description_1 = require("../common/tag-description");
9
+ const tags_alphabetical_1 = require("../common/tags-alphabetical");
10
+ const channels_kebab_case_1 = require("./channels-kebab-case");
11
+ const no_channel_trailing_slash_1 = require("./no-channel-trailing-slash");
12
+ exports.rules = {
13
+ spec: spec_1.Spec,
14
+ assertions: assertions_1.Assertions,
15
+ 'info-contact': info_contact_1.InfoContact,
16
+ 'operation-operationId': operation_operationId_1.OperationOperationId,
17
+ 'channels-kebab-case': channels_kebab_case_1.ChannelsKebabCase,
18
+ 'no-channel-trailing-slash': no_channel_trailing_slash_1.NoChannelTrailingSlash,
19
+ 'tag-description': tag_description_1.TagDescription,
20
+ 'tags-alphabetical': tags_alphabetical_1.TagsAlphabetical,
21
+ };
22
+ exports.preprocessors = {};
@@ -0,0 +1,2 @@
1
+ import { Async3Rule } from '../../visitors';
2
+ export declare const NoChannelTrailingSlash: Async3Rule;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NoChannelTrailingSlash = void 0;
4
+ const NoChannelTrailingSlash = () => {
5
+ return {
6
+ Channel(channel, { report, location }) {
7
+ if (channel.address.endsWith('/') && channel.address !== '/') {
8
+ report({
9
+ message: `\`${channel.address}\` should not have a trailing slash.`,
10
+ location: location.key(),
11
+ });
12
+ }
13
+ },
14
+ };
15
+ };
16
+ exports.NoChannelTrailingSlash = NoChannelTrailingSlash;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildAssertCustomFunction = exports.asserts = exports.runOnValuesSet = exports.runOnKeysSet = void 0;
3
+ exports.asserts = exports.runOnValuesSet = exports.runOnKeysSet = void 0;
4
+ exports.buildAssertCustomFunction = buildAssertCustomFunction;
4
5
  const utils_1 = require("../../../utils");
5
6
  const utils_2 = require("./utils");
6
7
  exports.runOnKeysSet = new Set([
@@ -41,7 +42,7 @@ exports.asserts = {
41
42
  const values = Array.isArray(value) ? value : [value];
42
43
  const regex = (0, utils_2.regexFromString)(condition);
43
44
  return values
44
- .map((_val) => !(regex === null || regex === void 0 ? void 0 : regex.test(_val)) && {
45
+ .map((_val) => !regex?.test(_val) && {
45
46
  message: `"${_val}" should match a regex ${condition}`,
46
47
  location: (0, utils_1.isString)(value)
47
48
  ? baseLocation
@@ -57,7 +58,7 @@ exports.asserts = {
57
58
  const values = Array.isArray(value) ? value : [value];
58
59
  const regex = (0, utils_2.regexFromString)(condition);
59
60
  return values
60
- .map((_val) => (regex === null || regex === void 0 ? void 0 : regex.test(_val)) && {
61
+ .map((_val) => regex?.test(_val) && {
61
62
  message: `"${_val}" should not match a regex ${condition}`,
62
63
  location: (0, utils_1.isString)(value)
63
64
  ? baseLocation
@@ -264,7 +265,7 @@ exports.asserts = {
264
265
  ];
265
266
  }
266
267
  const regex = (0, utils_2.regexFromString)(condition);
267
- const isValid = hasRef && (regex === null || regex === void 0 ? void 0 : regex.test(rawValue['$ref']));
268
+ const isValid = hasRef && regex?.test(rawValue['$ref']);
268
269
  return isValid
269
270
  ? []
270
271
  : [
@@ -278,4 +279,3 @@ exports.asserts = {
278
279
  function buildAssertCustomFunction(fn) {
279
280
  return (value, options, ctx) => fn.call(null, value, options, ctx);
280
281
  }
281
- exports.buildAssertCustomFunction = buildAssertCustomFunction;
@@ -1,6 +1,7 @@
1
- import { asserts, AssertionFn } from './asserts';
2
- import { Oas2Visitor, Oas3Visitor } from '../../../visitors';
3
- import { RuleSeverity } from '../../../config';
1
+ import { asserts } from './asserts';
2
+ import type { AssertionFn } from './asserts';
3
+ import type { ArazzoVisitor, Async2Visitor, Async3Visitor, Oas2Visitor, Oas3Visitor } from '../../../visitors';
4
+ import type { RuleSeverity } from '../../../config';
4
5
  export type AssertionLocators = {
5
6
  filterInParentKeys?: (string | number)[];
6
7
  filterOutParentKeys?: (string | number)[];
@@ -24,4 +25,4 @@ export type RawAssertion = AssertionDefinition & {
24
25
  export type Assertion = RawAssertion & {
25
26
  assertionId: string;
26
27
  };
27
- export declare const Assertions: (opts: Record<string, Assertion>) => (Oas3Visitor | Oas2Visitor)[];
28
+ export declare const Assertions: (opts: Record<string, Assertion>) => (Oas3Visitor | Oas2Visitor | Async2Visitor | Async3Visitor | ArazzoVisitor)[];