Skip to content

Commit

Permalink
feat(ns-openapi-2): add support for XML Object (#3234)
Browse files Browse the repository at this point in the history
Refs #3097
  • Loading branch information
char0n authored Oct 6, 2023
1 parent a3a96d1 commit 9c0b4f5
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/apidom-ns-openapi-2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ Only fully implemented specification objects should be checked here.
- [ ] [Tag Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-tag-object)
- [ ] [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-reference-object)
- [ ] [Schema Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-schema-object)
- [ ] [XML Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-xml-object)
- [x] [XML Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-xml-object)
- [ ] [Definitions Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-definitions-object)
- [ ] [Parameters Definitions Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-paramters-definitions-object)
- [ ] [Responses Definitions Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-responses-definitions-object)
Expand Down
56 changes: 56 additions & 0 deletions packages/apidom-ns-openapi-2/src/elements/Xml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
StringElement,
ObjectElement,
BooleanElement,
Attributes,
Meta,
} from '@swagger-api/apidom-core';

class Xml extends ObjectElement {
constructor(content?: Record<string, unknown>, meta?: Meta, attributes?: Attributes) {
super(content, meta, attributes);
this.element = 'xml';
}

get name(): StringElement | undefined {
return this.get('name');
}

set name(name: StringElement | undefined) {
this.set('name', name);
}

get namespace(): StringElement | undefined {
return this.get('namespace');
}

set namespace(namespace: StringElement | undefined) {
this.set('namespace', namespace);
}

get prefix(): StringElement | undefined {
return this.get('prefix');
}

set prefix(prefix: StringElement | undefined) {
this.set('prefix', prefix);
}

get attribute(): BooleanElement | undefined {
return this.get('attribute');
}

set attribute(attribute: BooleanElement | undefined) {
this.set('attribute', attribute);
}

get wrapped(): BooleanElement | undefined {
return this.get('wrapped');
}

set wrapped(wrapped: BooleanElement | undefined) {
this.set('wrapped', wrapped);
}
}

export default Xml;
2 changes: 2 additions & 0 deletions packages/apidom-ns-openapi-2/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export { default as refract, createRefractor } from './refractor';
export { default as specificationObj } from './refractor/specification';

export {
isXmlElement,
isSecurityDefinitionsElement,
isSecuritySchemeElement,
isScopesElement,
Expand All @@ -30,6 +31,7 @@ export { keyMap, getNodeType } from './traversal/visitor';

// OpenAPI 2.0 elements
export {
XmlElement,
SecurityDefinitionsElement,
SecuritySchemeElement,
ScopesElement,
Expand Down
2 changes: 2 additions & 0 deletions packages/apidom-ns-openapi-2/src/namespace.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NamespacePluginOptions } from '@swagger-api/apidom-core';

import XmlElement from './elements/Xml';
import SecurityDefinitionsElement from './elements/SecurityDefinitions';
import SecuritySchemeElement from './elements/SecurityScheme';
import ScopesElement from './elements/Scopes';
Expand All @@ -9,6 +10,7 @@ const openApi2 = {
namespace: (options: NamespacePluginOptions) => {
const { base } = options;

base.register('xml', XmlElement);
base.register('securityDefinitions', SecurityDefinitionsElement);
base.register('securityScheme', SecuritySchemeElement);
base.register('scopes', ScopesElement);
Expand Down
11 changes: 11 additions & 0 deletions packages/apidom-ns-openapi-2/src/predicates.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import { createPredicate } from '@swagger-api/apidom-core';

import XmlElement from './elements/Xml';
import SecurityDefinitionsElement from './elements/SecurityDefinitions';
import SecuritySchemeElement from './elements/SecurityScheme';
import SecurityRequirementElement from './elements/SecurityRequirement';
import ScopesElement from './elements/Scopes';

export const isXmlElement = createPredicate(
({ hasBasicElementProps, isElementType, primitiveEq }) => {
return (element: any) =>
element instanceof XmlElement ||
(hasBasicElementProps(element) &&
isElementType('xml', element) &&
primitiveEq('object', element));
},
);

export const isSecurityDefinitionsElement = createPredicate(
({ hasBasicElementProps, isElementType, primitiveEq }) => {
return (element: any) =>
Expand Down
3 changes: 3 additions & 0 deletions packages/apidom-ns-openapi-2/src/refractor/registration.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import XmlElement from '../elements/Xml';
import SecurityDefinitionsElement from '../elements/SecurityDefinitions';
import SecuritySchemeElement from '../elements/SecurityScheme';
import ScopesElement from '../elements/Scopes';
import SecurityRequirementElement from '../elements/SecurityRequirement';
import { createRefractor } from './index';

// register refractors specific to element types
XmlElement.refract = createRefractor(['visitors', 'document', 'objects', 'XML', '$visitor']);
SecurityDefinitionsElement.refract = createRefractor([
'visitors',
'document',
Expand All @@ -29,6 +31,7 @@ SecurityRequirementElement.refract = createRefractor([
]);

export {
XmlElement,
SecurityDefinitionsElement,
SecuritySchemeElement,
ScopesElement,
Expand Down
11 changes: 11 additions & 0 deletions packages/apidom-ns-openapi-2/src/refractor/specification.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import FallbackVisitor from './visitors/FallbackVisitor';
import XmlVisitor from './visitors/open-api-2/xml';
import SecurityDefinitionsVisitor from './visitors/open-api-2/security-definitions';
import SecuritySchemeVisitor from './visitors/open-api-2/security-scheme';
import ScopesVisitor from './visitors/open-api-2/scopes';
Expand All @@ -19,6 +20,16 @@ const specification = {
value: FallbackVisitor,
document: {
objects: {
XML: {
$visitor: XmlVisitor,
fixedFields: {
name: FallbackVisitor,
namespace: FallbackVisitor,
prefix: FallbackVisitor,
attribute: FallbackVisitor,
wrapped: FallbackVisitor,
},
},
SecurityDefinitions: {
$visitor: SecurityDefinitionsVisitor,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import stampit from 'stampit';
import { always } from 'ramda';

import XmlElement from '../../../../elements/Xml';
import FallbackVisitor from '../../FallbackVisitor';
import FixedFieldsVisitor from '../../generics/FixedFieldsVisitor';

const XmlVisitor = stampit(FixedFieldsVisitor, FallbackVisitor, {
props: {
specPath: always(['document', 'objects', 'XML']),
canSupportSpecificationExtensions: true,
},
init() {
this.element = new XmlElement();
},
});

export default XmlVisitor;
1 change: 1 addition & 0 deletions packages/apidom-ns-openapi-2/src/traversal/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const getNodeType = <T extends Element>(element: T): string | undefined =
*/

export const keyMap = {
XmlElement: ['content'],
SecurityDefinitionsElement: ['content'],
SecuritySchemeElement: ['content'],
ScopesElement: ['content'],
Expand Down
59 changes: 59 additions & 0 deletions packages/apidom-ns-openapi-2/test/predicates.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,76 @@
import { assert } from 'chai';

import {
XmlElement,
SecurityDefinitionsElement,
SecuritySchemeElement,
ScopesElement,
SecurityRequirementElement,
isXmlElement,
isSecurityDefinitionsElement,
isSecuritySchemeElement,
isScopesElement,
isSecurityRequirementElement,
} from '../src';

describe('predicates', function () {
context('isXmlElement', function () {
context('given XmlElement instance value', function () {
specify('should return true', function () {
const element = new XmlElement();

assert.isTrue(isXmlElement(element));
});
});

context('given subtype instance value', function () {
specify('should return true', function () {
// eslint-disable-next-line @typescript-eslint/naming-convention
class XmlSubElement extends XmlElement {}

assert.isTrue(isXmlElement(new XmlSubElement()));
});
});

context('given non XmlSubElement instance value', function () {
specify('should return false', function () {
assert.isFalse(isXmlElement(1));
assert.isFalse(isXmlElement(null));
assert.isFalse(isXmlElement(undefined));
assert.isFalse(isXmlElement({}));
assert.isFalse(isXmlElement([]));
assert.isFalse(isXmlElement('string'));
});
});

specify('should support duck-typing', function () {
const xmlElementDuck = {
_storedElement: 'xml',
_content: [],
primitive() {
return 'object';
},
get element() {
return this._storedElement;
},
};

const xmlElementSwan = {
_storedElement: undefined,
_content: undefined,
primitive() {
return 'swan';
},
get length() {
return 0;
},
};

assert.isTrue(isXmlElement(xmlElementDuck));
assert.isFalse(isXmlElement(xmlElementSwan));
});
});

context('isSecurityDefinitionsElement', function () {
context('given SecurityDefinitionsElement instance value', function () {
specify('should return true', function () {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`refractor elements XmlElement should refract to semantic ApiDOM tree 1`] = `
(XmlElement
(MemberElement
(StringElement)
(StringElement))
(MemberElement
(StringElement)
(StringElement))
(MemberElement
(StringElement)
(StringElement))
(MemberElement
(StringElement)
(BooleanElement))
(MemberElement
(StringElement)
(BooleanElement)))
`;
34 changes: 34 additions & 0 deletions packages/apidom-ns-openapi-2/test/refractor/elements/Xml/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { expect, assert } from 'chai';
import { sexprs, includesClasses } from '@swagger-api/apidom-core';

import { XmlElement } from '../../../../src';

describe('refractor', function () {
context('elements', function () {
context('XmlElement', function () {
specify('should refract to semantic ApiDOM tree', function () {
const xmlElement = XmlElement.refract({
name: 'animal',
namespace: 'http://swagger.io/schema/sample',
prefix: 'sample',
attribute: true,
wrapped: false,
});

expect(sexprs(xmlElement)).toMatchSnapshot();
});

specify('should support specification extensions', function () {
const xmlElement = XmlElement.refract({
name: 'animal',
'x-extension': 'extension',
}) as XmlElement;

assert.isFalse(includesClasses(['specification-extension'], xmlElement.getMember('name')));
assert.isTrue(
includesClasses(['specification-extension'], xmlElement.getMember('x-extension')),
);
});
});
});
});

0 comments on commit 9c0b4f5

Please sign in to comment.