Skip to content

Commit

Permalink
feat(OpenApi3.1-Yaml): add support for Info, License and Contact
Browse files Browse the repository at this point in the history
Refs #1
  • Loading branch information
char0n committed Oct 8, 2020
1 parent d571830 commit b4161b6
Show file tree
Hide file tree
Showing 27 changed files with 350 additions and 17 deletions.
5 changes: 1 addition & 4 deletions apidom/packages/apidom-ast/src/nodes/yaml/YamlNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import YamlAnchor from './YamlAnchor';
import { YamlStyle, YamlStyleGroup } from './YamlStyle';

interface YamlNode extends Node {
content: unknown | null;
anchor: YamlAnchor | null;
tag: YamlTag | null;
style: YamlStyle;
Expand All @@ -15,14 +14,12 @@ interface YamlNode extends Node {

const YamlNode: stampit.Stamp<YamlNode> = stampit(Node, {
props: {
content: null,
anchor: null,
tag: null,
style: null,
styleGroup: null,
},
init({ content = null, anchor = null, tag = null, style = null, styleGroup = null } = {}) {
this.content = content;
init({ anchor = null, tag = null, style = null, styleGroup = null } = {}) {
this.anchor = anchor;
this.tag = tag;
this.style = style;
Expand Down
16 changes: 14 additions & 2 deletions apidom/packages/apidom-ast/src/nodes/yaml/YamlScalar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,28 @@ import YamlNode from './YamlNode';
interface YamlScalar extends YamlNode {
type: 'scalar';
format: string | null;
content: string | null;
text: string | null;
readonly content: string | null;
}

const YamlScalar: stampit.Stamp<YamlScalar> = stampit(YamlNode, {
statics: {
type: 'scalar',
},
init({ format = null } = {}) {
props: {
text: null,
},
init({ text = null, format = null } = {}) {
this.text = text;
this.format = format;
},
methods: {
// @ts-ignore
get content() {
// @ts-ignore
return this.text;
},
},
});

export default YamlScalar;
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ const Visitor = stampit({
}

return YamlScalar({
content: '',
text: '',
position: Position({ start: surrogatePoint, end: surrogatePoint }),
tag,
anchor,
Expand Down Expand Up @@ -410,7 +410,7 @@ const Visitor = stampit({
const anchor = kindNodeToYamlAnchor(node);

return YamlScalar({
content: node.text,
text: node.text,
anchor,
tag,
position,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const ContactVisitor = stampit(ValueVisitor, FixedFieldsJsonObjectVisitor, {
specPath: always(['document', 'objects', 'Contact']),
},
init() {
this.element = new this.namespace.elements.License();
this.element = new this.namespace.elements.Contact();
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Element } from 'minim';

// eslint-disable-next-line import/prefer-default-export
export const appendMetadata = <T extends Element>(metadata: string[], element: T): T => {
metadata.forEach((md: string) => {
element.classes.push(md);
element.getMetaProperty('symbols', []).push(md);
});

return element;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ import DocumentVisitor from './visitors/DocumentVisitor';
import ErrorVisitor from './visitors/ErrorVisitor';
import { ScalarVisitor, MappingVisitor, SequenceVisitor, KindVisitor } from './visitors/generics';
import SpecificationExtensionVisitor from './visitors/SpecificationExtensionVisitor';
import OpenApi3_1Visitor from './visitors/open-api-3-1';
import OpenapiVisitor from './visitors/open-api-3-1/OpenapiVisitor';
import InfoVisitor from './visitors/open-api-3-1/info';
import InfoTitleVisitor from './visitors/open-api-3-1/info/TitleVisitor';
import InfoDescriptionVisitor from './visitors/open-api-3-1/info/DescriptionVisitor';
import InfoSummaryVisitor from './visitors/open-api-3-1/info/SummaryVisitor';
import InfoTermsOfServiceVisitor from './visitors/open-api-3-1/info/TermsOfServiceVisitor';
import InfoVersionVisitor from './visitors/open-api-3-1/info/VersionVisitor';
import ContactVisitor from './visitors/open-api-3-1/contact';
import ContactNameVisitor from './visitors/open-api-3-1/contact/NameVisitor';
import ContactUrlVisitor from './visitors/open-api-3-1/contact/UrlVisitor';
import ContactEmailVisitor from './visitors/open-api-3-1/contact/EmailVisitor';
import LicenseVisitor from './visitors/open-api-3-1/license';
import LicenseNameVisitor from './visitors/open-api-3-1/license/NameVisitor';
import LicenseIdentifierVisitor from './visitors/open-api-3-1/license/IdentifierVisitor';
import LicenseUrlVisitor from './visitors/open-api-3-1/license/UrlVisitor';

/**
* Specification object allows us to have complete control over visitors
Expand All @@ -25,6 +41,49 @@ const specification = {
},
document: {
$visitor: DocumentVisitor,
objects: {
OpenApi: {
$visitor: OpenApi3_1Visitor,
fixedFields: {
openapi: OpenapiVisitor,
info: {
$ref: '#/visitors/document/objects/Info',
},
},
},
Info: {
$visitor: InfoVisitor,
fixedFields: {
title: InfoTitleVisitor,
description: InfoDescriptionVisitor,
summary: InfoSummaryVisitor,
termsOfService: InfoTermsOfServiceVisitor,
version: InfoVersionVisitor,
contact: {
$ref: '#/visitors/document/objects/Contact',
},
license: {
$ref: '#/visitors/document/objects/License',
},
},
},
Contact: {
$visitor: ContactVisitor,
fixedFields: {
name: ContactNameVisitor,
url: ContactUrlVisitor,
email: ContactEmailVisitor,
},
},
License: {
$visitor: LicenseVisitor,
fixedFields: {
name: LicenseNameVisitor,
identifier: LicenseIdentifierVisitor,
url: LicenseUrlVisitor,
},
},
},
extension: SpecificationExtensionVisitor,
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import stampit from 'stampit';
import { YamlComment, YamlMapping, YamlScalar, YamlSequence } from 'apidom-ast';
import { YamlComment, YamlDocument, YamlMapping, YamlScalar, YamlSequence } from 'apidom-ast';

import SpecificationVisitor from './SpecificationVisitor';

const DocumentVisitor = stampit(SpecificationVisitor, {
props: {
keyMap: {
// @ts-ignore
[YamlDocument.type]: ['children'],
},
},
methods: {
scalar(scalarNode: YamlScalar) {
const element = this.nodeToElement(['scalar'], scalarNode);
this.element.content.push(element);
},

mapping(mappingNode: YamlMapping) {
const openApiElement = this.nodeToElement(['mapping'], mappingNode);
const openApiElement = this.nodeToElement(['document', 'objects', 'OpenApi'], mappingNode);
this.element.content.push(openApiElement);
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,7 @@ const StreamVisitor = stampit(SpecificationVisitor, {
}

const documentVisitor = this.retrieveVisitorInstance(['document']);
const keyMap = {
// @ts-ignore
[YamlDocument.type]: ['children'],
};
visit(documentNode, documentVisitor, {
keyMap,
// @ts-ignore
state: {
element: this.element,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Visitor = stampit({
element: null,
namespace: null,
sourceMap: false,
keyMap: null,
},
// @ts-ignore
init({ namespace = this.namespace, sourceMap = this.sourceMap } = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import stampit from 'stampit';
import { noop } from 'ramda-adjunct';
import { YamlKeyValuePair, YamlMapping } from 'apidom-ast';
import SpecificationVisitor from '../SpecificationVisitor';
import { isOpenApiExtension } from '../../predicates';
import { visit } from '..';

const FixedFieldsYamlMappingVisitor = stampit(SpecificationVisitor, {
props: {
specPath: noop,
ignoredFields: [],
keyMap: {
// @ts-ignore
[YamlMapping.type]: ['children'],
},
canSupportSpecificationExtensions: true,
},
init({
// @ts-ignore
specPath = this.specPath,
// @ts-ignore
ignoredFields = this.ignoredFields,
// @ts-ignore
canSupportSpecificationExtensions = this.canSupportSpecificationExtensions,
} = {}) {
this.specPath = specPath;
this.ignoredFields = ignoredFields;
this.canSupportSpecificationExtensions = canSupportSpecificationExtensions;
},
methods: {
mapping(mappingNode: YamlMapping) {
this.maybeAddSourceMap(mappingNode, this.element);
},

keyValuePair(keyValuePairNode: YamlKeyValuePair) {
const specPath = this.specPath(keyValuePairNode);
const fields = this.retrieveFixedFields(specPath);
const { MemberElement } = this.namespace.elements.Element.prototype;

const { key: keyNode, value: valueNode } = keyValuePairNode;
const keyName = keyNode.content;

if (fields.includes(keyName) && !this.ignoredFields.includes(keyName)) {
const visitor = this.retrieveVisitorInstance([...specPath, 'fixedFields', keyName]);
const keyElement = new this.namespace.elements.String(keyName);

visit(keyValuePairNode.value, visitor);

const memberElement = this.maybeAddSourceMap(
keyValuePairNode,
new MemberElement(this.maybeAddSourceMap(keyNode, keyElement), visitor.element),
);
memberElement.classes.push('fixedField');
this.element.content.push(memberElement);
} else if (
this.canSupportSpecificationExtensions &&
isOpenApiExtension({}, keyValuePairNode)
) {
const visitor = this.retrieveVisitorInstance(['document', 'extension']);
visit(keyValuePairNode, visitor);
this.element.content.push(visitor.element);
} else if (!this.ignoredFields.includes(keyName)) {
const keyElement = new this.namespace.elements.String(keyName);
const memberElement = this.maybeAddSourceMap(
keyValuePairNode,
new MemberElement(
this.maybeAddSourceMap(keyNode, keyElement),
this.nodeToElement(['kind'], valueNode),
),
);
this.element.content.push(memberElement);
}
},
},
});

export default FixedFieldsYamlMappingVisitor;
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { propOr } from 'ramda';
import {
YamlStream,
YamlDocument,
Expand Down Expand Up @@ -29,6 +30,9 @@ const keyMapDefault = {

// @ts-ignore
export const visit = (root, visitor, { keyMap = keyMapDefault, ...rest } = {}) => {
// if visitor is associated with the keymap, we prefer this visitor keymap
const effectiveKeyMap = propOr(keyMap, 'keyMap', visitor);

// @ts-ignore
return astVisit(root, visitor, { ...rest, keyMap });
return astVisit(root, visitor, { ...rest, keyMap: effectiveKeyMap });
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import stampit from 'stampit';
import { YamlScalar } from 'apidom-ast';

import { BREAK } from '..';
import SpecificationVisitor from '../SpecificationVisitor';
import { KindVisitor } from '../generics';

const OpenapiVisitor = stampit(KindVisitor, SpecificationVisitor, {
methods: {
scalar(scalarNode: YamlScalar) {
const openapiElement = new this.namespace.elements.Openapi(scalarNode.content);
this.element = this.maybeAddSourceMap(scalarNode, openapiElement);
return BREAK;
},
},
});

export default OpenapiVisitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import stampit from 'stampit';
import { KindVisitor } from '../../generics';

const EmailVisitor = stampit(KindVisitor);

export default EmailVisitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import stampit from 'stampit';

import { KindVisitor } from '../../generics';

const NameVisitor = stampit(KindVisitor);

export default NameVisitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import stampit from 'stampit';

import { KindVisitor } from '../../generics';

const UrlVisitor = stampit(KindVisitor);

export default UrlVisitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import stampit from 'stampit';
import { always } from 'ramda';

import FixedFieldsYamlMappingVisitor from '../../generics/FixedFieldsYamlMappingVisitor';
import { KindVisitor } from '../../generics';

const ContactVisitor = stampit(KindVisitor, FixedFieldsYamlMappingVisitor, {
props: {
specPath: always(['document', 'objects', 'Contact']),
},
init() {
this.element = new this.namespace.elements.Contact();
},
});

export default ContactVisitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import stampit from 'stampit';
import { always } from 'ramda';

import { KindVisitor } from '../generics';
import FixedFieldsYamlMappingVisitor from '../generics/FixedFieldsYamlMappingVisitor';

const OpenApi3_1Visitor = stampit(KindVisitor, FixedFieldsYamlMappingVisitor, {
props: {
specPath: always(['document', 'objects', 'OpenApi']),
},
init() {
this.element = new this.namespace.elements.OpenApi3_1();
},
});

export default OpenApi3_1Visitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import stampit from 'stampit';

import { KindVisitor } from '../../generics';

const DescriptionVisitor = stampit(KindVisitor);

export default DescriptionVisitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import stampit from 'stampit';

import { KindVisitor } from '../../generics';

const SummaryVisitor = stampit(KindVisitor);

export default SummaryVisitor;
Loading

0 comments on commit b4161b6

Please sign in to comment.