@speclynx/apidom-reference 5.2.5 → 5.2.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@speclynx/apidom-reference",
3
- "version": "5.2.5",
3
+ "version": "5.2.6",
4
4
  "description": "Advanced algorithms for semantic ApiDOM manipulations like dereferencing or resolution.",
5
5
  "keywords": [
6
6
  "apidom",
@@ -298,33 +298,33 @@
298
298
  "author": "Vladimir Gorej",
299
299
  "license": "Apache-2.0",
300
300
  "dependencies": {
301
- "@babel/runtime-corejs3": "^8.0.0",
302
- "@speclynx/apidom-core": "5.2.5",
303
- "@speclynx/apidom-datamodel": "5.2.5",
304
- "@speclynx/apidom-error": "5.2.5",
305
- "@speclynx/apidom-json-pointer": "5.2.5",
306
- "@speclynx/apidom-ns-arazzo-1": "5.2.5",
307
- "@speclynx/apidom-ns-asyncapi-2": "5.2.5",
308
- "@speclynx/apidom-ns-json-schema-2020-12": "5.2.5",
309
- "@speclynx/apidom-ns-openapi-2": "5.2.5",
310
- "@speclynx/apidom-ns-openapi-3-0": "5.2.5",
311
- "@speclynx/apidom-ns-openapi-3-1": "5.2.5",
312
- "@speclynx/apidom-ns-overlay-1": "5.2.5",
313
- "@speclynx/apidom-parser-adapter-arazzo-json-1": "5.2.5",
314
- "@speclynx/apidom-parser-adapter-arazzo-yaml-1": "5.2.5",
315
- "@speclynx/apidom-parser-adapter-asyncapi-json-2": "5.2.5",
316
- "@speclynx/apidom-parser-adapter-asyncapi-yaml-2": "5.2.5",
317
- "@speclynx/apidom-parser-adapter-json": "5.2.5",
318
- "@speclynx/apidom-parser-adapter-openapi-json-2": "5.2.5",
319
- "@speclynx/apidom-parser-adapter-openapi-json-3-0": "5.2.5",
320
- "@speclynx/apidom-parser-adapter-openapi-json-3-1": "5.2.5",
321
- "@speclynx/apidom-parser-adapter-openapi-yaml-2": "5.2.5",
322
- "@speclynx/apidom-parser-adapter-openapi-yaml-3-0": "5.2.5",
323
- "@speclynx/apidom-parser-adapter-openapi-yaml-3-1": "5.2.5",
324
- "@speclynx/apidom-parser-adapter-overlay-json-1": "5.2.5",
325
- "@speclynx/apidom-parser-adapter-overlay-yaml-1": "5.2.5",
326
- "@speclynx/apidom-parser-adapter-yaml-1-2": "5.2.5",
327
- "@speclynx/apidom-traverse": "5.2.5",
301
+ "@babel/runtime-corejs3": "^8.0.5",
302
+ "@speclynx/apidom-core": "5.2.6",
303
+ "@speclynx/apidom-datamodel": "5.2.6",
304
+ "@speclynx/apidom-error": "5.2.6",
305
+ "@speclynx/apidom-json-pointer": "5.2.6",
306
+ "@speclynx/apidom-ns-arazzo-1": "5.2.6",
307
+ "@speclynx/apidom-ns-asyncapi-2": "5.2.6",
308
+ "@speclynx/apidom-ns-json-schema-2020-12": "5.2.6",
309
+ "@speclynx/apidom-ns-openapi-2": "5.2.6",
310
+ "@speclynx/apidom-ns-openapi-3-0": "5.2.6",
311
+ "@speclynx/apidom-ns-openapi-3-1": "5.2.6",
312
+ "@speclynx/apidom-ns-overlay-1": "5.2.6",
313
+ "@speclynx/apidom-parser-adapter-arazzo-json-1": "5.2.6",
314
+ "@speclynx/apidom-parser-adapter-arazzo-yaml-1": "5.2.6",
315
+ "@speclynx/apidom-parser-adapter-asyncapi-json-2": "5.2.6",
316
+ "@speclynx/apidom-parser-adapter-asyncapi-yaml-2": "5.2.6",
317
+ "@speclynx/apidom-parser-adapter-json": "5.2.6",
318
+ "@speclynx/apidom-parser-adapter-openapi-json-2": "5.2.6",
319
+ "@speclynx/apidom-parser-adapter-openapi-json-3-0": "5.2.6",
320
+ "@speclynx/apidom-parser-adapter-openapi-json-3-1": "5.2.6",
321
+ "@speclynx/apidom-parser-adapter-openapi-yaml-2": "5.2.6",
322
+ "@speclynx/apidom-parser-adapter-openapi-yaml-3-0": "5.2.6",
323
+ "@speclynx/apidom-parser-adapter-openapi-yaml-3-1": "5.2.6",
324
+ "@speclynx/apidom-parser-adapter-overlay-json-1": "5.2.6",
325
+ "@speclynx/apidom-parser-adapter-overlay-yaml-1": "5.2.6",
326
+ "@speclynx/apidom-parser-adapter-yaml-1-2": "5.2.6",
327
+ "@speclynx/apidom-traverse": "5.2.6",
328
328
  "@swaggerexpert/arazzo-runtime-expression": "^3.2.0",
329
329
  "axios": "^1.20.0",
330
330
  "picomatch": "^4.0.7",
@@ -346,5 +346,5 @@
346
346
  "README.md",
347
347
  "CHANGELOG.md"
348
348
  ],
349
- "gitHead": "677f42e6af4e7b5311c74cd054283c943f8700a9"
349
+ "gitHead": "c78f4a79e2b91b9ad099dff6dff5dc35236ae75b"
350
350
  }
@@ -121,6 +121,17 @@ class Arazzo1DereferenceStrategy extends _DereferenceStrategy.default {
121
121
  })
122
122
  });
123
123
 
124
+ /**
125
+ * If immutable option is set, replay refs from the refSet.
126
+ * Replayed before source descriptions are dereferenced, so they can reuse the refs.
127
+ */
128
+ if (options.dereference.immutable) {
129
+ mutableRefSet.refs.filter(ref => ref.uri.startsWith('immutable://')).map(ref => new _Reference.default({
130
+ ...ref,
131
+ uri: ref.uri.replace(/^immutable:\/\//, '')
132
+ })).forEach(ref => immutableRefSet.add(ref));
133
+ }
134
+
124
135
  /**
125
136
  * Dereference source descriptions if option is enabled.
126
137
  */
@@ -135,16 +146,6 @@ class Arazzo1DereferenceStrategy extends _DereferenceStrategy.default {
135
146
  parseResult.push(...sourceDescriptions);
136
147
  }
137
148
 
138
- /**
139
- * If immutable option is set, replay refs from the refSet.
140
- */
141
- if (options.dereference.immutable) {
142
- mutableRefSet.refs.filter(ref => ref.uri.startsWith('immutable://')).map(ref => new _Reference.default({
143
- ...ref,
144
- uri: ref.uri.replace(/^immutable:\/\//, '')
145
- })).forEach(ref => immutableRefSet.add(ref));
146
- }
147
-
148
149
  /**
149
150
  * Release all memory if this refSet was not provided as a configuration option.
150
151
  * If provided as configuration option, then provider is responsible for cleanup.
@@ -70,6 +70,17 @@ class Arazzo1DereferenceStrategy extends DereferenceStrategy {
70
70
  })
71
71
  });
72
72
 
73
+ /**
74
+ * If immutable option is set, replay refs from the refSet.
75
+ * Replayed before source descriptions are dereferenced, so they can reuse the refs.
76
+ */
77
+ if (options.dereference.immutable) {
78
+ mutableRefSet.refs.filter(ref => ref.uri.startsWith('immutable://')).map(ref => new Reference({
79
+ ...ref,
80
+ uri: ref.uri.replace(/^immutable:\/\//, '')
81
+ })).forEach(ref => immutableRefSet.add(ref));
82
+ }
83
+
73
84
  /**
74
85
  * Dereference source descriptions if option is enabled.
75
86
  */
@@ -84,16 +95,6 @@ class Arazzo1DereferenceStrategy extends DereferenceStrategy {
84
95
  parseResult.push(...sourceDescriptions);
85
96
  }
86
97
 
87
- /**
88
- * If immutable option is set, replay refs from the refSet.
89
- */
90
- if (options.dereference.immutable) {
91
- mutableRefSet.refs.filter(ref => ref.uri.startsWith('immutable://')).map(ref => new Reference({
92
- ...ref,
93
- uri: ref.uri.replace(/^immutable:\/\//, '')
94
- })).forEach(ref => immutableRefSet.add(ref));
95
- }
96
-
97
98
  /**
98
99
  * Release all memory if this refSet was not provided as a configuration option.
99
100
  * If provided as configuration option, then provider is responsible for cleanup.
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
3
4
  var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard").default;
4
5
  Object.defineProperty(exports, "__esModule", {
5
6
  value: true
@@ -8,9 +9,13 @@ exports.dereferenceSourceDescriptions = dereferenceSourceDescriptions;
8
9
  var _apidomDatamodel = require("@speclynx/apidom-datamodel");
9
10
  var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
10
11
  var _apidomCore = require("@speclynx/apidom-core");
12
+ var _ramda = require("ramda");
11
13
  var url = _interopRequireWildcard(require("../../../util/url.cjs"));
14
+ var _Reference = _interopRequireDefault(require("../../../Reference.cjs"));
15
+ var _ReferenceSet = _interopRequireDefault(require("../../../ReferenceSet.cjs"));
12
16
  var _util = require("../../../options/util.cjs");
13
- var _index = _interopRequireWildcard(require("../../index.cjs"));
17
+ var _index = _interopRequireDefault(require("../../../parse/index.cjs"));
18
+ var _index2 = require("../../index.cjs");
14
19
  var _util2 = require("./util.cjs");
15
20
  /**
16
21
  * Dereferences a single source description element.
@@ -63,53 +68,64 @@ async function dereferenceSourceDescription(sourceDescription, ctx) {
63
68
 
64
69
  // check if source description was already parsed (e.g., during parse phase with sourceDescriptions: true)
65
70
  const existingParseResult = sourceDescription.meta.get('parseResult');
71
+ const parentRefSet = ctx.options.dereference.refSet;
72
+ let refSet = null;
66
73
  try {
67
- let sourceDescriptionDereferenced;
68
- if ((0, _apidomDatamodel.isParseResultElement)(existingParseResult)) {
69
- // use existing parsed result - just dereference it (no re-fetch/re-parse)
70
- sourceDescriptionDereferenced = await (0, _index.dereferenceApiDOM)(existingParseResult, (0, _util.merge)(ctx.options, {
71
- parse: {
72
- mediaType: 'text/plain' // allow dereference strategy detection via ApiDOM inspection
73
- },
74
- resolve: {
75
- baseURI: retrievalURI
76
- },
77
- dereference: {
78
- strategyOpts: {
79
- // nested documents should dereference all their source descriptions
80
- // (parent's name filter doesn't apply to nested documents)
81
- // set at strategy-specific level to override any inherited filters
82
- [ctx.strategyName]: {
83
- sourceDescriptions: true,
84
- sourceDescriptionsDepth: ctx.currentDepth + 1,
85
- sourceDescriptionsAncestors: ctx.ancestors,
86
- sourceDescriptionsDereferenced: ctx.dereferenced
87
- }
88
- }
89
- }
90
- }));
74
+ // source description document comes from, in order of preference:
75
+ // caller-supplied refSet, parse phase, or is fetched and parsed now
76
+ const cachedReference = parentRefSet?.find(ref => ref.uri === retrievalURI);
77
+ let sourceDescriptionParseResult;
78
+ let isFreshlyParsed = false;
79
+ if (cachedReference !== undefined) {
80
+ sourceDescriptionParseResult = cachedReference.value;
81
+ } else if ((0, _apidomDatamodel.isParseResultElement)(existingParseResult)) {
82
+ sourceDescriptionParseResult = existingParseResult;
91
83
  } else {
92
- // no existing parse result - fetch, parse, and dereference
93
- sourceDescriptionDereferenced = await (0, _index.default)(retrievalURI, (0, _util.merge)(ctx.options, {
84
+ sourceDescriptionParseResult = await (0, _index.default)(retrievalURI, (0, _util.merge)(ctx.options, {
94
85
  parse: {
95
- mediaType: 'text/plain' // allow parser plugin detection
96
- },
97
- dereference: {
98
- strategyOpts: {
99
- // nested documents should dereference all their source descriptions
100
- // (parent's name filter doesn't apply to nested documents)
101
- // set at strategy-specific level to override any inherited filters
102
- [ctx.strategyName]: {
103
- sourceDescriptions: true,
104
- sourceDescriptionsDepth: ctx.currentDepth + 1,
105
- sourceDescriptionsAncestors: ctx.ancestors,
106
- sourceDescriptionsDereferenced: ctx.dereferenced
107
- }
108
- }
109
- }
86
+ mediaType: 'text/plain'
87
+ } // allow parser plugin detection
110
88
  }));
89
+ isFreshlyParsed = true;
111
90
  }
112
91
 
92
+ // caller-supplied refSet is rooted at the entry document, but strategies dereference
93
+ // the root of the refSet; re-root its references at the source description
94
+ if (parentRefSet !== null) {
95
+ refSet = new _ReferenceSet.default({
96
+ refs: [new _Reference.default({
97
+ uri: retrievalURI,
98
+ value: sourceDescriptionParseResult
99
+ }), ...parentRefSet.refs.map(ref => new _Reference.default({
100
+ ...ref,
101
+ refSet: undefined
102
+ }))]
103
+ });
104
+ }
105
+ const sourceDescriptionDereferenced = await (0, _index2.dereferenceApiDOM)(sourceDescriptionParseResult, (0, _util.merge)((0, _ramda.assocPath)(['dereference', 'refSet'], refSet, ctx.options), {
106
+ parse: {
107
+ mediaType: 'text/plain' // allow dereference strategy detection via ApiDOM inspection
108
+ },
109
+ resolve: {
110
+ baseURI: retrievalURI
111
+ },
112
+ dereference: {
113
+ // freshly parsed document not reported to any refSet can be dereferenced in mutable mode
114
+ immutable: ctx.options.dereference.immutable && !(isFreshlyParsed && parentRefSet === null),
115
+ strategyOpts: {
116
+ // nested documents should dereference all their source descriptions
117
+ // (parent's name filter doesn't apply to nested documents)
118
+ // set at strategy-specific level to override any inherited filters
119
+ [ctx.strategyName]: {
120
+ sourceDescriptions: true,
121
+ sourceDescriptionsDepth: ctx.currentDepth + 1,
122
+ sourceDescriptionsAncestors: ctx.ancestors,
123
+ sourceDescriptionsDereferenced: ctx.dereferenced
124
+ }
125
+ }
126
+ }
127
+ }));
128
+
113
129
  // merge dereferenced result into our parse result
114
130
  for (const item of sourceDescriptionDereferenced) {
115
131
  parseResult.push(item);
@@ -121,6 +137,13 @@ async function dereferenceSourceDescription(sourceDescription, ctx) {
121
137
  annotation.classes.push('error');
122
138
  parseResult.push(annotation);
123
139
  return parseResult;
140
+ } finally {
141
+ // report documents reached through the source description to the caller-supplied refSet,
142
+ // even when dereferencing it failed
143
+ if (parentRefSet !== null && refSet !== null) {
144
+ parentRefSet.merge(refSet);
145
+ parentRefSet.circular ||= refSet.circular;
146
+ }
124
147
  }
125
148
 
126
149
  // register dereferenced document for later references to it
@@ -1,9 +1,13 @@
1
1
  import { ParseResultElement, AnnotationElement, isArrayElement, isStringElement, isParseResultElement } from '@speclynx/apidom-datamodel';
2
2
  import { isArazzoSpecification1Element, isSourceDescriptionElement } from '@speclynx/apidom-ns-arazzo-1';
3
3
  import { toValue } from '@speclynx/apidom-core';
4
+ import { assocPath } from 'ramda';
4
5
  import * as url from "../../../util/url.mjs";
6
+ import Reference from "../../../Reference.mjs";
7
+ import ReferenceSet from "../../../ReferenceSet.mjs";
5
8
  import { merge as mergeOptions } from "../../../options/util.mjs";
6
- import dereference, { dereferenceApiDOM } from "../../index.mjs";
9
+ import parse from "../../../parse/index.mjs";
10
+ import { dereferenceApiDOM } from "../../index.mjs";
7
11
  import { arazzoDocumentURIs, resolveArazzo$selfField, validateSourceDescriptionAPI } from "./util.mjs";
8
12
  /**
9
13
  * Dereferences a single source description element.
@@ -56,53 +60,64 @@ async function dereferenceSourceDescription(sourceDescription, ctx) {
56
60
 
57
61
  // check if source description was already parsed (e.g., during parse phase with sourceDescriptions: true)
58
62
  const existingParseResult = sourceDescription.meta.get('parseResult');
63
+ const parentRefSet = ctx.options.dereference.refSet;
64
+ let refSet = null;
59
65
  try {
60
- let sourceDescriptionDereferenced;
61
- if (isParseResultElement(existingParseResult)) {
62
- // use existing parsed result - just dereference it (no re-fetch/re-parse)
63
- sourceDescriptionDereferenced = await dereferenceApiDOM(existingParseResult, mergeOptions(ctx.options, {
64
- parse: {
65
- mediaType: 'text/plain' // allow dereference strategy detection via ApiDOM inspection
66
- },
67
- resolve: {
68
- baseURI: retrievalURI
69
- },
70
- dereference: {
71
- strategyOpts: {
72
- // nested documents should dereference all their source descriptions
73
- // (parent's name filter doesn't apply to nested documents)
74
- // set at strategy-specific level to override any inherited filters
75
- [ctx.strategyName]: {
76
- sourceDescriptions: true,
77
- sourceDescriptionsDepth: ctx.currentDepth + 1,
78
- sourceDescriptionsAncestors: ctx.ancestors,
79
- sourceDescriptionsDereferenced: ctx.dereferenced
80
- }
81
- }
82
- }
83
- }));
66
+ // source description document comes from, in order of preference:
67
+ // caller-supplied refSet, parse phase, or is fetched and parsed now
68
+ const cachedReference = parentRefSet?.find(ref => ref.uri === retrievalURI);
69
+ let sourceDescriptionParseResult;
70
+ let isFreshlyParsed = false;
71
+ if (cachedReference !== undefined) {
72
+ sourceDescriptionParseResult = cachedReference.value;
73
+ } else if (isParseResultElement(existingParseResult)) {
74
+ sourceDescriptionParseResult = existingParseResult;
84
75
  } else {
85
- // no existing parse result - fetch, parse, and dereference
86
- sourceDescriptionDereferenced = await dereference(retrievalURI, mergeOptions(ctx.options, {
76
+ sourceDescriptionParseResult = await parse(retrievalURI, mergeOptions(ctx.options, {
87
77
  parse: {
88
- mediaType: 'text/plain' // allow parser plugin detection
89
- },
90
- dereference: {
91
- strategyOpts: {
92
- // nested documents should dereference all their source descriptions
93
- // (parent's name filter doesn't apply to nested documents)
94
- // set at strategy-specific level to override any inherited filters
95
- [ctx.strategyName]: {
96
- sourceDescriptions: true,
97
- sourceDescriptionsDepth: ctx.currentDepth + 1,
98
- sourceDescriptionsAncestors: ctx.ancestors,
99
- sourceDescriptionsDereferenced: ctx.dereferenced
100
- }
101
- }
102
- }
78
+ mediaType: 'text/plain'
79
+ } // allow parser plugin detection
103
80
  }));
81
+ isFreshlyParsed = true;
104
82
  }
105
83
 
84
+ // caller-supplied refSet is rooted at the entry document, but strategies dereference
85
+ // the root of the refSet; re-root its references at the source description
86
+ if (parentRefSet !== null) {
87
+ refSet = new ReferenceSet({
88
+ refs: [new Reference({
89
+ uri: retrievalURI,
90
+ value: sourceDescriptionParseResult
91
+ }), ...parentRefSet.refs.map(ref => new Reference({
92
+ ...ref,
93
+ refSet: undefined
94
+ }))]
95
+ });
96
+ }
97
+ const sourceDescriptionDereferenced = await dereferenceApiDOM(sourceDescriptionParseResult, mergeOptions(assocPath(['dereference', 'refSet'], refSet, ctx.options), {
98
+ parse: {
99
+ mediaType: 'text/plain' // allow dereference strategy detection via ApiDOM inspection
100
+ },
101
+ resolve: {
102
+ baseURI: retrievalURI
103
+ },
104
+ dereference: {
105
+ // freshly parsed document not reported to any refSet can be dereferenced in mutable mode
106
+ immutable: ctx.options.dereference.immutable && !(isFreshlyParsed && parentRefSet === null),
107
+ strategyOpts: {
108
+ // nested documents should dereference all their source descriptions
109
+ // (parent's name filter doesn't apply to nested documents)
110
+ // set at strategy-specific level to override any inherited filters
111
+ [ctx.strategyName]: {
112
+ sourceDescriptions: true,
113
+ sourceDescriptionsDepth: ctx.currentDepth + 1,
114
+ sourceDescriptionsAncestors: ctx.ancestors,
115
+ sourceDescriptionsDereferenced: ctx.dereferenced
116
+ }
117
+ }
118
+ }
119
+ }));
120
+
106
121
  // merge dereferenced result into our parse result
107
122
  for (const item of sourceDescriptionDereferenced) {
108
123
  parseResult.push(item);
@@ -114,6 +129,13 @@ async function dereferenceSourceDescription(sourceDescription, ctx) {
114
129
  annotation.classes.push('error');
115
130
  parseResult.push(annotation);
116
131
  return parseResult;
132
+ } finally {
133
+ // report documents reached through the source description to the caller-supplied refSet,
134
+ // even when dereferencing it failed
135
+ if (parentRefSet !== null && refSet !== null) {
136
+ parentRefSet.merge(refSet);
137
+ parentRefSet.circular ||= refSet.circular;
138
+ }
117
139
  }
118
140
 
119
141
  // register dereferenced document for later references to it
@@ -252,34 +252,38 @@ class Arazzo1DereferenceVisitor {
252
252
  return;
253
253
  }
254
254
  const runtimeExpression = (0, _apidomCore.toValue)(referencingElement.reference);
255
-
256
- // parse the runtime expression
257
- const {
258
- result,
259
- tree
260
- } = (0, _arazzoRuntimeExpression.parse)(runtimeExpression);
261
- if (!result.success) {
262
- throw new _apidomError.ApiDOMStructuredError(`Invalid Reusable Object reference format: "${runtimeExpression}"`, {
263
- runtimeExpression
264
- });
265
- }
266
-
267
- // ReusableElement can only reference components
268
- if (tree.type !== 'ComponentsExpression') {
269
- throw new _apidomError.ApiDOMStructuredError(`Reusable Object reference "${runtimeExpression}" must be a components expression`, {
270
- runtimeExpression
271
- });
272
- }
273
-
274
- // evaluate runtime expression as JSON Pointer to get the referenced element
275
- const jsonPointer = (0, _apidomJsonPointer.compile)(['components', tree.componentType, tree.componentName]);
276
255
  let referencedElement;
277
256
  try {
278
- referencedElement = (0, _apidomJsonPointer.evaluate)(this.reference.value.result, jsonPointer);
279
- } catch {
280
- throw new _apidomError.ApiDOMStructuredError(`Reusable Object reference "${runtimeExpression}" cannot be resolved`, {
281
- runtimeExpression
282
- });
257
+ // parse the runtime expression
258
+ const {
259
+ result,
260
+ tree
261
+ } = (0, _arazzoRuntimeExpression.parse)(runtimeExpression);
262
+ if (!result.success) {
263
+ throw new _apidomError.ApiDOMStructuredError(`Invalid Reusable Object reference format: "${runtimeExpression}"`, {
264
+ runtimeExpression
265
+ });
266
+ }
267
+
268
+ // ReusableElement can only reference components
269
+ if (tree.type !== 'ComponentsExpression') {
270
+ throw new _apidomError.ApiDOMStructuredError(`Reusable Object reference "${runtimeExpression}" must be a components expression`, {
271
+ runtimeExpression
272
+ });
273
+ }
274
+
275
+ // evaluate runtime expression as JSON Pointer to get the referenced element
276
+ const jsonPointer = (0, _apidomJsonPointer.compile)(['components', tree.componentType, tree.componentName]);
277
+ try {
278
+ referencedElement = (0, _apidomJsonPointer.evaluate)(this.reference.value.result, jsonPointer);
279
+ } catch {
280
+ throw new _apidomError.ApiDOMStructuredError(`Reusable Object reference "${runtimeExpression}" cannot be resolved`, {
281
+ runtimeExpression
282
+ });
283
+ }
284
+ } catch (error) {
285
+ this.handleError(`Error while dereferencing Reusable Object. Cannot resolve reference "${runtimeExpression}": ${error.message}`, error, referencingElement, 'reference', runtimeExpression, path);
286
+ return;
283
287
  }
284
288
 
285
289
  /**
@@ -243,34 +243,38 @@ class Arazzo1DereferenceVisitor {
243
243
  return;
244
244
  }
245
245
  const runtimeExpression = toValue(referencingElement.reference);
246
-
247
- // parse the runtime expression
248
- const {
249
- result,
250
- tree
251
- } = parseRuntimeExpression(runtimeExpression);
252
- if (!result.success) {
253
- throw new ApiDOMStructuredError(`Invalid Reusable Object reference format: "${runtimeExpression}"`, {
254
- runtimeExpression
255
- });
256
- }
257
-
258
- // ReusableElement can only reference components
259
- if (tree.type !== 'ComponentsExpression') {
260
- throw new ApiDOMStructuredError(`Reusable Object reference "${runtimeExpression}" must be a components expression`, {
261
- runtimeExpression
262
- });
263
- }
264
-
265
- // evaluate runtime expression as JSON Pointer to get the referenced element
266
- const jsonPointer = jsonPointerCompile(['components', tree.componentType, tree.componentName]);
267
246
  let referencedElement;
268
247
  try {
269
- referencedElement = jsonPointerEvaluate(this.reference.value.result, jsonPointer);
270
- } catch {
271
- throw new ApiDOMStructuredError(`Reusable Object reference "${runtimeExpression}" cannot be resolved`, {
272
- runtimeExpression
273
- });
248
+ // parse the runtime expression
249
+ const {
250
+ result,
251
+ tree
252
+ } = parseRuntimeExpression(runtimeExpression);
253
+ if (!result.success) {
254
+ throw new ApiDOMStructuredError(`Invalid Reusable Object reference format: "${runtimeExpression}"`, {
255
+ runtimeExpression
256
+ });
257
+ }
258
+
259
+ // ReusableElement can only reference components
260
+ if (tree.type !== 'ComponentsExpression') {
261
+ throw new ApiDOMStructuredError(`Reusable Object reference "${runtimeExpression}" must be a components expression`, {
262
+ runtimeExpression
263
+ });
264
+ }
265
+
266
+ // evaluate runtime expression as JSON Pointer to get the referenced element
267
+ const jsonPointer = jsonPointerCompile(['components', tree.componentType, tree.componentName]);
268
+ try {
269
+ referencedElement = jsonPointerEvaluate(this.reference.value.result, jsonPointer);
270
+ } catch {
271
+ throw new ApiDOMStructuredError(`Reusable Object reference "${runtimeExpression}" cannot be resolved`, {
272
+ runtimeExpression
273
+ });
274
+ }
275
+ } catch (error) {
276
+ this.handleError(`Error while dereferencing Reusable Object. Cannot resolve reference "${runtimeExpression}": ${error.message}`, error, referencingElement, 'reference', runtimeExpression, path);
277
+ return;
274
278
  }
275
279
 
276
280
  /**