diff --git a/packages/apidom-ns-openapi-3-1/src/index.ts b/packages/apidom-ns-openapi-3-1/src/index.ts index fae8545ea0..55fa8baf31 100644 --- a/packages/apidom-ns-openapi-3-1/src/index.ts +++ b/packages/apidom-ns-openapi-3-1/src/index.ts @@ -52,7 +52,6 @@ export { isContactElement, isExampleElement, isLinkElement, - isLinkElementExternal, isRequestBodyElement, isPathsElement, } from './predicates'; diff --git a/packages/apidom-ns-openapi-3-1/src/predicates.ts b/packages/apidom-ns-openapi-3-1/src/predicates.ts index 432098f1af..f83a7eaa1c 100644 --- a/packages/apidom-ns-openapi-3-1/src/predicates.ts +++ b/packages/apidom-ns-openapi-3-1/src/predicates.ts @@ -133,21 +133,6 @@ export const isLinkElement = createPredicate( }, ); -export const isLinkElementExternal: ElementPredicate = ( - element: unknown, -): element is LinkElement => { - if (!isLinkElement(element)) { - return false; - } - if (!isStringElement(element.operationRef)) { - return false; - } - - const value = toValue(element.operationRef); - - return typeof value === 'string' && value.length > 0 && !value.startsWith('#'); -}; - export const isOpenapiElement = createPredicate( ({ hasBasicElementProps, isElementType, primitiveEq }) => { return (element: unknown): element is OpenapiElement => @@ -200,6 +185,12 @@ export const isPathItemElement = createPredicate( }, ); +/** + * @deprecated + * Determining whether a PathItemElement is external or internal is not possible by just looking + * at value of the $ref fixed field. The value of the $ref field needs to be resolved in runtime + * using the referring document as the Base URI. + */ export const isPathItemElementExternal: ElementPredicate = ( element: unknown, ): element is PathItemElement => { @@ -235,6 +226,12 @@ export const isReferenceElement = createPredicate( }, ); +/** + * @deprecated + * Determining whether a ReferenceElement is external or internal is not possible by just looking + * at value of the $ref fixed field. The value of the $ref field needs to be resolved in runtime + * using the referring document as the Base URI. + */ export const isReferenceElementExternal: ElementPredicate = ( element: unknown, ): element is ReferenceElement => { diff --git a/packages/apidom-reference/src/dereference/strategies/openapi-3-1/visitor.ts b/packages/apidom-reference/src/dereference/strategies/openapi-3-1/visitor.ts index 928af9b524..abb3fec52b 100644 --- a/packages/apidom-reference/src/dereference/strategies/openapi-3-1/visitor.ts +++ b/packages/apidom-reference/src/dereference/strategies/openapi-3-1/visitor.ts @@ -27,9 +27,6 @@ import { OperationElement, ExampleElement, SchemaElement, - isReferenceElementExternal, - isPathItemElementExternal, - isLinkElementExternal, isOperationElement, isBooleanJsonSchemaElement, } from '@swagger-api/apidom-ns-openapi-3-1'; @@ -147,13 +144,15 @@ const OpenApi3_1DereferenceVisitor = stampit({ return false; } + const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref)); + // ignore resolving external Reference Objects - if (!this.options.resolve.external && isReferenceElementExternal(referencingElement)) { - return false; + if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) { + // skip traversing this reference element but traverse all it's child elements + return undefined; } const reference = await this.toReference(toValue(referencingElement.$ref)); - const { uri: retrievalURI } = reference; const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref)); this.indirections.push(referencingElement); @@ -288,13 +287,15 @@ const OpenApi3_1DereferenceVisitor = stampit({ return false; } - // ignore resolving external Path Item Elements - if (!this.options.resolve.external && isPathItemElementExternal(referencingElement)) { + const retrievalURI = this.toBaseURI(toValue(referencingElement.$ref)); + + // ignore resolving external Path Item Objects + if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) { + // skip traversing this Path Item element but traverse all it's child elements return undefined; } const reference = await this.toReference(toValue(referencingElement.$ref)); - const { uri: retrievalURI } = reference; const $refBaseURI = url.resolve(retrievalURI, toValue(referencingElement.$ref)); this.indirections.push(referencingElement); @@ -399,11 +400,6 @@ const OpenApi3_1DereferenceVisitor = stampit({ return undefined; } - // ignore resolving external Path Item Elements - if (!this.options.resolve.external && isLinkElementExternal(linkElement)) { - return undefined; - } - // operationRef and operationId fields are mutually exclusive if (isStringElement(linkElement.operationRef) && isStringElement(linkElement.operationId)) { throw new ApiDOMError( @@ -416,7 +412,16 @@ const OpenApi3_1DereferenceVisitor = stampit({ if (isStringElement(linkElement.operationRef)) { // possibly non-semantic referenced element const jsonPointer = uriToPointer(toValue(linkElement.operationRef)); + const retrievalURI = this.toBaseURI(toValue(linkElement.operationRef)); + + // ignore resolving external Operation Object reference + if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) { + // skip traversing this Link element but traverse all it's child elements + return undefined; + } + const reference = await this.toReference(toValue(linkElement.operationRef)); + operationElement = jsonPointerEvaluate(jsonPointer, reference.value.result); // applying semantics to a referenced element if (isPrimitiveElement(operationElement)) { @@ -472,11 +477,6 @@ const OpenApi3_1DereferenceVisitor = stampit({ return false; } - // ignore resolving ExampleElement externalValue - if (!this.options.resolve.external && isStringElement(exampleElement.externalValue)) { - return undefined; - } - // value and externalValue fields are mutually exclusive if (exampleElement.hasKey('value') && isStringElement(exampleElement.externalValue)) { throw new ApiDOMError( @@ -484,6 +484,14 @@ const OpenApi3_1DereferenceVisitor = stampit({ ); } + const retrievalURI = this.toBaseURI(toValue(exampleElement.externalValue)); + + // ignore resolving external Example Objects + if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) { + // skip traversing this Example element but traverse all it's child elements + return undefined; + } + const reference = await this.toReference(toValue(exampleElement.externalValue)); // shallow clone of the referenced element @@ -524,13 +532,7 @@ const OpenApi3_1DereferenceVisitor = stampit({ const file = File({ uri: $refBaseURIStrippedHash }); const isUnknownURI = none((r: IResolver) => r.canRead(file), this.options.resolve.resolvers); const isURL = !isUnknownURI; - const isExternal = isURL && retrievalURI !== $refBaseURIStrippedHash; - - // ignore resolving external Schema Objects - if (!this.options.resolve.external && isExternal) { - // skip traversing this schema but traverse all it's child schemas - return undefined; - } + const isExternalURL = (uri: string) => url.stripHash(this.reference.uri) !== uri; this.indirections.push(referencingElement); @@ -549,6 +551,14 @@ const OpenApi3_1DereferenceVisitor = stampit({ } else { // we're assuming here that we're dealing with JSON Pointer here reference = await this.toReference(url.unsanitize($refBaseURI)); + retrievalURI = reference.uri; + + // ignore resolving external Schema Objects + if (!this.options.resolve.external && isExternalURL(retrievalURI)) { + // skip traversing this schema element but traverse all it's child elements + return undefined; + } + const selector = uriToPointer($refBaseURI); referencedElement = maybeRefractToSchemaElement( // @ts-ignore @@ -565,6 +575,13 @@ const OpenApi3_1DereferenceVisitor = stampit({ // we're dealing with JSON Schema $anchor here reference = await this.toReference(url.unsanitize($refBaseURI)); retrievalURI = reference.uri; + + // ignore resolving external Schema Objects + if (!this.options.resolve.external && isExternalURL(retrievalURI)) { + // skip traversing this schema element but traverse all it's child elements + return undefined; + } + const selector = uriToAnchor($refBaseURI); referencedElement = $anchorEvaluate( selector, @@ -575,6 +592,13 @@ const OpenApi3_1DereferenceVisitor = stampit({ // we're assuming here that we're dealing with JSON Pointer here reference = await this.toReference(url.unsanitize($refBaseURI)); retrievalURI = reference.uri; + + // ignore resolving external Schema Objects + if (!this.options.resolve.external && isExternalURL(retrievalURI)) { + // skip traversing this schema element but traverse all it's child elements + return undefined; + } + const selector = uriToPointer($refBaseURI); referencedElement = maybeRefractToSchemaElement( // @ts-ignore