From 243ee05753de48af4dcf679b3d6f23d43748fd55 Mon Sep 17 00:00:00 2001 From: filipomar Date: Fri, 6 May 2022 20:12:43 +0200 Subject: [PATCH] feat: add support for intersection of arrays and tuples (#1237) * feat: adding support for intersection of arrays and tuples * refactor: updating variable names for PR * refactor: remove functionally useless branches * style: fix coding style Co-authored-by: Filipe Pomar --- .../IntersectionTypeFormatter.ts | 32 +++++++++++---- test/valid-data-type.test.ts | 1 + .../type-intersection-with-arrays/main.ts | 5 +++ .../type-intersection-with-arrays/schema.json | 39 +++++++++++++++++++ 4 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 test/valid-data/type-intersection-with-arrays/main.ts create mode 100644 test/valid-data/type-intersection-with-arrays/schema.json diff --git a/src/TypeFormatter/IntersectionTypeFormatter.ts b/src/TypeFormatter/IntersectionTypeFormatter.ts index 6f19d7e43..7530499f1 100644 --- a/src/TypeFormatter/IntersectionTypeFormatter.ts +++ b/src/TypeFormatter/IntersectionTypeFormatter.ts @@ -1,7 +1,9 @@ import { Definition } from "../Schema/Definition"; import { SubTypeFormatter } from "../SubTypeFormatter"; +import { ArrayType } from "../Type/ArrayType"; import { BaseType } from "../Type/BaseType"; import { IntersectionType } from "../Type/IntersectionType"; +import { TupleType } from "../Type/TupleType"; import { TypeFormatter } from "../TypeFormatter"; import { getAllOfDefinitionReducer } from "../Utils/allOfDefinition"; import { uniqueArray } from "../Utils/uniqueArray"; @@ -14,14 +16,30 @@ export class IntersectionTypeFormatter implements SubTypeFormatter { } public getDefinition(type: IntersectionType): Definition { - const types = type.getTypes(); + const dependencies: Definition[] = []; + const nonArrayLikeTypes: BaseType[] = []; - return types.length > 1 - ? types.reduce(getAllOfDefinitionReducer(this.childTypeFormatter), { - type: "object", - additionalProperties: false, - } as Definition) - : this.childTypeFormatter.getDefinition(types[0]); + for (const t of type.getTypes()) { + // Filter out Array like definitions that cannot be + // easily mergeable into a single json-schema object + if (t instanceof ArrayType || t instanceof TupleType) { + dependencies.push(this.childTypeFormatter.getDefinition(t)); + } else { + nonArrayLikeTypes.push(t); + } + } + + if (nonArrayLikeTypes.length) { + // There are non array (mergeable requirements) + dependencies.push( + nonArrayLikeTypes.reduce(getAllOfDefinitionReducer(this.childTypeFormatter), { + type: "object", + additionalProperties: false, + }) + ); + } + + return dependencies.length === 1 ? dependencies[0] : { allOf: dependencies }; } public getChildren(type: IntersectionType): BaseType[] { diff --git a/test/valid-data-type.test.ts b/test/valid-data-type.test.ts index a05bc9c3d..596e3cc62 100644 --- a/test/valid-data-type.test.ts +++ b/test/valid-data-type.test.ts @@ -36,6 +36,7 @@ describe("valid-data-type", () => { it("type-union", assertValidSchema("type-union", "TypeUnion")); it("type-union-tagged", assertValidSchema("type-union-tagged", "Shape")); it("type-intersection", assertValidSchema("type-intersection", "MyObject")); + it("type-intersection-with-arrays", assertValidSchema("type-intersection-with-arrays", "*")); it("type-intersection-conflict", assertValidSchema("type-intersection-conflict", "MyObject")); it("type-intersection-partial-conflict", assertValidSchema("type-intersection-partial-conflict", "MyType")); it("type-intersection-partial-conflict-ref", assertValidSchema("type-intersection-partial-conflict", "MyType")); diff --git a/test/valid-data/type-intersection-with-arrays/main.ts b/test/valid-data/type-intersection-with-arrays/main.ts new file mode 100644 index 000000000..78ec504e4 --- /dev/null +++ b/test/valid-data/type-intersection-with-arrays/main.ts @@ -0,0 +1,5 @@ +export type NonEmptyNumberArrayVariationOne = [number, ...number[]] & number[]; + +type NonEmptyGenericArrayVariationOne = [T, ...T[]] & T[]; + +export type NonEmptyNumberArrayVariationTwo = NonEmptyGenericArrayVariationOne; diff --git a/test/valid-data/type-intersection-with-arrays/schema.json b/test/valid-data/type-intersection-with-arrays/schema.json new file mode 100644 index 000000000..47f8a3681 --- /dev/null +++ b/test/valid-data/type-intersection-with-arrays/schema.json @@ -0,0 +1,39 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "NonEmptyNumberArrayVariationOne": { + "allOf": [ + { + "items": { + "type": "number" + }, + "minItems": 1, + "type": "array" + }, + { + "items": { + "type": "number" + }, + "type": "array" + } + ] + }, + "NonEmptyNumberArrayVariationTwo": { + "allOf": [ + { + "items": { + "type": "number" + }, + "minItems": 1, + "type": "array" + }, + { + "items": { + "type": "number" + }, + "type": "array" + } + ] + } + } +}