From bf7954778967a64f57f837a1b42c3fc6bad51af1 Mon Sep 17 00:00:00 2001 From: Vladimir Gorej Date: Thu, 1 Apr 2021 16:40:27 +0200 Subject: [PATCH 1/2] feat(reference): add AsyncApi 2.0.0 external resolution Closes #305 --- .../apidom-ns-asyncapi-2-0/src/predicates.ts | 2 +- .../apidom-ns-openapi-3-1/src/predicates.ts | 2 +- .../apidom-reference/src/options/index.ts | 3 +- .../resolve/strategies/asyncapi-2-0/index.ts | 56 +++++ .../strategies/asyncapi-2-0/visitor.ts | 167 ++++++++++++++ .../resolve/strategies/openapi-3-1/visitor.ts | 2 +- .../test/dereference/index.ts | 16 +- .../refset-as-option/dereferenced.json | 15 ++ .../fixtures/refset-as-option/ex1.json | 0 .../fixtures/refset-as-option/ex2.json | 0 .../fixtures/refset-as-option/ex3.json | 8 + .../fixtures/refset-as-option/root.json | 10 + .../asyncapi-2-0/reference-object/index.ts | 16 +- .../refset-as-option/dereferenced.json | 0 .../fixtures/refset-as-option/ex1.json | 5 + .../fixtures/refset-as-option/ex2.json | 5 + .../fixtures/refset-as-option/ex3.json | 0 .../fixtures/refset-as-option/root.json | 0 .../openapi-3-1/reference-object/index.ts | 16 +- .../fixtures/circular/dereferenced.json | 14 ++ .../fixtures/circular/ex.json | 15 ++ .../fixtures/circular/root.json | 10 + .../fixtures/direct-external-circular/ex.json | 5 + .../direct-external-circular/root.json | 10 + .../direct-internal-circular/root.json | 10 + .../external-indirections/dereferenced.json | 15 ++ .../fixtures/external-indirections/ex1.json | 5 + .../fixtures/external-indirections/ex2.json | 5 + .../fixtures/external-indirections/ex3.json | 8 + .../fixtures/external-indirections/root.json | 10 + .../fixtures/external-only/dereferenced.json | 15 ++ .../fixtures/external-only/ex.json | 8 + .../fixtures/external-only/root.json | 10 + .../ignore-external/dereferenced.json | 36 ++++ .../fixtures/ignore-external/ex.json | 8 + .../fixtures/ignore-external/root.json | 25 +++ .../indirect-external-circular/ex1.json | 5 + .../indirect-external-circular/ex2.json | 5 + .../indirect-external-circular/ex3.json | 5 + .../indirect-external-circular/root.json | 10 + .../indirect-internal-circular/root.json | 19 ++ .../internal-external/dereferenced.json | 39 ++++ .../fixtures/internal-external/ex.json | 8 + .../fixtures/internal-external/root.json | 25 +++ .../fixtures/internal-only/dereferenced.json | 33 +++ .../fixtures/internal-only/root.json | 22 ++ .../fixtures/invalid-pointer/root.json | 16 ++ .../fixtures/max-depth/ex1.json | 5 + .../fixtures/max-depth/ex2.json | 5 + .../fixtures/max-depth/ex3.json | 8 + .../fixtures/max-depth/root.json | 10 + .../fixtures/unresolvable-reference/root.json | 10 + .../asyncapi-2-0/reference-object/index.ts | 204 ++++++++++++++++++ 53 files changed, 940 insertions(+), 21 deletions(-) create mode 100644 apidom/packages/apidom-reference/src/resolve/strategies/asyncapi-2-0/index.ts create mode 100644 apidom/packages/apidom-reference/src/resolve/strategies/asyncapi-2-0/visitor.ts create mode 100644 apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/dereferenced.json rename apidom/packages/apidom-reference/test/dereference/{ => strategies/asyncapi-2-0/reference-object}/fixtures/refset-as-option/ex1.json (100%) rename apidom/packages/apidom-reference/test/dereference/{ => strategies/asyncapi-2-0/reference-object}/fixtures/refset-as-option/ex2.json (100%) create mode 100644 apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/ex3.json create mode 100644 apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/root.json rename apidom/packages/apidom-reference/test/dereference/{ => strategies/openapi-3-1/reference-object}/fixtures/refset-as-option/dereferenced.json (100%) create mode 100644 apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/ex1.json create mode 100644 apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/ex2.json rename apidom/packages/apidom-reference/test/dereference/{ => strategies/openapi-3-1/reference-object}/fixtures/refset-as-option/ex3.json (100%) rename apidom/packages/apidom-reference/test/dereference/{ => strategies/openapi-3-1/reference-object}/fixtures/refset-as-option/root.json (100%) create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/dereferenced.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/ex.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-external-circular/ex.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-external-circular/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-internal-circular/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/dereferenced.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex1.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex2.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex3.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/dereferenced.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/ex.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/dereferenced.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/ex.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex1.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex2.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex3.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-internal-circular/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/dereferenced.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/ex.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-only/dereferenced.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-only/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/invalid-pointer/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex1.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex2.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex3.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/unresolvable-reference/root.json create mode 100644 apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/index.ts diff --git a/apidom/packages/apidom-ns-asyncapi-2-0/src/predicates.ts b/apidom/packages/apidom-ns-asyncapi-2-0/src/predicates.ts index a0bb27d0a5..eff8405860 100644 --- a/apidom/packages/apidom-ns-asyncapi-2-0/src/predicates.ts +++ b/apidom/packages/apidom-ns-asyncapi-2-0/src/predicates.ts @@ -25,7 +25,7 @@ import ServerVariableElement from './elements/ServerVariable'; export const isAsyncApi2_0Element = createPredicate( ({ hasBasicElementProps, isElementType, primitiveEq, hasClass }) => { - const isElementTypeAsyncApi2_0 = isElementType('asyncApi2-0'); + const isElementTypeAsyncApi2_0 = isElementType('asyncApi2_0'); const primitiveEqObject = primitiveEq('object'); const hasClassApi = hasClass('api'); diff --git a/apidom/packages/apidom-ns-openapi-3-1/src/predicates.ts b/apidom/packages/apidom-ns-openapi-3-1/src/predicates.ts index 01dda20aee..31a36f1c22 100644 --- a/apidom/packages/apidom-ns-openapi-3-1/src/predicates.ts +++ b/apidom/packages/apidom-ns-openapi-3-1/src/predicates.ts @@ -110,7 +110,7 @@ export const isOpenapiElement = createPredicate( export const isOpenApi3_1Element = createPredicate( ({ hasBasicElementProps, isElementType, primitiveEq, hasClass }) => { - const isElementTypeOpenApi3_1 = isElementType('openApi3-1'); + const isElementTypeOpenApi3_1 = isElementType('openApi3_1'); const primitiveEqObject = primitiveEq('object'); const hasClassApi = hasClass('api'); diff --git a/apidom/packages/apidom-reference/src/options/index.ts b/apidom/packages/apidom-reference/src/options/index.ts index f21e524691..3bc5123286 100644 --- a/apidom/packages/apidom-reference/src/options/index.ts +++ b/apidom/packages/apidom-reference/src/options/index.ts @@ -1,6 +1,7 @@ import FileResolver from '../resolve/resolvers/FileResolver'; import HttpResolverAxios from '../resolve/resolvers/HttpResolverAxios'; import OpenApi3_1ResolveStrategy from '../resolve/strategies/openapi-3-1'; +import AsyncApi2_0ResolveStrategy from '../resolve/strategies/asyncapi-2-0'; import OpenApiJson3_1Parser from '../parse/parsers/apidom-reference-parser-openapi-json-3-1'; import OpenApiYaml3_1Parser from '../parse/parsers/apidom-reference-parser-openapi-yaml-3-1'; import AsyncApiJson2_0Parser from '../parse/parsers/apidom-reference-parser-asyncapi-json-2-0'; @@ -56,7 +57,7 @@ const defaultOptions: IReferenceOptions = { * You can add additional resolver strategies of your own, replace an existing one with * your own implementation, or remove any resolve strategy by removing it from the list. */ - strategies: [OpenApi3_1ResolveStrategy()], + strategies: [OpenApi3_1ResolveStrategy(), AsyncApi2_0ResolveStrategy()], /** * Determines whether external references will be resolved. * If this option is disabled, then none of above resolvers will be called. diff --git a/apidom/packages/apidom-reference/src/resolve/strategies/asyncapi-2-0/index.ts b/apidom/packages/apidom-reference/src/resolve/strategies/asyncapi-2-0/index.ts new file mode 100644 index 0000000000..437188a5d3 --- /dev/null +++ b/apidom/packages/apidom-reference/src/resolve/strategies/asyncapi-2-0/index.ts @@ -0,0 +1,56 @@ +import stampit from 'stampit'; +import { createNamespace, visit } from 'apidom'; +import asyncApi2_0Namespace, { + getNodeType, + isAsyncApi2_0Element, + keyMap, +} from 'apidom-ns-asyncapi-2-0'; + +import ResolveStrategy from '../ResolveStrategy'; +import { + File as IFile, + ReferenceOptions as IReferenceOptions, + ResolveStrategy as IResolveStrategy, +} from '../../../types'; +import ReferenceSet from '../../../ReferenceSet'; +import Reference from '../../../Reference'; +import AsyncApi2_0ResolveVisitor from './visitor'; + +// @ts-ignore +const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')]; + +const AsyncApi2_0ResolveStrategy: stampit.Stamp = stampit(ResolveStrategy, { + methods: { + canResolve(file: IFile) { + // assert by media type + if (file.mediaType !== 'text/plain') { + return [ + 'application/vnd.aai.asyncapi;version=2.0.0', + 'application/vnd.aai.asyncapi+json;version=2.0.0', + 'application/vnd.aai.asyncapi+yaml;version=2.0.0', + ].includes(file.mediaType); + } + + // assert by inspecting ApiDOM + return isAsyncApi2_0Element(file.parseResult?.api); + }, + + async resolve(file: IFile, options: IReferenceOptions) { + const namespace = createNamespace(asyncApi2_0Namespace); + const reference = Reference({ uri: file.uri, value: file.parseResult }); + const visitor = AsyncApi2_0ResolveVisitor({ reference, namespace, options }); + const refSet = ReferenceSet(); + refSet.add(reference); + + await visitAsync(refSet.rootRef.value, visitor, { + keyMap, + nodeTypeGetter: getNodeType, + }); + await visitor.crawl(); + + return refSet; + }, + }, +}); + +export default AsyncApi2_0ResolveStrategy; diff --git a/apidom/packages/apidom-reference/src/resolve/strategies/asyncapi-2-0/visitor.ts b/apidom/packages/apidom-reference/src/resolve/strategies/asyncapi-2-0/visitor.ts new file mode 100644 index 0000000000..28640e8aa5 --- /dev/null +++ b/apidom/packages/apidom-reference/src/resolve/strategies/asyncapi-2-0/visitor.ts @@ -0,0 +1,167 @@ +import stampit from 'stampit'; +import { propEq, values, has, pipe } from 'ramda'; +import { allP } from 'ramda-adjunct'; +import { isPrimitiveElement, visit } from 'apidom'; +import { + getNodeType, + isReferenceElement, + isReferenceLikeElement, + keyMap, + ReferenceElement, + isReferenceElementExternal, +} from 'apidom-ns-asyncapi-2-0'; + +import { Reference as IReference } from '../../../types'; +import { MaximumDereferenceDepthError, MaximumResolverDepthError } from '../../../util/errors'; +import * as url from '../../../util/url'; +import parse from '../../../parse'; +import Reference from '../../../Reference'; +import { evaluate, uriToPointer } from '../../../selectors/json-pointer'; + +// @ts-ignore +const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')]; + +const AsyncApi2_0ResolveVisitor = stampit({ + props: { + indirections: [], + namespace: null, + reference: null, + crawledElements: null, + crawlingMap: null, + options: null, + }, + init({ reference, namespace, indirections = [], options }) { + this.indirections = indirections; + this.namespace = namespace; + this.reference = reference; + this.crawledElements = []; + this.crawlingMap = {}; + this.options = options; + }, + methods: { + toBaseURI(uri: string): string { + const uriWithoutHash = url.stripHash(uri); + const sanitizedURI = url.isFileSystemPath(uriWithoutHash) + ? url.fromFileSystemPath(uriWithoutHash) + : uriWithoutHash; + + return url.resolve(this.reference.uri, sanitizedURI); + }, + + async toReference(uri: string): Promise { + // detect maximum depth of resolution + if (this.reference.depth >= this.options.resolve.maxDepth) { + throw new MaximumResolverDepthError( + `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('uri', baseURI)); + } + + const parseResult = await parse(baseURI, this.options); + + // 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) { + // ignore resolving external Reference Objects + if (!this.options.resolve.external && isReferenceElementExternal(referenceElement)) { + return false; + } + + const uri = referenceElement.$ref.toValue(); + const baseURI = this.toBaseURI(uri); + + if (!has(baseURI, this.crawlingMap)) { + this.crawlingMap[baseURI] = this.toReference(uri); + } + this.crawledElements.push(referenceElement); + + return undefined; + }, + + async crawlReferenceElement(referenceElement: ReferenceElement) { + // @ts-ignore + const reference = await this.toReference(referenceElement.$ref.toValue()); + + this.indirections.push(referenceElement); + + const jsonPointer = uriToPointer(referenceElement.$ref.toValue()); + + // possibly non-semantic fragment + let fragment = evaluate(jsonPointer, reference.value.result); + + // applying semantics to a fragment + if (isPrimitiveElement(fragment)) { + const referencedElementType = referenceElement.meta.get('referenced-element').toValue(); + + 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 Error('Recursive JSON Pointer 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 = AsyncApi2_0ResolveVisitor({ + reference, + namespace: this.namespace, + indirections: [...this.indirections], + options: this.options, + }); + await visitAsync(fragment, visitor, { keyMap, nodeTypeGetter: getNodeType }); + await visitor.crawl(); + + this.indirections.pop(); + }, + + 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; + + for (const element of this.crawledElements) { + if (isReferenceElement(element)) { + await this.crawlReferenceElement(element); // eslint-disable-line no-await-in-loop + } + } + }, + }, +}); + +export default AsyncApi2_0ResolveVisitor; diff --git a/apidom/packages/apidom-reference/src/resolve/strategies/openapi-3-1/visitor.ts b/apidom/packages/apidom-reference/src/resolve/strategies/openapi-3-1/visitor.ts index e30507cbe0..1205b70780 100644 --- a/apidom/packages/apidom-reference/src/resolve/strategies/openapi-3-1/visitor.ts +++ b/apidom/packages/apidom-reference/src/resolve/strategies/openapi-3-1/visitor.ts @@ -27,7 +27,7 @@ const OpenApi3_1ResolveVisitor = stampit({ namespace: null, reference: null, crawledElements: null, - crawlingMap: {}, + crawlingMap: null, options: null, }, init({ reference, namespace, indirections = [], options }) { diff --git a/apidom/packages/apidom-reference/test/dereference/index.ts b/apidom/packages/apidom-reference/test/dereference/index.ts index e408f072c8..ff395eac48 100644 --- a/apidom/packages/apidom-reference/test/dereference/index.ts +++ b/apidom/packages/apidom-reference/test/dereference/index.ts @@ -2,7 +2,7 @@ import { assert } from 'chai'; import path from 'path'; import { toValue } from 'apidom'; -import { dereference, dereferenceApiDOM, parse, resolve } from '../../src'; +import { dereference, dereferenceApiDOM, parse } from '../../src'; import { loadJsonFile } from '../helpers'; describe('dereference', function () { @@ -39,18 +39,4 @@ describe('dereference', function () { }); }); }); - - context('given refSet is provided as an option', function () { - specify('should dereference without external resolution', async function () { - const fixturePath = path.join(__dirname, 'fixtures', 'refset-as-option'); - const uri = path.join(fixturePath, 'root.json'); - const refSet = await resolve(uri, { - parse: { mediaType: 'application/vnd.oai.openapi+json;version=3.1.0' }, - }); - const actual = await dereference(uri, { dereference: { refSet } }); - const expected = loadJsonFile(path.join(fixturePath, 'dereferenced.json')); - - assert.deepEqual(toValue(actual), expected); - }); - }); }); diff --git a/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/dereferenced.json b/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/dereferenced.json new file mode 100644 index 0000000000..9d6f6d1ed6 --- /dev/null +++ b/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/dereferenced.json @@ -0,0 +1,15 @@ +[ + { + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + } + } + } + } +] diff --git a/apidom/packages/apidom-reference/test/dereference/fixtures/refset-as-option/ex1.json b/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/ex1.json similarity index 100% rename from apidom/packages/apidom-reference/test/dereference/fixtures/refset-as-option/ex1.json rename to apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/ex1.json diff --git a/apidom/packages/apidom-reference/test/dereference/fixtures/refset-as-option/ex2.json b/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/ex2.json similarity index 100% rename from apidom/packages/apidom-reference/test/dereference/fixtures/refset-as-option/ex2.json rename to apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/ex2.json diff --git a/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/ex3.json b/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/ex3.json new file mode 100644 index 0000000000..c381aad33b --- /dev/null +++ b/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/ex3.json @@ -0,0 +1,8 @@ +{ + "externalParameter": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + } +} diff --git a/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/root.json b/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/root.json new file mode 100644 index 0000000000..851f83a58a --- /dev/null +++ b/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/fixtures/refset-as-option/root.json @@ -0,0 +1,10 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "$ref": "./ex1.json#/indirection" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/index.ts b/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/index.ts index ce1d95423d..cac66f26ef 100644 --- a/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/index.ts +++ b/apidom/packages/apidom-reference/test/dereference/strategies/asyncapi-2-0/reference-object/index.ts @@ -4,7 +4,7 @@ import { toValue } from 'apidom'; import { isParameterElement } from 'apidom-ns-asyncapi-2-0'; import { loadJsonFile } from '../../../../helpers'; -import { dereference } from '../../../../../src'; +import { dereference, resolve } from '../../../../../src'; import { evaluate } from '../../../../../src/selectors/json-pointer'; import { DereferenceError, @@ -266,6 +266,20 @@ describe('dereference', function () { } }); }); + + context('given refSet is provided as an option', function () { + specify('should dereference without external resolution', async function () { + const fixturePath = path.join(__dirname, 'fixtures', 'refset-as-option'); + const uri = path.join(fixturePath, 'root.json'); + const refSet = await resolve(uri, { + parse: { mediaType: 'application/vnd.oai.openapi+json;version=3.1.0' }, + }); + const actual = await dereference(uri, { dereference: { refSet } }); + const expected = loadJsonFile(path.join(fixturePath, 'dereferenced.json')); + + assert.deepEqual(toValue(actual), expected); + }); + }); }); }); }); diff --git a/apidom/packages/apidom-reference/test/dereference/fixtures/refset-as-option/dereferenced.json b/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/dereferenced.json similarity index 100% rename from apidom/packages/apidom-reference/test/dereference/fixtures/refset-as-option/dereferenced.json rename to apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/dereferenced.json diff --git a/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/ex1.json b/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/ex1.json new file mode 100644 index 0000000000..f46bebc5f4 --- /dev/null +++ b/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/ex1.json @@ -0,0 +1,5 @@ +{ + "indirection": { + "$ref": "./ex2.json#/indirection" + } +} diff --git a/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/ex2.json b/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/ex2.json new file mode 100644 index 0000000000..091689f702 --- /dev/null +++ b/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/ex2.json @@ -0,0 +1,5 @@ +{ + "indirection": { + "$ref": "./ex3.json#/externalParameter" + } +} diff --git a/apidom/packages/apidom-reference/test/dereference/fixtures/refset-as-option/ex3.json b/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/ex3.json similarity index 100% rename from apidom/packages/apidom-reference/test/dereference/fixtures/refset-as-option/ex3.json rename to apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/ex3.json diff --git a/apidom/packages/apidom-reference/test/dereference/fixtures/refset-as-option/root.json b/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/root.json similarity index 100% rename from apidom/packages/apidom-reference/test/dereference/fixtures/refset-as-option/root.json rename to apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/fixtures/refset-as-option/root.json diff --git a/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/index.ts b/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/index.ts index 50e544fbf8..974b8362be 100644 --- a/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/index.ts +++ b/apidom/packages/apidom-reference/test/dereference/strategies/openapi-3-1/reference-object/index.ts @@ -4,7 +4,7 @@ import { toValue } from 'apidom'; import { isParameterElement } from 'apidom-ns-openapi-3-1'; import { loadJsonFile } from '../../../../helpers'; -import { dereference } from '../../../../../src'; +import { dereference, resolve } from '../../../../../src'; import { evaluate } from '../../../../../src/selectors/json-pointer'; import { DereferenceError, @@ -281,6 +281,20 @@ describe('dereference', function () { } }); }); + + context('given refSet is provided as an option', function () { + specify('should dereference without external resolution', async function () { + const fixturePath = path.join(__dirname, 'fixtures', 'refset-as-option'); + const uri = path.join(fixturePath, 'root.json'); + const refSet = await resolve(uri, { + parse: { mediaType: 'application/vnd.oai.openapi+json;version=3.1.0' }, + }); + const actual = await dereference(uri, { dereference: { refSet } }); + const expected = loadJsonFile(path.join(fixturePath, 'dereferenced.json')); + + assert.deepEqual(toValue(actual), expected); + }); + }); }); }); }); diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/dereferenced.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/dereferenced.json new file mode 100644 index 0000000000..2c50f76d7d --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/dereferenced.json @@ -0,0 +1,14 @@ +[ + { + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "a": { + "$ref": "#/three" + } + } + } + } + } +] diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/ex.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/ex.json new file mode 100644 index 0000000000..2e53208cfc --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/ex.json @@ -0,0 +1,15 @@ +{ + "one": { + "$ref": "#/two" + }, + "two": { + "a": { + "$ref": "#/three" + } + }, + "three": { + "b": { + "$ref": "#/two" + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/root.json new file mode 100644 index 0000000000..7883fdee0f --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/circular/root.json @@ -0,0 +1,10 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "$ref": "./ex.json#/one" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-external-circular/ex.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-external-circular/ex.json new file mode 100644 index 0000000000..cec551870e --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-external-circular/ex.json @@ -0,0 +1,5 @@ +{ + "externalParameter": { + "$ref": "./root.json#/components/parameters/userId" + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-external-circular/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-external-circular/root.json new file mode 100644 index 0000000000..c48527d554 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-external-circular/root.json @@ -0,0 +1,10 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "$ref": "./ex.json#/externalParameter" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-internal-circular/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-internal-circular/root.json new file mode 100644 index 0000000000..d11a69358d --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/direct-internal-circular/root.json @@ -0,0 +1,10 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "userId": { + "$ref": "#/components/parameters/userId" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/dereferenced.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/dereferenced.json new file mode 100644 index 0000000000..5635cd28a5 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/dereferenced.json @@ -0,0 +1,15 @@ +[ + { + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "description": "external parameter", + "schema": { + "type": "string" + } + } + } + } + } +] diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex1.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex1.json new file mode 100644 index 0000000000..f46bebc5f4 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex1.json @@ -0,0 +1,5 @@ +{ + "indirection": { + "$ref": "./ex2.json#/indirection" + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex2.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex2.json new file mode 100644 index 0000000000..091689f702 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex2.json @@ -0,0 +1,5 @@ +{ + "indirection": { + "$ref": "./ex3.json#/externalParameter" + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex3.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex3.json new file mode 100644 index 0000000000..8c121ad77b --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/ex3.json @@ -0,0 +1,8 @@ +{ + "externalParameter": { + "description": "external parameter", + "schema": { + "type": "string" + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/root.json new file mode 100644 index 0000000000..851f83a58a --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-indirections/root.json @@ -0,0 +1,10 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "$ref": "./ex1.json#/indirection" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/dereferenced.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/dereferenced.json new file mode 100644 index 0000000000..5635cd28a5 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/dereferenced.json @@ -0,0 +1,15 @@ +[ + { + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "description": "external parameter", + "schema": { + "type": "string" + } + } + } + } + } +] diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/ex.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/ex.json new file mode 100644 index 0000000000..8c121ad77b --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/ex.json @@ -0,0 +1,8 @@ +{ + "externalParameter": { + "description": "external parameter", + "schema": { + "type": "string" + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/root.json new file mode 100644 index 0000000000..c48527d554 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/external-only/root.json @@ -0,0 +1,10 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "$ref": "./ex.json#/externalParameter" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/dereferenced.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/dereferenced.json new file mode 100644 index 0000000000..37a2e62872 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/dereferenced.json @@ -0,0 +1,36 @@ +[ + { + "asyncapi": "2.0.0", + "components": { + "parameters": { + "userId": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "indirection1": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "indirection2": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "userIdRef": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "externalRef": { + "$ref": "./ex.json#/externalParameter" + } + } + } + } +] diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/ex.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/ex.json new file mode 100644 index 0000000000..8c121ad77b --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/ex.json @@ -0,0 +1,8 @@ +{ + "externalParameter": { + "description": "external parameter", + "schema": { + "type": "string" + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/root.json new file mode 100644 index 0000000000..eb685c738c --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/ignore-external/root.json @@ -0,0 +1,25 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "userId": { + "$ref": "#/components/parameters/indirection1" + }, + "indirection1": { + "$ref": "#/components/parameters/indirection2" + }, + "indirection2": { + "$ref": "#/components/parameters/userIdRef" + }, + "userIdRef": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "externalRef": { + "$ref": "./ex.json#/externalParameter" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex1.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex1.json new file mode 100644 index 0000000000..f46bebc5f4 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex1.json @@ -0,0 +1,5 @@ +{ + "indirection": { + "$ref": "./ex2.json#/indirection" + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex2.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex2.json new file mode 100644 index 0000000000..d44c814227 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex2.json @@ -0,0 +1,5 @@ +{ + "indirection": { + "$ref": "./ex3.json#/indirection" + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex3.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex3.json new file mode 100644 index 0000000000..92be82752c --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/ex3.json @@ -0,0 +1,5 @@ +{ + "indirection": { + "$ref": "./root.json#/components/parameters/externalRef" + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/root.json new file mode 100644 index 0000000000..beb41985df --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-external-circular/root.json @@ -0,0 +1,10 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "$ref": "./ex1.json#/indirection" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-internal-circular/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-internal-circular/root.json new file mode 100644 index 0000000000..1c84d23b00 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/indirect-internal-circular/root.json @@ -0,0 +1,19 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "userId": { + "$ref": "#/components/parameters/indirection1" + }, + "indirection1": { + "$ref": "#/components/parameters/indirection2" + }, + "indirection2": { + "$ref": "#/components/parameters/indirection3" + }, + "indirection3": { + "$ref": "#/components/parameters/userId" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/dereferenced.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/dereferenced.json new file mode 100644 index 0000000000..11f78d5bf8 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/dereferenced.json @@ -0,0 +1,39 @@ +[ + { + "asyncapi": "2.0.0", + "components": { + "parameters": { + "userId": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "indirection1": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "indirection2": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "userIdRef": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "externalRef": { + "description": "external parameter", + "schema": { + "type": "string" + } + } + } + } + } +] diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/ex.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/ex.json new file mode 100644 index 0000000000..8c121ad77b --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/ex.json @@ -0,0 +1,8 @@ +{ + "externalParameter": { + "description": "external parameter", + "schema": { + "type": "string" + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/root.json new file mode 100644 index 0000000000..eb685c738c --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-external/root.json @@ -0,0 +1,25 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "userId": { + "$ref": "#/components/parameters/indirection1" + }, + "indirection1": { + "$ref": "#/components/parameters/indirection2" + }, + "indirection2": { + "$ref": "#/components/parameters/userIdRef" + }, + "userIdRef": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "externalRef": { + "$ref": "./ex.json#/externalParameter" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-only/dereferenced.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-only/dereferenced.json new file mode 100644 index 0000000000..5e54ef2eb5 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-only/dereferenced.json @@ -0,0 +1,33 @@ +[ + { + "asyncapi": "2.0.0", + "components": { + "parameters": { + "userId": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "indirection1": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "indirection2": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + }, + "userIdRef": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + } + } + } + } +] diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-only/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-only/root.json new file mode 100644 index 0000000000..d52ba24e2b --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/internal-only/root.json @@ -0,0 +1,22 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "userId": { + "$ref": "#/components/parameters/indirection1" + }, + "indirection1": { + "$ref": "#/components/parameters/indirection2" + }, + "indirection2": { + "$ref": "#/components/parameters/userIdRef" + }, + "userIdRef": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/invalid-pointer/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/invalid-pointer/root.json new file mode 100644 index 0000000000..622231455c --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/invalid-pointer/root.json @@ -0,0 +1,16 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "userId": { + "$ref": "#/components/parameters/invalid-pointer" + }, + "userIdRef": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex1.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex1.json new file mode 100644 index 0000000000..f46bebc5f4 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex1.json @@ -0,0 +1,5 @@ +{ + "indirection": { + "$ref": "./ex2.json#/indirection" + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex2.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex2.json new file mode 100644 index 0000000000..091689f702 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex2.json @@ -0,0 +1,5 @@ +{ + "indirection": { + "$ref": "./ex3.json#/externalParameter" + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex3.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex3.json new file mode 100644 index 0000000000..c381aad33b --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/ex3.json @@ -0,0 +1,8 @@ +{ + "externalParameter": { + "description": "Id of the user.", + "schema": { + "type": "string" + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/root.json new file mode 100644 index 0000000000..851f83a58a --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/max-depth/root.json @@ -0,0 +1,10 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "$ref": "./ex1.json#/indirection" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/unresolvable-reference/root.json b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/unresolvable-reference/root.json new file mode 100644 index 0000000000..c48527d554 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/fixtures/unresolvable-reference/root.json @@ -0,0 +1,10 @@ +{ + "asyncapi": "2.0.0", + "components": { + "parameters": { + "externalRef": { + "$ref": "./ex.json#/externalParameter" + } + } + } +} diff --git a/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/index.ts b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/index.ts new file mode 100644 index 0000000000..f1c1b99c87 --- /dev/null +++ b/apidom/packages/apidom-reference/test/resolve/strategies/asyncapi-2-0/reference-object/index.ts @@ -0,0 +1,204 @@ +import path from 'path'; +import { assert } from 'chai'; + +import { resolve } from '../../../../../src'; +import { MaximumResolverDepthError, ResolverError } from '../../../../../src/util/errors'; + +const rootFixturePath = path.join(__dirname, 'fixtures'); + +describe('resolve', function () { + context('strategies', function () { + context('asyncapi-2-0', function () { + context('Reference Object', function () { + context('given Reference Objects pointing internally and externally', function () { + const fixturePath = path.join(rootFixturePath, 'internal-external'); + + specify('should resolve', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + const refSet = await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + + assert.strictEqual(refSet.size, 2); + }); + }); + + context('given Reference Objects pointing internally only', function () { + const fixturePath = path.join(rootFixturePath, 'internal-only'); + + specify('should resolve', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + const refSet = await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + + assert.strictEqual(refSet.size, 1); + }); + }); + + context('given Reference Objects pointing externally only', function () { + const fixturePath = path.join(rootFixturePath, 'external-only'); + + specify('should resolve', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + const refSet = await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + + assert.strictEqual(refSet.size, 2); + }); + }); + + context('given Reference Objects pointing to external indirections', function () { + const fixturePath = path.join(rootFixturePath, 'external-indirections'); + + specify('should resolve', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + const refSet = await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + + assert.strictEqual(refSet.size, 4); + }); + }); + + context('given Reference Objects with external resolution disable', function () { + const fixturePath = path.join(rootFixturePath, 'ignore-external'); + + specify('should resolve', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + const refSet = await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + resolve: { external: false }, + }); + + assert.strictEqual(refSet.size, 1); + }); + }); + + context('given Reference Objects with direct circular internal reference', function () { + const fixturePath = path.join(rootFixturePath, 'direct-internal-circular'); + + specify('should throw error', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + try { + await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + } catch (e) { + assert.instanceOf(e, ResolverError); + } + }); + }); + + context('given Reference Objects with indirect circular internal reference', function () { + const fixturePath = path.join(rootFixturePath, 'indirect-internal-circular'); + + specify('should throw error', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + try { + await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + } catch (e) { + assert.instanceOf(e, ResolverError); + } + }); + }); + + context('given Reference Objects with direct circular external reference', function () { + const fixturePath = path.join(rootFixturePath, 'direct-external-circular'); + + specify('should throw error', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + try { + await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + } catch (e) { + assert.instanceOf(e, ResolverError); + } + }); + }); + + context('given Reference Objects with indirect circular external reference', function () { + const fixturePath = path.join(rootFixturePath, 'indirect-external-circular'); + + specify('should throw error', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + try { + await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + } catch (e) { + assert.instanceOf(e, ResolverError); + } + }); + }); + + context('given Reference Objects with unresolvable reference', function () { + const fixturePath = path.join(rootFixturePath, 'unresolvable-reference'); + + specify('should throw error', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + try { + await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + } catch (e) { + assert.instanceOf(e, ResolverError); + } + }); + }); + + context('given Reference Objects with invalid JSON Pointer', function () { + const fixturePath = path.join(rootFixturePath, 'invalid-pointer'); + + specify('should throw error', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + try { + await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + } catch (e) { + assert.instanceOf(e, ResolverError); + } + }); + }); + + context('given Reference Objects with resolvable circular references', function () { + const fixturePath = path.join(rootFixturePath, 'circular'); + + specify('should resolve', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + const refSet = await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + }); + + assert.strictEqual(refSet.size, 2); + }); + }); + + context('given Reference Objects and maxDepth of resolution', function () { + const fixturePath = path.join(rootFixturePath, 'max-depth'); + + specify('should throw error', async function () { + const rootFilePath = path.join(fixturePath, 'root.json'); + + try { + await resolve(rootFilePath, { + parse: { mediaType: 'application/vnd.aai.asyncapi+json;version=2.0.0' }, + resolve: { maxDepth: 2 }, + }); + assert.fail('should throw MaximumResolverDepthError'); + } catch (error) { + assert.instanceOf(error, ResolverError); + assert.instanceOf(error.cause.cause, MaximumResolverDepthError); + assert.match(error.cause.cause.message, /fixtures\/max-depth\/ex2.json"$/); + } + }); + }); + }); + }); + }); +}); From b0cb9d2b96c4e46928a794a071f2a22aa16de2ea Mon Sep 17 00:00:00 2001 From: Vladimir Gorej Date: Thu, 1 Apr 2021 16:59:43 +0200 Subject: [PATCH 2/2] fix: tests --- apidom/packages/apidom-ns-asyncapi-2-0/test/predicates.ts | 2 +- apidom/packages/apidom-ns-openapi-3-1/test/predicates.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apidom/packages/apidom-ns-asyncapi-2-0/test/predicates.ts b/apidom/packages/apidom-ns-asyncapi-2-0/test/predicates.ts index ffe52bdedd..3c654d247b 100644 --- a/apidom/packages/apidom-ns-asyncapi-2-0/test/predicates.ts +++ b/apidom/packages/apidom-ns-asyncapi-2-0/test/predicates.ts @@ -65,7 +65,7 @@ describe('predicates', function () { specify('should support duck-typing', function () { const asyncApi2_0ElementDuck = { - _storedElement: 'asyncApi2-0', + _storedElement: 'asyncApi2_0', _content: [], classes: new ArrayElement(['api']), primitive() { diff --git a/apidom/packages/apidom-ns-openapi-3-1/test/predicates.ts b/apidom/packages/apidom-ns-openapi-3-1/test/predicates.ts index 6955de720a..e54e70aa8b 100644 --- a/apidom/packages/apidom-ns-openapi-3-1/test/predicates.ts +++ b/apidom/packages/apidom-ns-openapi-3-1/test/predicates.ts @@ -61,7 +61,7 @@ describe('predicates', function () { specify('should support duck-typing', function () { const openApi3_1ElementDuck = { - _storedElement: 'openApi3-1', + _storedElement: 'openApi3_1', classes: new ArrayElement(['api']), _content: [], primitive() {