Skip to content

Commit

Permalink
feat(ns-openapi-2): add support for Schema Object (#3273)
Browse files Browse the repository at this point in the history
Refs #3097
  • Loading branch information
char0n authored Oct 17, 2023
1 parent b824b56 commit 6e046ac
Show file tree
Hide file tree
Showing 18 changed files with 651 additions and 41 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 @@ -201,7 +201,7 @@ Only fully implemented specification objects should be checked here.
- [x] [Header Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-header-object)
- [x] [Tag Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-tag-object)
- [x] [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)
- [x] [Schema Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#user-content-schema-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)
Expand Down
22 changes: 0 additions & 22 deletions packages/apidom-ns-openapi-2/src/elements/Header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,28 +216,6 @@ class Header extends JSONSchemaElement {
throw new UnsupportedOperationError('title setter in Header class is not not supported.');
}

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

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

/**
* Semantic validation with "format"
*
* URI: https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#section-7
*/

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

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

/**
* JSON Hyper-Schema
*
Expand Down
14 changes: 0 additions & 14 deletions packages/apidom-ns-openapi-2/src/elements/Items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,20 +219,6 @@ class Items extends JSONSchemaElement {
throw new UnsupportedOperationError('description setter in Items class is not not supported.');
}

/**
* Semantic validation with "format"
*
* URI: https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#section-7
*/

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

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

/**
* JSON Hyper-Schema
*
Expand Down
148 changes: 146 additions & 2 deletions packages/apidom-ns-openapi-2/src/elements/Schema.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,156 @@
import { Attributes, Meta } from '@swagger-api/apidom-core';
import { JSONSchemaElement } from '@swagger-api/apidom-ns-json-schema-draft-4';
import {
Attributes,
Meta,
ArrayElement,
BooleanElement,
ObjectElement,
StringElement,
} from '@swagger-api/apidom-core';
import { UnsupportedOperationError } from '@swagger-api/apidom-error';
import {
JSONReferenceElement,
JSONSchemaElement,
MediaElement,
} from '@swagger-api/apidom-ns-json-schema-draft-4';

/* eslint-disable class-methods-use-this */
class Schema extends JSONSchemaElement {
constructor(content?: Record<string, unknown>, meta?: Meta, attributes?: Attributes) {
super(content, meta, attributes);
this.element = 'schema';
this.classes.push('json-schema-draft-4');
}

/**
* Core vocabulary
*
* URI: https://tools.ietf.org/html/draft-wright-json-schema-00
*/
get idProp(): StringElement | undefined {
throw new UnsupportedOperationError('idProp getter in Schema class is not not supported.');
}

set idProp(idProps: StringElement | undefined) {
throw new UnsupportedOperationError('idProp setter in Schema class is not not supported.');
}

get $schema(): StringElement | undefined {
throw new UnsupportedOperationError('$schema getter in Schema class is not not supported.');
}

set $schema($schema: StringElement | undefined) {
throw new UnsupportedOperationError('$schema setter in Schema class is not not supported.');
}

/**
* Validation keywords for arrays
*/

get additionalItems(): this | JSONReferenceElement | BooleanElement | undefined {
throw new UnsupportedOperationError(
'additionalItems getter in Schema class is not not supported.',
);
}

set additionalItems(additionalItems: this | JSONReferenceElement | BooleanElement | undefined) {
throw new UnsupportedOperationError(
'additionalItems setter in Schema class is not not supported.',
);
}

/**
* Validation keywords for objects
*/

get patternProperties(): ObjectElement | undefined {
throw new UnsupportedOperationError(
'patternProperties getter in Schema class is not not supported.',
);
}

set patternProperties(patternProperties: ObjectElement | undefined) {
throw new UnsupportedOperationError(
'patternProperties setter in Schema class is not not supported.',
);
}

get dependencies(): ObjectElement | undefined {
throw new UnsupportedOperationError(
'dependencies getter in Schema class is not not supported.',
);
}

set dependencies(dependencies: ObjectElement | undefined) {
throw new UnsupportedOperationError(
'dependencies setter in Schema class is not not supported.',
);
}

/**
* Validation keywords for any instance type
*/
get anyOf(): ArrayElement | undefined {
throw new UnsupportedOperationError('anyOf getter in Schema class is not not supported.');
}

set anyOf(anyOf: ArrayElement | undefined) {
throw new UnsupportedOperationError('anyOf setter in Schema class is not not supported.');
}

get oneOf(): ArrayElement | undefined {
throw new UnsupportedOperationError('oneOf getter in Schema class is not not supported.');
}

set oneOf(oneOf: ArrayElement | undefined) {
throw new UnsupportedOperationError('oneOf setter in Schema class is not not supported.');
}

get not(): this | JSONReferenceElement | undefined {
throw new UnsupportedOperationError('not getter in Schema class is not not supported.');
}

set not(not: this | JSONReferenceElement | undefined) {
throw new UnsupportedOperationError('not setter in Schema class is not not supported.');
}

get definitions(): ObjectElement | undefined {
throw new UnsupportedOperationError('definitions getter in Schema class is not not supported.');
}

set definitions(definitions: ObjectElement | undefined) {
throw new UnsupportedOperationError('definitions setter in Schema class is not not supported.');
}

/**
* JSON Hyper-Schema
*
* URI: https://datatracker.ietf.org/doc/html/draft-wright-json-schema-hyperschema-00
*/

get base(): StringElement | undefined {
throw new UnsupportedOperationError('base getter in Schema class is not not supported.');
}

set base(base: StringElement | undefined) {
throw new UnsupportedOperationError('base setter in Schema class is not not supported.');
}

get links(): ArrayElement | undefined {
throw new UnsupportedOperationError('links getter in Schema class is not not supported.');
}

set links(links: ArrayElement | undefined) {
throw new UnsupportedOperationError('links setter in Schema class is not not supported.');
}

get media(): MediaElement | undefined {
throw new UnsupportedOperationError('media getter in Schema class is not not supported.');
}

set media(media: MediaElement | undefined) {
throw new UnsupportedOperationError('media setter in Schema class is not not supported.');
}
}
/* eslint-enable class-methods-use-this */

export default Schema;
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 @@ -31,6 +31,7 @@ export {
isHeaderElement,
isTagElement,
isReferenceElement,
isSchemaElement,
isXmlElement,
isSecurityDefinitionsElement,
isSecuritySchemeElement,
Expand All @@ -53,6 +54,7 @@ export {
HeaderElement,
TagElement,
ReferenceElement,
SchemaElement,
XmlElement,
SecurityDefinitionsElement,
SecuritySchemeElement,
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
Expand Up @@ -10,6 +10,7 @@ import ExampleElement from './elements/Example';
import HeadersElement from './elements/Headers';
import HeaderElement from './elements/Header';
import TagElement from './elements/Tag';
import SchemaElement from './elements/Schema';
import XmlElement from './elements/Xml';
import ReferenceElement from './elements/Reference';
import SecurityDefinitionsElement from './elements/SecurityDefinitions';
Expand All @@ -32,6 +33,7 @@ const openApi2 = {
base.register('header', HeaderElement);
base.register('tag', TagElement);
base.register('reference', ReferenceElement);
base.register('schema', SchemaElement);
base.register('xml', XmlElement);
base.register('securityDefinitions', SecurityDefinitionsElement);
base.register('securityScheme', SecuritySchemeElement);
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 @@ -11,6 +11,7 @@ import HeadersElement from './elements/Headers';
import HeaderElement from './elements/Header';
import TagElement from './elements/Tag';
import ReferenceElement from './elements/Reference';
import SchemaElement from './elements/Schema';
import XmlElement from './elements/Xml';
import SecurityDefinitionsElement from './elements/SecurityDefinitions';
import SecuritySchemeElement from './elements/SecurityScheme';
Expand Down Expand Up @@ -126,6 +127,16 @@ export const isReferenceElement = createPredicate(
},
);

export const isSchemaElement = createPredicate(
({ hasBasicElementProps, isElementType, primitiveEq }) => {
return (element: unknown) =>
element instanceof SchemaElement ||
(hasBasicElementProps(element) &&
isElementType('schema', element) &&
primitiveEq('object', element));
},
);

export const isXmlElement = createPredicate(
({ hasBasicElementProps, isElementType, primitiveEq }) => {
return (element: unknown) =>
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
Expand Up @@ -9,6 +9,7 @@ import ExampleElement from '../elements/Example';
import HeaderElement from '../elements/Header';
import TagElement from '../elements/Tag';
import ReferenceElement from '../elements/Reference';
import SchemaElement from '../elements/Schema';
import XmlElement from '../elements/Xml';
import SecurityDefinitionsElement from '../elements/SecurityDefinitions';
import SecuritySchemeElement from '../elements/SecurityScheme';
Expand Down Expand Up @@ -70,6 +71,7 @@ ReferenceElement.refract = createRefractor([
'Reference',
'$visitor',
]);
SchemaElement.refract = createRefractor(['visitors', 'document', 'objects', 'Schema', '$visitor']);
XmlElement.refract = createRefractor(['visitors', 'document', 'objects', 'XML', '$visitor']);
SecurityDefinitionsElement.refract = createRefractor([
'visitors',
Expand Down Expand Up @@ -106,6 +108,7 @@ export {
HeaderElement,
TagElement,
ReferenceElement,
SchemaElement,
XmlElement,
SecurityDefinitionsElement,
SecuritySchemeElement,
Expand Down
46 changes: 46 additions & 0 deletions packages/apidom-ns-openapi-2/src/refractor/specification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import TagVisitor from './visitors/open-api-2/tag';
import ReferenceVisitor from './visitors/open-api-2/reference';
import Reference$RefVisitor from './visitors/open-api-2/reference/$RefVisitor';
import SchemaVisitor from './visitors/open-api-2/schema';
import SchemaAllOfVisitor from './visitors/open-api-2/schema/AllOfVisitor';
import SchemaItemsVisitor from './visitors/open-api-2/schema/ItemsVisitor';
import SchemaPropertiesVisitor from './visitors/open-api-2/schema/PropertiesVisitor';
import SchemaOrJSONReferenceVisitor from './visitors/open-api-2/schema/SchemaOrJSONReferenceVisitor';
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';
Expand Down Expand Up @@ -178,8 +182,50 @@ const specification = {
$ref: Reference$RefVisitor,
},
},
JSONReference: JSONSchemaDraft4Specification.visitors.document.objects.JSONReference,
JSONSchema: {
$ref: '#/visitors/document/objects/Schema',
},
Schema: {
$visitor: SchemaVisitor,
fixedFields: {
// the following properties are taken directly from the JSON Schema definition and follow the same specifications
format: jsonSchemaFixedFields.format,
title: jsonSchemaFixedFields.title,
description: jsonSchemaFixedFields.description,
default: jsonSchemaFixedFields.default,
multipleOf: jsonSchemaFixedFields.multipleOf,
maximum: jsonSchemaFixedFields.maximum,
exclusiveMaximum: jsonSchemaFixedFields.exclusiveMaximum,
minimum: jsonSchemaFixedFields.minimum,
exclusiveMinimum: jsonSchemaFixedFields.exclusiveMinimum,
maxLength: jsonSchemaFixedFields.maxLength,
minLength: jsonSchemaFixedFields.minLength,
pattern: jsonSchemaFixedFields.pattern,
maxItems: jsonSchemaFixedFields.maxItems,
minItems: jsonSchemaFixedFields.minItems,
uniqueItems: jsonSchemaFixedFields.uniqueItems,
maxProperties: jsonSchemaFixedFields.maxProperties,
minProperties: jsonSchemaFixedFields.minProperties,
required: jsonSchemaFixedFields.required,
enum: jsonSchemaFixedFields.enum,
type: jsonSchemaFixedFields.type,
readOnly: jsonSchemaFixedFields.readOnly,
// the following properties are taken from the JSON Schema definition but their definitions were adjusted to the Swagger Specification
items: SchemaItemsVisitor,
allOf: SchemaAllOfVisitor,
properties: SchemaPropertiesVisitor,
additionalProperties: SchemaOrJSONReferenceVisitor,
// OpenAPI vocabulary
discriminator: FallbackVisitor,
xml: {
$ref: '#/visitors/document/objects/XML',
},
externalDocs: {
$ref: '#/visitors/document/objects/ExternalDocumentation',
},
example: FallbackVisitor,
},
},
XML: {
$visitor: XmlVisitor,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import stampit from 'stampit';
import { ArrayElement } from '@swagger-api/apidom-core';
import {
specificationObj as JSONSchemaDraft4Specification,
isJSONReferenceElement,
JSONReferenceElement,
} from '@swagger-api/apidom-ns-json-schema-draft-4';

const { allOf: JSONSchemaAllOfVisitor } =
JSONSchemaDraft4Specification.visitors.document.objects.JSONSchema.fixedFields;

const AllOfVisitor = stampit(JSONSchemaAllOfVisitor, {
methods: {
ArrayElement(arrayElement: ArrayElement) {
// @ts-ignore
const result = JSONSchemaAllOfVisitor.compose.methods.ArrayElement.call(this, arrayElement);

this.element
.filter(isJSONReferenceElement)
.forEach((referenceElement: JSONReferenceElement) => {
referenceElement.setMetaProperty('referenced-element', 'schema');
});

return result;
},
},
});

export default AllOfVisitor;
Loading

0 comments on commit 6e046ac

Please sign in to comment.