diff --git a/packages/apidom-ns-openapi-3-0/src/refractor/specification.ts b/packages/apidom-ns-openapi-3-0/src/refractor/specification.ts index 1a0df1ba5..c479ca304 100644 --- a/packages/apidom-ns-openapi-3-0/src/refractor/specification.ts +++ b/packages/apidom-ns-openapi-3-0/src/refractor/specification.ts @@ -68,8 +68,13 @@ import HeaderExampleVisitor from './visitors/open-api-3-0/header/ExampleVisitor' import HeaderExamplesVisitor from './visitors/open-api-3-0/header/ExamplesVisitor'; import HeaderContentVisitor from './visitors/open-api-3-0/header/ContentVisitor'; import SchemaVisitor from './visitors/open-api-3-0/schema'; +import SchemaAllOfVisitor from './visitors/open-api-3-0/schema/AllOfVisitor'; +import SchemaAnyOfVisitor from './visitors/open-api-3-0/schema/AnyOfVisitor'; +import SchemaOneOfVisitor from './visitors/open-api-3-0/schema/OneOfVisitor'; +import SchemaDependenciesVisitor from './visitors/open-api-3-0/schema/DependenciesVisitor'; import SchemaItemsVisitor from './visitors/open-api-3-0/schema/ItemsVisitor'; import SchemaPropertiesVisitor from './visitors/open-api-3-0/schema/PropertiesVisitor'; +import SchemaPatternPropertiesVisitor from './visitors/open-api-3-0/schema/PatternPropertiesVisitor'; import SchemaTypeVisitor from './visitors/open-api-3-0/schema/TypeVisitor'; import SchemaNullableVisitor from './visitors/open-api-3-0/schema/NullableVisitor'; import SchemaWriteOnlyVisitor from './visitors/open-api-3-0/schema/WriteOnlyVisitor'; @@ -178,10 +183,16 @@ const SchemaSpecification = { fixedFields: { ...schemaInheritedFixedFields, // validation vocabulary + // validation keywords for any instance type + allOf: SchemaAllOfVisitor, + anyOf: SchemaAnyOfVisitor, + oneOf: SchemaOneOfVisitor, // validation keywords for arrays items: SchemaItemsVisitor, // Validation keywords for objects + dependencies: SchemaDependenciesVisitor, properties: SchemaPropertiesVisitor, + patternProperties: SchemaPatternPropertiesVisitor, // validation keywords for any instance type type: SchemaTypeVisitor, // OpenAPI vocabulary diff --git a/packages/apidom-ns-openapi-3-0/src/refractor/visitors/open-api-3-0/schema/DependenciesVisitor.ts b/packages/apidom-ns-openapi-3-0/src/refractor/visitors/open-api-3-0/schema/DependenciesVisitor.ts new file mode 100644 index 000000000..38b7f7086 --- /dev/null +++ b/packages/apidom-ns-openapi-3-0/src/refractor/visitors/open-api-3-0/schema/DependenciesVisitor.ts @@ -0,0 +1,29 @@ +import stampit from 'stampit'; +import { ObjectElement } from '@swagger-api/apidom-core'; +import { specificationObj as JSONSchemaDraft4Specification } from '@swagger-api/apidom-ns-json-schema-draft-4'; + +import ReferenceElement from '../../../../elements/Reference'; +import { isReferenceElement } from '../../../../predicates'; + +const { dependencies: JSONSchemaDependenciesVisitor } = + JSONSchemaDraft4Specification.visitors.document.objects.JSONSchema.fixedFields; + +const DependenciesVisitor = stampit(JSONSchemaDependenciesVisitor, { + methods: { + ObjectElement(objectElement: ObjectElement) { + // @ts-ignore + const result = JSONSchemaDependenciesVisitor.compose.methods.ObjectElement.call( + this, + objectElement, + ); + + this.element.filter(isReferenceElement).forEach((referenceElement: ReferenceElement) => { + referenceElement.setMetaProperty('referenced-element', 'schema'); + }); + + return result; + }, + }, +}); + +export default DependenciesVisitor; diff --git a/packages/apidom-ns-openapi-3-0/src/refractor/visitors/open-api-3-0/schema/PatternPropertiesVisitor.ts b/packages/apidom-ns-openapi-3-0/src/refractor/visitors/open-api-3-0/schema/PatternPropertiesVisitor.ts new file mode 100644 index 000000000..bff2ecfa2 --- /dev/null +++ b/packages/apidom-ns-openapi-3-0/src/refractor/visitors/open-api-3-0/schema/PatternPropertiesVisitor.ts @@ -0,0 +1,29 @@ +import stampit from 'stampit'; +import { ObjectElement } from '@swagger-api/apidom-core'; +import { specificationObj as JSONSchemaDraft4Specification } from '@swagger-api/apidom-ns-json-schema-draft-4'; + +import ReferenceElement from '../../../../elements/Reference'; +import { isReferenceElement } from '../../../../predicates'; + +const { patternProperties: JSONSchemaPatternPropertiesVisitor } = + JSONSchemaDraft4Specification.visitors.document.objects.JSONSchema.fixedFields; + +const PatternPropertiesVisitor = stampit(JSONSchemaPatternPropertiesVisitor, { + methods: { + ObjectElement(objectElement: ObjectElement) { + // @ts-ignore + const result = JSONSchemaPatternPropertiesVisitor.compose.methods.ObjectElement.call( + this, + objectElement, + ); + + this.element.filter(isReferenceElement).forEach((referenceElement: ReferenceElement) => { + referenceElement.setMetaProperty('referenced-element', 'schema'); + }); + + return result; + }, + }, +}); + +export default PatternPropertiesVisitor; diff --git a/packages/apidom-ns-openapi-3-0/test/refractor/elements/Schema/__snapshots__/index.ts.snap b/packages/apidom-ns-openapi-3-0/test/refractor/elements/Schema/__snapshots__/index.ts.snap index a55a5bd55..e40f681cc 100644 --- a/packages/apidom-ns-openapi-3-0/test/refractor/elements/Schema/__snapshots__/index.ts.snap +++ b/packages/apidom-ns-openapi-3-0/test/refractor/elements/Schema/__snapshots__/index.ts.snap @@ -1,5 +1,40 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`refractor elements SchemaElement given allOf keyword with reference should refract to semantic ApiDOM tree 1`] = ` +(SchemaElement + (MemberElement + (StringElement) + (ArrayElement + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))))) +`; + +exports[`refractor elements SchemaElement given anyOf keyword with reference should refract to semantic ApiDOM tree 1`] = ` +(SchemaElement + (MemberElement + (StringElement) + (ArrayElement + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))))) +`; + +exports[`refractor elements SchemaElement given dependencies keyword with reference should refract to semantic ApiDOM tree 1`] = ` +(SchemaElement + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement))))))) +`; + exports[`refractor elements SchemaElement given embedded SchemaElements should refract to semantic ApiDOM tree 1`] = ` (SchemaElement (MemberElement @@ -27,6 +62,43 @@ exports[`refractor elements SchemaElement given items keyword in form of object (SchemaElement))) `; +exports[`refractor elements SchemaElement given oneOf keyword with reference should refract to semantic ApiDOM tree 1`] = ` +(SchemaElement + (MemberElement + (StringElement) + (ArrayElement + (ReferenceElement + (MemberElement + (StringElement) + (StringElement)))))) +`; + +exports[`refractor elements SchemaElement given patternProperties keyword with reference should refract to semantic ApiDOM tree 1`] = ` +(SchemaElement + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement))))))) +`; + +exports[`refractor elements SchemaElement given properties keyword with reference should refract to semantic ApiDOM tree 1`] = ` +(SchemaElement + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (ReferenceElement + (MemberElement + (StringElement) + (StringElement))))))) +`; + exports[`refractor elements SchemaElement should refract to semantic ApiDOM tree 1`] = ` (SchemaElement (MemberElement diff --git a/packages/apidom-ns-openapi-3-0/test/refractor/elements/Schema/index.ts b/packages/apidom-ns-openapi-3-0/test/refractor/elements/Schema/index.ts index 1d2097953..c6ddbdc3c 100644 --- a/packages/apidom-ns-openapi-3-0/test/refractor/elements/Schema/index.ts +++ b/packages/apidom-ns-openapi-3-0/test/refractor/elements/Schema/index.ts @@ -1,4 +1,4 @@ -import { expect } from 'chai'; +import { expect, assert } from 'chai'; import { sexprs } from '@swagger-api/apidom-core'; import { SchemaElement } from '../../../../src'; @@ -81,6 +81,108 @@ describe('refractor', function () { expect(sexprs(schemaElement)).toMatchSnapshot(); }); }); + + context('given allOf keyword with reference', function () { + const schemaElement = SchemaElement.refract({ + allOf: [{ $ref: '#/path/to/schema' }], + }) as SchemaElement; + + specify('should refract to semantic ApiDOM tree', function () { + expect(sexprs(schemaElement)).toMatchSnapshot(); + }); + + specify('should contain referenced-element meta', function () { + const referenceElement = schemaElement.allOf?.get(0); + const referencedElementMeta = referenceElement?.getMetaProperty('referenced-element'); + + assert.strictEqual(referencedElementMeta.toValue(), 'schema'); + }); + }); + + context('given anyOf keyword with reference', function () { + const schemaElement = SchemaElement.refract({ + anyOf: [{ $ref: '#/path/to/schema' }], + }) as SchemaElement; + + specify('should refract to semantic ApiDOM tree', function () { + expect(sexprs(schemaElement)).toMatchSnapshot(); + }); + + specify('should contain referenced-element meta', function () { + const referenceElement = schemaElement.anyOf?.get(0); + const referencedElementMeta = referenceElement?.getMetaProperty('referenced-element'); + + assert.strictEqual(referencedElementMeta.toValue(), 'schema'); + }); + }); + + context('given oneOf keyword with reference', function () { + const schemaElement = SchemaElement.refract({ + oneOf: [{ $ref: '#/path/to/schema' }], + }) as SchemaElement; + + specify('should refract to semantic ApiDOM tree', function () { + expect(sexprs(schemaElement)).toMatchSnapshot(); + }); + + specify('should contain referenced-element meta', function () { + const referenceElement = schemaElement.oneOf?.get(0); + const referencedElementMeta = referenceElement?.getMetaProperty('referenced-element'); + + assert.strictEqual(referencedElementMeta.toValue(), 'schema'); + }); + }); + + context('given dependencies keyword with reference', function () { + const schemaElement = SchemaElement.refract({ + dependencies: { dep1: { $ref: '#/path/to/schema' } }, + }) as SchemaElement; + + specify('should refract to semantic ApiDOM tree', function () { + expect(sexprs(schemaElement)).toMatchSnapshot(); + }); + + specify('should contain referenced-element meta', function () { + const referenceElement = schemaElement.dependencies?.get('dep1'); + const referencedElementMeta = referenceElement?.getMetaProperty('referenced-element'); + + assert.strictEqual(referencedElementMeta.toValue(), 'schema'); + }); + }); + + context('given properties keyword with reference', function () { + const schemaElement = SchemaElement.refract({ + properties: { prop1: { $ref: '#/path/to/schema' } }, + }) as SchemaElement; + + specify('should refract to semantic ApiDOM tree', function () { + expect(sexprs(schemaElement)).toMatchSnapshot(); + }); + + specify('should contain referenced-element meta', function () { + const referenceElement = schemaElement.properties?.get('prop1'); + const referencedElementMeta = referenceElement?.getMetaProperty('referenced-element'); + + assert.strictEqual(referencedElementMeta.toValue(), 'schema'); + }); + }); + + context('given patternProperties keyword with reference', function () { + const schemaElement = SchemaElement.refract({ + patternProperties: { pattern: { $ref: '#/path/to/schema' } }, + }) as SchemaElement; + + specify('should refract to semantic ApiDOM tree', function () { + expect(sexprs(schemaElement)).toMatchSnapshot(); + }); + + specify('should contain referenced-element meta', function () { + const referenceElement = schemaElement.patternProperties?.get('pattern'); + const referencedElementMeta = referenceElement?.getMetaProperty('referenced-element'); + + assert.strictEqual(referencedElementMeta.toValue(), 'schema'); + }); + }); }); }); });