Skip to content

Commit

Permalink
feat: add support for intersection of arrays and tuples (#1237)
Browse files Browse the repository at this point in the history
* 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 <filipe.pomar@cybus.io>
  • Loading branch information
filipomar and Filipe Pomar committed May 6, 2022
1 parent 1d9605b commit 243ee05
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 7 deletions.
32 changes: 25 additions & 7 deletions 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";
Expand All @@ -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[] {
Expand Down
1 change: 1 addition & 0 deletions test/valid-data-type.test.ts
Expand Up @@ -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"));
Expand Down
5 changes: 5 additions & 0 deletions test/valid-data/type-intersection-with-arrays/main.ts
@@ -0,0 +1,5 @@
export type NonEmptyNumberArrayVariationOne = [number, ...number[]] & number[];

type NonEmptyGenericArrayVariationOne<T> = [T, ...T[]] & T[];

export type NonEmptyNumberArrayVariationTwo = NonEmptyGenericArrayVariationOne<number>;
39 changes: 39 additions & 0 deletions 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"
}
]
}
}
}

0 comments on commit 243ee05

Please sign in to comment.