diff --git a/packages/apidom-reference/src/dereference/strategies/openapi-3-1/index.ts b/packages/apidom-reference/src/dereference/strategies/openapi-3-1/index.ts index b8a2f44752..67e731eb26 100644 --- a/packages/apidom-reference/src/dereference/strategies/openapi-3-1/index.ts +++ b/packages/apidom-reference/src/dereference/strategies/openapi-3-1/index.ts @@ -73,9 +73,6 @@ const OpenApi3_1DereferenceStrategy: stampit.Stamp = stamp ); export { OpenApi3_1DereferenceVisitor }; -export { - resolveSchema$refField, - maybeRefractToSchemaElement, -} from '../../../resolve/strategies/openapi-3-1/util'; +export { resolveSchema$refField, resolveSchema$idField, maybeRefractToSchemaElement } from './util'; export default OpenApi3_1DereferenceStrategy; diff --git a/packages/apidom-reference/src/dereference/strategies/openapi-3-1/selectors/uri.ts b/packages/apidom-reference/src/dereference/strategies/openapi-3-1/selectors/uri.ts index 48f16b9931..6ace87124f 100644 --- a/packages/apidom-reference/src/dereference/strategies/openapi-3-1/selectors/uri.ts +++ b/packages/apidom-reference/src/dereference/strategies/openapi-3-1/selectors/uri.ts @@ -6,7 +6,7 @@ import { uriToPointer, evaluate as jsonPointerEvaluate } from '@swagger-api/apid import * as url from '../../../../util/url'; import EvaluationJsonSchemaUriError from '../../../../errors/EvaluationJsonSchemaUriError'; import { isAnchor, uriToAnchor, evaluate as $anchorEvaluate } from './$anchor'; -import { resolveSchema$idField } from '../../../../resolve/strategies/openapi-3-1/util'; +import { resolveSchema$idField } from '../util'; /** * Evaluates JSON Schema $ref containing unknown URI against ApiDOM fragment. diff --git a/packages/apidom-reference/src/resolve/strategies/openapi-3-1/util.ts b/packages/apidom-reference/src/dereference/strategies/openapi-3-1/util.ts similarity index 100% rename from packages/apidom-reference/src/resolve/strategies/openapi-3-1/util.ts rename to packages/apidom-reference/src/dereference/strategies/openapi-3-1/util.ts 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 742b146f84..bce8e4568a 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 @@ -40,10 +40,7 @@ import * as url from '../../../util/url'; import parse from '../../../parse'; import Reference from '../../../Reference'; import File from '../../../util/File'; -import { - resolveSchema$refField, - maybeRefractToSchemaElement, -} from '../../../resolve/strategies/openapi-3-1/util'; +import { resolveSchema$refField, maybeRefractToSchemaElement } from './util'; import { AncestorLineage } from '../../util'; import EvaluationJsonSchemaUriError from '../../../errors/EvaluationJsonSchemaUriError'; diff --git a/packages/apidom-reference/src/resolve/strategies/apidom/index.ts b/packages/apidom-reference/src/resolve/strategies/apidom/index.ts index c5bd010280..6e385e5cb2 100644 --- a/packages/apidom-reference/src/resolve/strategies/apidom/index.ts +++ b/packages/apidom-reference/src/resolve/strategies/apidom/index.ts @@ -9,8 +9,8 @@ import { } from '../../../types'; import ReferenceSet from '../../../ReferenceSet'; import Reference from '../../../Reference'; -import ApiDOMResolveVisitor from './visitor'; import { merge as mergeOptions } from '../../../options/util'; +import ApiDOMResolveVisitor from './visitor'; // @ts-ignore const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')]; diff --git a/packages/apidom-reference/src/resolve/strategies/asyncapi-2/index.ts b/packages/apidom-reference/src/resolve/strategies/asyncapi-2/index.ts index b6dc2f417f..4df0680e31 100644 --- a/packages/apidom-reference/src/resolve/strategies/asyncapi-2/index.ts +++ b/packages/apidom-reference/src/resolve/strategies/asyncapi-2/index.ts @@ -15,6 +15,7 @@ import { } from '../../../types'; import ReferenceSet from '../../../ReferenceSet'; import Reference from '../../../Reference'; +import { merge as mergeOptions } from '../../../options/util'; import AsyncApi2ResolveVisitor from './visitor'; // @ts-ignore @@ -38,7 +39,8 @@ const AsyncApi2ResolveStrategy: stampit.Stamp = stampit(Resolv async resolve(file: IFile, options: IReferenceOptions) { const namespace = createNamespace(asyncApi2Namespace); const reference = Reference({ uri: file.uri, value: file.parseResult }); - const visitor = AsyncApi2ResolveVisitor({ reference, namespace, options }); + const mergedOptions = mergeOptions(options, { resolve: { internal: false } }); + const visitor = AsyncApi2ResolveVisitor({ reference, namespace, options: mergedOptions }); const refSet = ReferenceSet(); refSet.add(reference); diff --git a/packages/apidom-reference/src/resolve/strategies/openapi-2/index.ts b/packages/apidom-reference/src/resolve/strategies/openapi-2/index.ts index 6c13c70b87..150bc724eb 100644 --- a/packages/apidom-reference/src/resolve/strategies/openapi-2/index.ts +++ b/packages/apidom-reference/src/resolve/strategies/openapi-2/index.ts @@ -15,8 +15,8 @@ import { } from '../../../types'; import ReferenceSet from '../../../ReferenceSet'; import Reference from '../../../Reference'; -import OpenApi2ResolveVisitor from './visitor'; import { merge as mergeOptions } from '../../../options/util'; +import OpenApi2ResolveVisitor from './visitor'; // @ts-ignore const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')]; diff --git a/packages/apidom-reference/src/resolve/strategies/openapi-3-0/index.ts b/packages/apidom-reference/src/resolve/strategies/openapi-3-0/index.ts index 38c24cf5e4..45516a1f05 100644 --- a/packages/apidom-reference/src/resolve/strategies/openapi-3-0/index.ts +++ b/packages/apidom-reference/src/resolve/strategies/openapi-3-0/index.ts @@ -15,8 +15,8 @@ import { } from '../../../types'; import ReferenceSet from '../../../ReferenceSet'; import Reference from '../../../Reference'; -import OpenApi3_0ResolveVisitor from './visitor'; import { merge as mergeOptions } from '../../../options/util'; +import OpenApi3_0ResolveVisitor from './visitor'; // @ts-ignore const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')]; diff --git a/packages/apidom-reference/src/resolve/strategies/openapi-3-1/index.ts b/packages/apidom-reference/src/resolve/strategies/openapi-3-1/index.ts index b75e770c97..ac0837fff6 100644 --- a/packages/apidom-reference/src/resolve/strategies/openapi-3-1/index.ts +++ b/packages/apidom-reference/src/resolve/strategies/openapi-3-1/index.ts @@ -15,6 +15,7 @@ import { } from '../../../types'; import ReferenceSet from '../../../ReferenceSet'; import Reference from '../../../Reference'; +import { merge as mergeOptions } from '../../../options/util'; import OpenApi3_1ResolveVisitor from './visitor'; // @ts-ignore @@ -39,7 +40,8 @@ const OpenApi3_1ResolveStrategy: stampit.Stamp = stampit(Resol async resolve(file: IFile, options: IReferenceOptions) { const namespace = createNamespace(openApi3_1Namespace); const reference = Reference({ uri: file.uri, value: file.parseResult }); - const visitor = OpenApi3_1ResolveVisitor({ reference, namespace, options }); + const mergedOptions = mergeOptions(options, { resolve: { internal: false } }); + const visitor = OpenApi3_1ResolveVisitor({ reference, namespace, options: mergedOptions }); const refSet = ReferenceSet(); refSet.add(reference); @@ -47,7 +49,6 @@ const OpenApi3_1ResolveStrategy: stampit.Stamp = stampit(Resol keyMap, nodeTypeGetter: getNodeType, }); - await visitor.crawl(); return refSet; }, diff --git a/packages/apidom-reference/src/resolve/strategies/openapi-3-1/visitor.ts b/packages/apidom-reference/src/resolve/strategies/openapi-3-1/visitor.ts index 031f0a064d..98337c6f1c 100644 --- a/packages/apidom-reference/src/resolve/strategies/openapi-3-1/visitor.ts +++ b/packages/apidom-reference/src/resolve/strategies/openapi-3-1/visitor.ts @@ -1,502 +1,8 @@ import stampit from 'stampit'; -import { propEq, values, has, pipe, none } from 'ramda'; -import { allP } from 'ramda-adjunct'; -import { isPrimitiveElement, isStringElement, visit, toValue } from '@swagger-api/apidom-core'; -import { ApiDOMError } from '@swagger-api/apidom-error'; -import { evaluate as jsonPointerEvaluate, uriToPointer } from '@swagger-api/apidom-json-pointer'; -import { - getNodeType, - isReferenceElement, - isReferenceLikeElement, - keyMap, - ReferenceElement, - PathItemElement, - LinkElement, - ExampleElement, - SchemaElement, - isSchemaElement, - isPathItemElement, -} from '@swagger-api/apidom-ns-openapi-3-1'; -import { Reference as IReference, Resolver as IResolver } from '../../../types'; -import MaximumDereferenceDepthError from '../../../errors/MaximumDereferenceDepthError'; -import MaximumResolveDepthError from '../../../errors/MaximumResolveDepthError'; -import EvaluationJsonSchemaUriError from '../../../errors/EvaluationJsonSchemaUriError'; -import * as url from '../../../util/url'; -import parse from '../../../parse'; -import Reference from '../../../Reference'; -import File from '../../../util/File'; -import { evaluate as uriEvaluate } from '../../../dereference/strategies/openapi-3-1/selectors/uri'; -import { maybeRefractToSchemaElement, resolveSchema$refField } from './util'; -import { - evaluate as $anchorEvaluate, - isAnchor, - uriToAnchor, -} from '../../../dereference/strategies/openapi-3-1/selectors/$anchor'; - -// @ts-ignore -const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')]; +import OpenApi3_1DereferenceVisitor from '../../../dereference/strategies/openapi-3-1/visitor'; // eslint-disable-next-line @typescript-eslint/naming-convention -const OpenApi3_1ResolveVisitor = stampit({ - props: { - indirections: [], - namespace: null, - reference: null, - crawledElements: null, - crawlingMap: null, - visited: null, - options: null, - }, - init({ reference, namespace, indirections = [], visited = new WeakSet(), options }) { - this.indirections = indirections; - this.namespace = namespace; - this.reference = reference; - this.crawledElements = []; - this.crawlingMap = {}; - this.visited = visited; - this.options = options; - }, - methods: { - toBaseURI(uri: string): string { - return url.resolve(this.reference.uri, url.sanitize(url.stripHash(uri))); - }, - - async toReference(uri: string): Promise { - // detect maximum depth of resolution - if (this.reference.depth >= this.options.resolve.maxDepth) { - throw new MaximumResolveDepthError( - `Maximum resolution depth of ${this.options.resolve.maxDepth} has been exceeded by file "${this.reference.uri}"`, - ); - } - - const baseURI = this.toBaseURI(uri); - const { refSet } = this.reference; - - // we've already processed this Reference in past - if (refSet.has(baseURI)) { - return refSet.find(propEq(baseURI, 'uri')); - } - - const parseResult = await parse(url.unsanitize(baseURI), { - ...this.options, - parse: { ...this.options.parse, mediaType: 'text/plain' }, - }); - - // register new Reference with ReferenceSet - const reference = Reference({ - uri: baseURI, - value: parseResult, - depth: this.reference.depth + 1, - }); - - refSet.add(reference); - - return reference; - }, - - ReferenceElement(referenceElement: ReferenceElement) { - const uri = toValue(referenceElement.$ref); - const retrievalURI = this.toBaseURI(uri); - - // ignore resolving external Reference Objects - if (!this.options.resolve.external && url.stripHash(this.reference.uri) !== retrievalURI) { - // skip traversing this reference element and all it's child elements - return false; - } - - if (!has(retrievalURI, this.crawlingMap)) { - this.crawlingMap[retrievalURI] = this.toReference(uri); - } - this.crawledElements.push(referenceElement); - - return undefined; - }, - - PathItemElement(pathItemElement: PathItemElement) { - // ignore PathItemElement without $ref field - if (!isStringElement(pathItemElement.$ref)) { - return undefined; - } - - const uri = toValue(pathItemElement.$ref); - const retrievalURI = this.toBaseURI(uri); - - // 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; - } - - if (!has(retrievalURI, this.crawlingMap)) { - this.crawlingMap[retrievalURI] = this.toReference(uri); - } - this.crawledElements.push(pathItemElement); - - return undefined; - }, - - LinkElement(linkElement: LinkElement) { - // ignore LinkElement without operationRef or operationId field - if (!isStringElement(linkElement.operationRef) && !isStringElement(linkElement.operationId)) { - return undefined; - } - - const uri = toValue(linkElement.operationRef); - const retrievalURI = this.toBaseURI(uri); - - // ignore resolving external Path Item Elements - const isExternal = url.stripHash(this.reference.uri) !== retrievalURI; - if (!this.options.resolve.external && isExternal) { - return undefined; - } - - // operationRef and operationId are mutually exclusive - if (isStringElement(linkElement.operationRef) && isStringElement(linkElement.operationId)) { - throw new ApiDOMError('LinkElement operationRef and operationId are mutually exclusive.'); - } - - if (isExternal) { - if (!has(retrievalURI, this.crawlingMap)) { - this.crawlingMap[retrievalURI] = this.toReference(uri); - } - } - - return undefined; - }, - - ExampleElement(exampleElement: ExampleElement) { - // ignore ExampleElement without externalValue field - if (!isStringElement(exampleElement.externalValue)) { - return undefined; - } - - // value and externalValue fields are mutually exclusive - if (exampleElement.hasKey('value') && isStringElement(exampleElement.externalValue)) { - throw new ApiDOMError( - 'ExampleElement value and externalValue fields are mutually exclusive.', - ); - } - - const uri = toValue(exampleElement.externalValue); - const retrievalURI = this.toBaseURI(uri); - - // 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; - } - - if (!has(retrievalURI, this.crawlingMap)) { - this.crawlingMap[retrievalURI] = this.toReference(uri); - } - - return undefined; - }, - - async SchemaElement(schemaElement: SchemaElement) { - /** - * Skip traversal for already visited schemas and all their child schemas. - * visit function detects cycles in path automatically. - */ - if (this.visited.has(schemaElement)) { - return false; - } - // skip current referencing schema as $ref keyword was not defined - if (!isStringElement(schemaElement.$ref)) { - // mark current referencing schema as visited - this.visited.add(schemaElement); - // skip traversing this schema but traverse all it's child schemas - return undefined; - } - - // compute baseURI using rules around $id and $ref keywords - const reference = await this.toReference(url.unsanitize(this.reference.uri)); - let { uri: retrievalURI } = reference; - const $refBaseURI = resolveSchema$refField(retrievalURI, schemaElement) as string; - const $refBaseURIStrippedHash = url.stripHash($refBaseURI); - const file = File({ uri: $refBaseURIStrippedHash }); - const isUnknownURI = none((r: IResolver) => r.canRead(file), this.options.resolve.resolvers); - const isURL = !isUnknownURI; - const isExternalURL = (uri: string) => url.stripHash(this.reference.uri) !== uri; - - if (!has($refBaseURIStrippedHash, this.crawlingMap)) { - try { - if (isUnknownURI || isURL) { - this.crawlingMap[$refBaseURIStrippedHash] = reference; - } else { - retrievalURI = this.toBaseURI(toValue($refBaseURI)); - - // ignore resolving external Schema Objects - if (!this.options.resolve.external && isExternalURL(retrievalURI)) { - // skip traversing this schema element but traverse all it's child elements - this.visited.add(schemaElement); - return undefined; - } - - this.crawlingMap[$refBaseURIStrippedHash] = this.toReference( - url.unsanitize($refBaseURI), - ); - } - } catch (error) { - if (isURL && error instanceof EvaluationJsonSchemaUriError) { - retrievalURI = this.toBaseURI(url.unsanitize($refBaseURI)); - - // ignore resolving external Schema Objects - if (!this.options.resolve.external && isExternalURL(retrievalURI)) { - // skip traversing this schema element but traverse all it's child elements - this.visited.add(schemaElement); - return undefined; - } - - this.crawlingMap[$refBaseURIStrippedHash] = this.toReference( - url.unsanitize($refBaseURI), - ); - } else { - throw error; - } - } - } - this.crawledElements.push(schemaElement); - - return undefined; - }, - - async crawlReferenceElement(referenceElement: ReferenceElement) { - // @ts-ignore - const reference = await this.toReference(toValue(referenceElement.$ref)); - - this.indirections.push(referenceElement); - - const jsonPointer = uriToPointer(toValue(referenceElement.$ref)); - - // possibly non-semantic fragment - let fragment = jsonPointerEvaluate(jsonPointer, reference.value.result); - - // applying semantics to a fragment - if (isPrimitiveElement(fragment)) { - const referencedElementType = toValue(referenceElement.meta.get('referenced-element')); - - if (isReferenceLikeElement(fragment)) { - // handling indirect references - fragment = ReferenceElement.refract(fragment); - fragment.setMetaProperty('referenced-element', referencedElementType); - } else { - // handling direct references - const ElementClass = this.namespace.getElementClass(referencedElementType); - fragment = ElementClass.refract(fragment); - } - } - - // detect direct or circular reference - if (this.indirections.includes(fragment)) { - throw new ApiDOMError('Recursive Reference Object detected'); - } - - // detect maximum depth of dereferencing - if (this.indirections.length > this.options.dereference.maxDepth) { - throw new MaximumDereferenceDepthError( - `Maximum dereference depth of "${this.options.dereference.maxDepth}" has been exceeded in file "${this.reference.uri}"`, - ); - } - - // dive deep into the fragment - const visitor = OpenApi3_1ResolveVisitor({ - reference, - namespace: this.namespace, - indirections: [...this.indirections], - options: this.options, - }); - await visitAsync(fragment, visitor, { keyMap, nodeTypeGetter: getNodeType }); - await visitor.crawl(); - - this.indirections.pop(); - }, - - async crawlPathItemElement(pathItemElement: PathItemElement) { - // @ts-ignore - const reference = await this.toReference(toValue(pathItemElement.$ref)); - - this.indirections.push(pathItemElement); - - const jsonPointer = uriToPointer(toValue(pathItemElement.$ref)); - - // possibly non-semantic fragment - let referencedElement = jsonPointerEvaluate(jsonPointer, reference.value.result); - - // applying semantics to a fragment - if (isPrimitiveElement(referencedElement)) { - referencedElement = PathItemElement.refract(referencedElement); - } - - // detect direct or indirect reference - if (this.indirections.includes(referencedElement)) { - throw new ApiDOMError('Recursive Path Item Object reference detected'); - } - - // detect maximum depth of dereferencing - if (this.indirections.length > this.options.dereference.maxDepth) { - throw new MaximumDereferenceDepthError( - `Maximum dereference depth of "${this.options.dereference.maxDepth}" has been exceeded in file "${this.reference.uri}"`, - ); - } - - // dive deep into the fragment - const visitor: any = OpenApi3_1ResolveVisitor({ - reference, - namespace: this.namespace, - indirections: [...this.indirections], - options: this.options, - }); - await visitAsync(referencedElement, visitor, { keyMap, nodeTypeGetter: getNodeType }); - await visitor.crawl(); - - this.indirections.pop(); - }, - - async crawlSchemaElement(referencingElement: SchemaElement) { - // compute baseURI using rules around $id and $ref keywords - let reference = await this.toReference(url.unsanitize(this.reference.uri)); - let { uri: retrievalURI } = reference; - const $refBaseURI = resolveSchema$refField(retrievalURI, referencingElement) as string; - const $refBaseURIStrippedHash = url.stripHash($refBaseURI); - const file = File({ uri: $refBaseURIStrippedHash }); - const isUnknownURI = none((r: IResolver) => r.canRead(file), this.options.resolve.resolvers); - const isURL = !isUnknownURI; - const isExternalURL = (uri: string) => url.stripHash(this.reference.uri) !== uri; - - this.indirections.push(referencingElement); - - // determining reference, proper evaluation and selection mechanism - let referencedElement; - - try { - if (isUnknownURI || isURL) { - // we're dealing with canonical URI or URL with possible fragment - const selector = $refBaseURI; - referencedElement = uriEvaluate( - selector, - // @ts-ignore - maybeRefractToSchemaElement(reference.value.result), - ); - } else { - // we're assuming here that we're dealing with JSON Pointer here - retrievalURI = this.toBaseURI(toValue($refBaseURI)); - - // 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; - } - - reference = await this.toReference(url.unsanitize($refBaseURI)); - const selector = uriToPointer($refBaseURI); - referencedElement = maybeRefractToSchemaElement( - // @ts-ignore - jsonPointerEvaluate(selector, reference.value.result), - ); - } - } catch (error) { - /** - * No SchemaElement($id=URL) was not found, so we're going to try to resolve - * the URL and assume the returned response is a JSON Schema. - */ - if (isURL && error instanceof EvaluationJsonSchemaUriError) { - if (isAnchor(uriToAnchor($refBaseURI))) { - // we're dealing with JSON Schema $anchor here - retrievalURI = this.toBaseURI(toValue($refBaseURI)); - - // 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; - } - - reference = await this.toReference(url.unsanitize($refBaseURI)); - const selector = uriToAnchor($refBaseURI); - referencedElement = $anchorEvaluate( - selector, - // @ts-ignore - maybeRefractToSchemaElement(reference.value.result), - ); - } else { - // we're assuming here that we're dealing with JSON Pointer here - retrievalURI = this.toBaseURI(toValue($refBaseURI)); - - // 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; - } - - reference = await this.toReference(url.unsanitize($refBaseURI)); - const selector = uriToPointer($refBaseURI); - referencedElement = maybeRefractToSchemaElement( - // @ts-ignore - jsonPointerEvaluate(selector, reference.value.result), - ); - } - } else { - throw error; - } - } - - // mark current referencing schema as visited - this.visited.add(referencingElement); - - // detect direct or indirect reference - if (this.indirections.includes(referencedElement)) { - throw new ApiDOMError('Recursive Schema Object reference detected'); - } - - // detect maximum depth of dereferencing - if (this.indirections.length > this.options.dereference.maxDepth) { - throw new MaximumDereferenceDepthError( - `Maximum dereference depth of "${this.options.dereference.maxDepth}" has been exceeded in file "${this.reference.uri}"`, - ); - } - - // dive deep into the fragment - const visitor: any = OpenApi3_1ResolveVisitor({ - reference, - namespace: this.namespace, - indirections: [...this.indirections], - options: this.options, - visited: this.visited, - }); - await visitAsync(referencedElement, visitor, { - keyMap, - nodeTypeGetter: getNodeType, - }); - await visitor.crawl(); - - this.indirections.pop(); - - return undefined; - }, - - async crawl() { - /** - * Synchronize all parallel resolutions in this place. - * After synchronization happened we can be sure that refSet - * contains resolved Reference objects. - */ - await pipe(values, allP)(this.crawlingMap); - this.crawlingMap = null; - - /* eslint-disable no-await-in-loop */ - for (const element of this.crawledElements) { - if (isReferenceElement(element)) { - await this.crawlReferenceElement(element); - } else if (isSchemaElement(element)) { - await this.crawlSchemaElement(element); - } else if (isPathItemElement(element)) { - await this.crawlPathItemElement(element); - } - } - /* eslint-enable */ - }, - }, -}); +const OpenApi3_1ResolveVisitor = stampit(OpenApi3_1DereferenceVisitor); export default OpenApi3_1ResolveVisitor; diff --git a/packages/apidom-reference/test/resolve/strategies/asyncapi-2/channel-item-object/fixtures/unresolvable-channel-item/ex.json b/packages/apidom-reference/test/resolve/strategies/asyncapi-2/channel-item-object/fixtures/unresolvable-channel-item/ex.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/apidom-reference/test/resolve/strategies/asyncapi-2/channel-item-object/fixtures/unresolvable-channel-item/ex.json @@ -0,0 +1 @@ +{} diff --git a/packages/apidom-reference/test/resolve/strategies/asyncapi-2/channel-item-object/fixtures/unresolvable-channel-item/root.json b/packages/apidom-reference/test/resolve/strategies/asyncapi-2/channel-item-object/fixtures/unresolvable-channel-item/root.json index 3ae243d4f5..1c35f882cc 100644 --- a/packages/apidom-reference/test/resolve/strategies/asyncapi-2/channel-item-object/fixtures/unresolvable-channel-item/root.json +++ b/packages/apidom-reference/test/resolve/strategies/asyncapi-2/channel-item-object/fixtures/unresolvable-channel-item/root.json @@ -2,7 +2,7 @@ "asyncapi": "2.6.0", "channels": { "channelItem1": { - "$ref": "#/channels/invalid-pointer" + "$ref": "./ex.json#/channels/invalid-pointer" }, "channelItem2": { "description": "channel item 2 description" diff --git a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/link-object/index.ts b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/link-object/index.ts index 624de2ba38..8c44fa3969 100644 --- a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/link-object/index.ts +++ b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/link-object/index.ts @@ -43,14 +43,20 @@ describe('resolve', function () { context('and with invalid JSON Pointer', function () { const fixturePath = path.join(rootFixturePath, 'operation-ref-invalid-pointer'); - specify('should resolve', async function () { - // external resolution of Link Object is not concerned with validity of JSON Pointer (if defined) - const rootFilePath = path.join(fixturePath, 'root.json'); - const refSet = await resolve(rootFilePath, { - parse: { mediaType: mediaTypes.latest('json') }, - }); - - assert.strictEqual(refSet.size, 2); + specify('should throw error', async function () { + try { + const rootFilePath = path.join(fixturePath, 'root.json'); + await resolve(rootFilePath, { + parse: { mediaType: mediaTypes.latest('json') }, + }); + assert.fail('should throw ResolverError'); + } catch (error: any) { + assert.strictEqual( + error.cause.cause.message, + 'JSON Pointer evaluation failed while parsing the pointer "invalid-pointer".', + ); + assert.instanceOf(error, ResolverError); + } }); }); @@ -85,7 +91,7 @@ describe('resolve', function () { } catch (error: any) { assert.strictEqual( error.cause.cause.message, - 'LinkElement operationRef and operationId are mutually exclusive.', + 'LinkElement operationRef and operationId fields are mutually exclusive.', ); assert.instanceOf(error, ResolverError); } diff --git a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/path-item-object/fixtures/unresolvable-path-item/ex.json b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/path-item-object/fixtures/unresolvable-path-item/ex.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/path-item-object/fixtures/unresolvable-path-item/ex.json @@ -0,0 +1 @@ +{} diff --git a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/path-item-object/fixtures/unresolvable-path-item/root.json b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/path-item-object/fixtures/unresolvable-path-item/root.json index 1f7c6dcf9b..3c0bce2b3f 100644 --- a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/path-item-object/fixtures/unresolvable-path-item/root.json +++ b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/path-item-object/fixtures/unresolvable-path-item/root.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "paths": { "/path1": { - "$ref": "#/paths/invalid-pointer" + "$ref": "./ex.json#/paths/invalid-pointer" }, "/path2": { "summary": "path item summary", diff --git a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/$anchor-not-found/ex.json b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/$anchor-not-found/ex.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/$anchor-not-found/ex.json @@ -0,0 +1 @@ +{} diff --git a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/$anchor-not-found/root.json b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/$anchor-not-found/root.json index f0f2dce912..5f55276688 100644 --- a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/$anchor-not-found/root.json +++ b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/$anchor-not-found/root.json @@ -12,7 +12,7 @@ "type": "string" }, "profile": { - "$ref": "#user-profile" + "$ref": "./ex.json#user-profile" } } } diff --git a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/invalid-pointer/ex.json b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/invalid-pointer/ex.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/invalid-pointer/ex.json @@ -0,0 +1 @@ +{} diff --git a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/invalid-pointer/root.json b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/invalid-pointer/root.json index 4a8c563523..868db394e9 100644 --- a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/invalid-pointer/root.json +++ b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/invalid-pointer/root.json @@ -4,7 +4,7 @@ "schemas": { "User": { "type": "object", - "$ref": "#/components/schemas/invalid-pointer" + "$ref": "./ex.json#/components/schemas/invalid-pointer" } } } diff --git a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/unresolvable-reference/ex.json b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/unresolvable-reference/ex.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/unresolvable-reference/root.json b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/unresolvable-reference/root.json index 6269b86390..9548b5e983 100644 --- a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/unresolvable-reference/root.json +++ b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/fixtures/unresolvable-reference/root.json @@ -5,7 +5,7 @@ "User": { "properties": { "profile": { - "$ref": "#/components/schemas/UserProfile" + "$ref": "./ex.json#/components/schemas/UserProfile" } } } diff --git a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/index.ts b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/index.ts index 8c95644b6d..6415104bc8 100644 --- a/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/index.ts +++ b/packages/apidom-reference/test/resolve/strategies/openapi-3-1/schema-object/index.ts @@ -460,16 +460,13 @@ describe('resolve', function () { context('given Schema Objects with infinite recursion', function () { const fixturePath = path.join(rootFixturePath, 'infinite-recursion'); - specify('should throw error', async function () { + specify('should resolve as internal references are ignored', async function () { const rootFilePath = path.join(fixturePath, 'root.json'); - try { - await resolve(rootFilePath, { - parse: { mediaType: mediaTypes.latest('json') }, - }); - assert.fail('should throw ResolverError'); - } catch (e) { - assert.instanceOf(e, ResolverError); - } + const refSet = await resolve(rootFilePath, { + parse: { mediaType: mediaTypes.latest('json') }, + }); + + assert.strictEqual(refSet.size, 1); }); }); @@ -492,16 +489,13 @@ describe('resolve', function () { context('given Schema Objects with direct circular internal reference', function () { const fixturePath = path.join(rootFixturePath, 'direct-internal-circular'); - specify('should throw error', async function () { + specify('should resolve as internal references are ignored', async function () { const rootFilePath = path.join(fixturePath, 'root.json'); - try { - await resolve(rootFilePath, { - parse: { mediaType: mediaTypes.latest('json') }, - }); - assert.fail('should throw ResolverError'); - } catch (e) { - assert.instanceOf(e, ResolverError); - } + const refSet = await resolve(rootFilePath, { + parse: { mediaType: mediaTypes.latest('json') }, + }); + + assert.strictEqual(refSet.size, 1); }); }); @@ -537,16 +531,13 @@ describe('resolve', function () { context('given Reference Objects with indirect circular internal reference', function () { const fixturePath = path.join(rootFixturePath, 'indirect-internal-circular'); - specify('should throw error', async function () { + specify('should resolve as internal references are ignored', async function () { const rootFilePath = path.join(fixturePath, 'root.json'); - try { - await resolve(rootFilePath, { - parse: { mediaType: mediaTypes.latest('json') }, - }); - assert.fail('should throw ResolveError'); - } catch (e) { - assert.instanceOf(e, ResolveError); - } + const refSet = await resolve(rootFilePath, { + parse: { mediaType: mediaTypes.latest('json') }, + }); + + assert.strictEqual(refSet.size, 1); }); }); });