Skip to content

Commit

Permalink
fix(reference): fix regression in OpenAPI 2.0 derferencing (#3976)
Browse files Browse the repository at this point in the history
Refs #3974
  • Loading branch information
char0n committed Mar 28, 2024
1 parent 6e8d9a0 commit 2e4d15a
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,17 @@ const OpenApi2DereferenceVisitor = stampit({
*
* Cases to consider:
* 1. We're crossing document boundary
* 2. Fragment is a Reference Object. We need to follow it to get the eventual value
* 3. We are dereferencing the fragment lazily/eagerly depending on circular mode
* 2. Fragment is from non-root document
* 3. Fragment is a Reference Object. We need to follow it to get the eventual value
* 4. We are dereferencing the fragment lazily/eagerly depending on circular mode
*/
const isNonRootDocument = reference.refSet.rootRef.uri !== reference.uri;
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
if (
(isExternalReference ||
isNonRootDocument ||
isReferenceElement(referencedElement) ||
['error', 'replace'].includes(this.options.dereference.circular)) &&
shouldDetectCircular) &&
!ancestorsLineage.includesCycle(referencedElement)
) {
// append referencing reference to ancestors lineage
Expand Down Expand Up @@ -398,13 +402,17 @@ const OpenApi2DereferenceVisitor = stampit({
*
* Cases to consider:
* 1. We're crossing document boundary
* 2. Fragment is a Paht Item Object with $ref field. We need to follow it to get the eventual value
* 3. We are dereferencing the fragment lazily/eagerly depending on circular mode
* 2. Fragment is from non-root document
* 3. Fragment is a Paht Item Object with $ref field. We need to follow it to get the eventual value
* 4. We are dereferencing the fragment lazily/eagerly depending on circular mode
*/
const isNonRootDocument = reference.refSet.rootRef.uri !== reference.uri;
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
if (
(isExternalReference ||
isNonRootDocument ||
(isPathItemElement(referencedElement) && isStringElement(referencedElement.$ref)) ||
['error', 'replace'].includes(this.options.dereference.circular)) &&
shouldDetectCircular) &&
!ancestorsLineage.includesCycle(referencedElement)
) {
// append referencing reference to ancestors lineage
Expand Down Expand Up @@ -581,13 +589,17 @@ const OpenApi2DereferenceVisitor = stampit({
*
* Cases to consider:
* 1. We're crossing document boundary
* 2. Fragment is a JSON Reference Object. We need to follow it to get the eventual value
* 3. We are dereferencing the fragment lazily/eagerly depending on circular mode
2. Fragment is from non-root document
* 3. Fragment is a JSON Reference Object. We need to follow it to get the eventual value
* 4. We are dereferencing the fragment lazily/eagerly depending on circular mode
*/
const isNonRootDocument = reference.refSet.rootRef.uri !== reference.uri;
const shouldDetectCircular = ['error', 'replace'].includes(this.options.dereference.circular);
if (
(isExternalReference ||
isNonRootDocument ||
isJSONReferenceElement(referencedElement) ||
['error', 'replace'].includes(this.options.dereference.circular)) &&
shouldDetectCircular) &&
!ancestorsLineage.includesCycle(referencedElement)
) {
// append referencing reference to ancestors lineage
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import path from 'node:path';
import { assert } from 'chai';
import { mediaTypes, isParameterElement, SwaggerElement } from '@swagger-api/apidom-ns-openapi-2';
import {
mediaTypes,
isParameterElement,
isSchemaElement,
SwaggerElement,
} from '@swagger-api/apidom-ns-openapi-2';
import { toValue } from '@swagger-api/apidom-core';
import { evaluate } from '@swagger-api/apidom-json-pointer';

Expand Down Expand Up @@ -119,23 +124,23 @@ describe('dereference', function () {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/paths/~1/parameters/0',
'/definitions/externalSchema',
parseResult.api as SwaggerElement,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: fixturePath },
});

assert.isTrue(isParameterElement(dereferenced));
assert.isTrue(isSchemaElement(dereferenced));
});

specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/paths/~1/parameters/0',
'/definitions/externalSchema',
parseResult.api as SwaggerElement,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
Expand Down Expand Up @@ -169,23 +174,23 @@ describe('dereference', function () {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/paths/~1/parameters/0',
'/definitions/externalSchema',
parseResult.api as SwaggerElement,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: `http://localhost:${httpPort}/root.json` },
});

assert.isTrue(isParameterElement(dereferenced));
assert.isTrue(isSchemaElement(dereferenced));
});

specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/paths/~1/parameters/0',
'/definitions/externalSchema',
parseResult.api as SwaggerElement,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
[
{
"swagger": "2.0",
"paths": {
"/": {
"parameters": [
{
"name": "externalParameter",
"in": "query",
"description": "this is parameter stored in external file",
"required": true
"definitions": {
"externalSchema": {
"type": "object",
"properties": {
"sentAt": {
"type": "string",
"format": "date-time",
"description": "Date and time when the message was sent."
}
]
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
{
"externalParameter": {
"name": "externalParameter",
"in": "query",
"description": "this is parameter stored in external file",
"required": true
"openapi": "2.0",
"definitions": {
"schema1": {
"$ref": "#/definitions/somePayload"
},
"somePayload": {
"type": "object",
"properties": {
"sentAt": {
"$ref": "#/definitions/sentAt"
}
}
},
"sentAt": {
"type": "string",
"format": "date-time",
"description": "Date and time when the message was sent."
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
{
"swagger": "2.0",
"paths": {
"/": {
"parameters": [
{
"$ref": "./ex.json#/externalParameter"
}
]
"definitions": {
"externalSchema": {
"$ref": "./ex.json#/definitions/schema1"
}
}
}

0 comments on commit 2e4d15a

Please sign in to comment.