Skip to content

Commit

Permalink
feat(ns-openapi-2): add support for PathItem Object (#3307)
Browse files Browse the repository at this point in the history
Refs #3097
  • Loading branch information
char0n authored Oct 20, 2023
1 parent e527222 commit 9ad49be
Show file tree
Hide file tree
Showing 16 changed files with 410 additions and 3 deletions.
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 @@ -189,7 +189,7 @@ Only fully implemented specification objects should be checked here.
- [x] [Contact Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-contact-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)
- [x] [Path Item Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-path-item-object)
- [x] [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-operation-object)
- [x] [External Documentation Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-external-documentation-object)
- [x] [Parameter Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-parameter-object)
Expand Down
90 changes: 90 additions & 0 deletions packages/apidom-ns-openapi-2/src/elements/PathItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {
StringElement,
ObjectElement,
ArrayElement,
Attributes,
Meta,
} from '@swagger-api/apidom-core';

import OperationElement from './Operation';

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

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

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

get GET(): OperationElement {
return this.get('get');
}

set GET(operation: OperationElement | undefined) {
this.set('GET', operation);
}

get PUT(): OperationElement {
return this.get('put');
}

set PUT(operation: OperationElement | undefined) {
this.set('PUT', operation);
}

get POST(): OperationElement {
return this.get('post');
}

set POST(operation: OperationElement | undefined) {
this.set('POST', operation);
}

get DELETE(): OperationElement {
return this.get('delete');
}

set DELETE(operation: OperationElement | undefined) {
this.set('DELETE', operation);
}

get OPTIONS(): OperationElement {
return this.get('options');
}

set OPTIONS(operation: OperationElement | undefined) {
this.set('OPTIONS', operation);
}

get HEAD(): OperationElement {
return this.get('head');
}

set HEAD(operation: OperationElement | undefined) {
this.set('HEAD', operation);
}

get PATCH(): OperationElement {
return this.get('patch');
}

set PATCH(operation: OperationElement | undefined) {
this.set('PATCH', operation);
}

get parameters(): ArrayElement {
return this.get('parameters');
}

set parameters(parameters: ArrayElement | undefined) {
this.set('parameters', parameters);
}
}

export default PathItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ArrayElement, Attributes, Meta } from '@swagger-api/apidom-core';

class PathItemParameters extends ArrayElement {
static primaryClass = 'path-item-parameters';

constructor(content?: Array<unknown>, meta?: Meta, attributes?: Attributes) {
super(content, meta, attributes);
this.classes.push(PathItemParameters.primaryClass);
this.classes.push('parameters');
}
}

export default PathItemParameters;
9 changes: 9 additions & 0 deletions packages/apidom-ns-openapi-2/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export {
isInfoElement,
isLicenseElement,
isContactElement,
isPathItemElement,
isOperationElement,
isExternalDocumentationElement,
isParameterElement,
Expand Down Expand Up @@ -56,6 +57,7 @@ export {
InfoElement,
LicenseElement,
ContactElement,
PathItemElement,
OperationElement,
ExternalDocumentationElement,
ParameterElement,
Expand All @@ -78,3 +80,10 @@ export {
SecurityRequirementElement,
} from './refractor/registration';
// NCE types
export { default as OperationConsumesElement } from './elements/nces/OperationConsumes';
export { default as OperationParametersElement } from './elements/nces/OperationParameters';
export { default as OperationProducesElement } from './elements/nces/OperationProduces';
export { default as OperationSchemesElement } from './elements/nces/OperationSchemes';
export { default as OperationSecurityElement } from './elements/nces/OperationSecurity';
export { default as OperationTagsElement } from './elements/nces/OperationTags';
export { default as PathItemParametersElement } from './elements/nces/PathItemParameters';
2 changes: 2 additions & 0 deletions packages/apidom-ns-openapi-2/src/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { NamespacePluginOptions } from '@swagger-api/apidom-core';
import InfoElement from './elements/Info';
import LicenseElement from './elements/License';
import ContactElement from './elements/Contact';
import PathItemElement from './elements/PathItem';
import OperationElement from './elements/Operation';
import ExternalDocumentation from './elements/ExternalDocumentation';
import ParameterElement from './elements/Parameter';
Expand Down Expand Up @@ -31,6 +32,7 @@ const openApi2 = {
base.register('info', InfoElement);
base.register('license', LicenseElement);
base.register('contact', ContactElement);
base.register('pathItem', PathItemElement);
base.register('operation', OperationElement);
base.register('externalDocumentation', ExternalDocumentation);
base.register('parameter', ParameterElement);
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
Expand Up @@ -3,6 +3,7 @@ import { createPredicate } from '@swagger-api/apidom-core';
import InfoElement from './elements/Info';
import LicenseElement from './elements/License';
import ContactElement from './elements/Contact';
import PathItemElement from './elements/PathItem';
import OperationElement from './elements/Operation';
import ExternalDocumentationElement from './elements/ExternalDocumentation';
import ParameterElement from './elements/Parameter';
Expand Down Expand Up @@ -54,6 +55,16 @@ export const isContactElement = createPredicate(
},
);

export const isPathItemElement = createPredicate(
({ hasBasicElementProps, isElementType, primitiveEq }) => {
return (element: unknown): element is PathItemElement =>
element instanceof PathItemElement ||
(hasBasicElementProps(element) &&
isElementType('pathItem', element) &&
primitiveEq('object', element));
},
);

export const isOperationElement = createPredicate(
({ hasBasicElementProps, isElementType, primitiveEq }) => {
return (element: unknown): element is OperationElement =>
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,6 +1,7 @@
import InfoElement from '../elements/Info';
import LicenseElement from '../elements/License';
import ContactElement from '../elements/Contact';
import PathItemElement from '../elements/PathItem';
import OperationElement from '../elements/Operation';
import ExternalDocumentationElement from '../elements/ExternalDocumentation';
import ParameterElement from '../elements/Parameter';
Expand Down Expand Up @@ -39,6 +40,13 @@ ContactElement.refract = createRefractor([
'Contact',
'$visitor',
]);
PathItemElement.refract = createRefractor([
'visitors',
'document',
'objects',
'PathItem',
'$visitor',
]);
OperationElement.refract = createRefractor([
'visitors',
'document',
Expand Down Expand Up @@ -148,6 +156,7 @@ export {
InfoElement,
LicenseElement,
ContactElement,
PathItemElement,
OperationElement,
ExternalDocumentationElement,
ParameterElement,
Expand Down
31 changes: 31 additions & 0 deletions packages/apidom-ns-openapi-2/src/refractor/specification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import InfoVisitor from './visitors/open-api-2/info';
import InfoVersionVisitor from './visitors/open-api-2/info/VersionVisitor';
import LicenseVisitor from './visitors/open-api-2/license';
import ContactVisitor from './visitors/open-api-2/contact';
import PathItemVisitor from './visitors/open-api-2/path-item';
import PathItem$RefVisitor from './visitors/open-api-2/path-item/$RefVisitor';
import PathItemParametersVisitor from './visitors/open-api-2/path-item/ParametersVisitor';
import OperationVisitor from './visitors/open-api-2/operation';
import OperationTagsVisitor from './visitors/open-api-2/operation/TagsVisitor';
import OperationConsumesVisitor from './visitors/open-api-2/operation/ConsumesVisitor';
Expand Down Expand Up @@ -92,6 +95,34 @@ const specification = {
email: { $ref: '#/visitors/value' },
},
},
PathItem: {
$visitor: PathItemVisitor,
fixedFields: {
$ref: PathItem$RefVisitor,
get: {
$ref: '#/visitors/document/objects/Operation',
},
put: {
$ref: '#/visitors/document/objects/Operation',
},
post: {
$ref: '#/visitors/document/objects/Operation',
},
delete: {
$ref: '#/visitors/document/objects/Operation',
},
options: {
$ref: '#/visitors/document/objects/Operation',
},
head: {
$ref: '#/visitors/document/objects/Operation',
},
patch: {
$ref: '#/visitors/document/objects/Operation',
},
parameters: PathItemParametersVisitor,
},
},
Operation: {
$visitor: OperationVisitor,
fixedFields: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ const AlternatingVisitor = stampit(SpecificationVisitor, {
methods: {
enter(element: Element) {
const functions = this.alternator.map(
({ predicate, specPath }: { predicate: (element: any) => boolean; specPath: string[] }) =>
ifElse(predicate, always(specPath), stubUndefined),
({
predicate,
specPath,
}: {
predicate: (element: unknown) => boolean;
specPath: string[];
}) => ifElse(predicate, always(specPath), stubUndefined),
);
const specPath = dispatch(functions)(element);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import stampit from 'stampit';
import { StringElement, BREAK, cloneDeep } from '@swagger-api/apidom-core';

import FallbackVisitor from '../../FallbackVisitor';

const $RefVisitor = stampit(FallbackVisitor, {
methods: {
StringElement(stringElement: StringElement) {
this.element = cloneDeep(stringElement);
this.element.classes.push('reference-value');

return BREAK;
},
},
});

export default $RefVisitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import stampit from 'stampit';
import { ArrayElement, Element, BREAK } from '@swagger-api/apidom-core';

import { isReferenceLikeElement } from '../../../predicates';
import { isReferenceElement } from '../../../../predicates';
import PathItemParametersElement from '../../../../elements/nces/PathItemParameters';
import FallbackVisitor from '../../FallbackVisitor';
import SpecificationVisitor from '../../SpecificationVisitor';

const ParametersVisitor = stampit(SpecificationVisitor, FallbackVisitor, {
init() {
this.element = new PathItemParametersElement();
},
methods: {
ArrayElement(arrayElement: ArrayElement) {
arrayElement.forEach((item: Element): void => {
const specPath = isReferenceLikeElement(item)
? ['document', 'objects', 'Reference']
: ['document', 'objects', 'Parameter'];
const element = this.toRefractedElement(specPath, item);

if (isReferenceElement(element)) {
element.setMetaProperty('referenced-element', 'parameter');
}

this.element.push(element);
});

this.copyMetaAndAttributes(arrayElement, this.element);

return BREAK;
},
},
});

export default ParametersVisitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import stampit from 'stampit';
import { always } from 'ramda';
import {
StringElement,
ObjectElement,
isStringElement,
cloneDeep,
toValue,
} from '@swagger-api/apidom-core';

import PathItemElement from '../../../../elements/PathItem';
import OperationElement from '../../../../elements/Operation';
import { isOperationElement } from '../../../../predicates';
import FixedFieldsVisitor from '../../generics/FixedFieldsVisitor';
import FallbackVisitor from '../../FallbackVisitor';

const PathItemVisitor = stampit(FixedFieldsVisitor, FallbackVisitor, {
props: {
specPath: always(['document', 'objects', 'PathItem']),
},
init() {
this.element = new PathItemElement();
},
methods: {
ObjectElement(objectElement: ObjectElement) {
// @ts-ignore
const result = FixedFieldsVisitor.compose.methods.ObjectElement.call(this, objectElement);

// decorate Operation elements with HTTP method
this.element
.filter(isOperationElement)
.forEach((operationElement: OperationElement, httpMethodElementCI: StringElement) => {
const httpMethodElementCS = cloneDeep(httpMethodElementCI);
httpMethodElementCS.content = toValue(httpMethodElementCS).toUpperCase();
operationElement.setMetaProperty('http-method', httpMethodElementCS);
});

// mark this PathItemElement with reference metadata
if (isStringElement(this.element.$ref)) {
this.element.classes.push('reference-element');
}

return result;
},
},
});

export default PathItemVisitor;
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 @@ -22,6 +22,7 @@ export const keyMap = {
InfoElement: ['content'],
LicenseElement: ['content'],
ContactElement: ['content'],
PathItemElement: ['content'],
OperationElement: ['content'],
ExternalDocumentationElement: ['content'],
ParameterElement: ['content'],
Expand Down
Loading

0 comments on commit 9ad49be

Please sign in to comment.