Skip to content

Commit 222e3f0

Browse files
authored
fix(reference): lazy fetch URLs only when needed (#3464)
This change affects all dereference and resolution strategies. Refs #3451
1 parent 2215480 commit 222e3f0

File tree

5 files changed

+90
-70
lines changed

5 files changed

+90
-70
lines changed

packages/apidom-reference/src/dereference/strategies/asyncapi-2/visitor.ts

+23-18
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,8 @@ const AsyncApi2DereferenceVisitor = stampit({
6565
this.ancestors = new AncestorLineage(...ancestors);
6666
},
6767
methods: {
68-
toAncestorLineage(ancestors) {
69-
/**
70-
* Compute full ancestors lineage.
71-
* Ancestors are flatten to unwrap all Element instances.
72-
*/
73-
const directAncestors = new Set<Element>(ancestors.filter(isElement));
74-
const ancestorsLineage = new AncestorLineage(...this.ancestors, directAncestors);
75-
76-
return [ancestorsLineage, directAncestors];
68+
toBaseURI(uri: string): string {
69+
return url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
7770
},
7871

7972
async toReference(uri: string): Promise<IReference> {
@@ -84,8 +77,7 @@ const AsyncApi2DereferenceVisitor = stampit({
8477
);
8578
}
8679

87-
const baseURI = url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
88-
80+
const baseURI = this.toBaseURI(uri);
8981
const { refSet } = this.reference;
9082

9183
// we've already processed this Reference in past
@@ -110,6 +102,17 @@ const AsyncApi2DereferenceVisitor = stampit({
110102
return reference;
111103
},
112104

105+
toAncestorLineage(ancestors) {
106+
/**
107+
* Compute full ancestors lineage.
108+
* Ancestors are flatten to unwrap all Element instances.
109+
*/
110+
const directAncestors = new Set<Element>(ancestors.filter(isElement));
111+
const ancestorsLineage = new AncestorLineage(...this.ancestors, directAncestors);
112+
113+
return [ancestorsLineage, directAncestors];
114+
},
115+
113116
async ReferenceElement(
114117
referencingElement: ReferenceElement,
115118
key: any,
@@ -124,16 +127,17 @@ const AsyncApi2DereferenceVisitor = stampit({
124127
return false;
125128
}
126129

127-
const reference = await this.toReference(toValue(referencingElement.$ref));
128-
const { uri: retrievalURI } = reference;
129-
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
130+
const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref));
130131

131132
// ignore resolving external Reference Objects
132133
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
133134
// skip traversing this reference element but traverse all it's child elements
134-
return undefined;
135+
return false;
135136
}
136137

138+
const reference = await this.toReference(toValue(referencingElement.$ref));
139+
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
140+
137141
this.indirections.push(referencingElement);
138142

139143
const jsonPointer = uriToPointer($refBaseURI);
@@ -264,16 +268,17 @@ const AsyncApi2DereferenceVisitor = stampit({
264268
return false;
265269
}
266270

267-
const reference = await this.toReference(toValue(referencingElement.$ref));
268-
const retrievalURI = reference.uri;
269-
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
271+
const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref));
270272

271273
// ignore resolving external Channel Item Objects
272274
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
273275
// skip traversing this channel item but traverse all it's child elements
274276
return undefined;
275277
}
276278

279+
const reference = await this.toReference(toValue(referencingElement.$ref));
280+
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
281+
277282
this.indirections.push(referencingElement);
278283

279284
const jsonPointer = uriToPointer($refBaseURI);

packages/apidom-reference/src/dereference/strategies/openapi-2/visitor.ts

+21-15
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ const OpenApi2DereferenceVisitor = stampit({
6666
this.ancestors = new AncestorLineage(...ancestors);
6767
},
6868
methods: {
69+
toBaseURI(uri: string): string {
70+
return url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
71+
},
72+
6973
async toReference(uri: string): Promise<IReference> {
7074
// detect maximum depth of resolution
7175
if (this.reference.depth >= this.options.resolve.maxDepth) {
@@ -74,8 +78,7 @@ const OpenApi2DereferenceVisitor = stampit({
7478
);
7579
}
7680

77-
const baseURI = url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
78-
81+
const baseURI = this.toBaseURI(uri);
7982
const { refSet } = this.reference;
8083

8184
// we've already processed this Reference in past
@@ -125,16 +128,17 @@ const OpenApi2DereferenceVisitor = stampit({
125128
return false;
126129
}
127130

128-
const reference = await this.toReference(toValue(referencingElement.$ref));
129-
const { uri: retrievalURI } = reference;
130-
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
131+
const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref));
131132

132133
// ignore resolving external Reference Objects
133134
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
134-
// skip traversing this reference element but traverse all it's child elements
135-
return undefined;
135+
// skip traversing this reference element and all it's child elements
136+
return false;
136137
}
137138

139+
const reference = await this.toReference(toValue(referencingElement.$ref));
140+
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
141+
138142
this.indirections.push(referencingElement);
139143

140144
const jsonPointer = uriToPointer($refBaseURI);
@@ -248,16 +252,17 @@ const OpenApi2DereferenceVisitor = stampit({
248252
return false;
249253
}
250254

251-
const reference = await this.toReference(toValue(referencingElement.$ref));
252-
const retrievalURI = reference.uri;
253-
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
255+
const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref));
254256

255257
// ignore resolving external Path Item Objects
256258
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
257259
// skip traversing this Path Item element but traverse all it's child elements
258260
return undefined;
259261
}
260262

263+
const reference = await this.toReference(toValue(referencingElement.$ref));
264+
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
265+
261266
this.indirections.push(referencingElement);
262267

263268
const jsonPointer = uriToPointer($refBaseURI);
@@ -368,16 +373,17 @@ const OpenApi2DereferenceVisitor = stampit({
368373
return false;
369374
}
370375

371-
const reference = await this.toReference(toValue(referencingElement.$ref));
372-
const { uri: retrievalURI } = reference;
373-
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
376+
const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref));
374377

375378
// ignore resolving external JSONReference Objects
376379
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
377-
// skip traversing this JSONReference element but traverse all it's child elements
378-
return undefined;
380+
// skip traversing this JSONReference element and all it's child elements
381+
return false;
379382
}
380383

384+
const reference = await this.toReference(toValue(referencingElement.$ref));
385+
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
386+
381387
this.indirections.push(referencingElement);
382388

383389
const jsonPointer = uriToPointer($refBaseURI);

packages/apidom-reference/src/dereference/strategies/openapi-3-0/visitor.ts

+21-12
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ const OpenApi3_0DereferenceVisitor = stampit({
7171
this.ancestors = new AncestorLineage(...ancestors);
7272
},
7373
methods: {
74+
toBaseURI(uri: string): string {
75+
return url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
76+
},
77+
7478
async toReference(uri: string): Promise<IReference> {
7579
// detect maximum depth of resolution
7680
if (this.reference.depth >= this.options.resolve.maxDepth) {
@@ -79,8 +83,7 @@ const OpenApi3_0DereferenceVisitor = stampit({
7983
);
8084
}
8185

82-
const baseURI = url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri)));
83-
86+
const baseURI = this.toBaseURI(uri);
8487
const { refSet } = this.reference;
8588

8689
// we've already processed this Reference in past
@@ -130,16 +133,17 @@ const OpenApi3_0DereferenceVisitor = stampit({
130133
return false;
131134
}
132135

133-
const reference = await this.toReference(toValue(referencingElement.$ref));
134-
const { uri: retrievalURI } = reference;
135-
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
136+
const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref));
136137

137138
// ignore resolving external Reference Objects
138139
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
139140
// skip traversing this reference element but traverse all it's child elements
140141
return undefined;
141142
}
142143

144+
const reference = await this.toReference(toValue(referencingElement.$ref));
145+
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
146+
143147
this.indirections.push(referencingElement);
144148

145149
const jsonPointer = uriToPointer($refBaseURI);
@@ -253,16 +257,17 @@ const OpenApi3_0DereferenceVisitor = stampit({
253257
return false;
254258
}
255259

256-
const reference = await this.toReference(toValue(referencingElement.$ref));
257-
const retrievalURI = reference.uri;
258-
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
260+
const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref));
259261

260262
// ignore resolving external Path Item Objects
261263
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
262264
// skip traversing this Path Item element but traverse all it's child elements
263265
return undefined;
264266
}
265267

268+
const reference = await this.toReference(toValue(referencingElement.$ref));
269+
const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref));
270+
266271
this.indirections.push(referencingElement);
267272

268273
const jsonPointer = uriToPointer($refBaseURI);
@@ -377,14 +382,16 @@ const OpenApi3_0DereferenceVisitor = stampit({
377382
if (isStringElement(linkElement.operationRef)) {
378383
// possibly non-semantic referenced element
379384
const jsonPointer = uriToPointer(toValue(linkElement.operationRef));
380-
const reference = await this.toReference(toValue(linkElement.operationRef));
385+
const retrievalURI = this.toBaseURI(toValue(linkElement.operationRef));
381386

382387
// ignore resolving external Operation Object reference
383-
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== reference.uri) {
388+
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
384389
// skip traversing this Link element but traverse all it's child elements
385390
return undefined;
386391
}
387392

393+
const reference = await this.toReference(toValue(linkElement.operationRef));
394+
388395
operationElement = evaluate(jsonPointer, reference.value.result);
389396
// applying semantics to a referenced element
390397
if (isPrimitiveElement(operationElement)) {
@@ -447,14 +454,16 @@ const OpenApi3_0DereferenceVisitor = stampit({
447454
);
448455
}
449456

450-
const reference = await this.toReference(toValue(exampleElement.externalValue));
457+
const retrievalURI = this.toBaseURI(toValue(exampleElement.externalValue));
451458

452459
// ignore resolving external Example Objects
453-
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== reference.uri) {
460+
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
454461
// skip traversing this Example element but traverse all it's child elements
455462
return undefined;
456463
}
457464

465+
const reference = await this.toReference(toValue(exampleElement.externalValue));
466+
458467
// shallow clone of the referenced element
459468
const valueElement = cloneShallow(reference.value.result);
460469
// annotate operation element with info about origin

packages/apidom-reference/src/resolve/strategies/asyncapi-2/visitor.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,15 @@ const AsyncApi2ResolveVisitor = stampit({
8181

8282
ReferenceElement(referenceElement: ReferenceElement) {
8383
const uri = toValue(referenceElement.$ref);
84-
const baseURI = this.toBaseURI(uri);
84+
const retrievalURI = this.toBaseURI(uri);
8585

8686
// ignore resolving external Reference Objects
87-
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== baseURI) {
87+
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
8888
return false;
8989
}
9090

91-
if (!has(baseURI, this.crawlingMap)) {
92-
this.crawlingMap[baseURI] = this.toReference(uri);
91+
if (!has(retrievalURI, this.crawlingMap)) {
92+
this.crawlingMap[retrievalURI] = this.toReference(uri);
9393
}
9494
this.crawledElements.push(referenceElement);
9595

@@ -103,15 +103,15 @@ const AsyncApi2ResolveVisitor = stampit({
103103
}
104104

105105
const uri = toValue(channelItemElement.$ref);
106-
const baseURI = this.toBaseURI(uri);
106+
const retrievalURI = this.toBaseURI(uri);
107107

108108
// ignore resolving external Channel Item Objects
109-
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== baseURI) {
109+
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
110110
return undefined;
111111
}
112112

113-
if (!has(baseURI, this.crawlingMap)) {
114-
this.crawlingMap[baseURI] = this.toReference(uri);
113+
if (!has(retrievalURI, this.crawlingMap)) {
114+
this.crawlingMap[retrievalURI] = this.toReference(uri);
115115
}
116116
this.crawledElements.push(channelItemElement);
117117

packages/apidom-reference/src/resolve/strategies/openapi-3-0/visitor.ts

+17-17
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,15 @@ const OpenApi3_0ResolveVisitor = stampit({
8484

8585
ReferenceElement(referenceElement: ReferenceElement) {
8686
const uri = toValue(referenceElement.$ref);
87-
const baseURI = this.toBaseURI(uri);
87+
const retrievalURI = this.toBaseURI(uri);
8888

8989
// ignore resolving external Reference Objects
90-
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== baseURI) {
91-
return undefined;
90+
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
91+
return false;
9292
}
9393

94-
if (!has(baseURI, this.crawlingMap)) {
95-
this.crawlingMap[baseURI] = this.toReference(uri);
94+
if (!has(retrievalURI, this.crawlingMap)) {
95+
this.crawlingMap[retrievalURI] = this.toReference(uri);
9696
}
9797
this.crawledElements.push(referenceElement);
9898

@@ -106,15 +106,15 @@ const OpenApi3_0ResolveVisitor = stampit({
106106
}
107107

108108
const uri = toValue(pathItemElement.$ref);
109-
const baseURI = this.toBaseURI(uri);
109+
const retrievalURI = this.toBaseURI(uri);
110110

111111
// ignore resolving external Path Item Objects
112-
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== baseURI) {
112+
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
113113
return undefined;
114114
}
115115

116-
if (!has(baseURI, this.crawlingMap)) {
117-
this.crawlingMap[baseURI] = this.toReference(uri);
116+
if (!has(retrievalURI, this.crawlingMap)) {
117+
this.crawlingMap[retrievalURI] = this.toReference(uri);
118118
}
119119
this.crawledElements.push(pathItemElement);
120120

@@ -134,15 +134,15 @@ const OpenApi3_0ResolveVisitor = stampit({
134134

135135
if (isStringElement(linkElement.operationRef)) {
136136
const uri = toValue(linkElement.operationRef);
137-
const baseURI = this.toBaseURI(uri);
137+
const retrievalURI = this.toBaseURI(uri);
138138

139139
// ignore resolving LinkElement.operationRef
140-
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== baseURI) {
140+
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
141141
return undefined;
142142
}
143143

144-
if (!has(baseURI, this.crawlingMap)) {
145-
this.crawlingMap[baseURI] = this.toReference(uri);
144+
if (!has(retrievalURI, this.crawlingMap)) {
145+
this.crawlingMap[retrievalURI] = this.toReference(uri);
146146
}
147147
}
148148

@@ -163,15 +163,15 @@ const OpenApi3_0ResolveVisitor = stampit({
163163
}
164164

165165
const uri = toValue(exampleElement.externalValue);
166-
const baseURI = this.toBaseURI(uri);
166+
const retrievalURI = this.toBaseURI(uri);
167167

168168
// ignore resolving ExampleElement externalValue
169-
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== baseURI) {
169+
if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) {
170170
return undefined;
171171
}
172172

173-
if (!has(baseURI, this.crawlingMap)) {
174-
this.crawlingMap[baseURI] = this.toReference(uri);
173+
if (!has(retrievalURI, this.crawlingMap)) {
174+
this.crawlingMap[retrievalURI] = this.toReference(uri);
175175
}
176176

177177
return undefined;

0 commit comments

Comments
 (0)