Skip to content

Commit b243110

Browse files
authored
fix(ns-openapi-2): retain meta & attributes during refracting (#3844)
This change is specific to cases when semantic ApiDOM is refractored from generic ApiDOM. Refs #3842
1 parent 6a9685b commit b243110

File tree

5 files changed

+61
-10
lines changed

5 files changed

+61
-10
lines changed

packages/apidom-ns-openapi-2/src/refractor/index.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ const refract = <T extends Element>(
1717
{ specPath = ['visitors', 'document', 'objects', 'Swagger', '$visitor'], plugins = [] } = {},
1818
): T => {
1919
const element = baseRefract(value);
20+
2021
const resolvedSpec = dereference(specification);
2122

2223
/**
2324
* This is where generic ApiDOM becomes semantic (namespace applied).
2425
* We don't allow consumers to hook into this translation.
2526
* Though we allow consumers to define their onw plugins on already transformed ApiDOM.
2627
*/
27-
const RootVistorClass = path(specPath, resolvedSpec) as typeof VisitorClass;
28-
const rootVisitor = new RootVistorClass({ specObj: resolvedSpec });
28+
const RootVisitorClass = path(specPath, resolvedSpec) as typeof VisitorClass;
29+
const rootVisitor = new RootVisitorClass({ specObj: resolvedSpec });
2930

3031
visit(element, rootVisitor);
3132

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Element, hasElementSourceMap } from '@swagger-api/apidom-core';
1+
import { Element, ObjectElement, hasElementSourceMap, deepmerge } from '@swagger-api/apidom-core';
22

33
export interface VisitorOptions {}
44

@@ -9,13 +9,20 @@ class Visitor {
99
Object.assign(this, options);
1010
}
1111

12-
// eslint-disable-next-line class-methods-use-this
12+
/* eslint-disable class-methods-use-this, no-param-reassign */
1313
public copyMetaAndAttributes(from: Element, to: Element) {
14-
// copy sourcemaps
15-
if (hasElementSourceMap(from)) {
16-
to.meta.set('sourceMap', from.meta.get('sourceMap'));
14+
if (from.meta.length > 0 || to.meta.length > 0) {
15+
to.meta = deepmerge(to.meta, from.meta) as ObjectElement;
16+
if (hasElementSourceMap(from)) {
17+
// avoid deep merging of source maps
18+
to.meta.set('sourceMap', from.meta.get('sourceMap'));
19+
}
20+
}
21+
if (from.attributes.length > 0 || from.meta.length > 0) {
22+
to.attributes = deepmerge(to.attributes, from.attributes) as ObjectElement; // eslint-disable-line no-param-reassign
1723
}
1824
}
25+
/* eslint-enable- class-methods-use-this, no-param-reassign */
1926
}
2027

2128
export default Visitor;

packages/apidom-ns-openapi-2/test/refractor/elements/Contact/__snapshots__/index.ts.snap

+13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`refractor elements ContactElement given generic ApiDOM element should refract to semantic ApiDOM tree 1`] = `
4+
(ContactElement
5+
(MemberElement
6+
(StringElement)
7+
(StringElement))
8+
(MemberElement
9+
(StringElement)
10+
(StringElement))
11+
(MemberElement
12+
(StringElement)
13+
(StringElement)))
14+
`;
15+
316
exports[`refractor elements ContactElement should refract to semantic ApiDOM tree 1`] = `
417
(ContactElement
518
(MemberElement

packages/apidom-ns-openapi-2/test/refractor/elements/Contact/index.ts

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { assert, expect } from 'chai';
2-
import { includesClasses, sexprs } from '@swagger-api/apidom-core';
2+
import { includesClasses, sexprs, ObjectElement } from '@swagger-api/apidom-core';
33

44
import { ContactElement } from '../../../../src';
55

@@ -16,6 +16,36 @@ describe('refractor', function () {
1616
expect(sexprs(contactElement)).toMatchSnapshot();
1717
});
1818

19+
context('given generic ApiDOM element', function () {
20+
let contactElement: ContactElement;
21+
22+
beforeEach(function () {
23+
contactElement = ContactElement.refract(
24+
new ObjectElement(
25+
{
26+
name: 'API Support',
27+
url: 'https://www.example.com/support',
28+
29+
},
30+
{ meta: true },
31+
{ attr: true },
32+
),
33+
) as ContactElement;
34+
});
35+
36+
specify('should refract to semantic ApiDOM tree', function () {
37+
expect(sexprs(contactElement)).toMatchSnapshot();
38+
});
39+
40+
specify('should retain attributes', function () {
41+
assert.isTrue(contactElement.attributes.get('attr').equals(true));
42+
});
43+
44+
specify('should retain meta', function () {
45+
assert.isTrue(contactElement.meta.get('meta').equals(true));
46+
});
47+
});
48+
1949
specify('should support specification extensions', function () {
2050
const contactElement = ContactElement.refract({
2151
name: 'API support',

packages/apidom-ns-openapi-3-0/src/refractor/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ const refract = <T extends Element>(
2424
* We don't allow consumers to hook into this translation.
2525
* Though we allow consumers to define their onw plugins on already transformed ApiDOM.
2626
*/
27-
const RootVistorClass = path(specPath, resolvedSpec) as typeof VisitorClass;
28-
const rootVisitor = new RootVistorClass({ specObj: resolvedSpec });
27+
const RootVisitorClass = path(specPath, resolvedSpec) as typeof VisitorClass;
28+
const rootVisitor = new RootVisitorClass({ specObj: resolvedSpec });
2929

3030
visit(element, rootVisitor);
3131

0 commit comments

Comments
 (0)