Skip to content

Commit

Permalink
feat(ns-openapi-2): add support for License Object (#3244)
Browse files Browse the repository at this point in the history
Refs #3097
  • Loading branch information
char0n authored Oct 10, 2023
1 parent 974201b commit a2737c5
Show file tree
Hide file tree
Showing 12 changed files with 167 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 @@ -187,7 +187,7 @@ Only fully implemented specification objects should be checked here.
- [ ] [Swagger Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-swagger-object)
- [ ] [Info Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-info-object)
- [x] [Contact Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-contact-object)
- [ ] [License Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-license-object)
- [x] [License Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-license-object)
- [ ] [Paths Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-paths-object)
- [ ] [Path Item Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-path-item-object)
- [ ] [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-operation-object)
Expand Down
26 changes: 26 additions & 0 deletions packages/apidom-ns-openapi-2/src/elements/License.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { StringElement, ObjectElement, Attributes, Meta } from '@swagger-api/apidom-core';

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

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

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

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

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

export default License;
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 {
isLicenseElement,
isContactElement,
isExternalDocumentationElement,
isXmlElement,
Expand All @@ -33,6 +34,7 @@ export { keyMap, getNodeType } from './traversal/visitor';

// OpenAPI 2.0 elements
export {
LicenseElement,
ContactElement,
ExternalDocumentationElement,
XmlElement,
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 LicenseElement from './elements/License';
import ContactElement from './elements/Contact';
import ExternalDocumentation from './elements/ExternalDocumentation';
import XmlElement from './elements/Xml';
Expand All @@ -12,6 +13,7 @@ const openApi2 = {
namespace: (options: NamespacePluginOptions) => {
const { base } = options;

base.register('license', LicenseElement);
base.register('contact', ContactElement);
base.register('externalDocumentation', ExternalDocumentation);
base.register('xml', XmlElement);
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,5 +1,6 @@
import { createPredicate } from '@swagger-api/apidom-core';

import LicenseElement from './elements/License';
import ContactElement from './elements/Contact';
import ExternalDocumentation from './elements/ExternalDocumentation';
import XmlElement from './elements/Xml';
Expand All @@ -8,6 +9,16 @@ import SecuritySchemeElement from './elements/SecurityScheme';
import SecurityRequirementElement from './elements/SecurityRequirement';
import ScopesElement from './elements/Scopes';

export const isLicenseElement = createPredicate(
({ hasBasicElementProps, isElementType, primitiveEq }) => {
return (element: any) =>
element instanceof LicenseElement ||
(hasBasicElementProps(element) &&
isElementType('license', element) &&
primitiveEq('object', element));
},
);

export const isContactElement = createPredicate(
({ hasBasicElementProps, isElementType, primitiveEq }) => {
return (element: any) =>
Expand Down
9 changes: 9 additions & 0 deletions packages/apidom-ns-openapi-2/src/refractor/registration.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import LicenseElement from '../elements/License';
import ContactElement from '../elements/Contact';
import ExternalDocumentationElement from '../elements/ExternalDocumentation';
import XmlElement from '../elements/Xml';
Expand All @@ -8,6 +9,13 @@ import SecurityRequirementElement from '../elements/SecurityRequirement';
import { createRefractor } from './index';

// register refractors specific to element types
LicenseElement.refract = createRefractor([
'visitors',
'document',
'objects',
'License',
'$visitor',
]);
ContactElement.refract = createRefractor([
'visitors',
'document',
Expand Down Expand Up @@ -47,6 +55,7 @@ SecurityRequirementElement.refract = createRefractor([
]);

export {
LicenseElement,
ContactElement,
ExternalDocumentationElement,
XmlElement,
Expand Down
8 changes: 8 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 LicenseVisitor from './visitors/open-api-2/license';
import ContactVisitor from './visitors/open-api-2/contact';
import ExternalDocumentationElement from './visitors/open-api-2/external-documentation';
import XmlVisitor from './visitors/open-api-2/xml';
Expand All @@ -22,6 +23,13 @@ const specification = {
value: FallbackVisitor,
document: {
objects: {
License: {
$visitor: LicenseVisitor,
fixedFields: {
name: FallbackVisitor,
url: FallbackVisitor,
},
},
Contact: {
$visitor: ContactVisitor,
fixedFields: {
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 LicenseElement from '../../../../elements/License';
import FallbackVisitor from '../../FallbackVisitor';
import FixedFieldsVisitor from '../../generics/FixedFieldsVisitor';

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

export default LicenseVisitor;
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 = {
LicenseElement: ['content'],
ContactElement: ['content'],
ExternalDocumentationElement: ['content'],
XmlElement: ['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,13 +1,15 @@
import { assert } from 'chai';

import {
LicenseElement,
ContactElement,
ExternalDocumentationElement,
XmlElement,
SecurityDefinitionsElement,
SecuritySchemeElement,
ScopesElement,
SecurityRequirementElement,
isLicenseElement,
isContactElement,
isExternalDocumentationElement,
isXmlElement,
Expand All @@ -18,6 +20,63 @@ import {
} from '../src';

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

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

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

assert.isTrue(isLicenseElement(new LicenseSubElement()));
});
});

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

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

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

assert.isTrue(isLicenseElement(licenseElementDuck));
assert.isFalse(isLicenseElement(licenseElementSwan));
});
});

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

exports[`refractor elements LicenseElement should refract to semantic ApiDOM tree 1`] = `
(LicenseElement
(MemberElement
(StringElement)
(StringElement))
(MemberElement
(StringElement)
(StringElement)))
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expect } from 'chai';
import { sexprs } from '@swagger-api/apidom-core';

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

describe('refractor', function () {
context('elements', function () {
context('LicenseElement', function () {
specify('should refract to semantic ApiDOM tree', function () {
const licenseElement = LicenseElement.refract({
name: 'Apache 2.0',
url: 'http://www.apache.org/licenses/LICENSE-2.0.html',
});

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

0 comments on commit a2737c5

Please sign in to comment.