Skip to content

Commit 39df17a

Browse files
committed
feat(reference): support native fragment deref/resolve-Schema Object
Refs #2934
1 parent 44acf6c commit 39df17a

File tree

3 files changed

+95
-37
lines changed

3 files changed

+95
-37
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ const OpenApi3_1DereferenceVisitor = stampit({
426426
}
427427

428428
// compute baseURI using rules around $id and $ref keywords
429-
let { reference } = this;
429+
let reference = await this.toReference(url.unsanitize(this.reference.uri));
430430
let { uri: retrievalURI } = reference;
431431
const $refBaseURI = resolveSchema$refField(retrievalURI, referencingElement) as string;
432432
const $refBaseURIStrippedHash = url.stripHash($refBaseURI);

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ const OpenApi3_1ResolveVisitor = stampit({
189189
return undefined;
190190
},
191191

192-
SchemaElement(schemaElement: SchemaElement) {
192+
async SchemaElement(schemaElement: SchemaElement) {
193193
/**
194194
* Skip traversal for already visited schemas and all their child schemas.
195195
* visit function detects cycles in path automatically.
@@ -206,13 +206,14 @@ const OpenApi3_1ResolveVisitor = stampit({
206206
}
207207

208208
// compute baseURI using rules around $id and $ref keywords
209-
const retrievalURI = this.reference.uri;
209+
const reference = await this.toReference(this.reference.uri);
210+
const { uri: retrievalURI } = reference;
210211
const $refBaseURI = resolveSchema$refField(retrievalURI, schemaElement) as string;
211212
const $refBaseURIStrippedHash = url.stripHash($refBaseURI);
212213
const file = File({ uri: $refBaseURIStrippedHash });
213214
const isUnknownURI = none((r: IResolver) => r.canRead(file), this.options.resolve.resolvers);
214215
const isURL = !isUnknownURI;
215-
const isExternal = !isUnknownURI && this.reference.uri !== $refBaseURIStrippedHash;
216+
const isExternal = !isUnknownURI && retrievalURI !== $refBaseURIStrippedHash;
216217

217218
// ignore resolving external Reference Objects
218219
if (!this.options.resolve.external && isExternal) {
@@ -225,7 +226,7 @@ const OpenApi3_1ResolveVisitor = stampit({
225226
if (!has($refBaseURIStrippedHash, this.crawlingMap)) {
226227
try {
227228
if (isUnknownURI || isURL) {
228-
this.crawlingMap[$refBaseURIStrippedHash] = this.reference;
229+
this.crawlingMap[$refBaseURIStrippedHash] = reference;
229230
} else {
230231
this.crawlingMap[$refBaseURIStrippedHash] = this.toReference(
231232
url.unsanitize($refBaseURI),
@@ -340,7 +341,8 @@ const OpenApi3_1ResolveVisitor = stampit({
340341

341342
async crawlSchemaElement(referencingElement: SchemaElement) {
342343
// compute baseURI using rules around $id and $ref keywords
343-
const retrievalURI = this.reference.uri;
344+
let reference = await this.toReference(url.unsanitize(this.reference.uri));
345+
const { uri: retrievalURI } = reference;
344346
const $refBaseURI = resolveSchema$refField(retrievalURI, referencingElement) as string;
345347
const $refBaseURIStrippedHash = url.stripHash($refBaseURI);
346348
const file = File({ uri: $refBaseURIStrippedHash });
@@ -350,13 +352,11 @@ const OpenApi3_1ResolveVisitor = stampit({
350352
this.indirections.push(referencingElement);
351353

352354
// determining reference, proper evaluation and selection mechanism
353-
let reference: IReference;
354355
let referencedElement;
355356

356357
try {
357358
if (isUnknownURI || isURL) {
358359
// we're dealing with canonical URI or URL with possible fragment
359-
reference = this.reference;
360360
const selector = $refBaseURI;
361361
referencedElement = uriEvaluate(
362362
selector,

packages/apidom-reference/test/dereference/strategies/openapi-3-1/schema-object/dereference-apidom.ts

+87-29
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,105 @@ import { assert } from 'chai';
33
import { mediaTypes, isSchemaElement, OpenApi3_1Element } from '@swagger-api/apidom-ns-openapi-3-1';
44
import { evaluate } from '@swagger-api/apidom-json-pointer';
55

6-
import { parse, dereferenceApiDOM } from '../../../../../src';
6+
import { parse, dereferenceApiDOM, Reference, ReferenceSet } from '../../../../../src';
77

88
describe('dereference', function () {
99
context('strategies', function () {
1010
context('openapi-3-1', function () {
1111
context('Schema Object', function () {
12-
context('given single SchemaElement passed to dereferenceApiDOM', function () {
13-
const fixturePath = path.join(__dirname, 'fixtures', 'external-only', 'root.json');
12+
context(
13+
'given single SchemaElement passed to dereferenceApiDOM with internal references',
14+
function () {
15+
const fixturePath = path.join(__dirname, 'fixtures', 'internal-only', 'root.json');
1416

15-
specify('should dereference', async function () {
16-
const parseResult = await parse(fixturePath, {
17-
parse: { mediaType: mediaTypes.latest('json') },
18-
});
19-
const schemaElement = evaluate(
20-
'/components/schemas/User/properties/profile',
21-
parseResult.api as OpenApi3_1Element,
22-
);
23-
const dereferenced = await dereferenceApiDOM(schemaElement, {
24-
parse: { mediaType: mediaTypes.latest('json') },
25-
resolve: { baseURI: fixturePath },
17+
specify('should dereference', async function () {
18+
const parseResult = await parse(fixturePath, {
19+
parse: { mediaType: mediaTypes.latest('json') },
20+
});
21+
const schemaElement = evaluate(
22+
'/components/schemas/User/properties/profile',
23+
parseResult.api as OpenApi3_1Element,
24+
);
25+
const reference = Reference({ uri: fixturePath, parseResult });
26+
const refSet = ReferenceSet({ refs: [reference] });
27+
// @ts-ignore
28+
refSet.rootRef = null;
29+
30+
const dereferenced = await dereferenceApiDOM(schemaElement, {
31+
parse: { mediaType: mediaTypes.latest('json') },
32+
resolve: { baseURI: `${fixturePath}#/components/schemas/User/properties/profile` },
33+
});
34+
35+
assert.isTrue(isSchemaElement(dereferenced));
2636
});
2737

28-
assert.isTrue(isSchemaElement(dereferenced));
29-
});
38+
specify('should dereference and contain metadata about origin', async function () {
39+
const parseResult = await parse(fixturePath, {
40+
parse: { mediaType: mediaTypes.latest('json') },
41+
});
42+
const schemaElement = evaluate(
43+
'/components/schemas/User/properties/profile',
44+
parseResult.api as OpenApi3_1Element,
45+
);
46+
const reference = Reference({ uri: fixturePath, parseResult });
47+
const refSet = ReferenceSet({ refs: [reference] });
48+
// @ts-ignore
49+
refSet.rootRef = null;
3050

31-
specify('should dereference and contain metadata about origin', async function () {
32-
const parseResult = await parse(fixturePath, {
33-
parse: { mediaType: mediaTypes.latest('json') },
51+
const dereferenced = await dereferenceApiDOM(schemaElement, {
52+
parse: { mediaType: mediaTypes.latest('json') },
53+
resolve: { baseURI: `${fixturePath}#/components/schemas/User/properties/profile` },
54+
});
55+
56+
assert.match(
57+
dereferenced.meta.get('ref-origin').toValue(),
58+
/internal-only\/root\.json$/,
59+
);
3460
});
35-
const pathItemElement = evaluate(
36-
'/components/schemas/User/properties/profile',
37-
parseResult.api as OpenApi3_1Element,
38-
);
39-
const dereferenced = await dereferenceApiDOM(pathItemElement, {
40-
parse: { mediaType: mediaTypes.latest('json') },
41-
resolve: { baseURI: fixturePath },
61+
},
62+
);
63+
64+
context(
65+
'given single SchemaElement passed to dereferenceApiDOM with external references',
66+
function () {
67+
const fixturePath = path.join(__dirname, 'fixtures', 'external-only', 'root.json');
68+
69+
specify('should dereference', async function () {
70+
const parseResult = await parse(fixturePath, {
71+
parse: { mediaType: mediaTypes.latest('json') },
72+
});
73+
const schemaElement = evaluate(
74+
'/components/schemas/User/properties/profile',
75+
parseResult.api as OpenApi3_1Element,
76+
);
77+
const dereferenced = await dereferenceApiDOM(schemaElement, {
78+
parse: { mediaType: mediaTypes.latest('json') },
79+
resolve: { baseURI: fixturePath },
80+
});
81+
82+
assert.isTrue(isSchemaElement(dereferenced));
4283
});
4384

44-
assert.match(dereferenced.meta.get('ref-origin').toValue(), /external-only\/ex\.json$/);
45-
});
46-
});
85+
specify('should dereference and contain metadata about origin', async function () {
86+
const parseResult = await parse(fixturePath, {
87+
parse: { mediaType: mediaTypes.latest('json') },
88+
});
89+
const pathItemElement = evaluate(
90+
'/components/schemas/User/properties/profile',
91+
parseResult.api as OpenApi3_1Element,
92+
);
93+
const dereferenced = await dereferenceApiDOM(pathItemElement, {
94+
parse: { mediaType: mediaTypes.latest('json') },
95+
resolve: { baseURI: fixturePath },
96+
});
97+
98+
assert.match(
99+
dereferenced.meta.get('ref-origin').toValue(),
100+
/external-only\/ex\.json$/,
101+
);
102+
});
103+
},
104+
);
47105
});
48106
});
49107
});

0 commit comments

Comments
 (0)