diff --git a/packages/apidom-ns-openapi-2/src/refractor/index.ts b/packages/apidom-ns-openapi-2/src/refractor/index.ts index 2f2d2ffcb..2431ee8a3 100644 --- a/packages/apidom-ns-openapi-2/src/refractor/index.ts +++ b/packages/apidom-ns-openapi-2/src/refractor/index.ts @@ -17,6 +17,7 @@ const refract = ( { specPath = ['visitors', 'document', 'objects', 'Swagger', '$visitor'], plugins = [] } = {}, ): T => { const element = baseRefract(value); + const resolvedSpec = dereference(specification); /** @@ -24,8 +25,8 @@ const refract = ( * We don't allow consumers to hook into this translation. * Though we allow consumers to define their onw plugins on already transformed ApiDOM. */ - const RootVistorClass = path(specPath, resolvedSpec) as typeof VisitorClass; - const rootVisitor = new RootVistorClass({ specObj: resolvedSpec }); + const RootVisitorClass = path(specPath, resolvedSpec) as typeof VisitorClass; + const rootVisitor = new RootVisitorClass({ specObj: resolvedSpec }); visit(element, rootVisitor); diff --git a/packages/apidom-ns-openapi-2/src/refractor/visitors/Visitor.ts b/packages/apidom-ns-openapi-2/src/refractor/visitors/Visitor.ts index 399a27eb8..97a87e3c8 100644 --- a/packages/apidom-ns-openapi-2/src/refractor/visitors/Visitor.ts +++ b/packages/apidom-ns-openapi-2/src/refractor/visitors/Visitor.ts @@ -1,4 +1,4 @@ -import { Element, hasElementSourceMap } from '@swagger-api/apidom-core'; +import { Element, ObjectElement, hasElementSourceMap, deepmerge } from '@swagger-api/apidom-core'; export interface VisitorOptions {} @@ -9,13 +9,20 @@ class Visitor { Object.assign(this, options); } - // eslint-disable-next-line class-methods-use-this + /* eslint-disable class-methods-use-this, no-param-reassign */ public copyMetaAndAttributes(from: Element, to: Element) { - // copy sourcemaps - if (hasElementSourceMap(from)) { - to.meta.set('sourceMap', from.meta.get('sourceMap')); + if (from.meta.length > 0 || to.meta.length > 0) { + to.meta = deepmerge(to.meta, from.meta) as ObjectElement; + if (hasElementSourceMap(from)) { + // avoid deep merging of source maps + to.meta.set('sourceMap', from.meta.get('sourceMap')); + } + } + if (from.attributes.length > 0 || from.meta.length > 0) { + to.attributes = deepmerge(to.attributes, from.attributes) as ObjectElement; // eslint-disable-line no-param-reassign } } + /* eslint-enable- class-methods-use-this, no-param-reassign */ } export default Visitor; diff --git a/packages/apidom-ns-openapi-2/test/refractor/elements/Contact/__snapshots__/index.ts.snap b/packages/apidom-ns-openapi-2/test/refractor/elements/Contact/__snapshots__/index.ts.snap index ba97c975e..0caad520c 100644 --- a/packages/apidom-ns-openapi-2/test/refractor/elements/Contact/__snapshots__/index.ts.snap +++ b/packages/apidom-ns-openapi-2/test/refractor/elements/Contact/__snapshots__/index.ts.snap @@ -1,5 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`refractor elements ContactElement given generic ApiDOM element should refract to semantic ApiDOM tree 1`] = ` +(ContactElement + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement))) +`; + exports[`refractor elements ContactElement should refract to semantic ApiDOM tree 1`] = ` (ContactElement (MemberElement diff --git a/packages/apidom-ns-openapi-2/test/refractor/elements/Contact/index.ts b/packages/apidom-ns-openapi-2/test/refractor/elements/Contact/index.ts index 2ebcd9bcf..9d288e51a 100644 --- a/packages/apidom-ns-openapi-2/test/refractor/elements/Contact/index.ts +++ b/packages/apidom-ns-openapi-2/test/refractor/elements/Contact/index.ts @@ -1,5 +1,5 @@ import { assert, expect } from 'chai'; -import { includesClasses, sexprs } from '@swagger-api/apidom-core'; +import { includesClasses, sexprs, ObjectElement } from '@swagger-api/apidom-core'; import { ContactElement } from '../../../../src'; @@ -16,6 +16,36 @@ describe('refractor', function () { expect(sexprs(contactElement)).toMatchSnapshot(); }); + context('given generic ApiDOM element', function () { + let contactElement: ContactElement; + + beforeEach(function () { + contactElement = ContactElement.refract( + new ObjectElement( + { + name: 'API Support', + url: 'https://www.example.com/support', + email: 'support@example.com', + }, + { meta: true }, + { attr: true }, + ), + ) as ContactElement; + }); + + specify('should refract to semantic ApiDOM tree', function () { + expect(sexprs(contactElement)).toMatchSnapshot(); + }); + + specify('should retain attributes', function () { + assert.isTrue(contactElement.attributes.get('attr').equals(true)); + }); + + specify('should retain meta', function () { + assert.isTrue(contactElement.meta.get('meta').equals(true)); + }); + }); + specify('should support specification extensions', function () { const contactElement = ContactElement.refract({ name: 'API support', diff --git a/packages/apidom-ns-openapi-3-0/src/refractor/index.ts b/packages/apidom-ns-openapi-3-0/src/refractor/index.ts index 2085f9e41..ac5b600d3 100644 --- a/packages/apidom-ns-openapi-3-0/src/refractor/index.ts +++ b/packages/apidom-ns-openapi-3-0/src/refractor/index.ts @@ -24,8 +24,8 @@ const refract = ( * We don't allow consumers to hook into this translation. * Though we allow consumers to define their onw plugins on already transformed ApiDOM. */ - const RootVistorClass = path(specPath, resolvedSpec) as typeof VisitorClass; - const rootVisitor = new RootVistorClass({ specObj: resolvedSpec }); + const RootVisitorClass = path(specPath, resolvedSpec) as typeof VisitorClass; + const rootVisitor = new RootVisitorClass({ specObj: resolvedSpec }); visit(element, rootVisitor);