json-to-ts
Version:
Convert json object to typescript interfaces
463 lines (384 loc) • 10.8 kB
text/typescript
import * as assert from "assert";
import { removeWhiteSpace } from "./util/index";
import JsonToTS from "../src/index";
describe("Array type merging", function () {
it("should work with arrays with same inner types", function () {
const json = {
cats: [{ name: "Kittin" }, { name: "Sparkles" }],
};
const expectedTypes = [
`interface RootObject {
cats: Cat[];
}`,
`interface Cat {
name: string;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 2);
});
it("union undefined type should be emited and field should be marked as optional", function () {
const json = [{ age: 42 }, { age: undefined }];
const expectedTypes = [
`interface RootObject {
age?: number;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 1);
});
it("union null type should be emited and field should be marked as optional", function () {
const json = [{ age: 42 }, { age: null }];
const expectedTypes = [
`interface RootObject {
age: null | number;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 1);
});
it("null should stay if it is part of array elements", function () {
const json = {
arr: [42, "42", null],
};
const expectedTypes = [
`interface RootObject {
arr: (null | number | string)[];
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 1);
});
it("array types should be merge even if they are undefined", function () {
const json = [
{
field: ["string"],
},
{
field: [42],
},
{
field: [null],
},
{
field: undefined,
},
{
field: [new Date()],
},
];
const expectedTypes = [
`interface RootObject {
field?:(Date|null|number|string)[];
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 1);
});
it("object types should be merge even if they are undefined", function () {
const json = [
{
field: { tag: "world" },
},
{
field: { tag: 42 },
},
{
field: undefined,
},
];
const expectedTypes = [
`interface RootObject {
field?: Field;
}`,
`interface Field {
tag: number | string;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 2);
});
it("should work with arrays with inner types that has optinal field", function () {
const json = {
cats: [{ name: "Kittin" }, { name: "Sparkles", age: 20 }],
};
const expectedTypes = [
`interface RootObject {
cats: Cat[];
}`,
`interface Cat {
name: string;
age?: number;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 2);
});
it("should work with arrays with inner types that has no common fields", function () {
const json = {
cats: [{ name: "Kittin" }, { age: 20 }],
};
const expectedTypes = [
`interface RootObject {
cats: Cat[];
}`,
`interface Cat {
name?: string;
age?: number;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 2);
});
it("should work with arrays with inner types that have common field that has different types", function () {
const json = {
cats: [{ age: "20" }, { age: 20 }],
};
const expectedTypes = [
`interface RootObject {
cats: Cat[];
}`,
`interface Cat {
age: number | string;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 2);
});
it("should solve edge case 1", function () {
const json = {
cats: [{ age: [42] }, { age: ["42"] }],
dads: ["hello", 42],
};
const expectedTypes = [
`interface RootObject {
cats: Cat[];
dads: (number | string)[];
}`,
`interface Cat {
age: (number | string)[];
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 2);
});
it("should solve edge case 2", function () {
const json = {
items: [
{
billables: [
{
quantity: 2,
price: 0,
},
],
},
{
billables: [
{
priceCategory: {
title: "Adult",
minAge: 0,
maxAge: 99,
},
quantity: 2,
price: 226,
},
],
},
],
};
const expectedTypes = [
`interface RootObject {
items: Item[];
}`,
`interface Item {
billables: Billable[];
}`,
`interface Billable {
quantity: number;
price: number;
priceCategory?: PriceCategory;
}`,
`interface PriceCategory {
title: string;
minAge: number;
maxAge: number;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 4);
});
it("should solve edge case 3", function () {
const json = [
{
nestedElements: [
{
commonField: 42,
optionalField: "field",
},
{
commonField: 42,
optionalField3: "field3",
},
],
},
{
nestedElements: [
{
commonField: "42",
optionalField2: "field2",
},
],
},
];
const expectedTypes = [
`interface RootObject {
nestedElements: NestedElement[];
}`,
`interface NestedElement {
commonField: number | string;
optionalField?: string;
optionalField3?: string;
optionalField2?: string;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 2);
});
it("should merge empty array with primitive types", function () {
const json = [
{
nestedElements: [],
},
{
nestedElements: ["kittin"],
},
];
const expectedTypes = [
`interface RootObject {
nestedElements: string[];
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 1);
});
it("should merge empty array with object types", function () {
const json = [
{
nestedElements: [],
},
{
nestedElements: [{ name: "kittin" }],
},
];
const expectedTypes = [
`interface RootObject {
nestedElements: NestedElement[];
}`,
`interface NestedElement {
name: string;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 2);
});
it("should merge empty array with array types", function () {
const json = [
{
nestedElements: [],
},
{
nestedElements: [["string"]],
},
];
const expectedTypes = [
`interface RootObject {
nestedElements: string[][];
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 1);
});
it("should merge union types with readable names ", function () {
const json = [
{
marius: "marius",
},
{
marius: [42],
},
];
const expectedTypes = [
`interface RootObject {
marius: number[] | string;
}`,
].map(removeWhiteSpace);
const interfaces = JsonToTS(json);
interfaces.forEach((i) => {
const noWhiteSpaceInterface = removeWhiteSpace(i);
assert(expectedTypes.includes(noWhiteSpaceInterface));
});
assert.strictEqual(interfaces.length, 1);
});
});