import { TypeAssertion, ValidationContext } from '../types'; import { validate, getType } from '../validator'; import { compile } from '../compiler'; import { serialize, deserialize } from '../serializer'; describe("compiler-3", function() { it("compiler-op-intersection-1", function() { const schemas = [compile(` interface A { a: string; } interface B extends A { b: number; } interface C { c: boolean; } type D = B & C; `), compile(` type D = B & C; interface C { c: boolean; } interface B extends A { b: number; } interface A { a: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'A', 'B', 'C', 'D', ]); expect(Array.from(schemas[1].keys())).toEqual([ 'D', 'C', 'B', 'A', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'D', typeName: 'D', kind: 'object', members: [ ['b', { name: 'b', kind: 'primitive', primitiveName: 'number', }], ['a', { name: 'a', kind: 'primitive', primitiveName: 'string', }], ['c', { name: 'c', kind: 'primitive', primitiveName: 'boolean', }], ], }; // const ty = getType(schema, 'D'); for (const ty of [getType(deserialize(serialize(schema)), 'D'), getType(schema, 'D')]) { expect(ty).toEqual(rhs); { const v = { a: '', b: 0, c: false, }; expect(validate(v, ty, {schema})).toEqual({value: v}); } } } } }); it("compiler-op-subtract+omit-1", function() { const schemas = [compile(` interface A { a: string; } interface B extends A { b: number; } interface C { b: bigint; c: boolean; } type D = B - C; `), compile(` type D = B - C; interface C { b: bigint; c: boolean; } interface B extends A { b: number; } interface A { a: string; } `), compile(` type D = Omit; interface C { b: bigint; c: boolean; } interface B extends A { b: number; } interface A { a: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'A', 'B', 'C', 'D', ]); expect(Array.from(schemas[1].keys())).toEqual([ 'D', 'C', 'B', 'A', ]); expect(Array.from(schemas[2].keys())).toEqual([ 'D', 'C', 'B', 'A', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'D', typeName: 'D', kind: 'object', members: [ ['a', { name: 'a', kind: 'primitive', primitiveName: 'string', }], ], }; // const ty = getType(schema, 'D'); for (const ty of [getType(deserialize(serialize(schema)), 'D'), getType(schema, 'D')]) { expect(ty).toEqual(rhs); { const v = { a: '', }; expect(validate(v, ty, {schema, noAdditionalProps: true})).toEqual({value: v}); } { const ctx: Partial = { checkAll: true, noAdditionalProps: true, schema, }; const v = { a: '', b: 0, c: false, }; expect(validate(v, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"b, c" of "D" are not matched to additional property patterns.', dataPath: 'D', constraints: {}, }]); } } } } }); it("compiler-op-pick-1", function() { const schemas = [compile(` interface A { a: string; b: number; } interface B extends A { c: boolean; d: bigint; } type C = Pick; `), compile(` type C = Pick; interface B extends A { c: boolean; d: bigint; } interface A { a: string; b: number; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'A', 'B', 'C', ]); expect(Array.from(schemas[1].keys())).toEqual([ 'C', 'B', 'A', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [ ['a', { name: 'a', kind: 'primitive', primitiveName: 'string', }], ['c', { name: 'c', kind: 'primitive', primitiveName: 'boolean', }], ], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); { const v = { a: '', c: false, }; expect(validate(v, ty, {schema, noAdditionalProps: true})).toEqual({value: v}); } { const ctx: Partial = { checkAll: true, noAdditionalProps: true, schema, }; const v = { a: '', b: 0, c: false, d: BigInt(5), }; expect(validate(v, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"b, d" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } } } } }); it("compiler-op-partial-1", function() { const schemas = [compile(` interface A { a: string; b: number; } interface B extends A { c: boolean; d: bigint; } type C = Partial; `), compile(` type C = Partial; interface B extends A { c: boolean; d: bigint; } interface A { a: string; b: number; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'A', 'B', 'C', ]); expect(Array.from(schemas[1].keys())).toEqual([ 'C', 'B', 'A', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [ ['c', { name: 'c', kind: 'optional', optional: { kind: 'primitive', primitiveName: 'boolean', }, }], ['d', { name: 'd', kind: 'optional', optional: { kind: 'primitive', primitiveName: 'bigint', }, }], ['a', { name: 'a', kind: 'optional', optional: { kind: 'primitive', primitiveName: 'string', }, }], ['b', { name: 'b', kind: 'optional', optional: { kind: 'primitive', primitiveName: 'number', }, }], ], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); { const v = { a: '', c: false, }; expect(validate(v, ty, {schema, noAdditionalProps: true})).toEqual({value: v}); } { const v = { a: '', b: 0, c: false, d: BigInt(5), }; expect(validate(v, ty, {schema, noAdditionalProps: true})).toEqual({value: v}); } } } } }); it("compiler-enum-1", function() { const schema = compile(` enum Foo { AAA, BBB, CCC, DDD, EEE, } `); { expect(Array.from(schema.keys())).toEqual([ 'Foo', ]); } { const rhs: TypeAssertion = { name: 'Foo', typeName: 'Foo', kind: 'enum', values: [ ['AAA', 0], ['BBB', 1], ['CCC', 2], ['DDD', 3], ['EEE', 4], ], }; // const ty = getType(schema, 'Foo'); for (const ty of [getType(deserialize(serialize(schema)), 'Foo'), getType(schema, 'Foo')]) { expect(ty).toEqual(rhs); expect(validate(-1, ty)).toEqual(null); expect(validate(0, ty)).toEqual({value: 0}); expect(validate(1, ty)).toEqual({value: 1}); expect(validate(2, ty)).toEqual({value: 2}); expect(validate(3, ty)).toEqual({value: 3}); expect(validate(4, ty)).toEqual({value: 4}); expect(validate(5, ty)).toEqual(null); } } }); it("compiler-enum-2", function() { const schema = compile(` enum Foo { AAA = 2, BBB, CCC = 10, DDD, EEE, } `); { expect(Array.from(schema.keys())).toEqual([ 'Foo', ]); } { const rhs: TypeAssertion = { name: 'Foo', typeName: 'Foo', kind: 'enum', values: [ ['AAA', 2], ['BBB', 3], ['CCC', 10], ['DDD', 11], ['EEE', 12], ], }; // const ty = getType(schema, 'Foo'); for (const ty of [getType(deserialize(serialize(schema)), 'Foo'), getType(schema, 'Foo')]) { expect(ty).toEqual(rhs); expect(validate(-1, ty)).toEqual(null); expect(validate(0, ty)).toEqual(null); expect(validate(1, ty)).toEqual(null); expect(validate(2, ty)).toEqual({value: 2}); expect(validate(3, ty)).toEqual({value: 3}); expect(validate(4, ty)).toEqual(null); expect(validate(9, ty)).toEqual(null); expect(validate(10, ty)).toEqual({value: 10}); expect(validate(11, ty)).toEqual({value: 11}); expect(validate(12, ty)).toEqual({value: 12}); expect(validate(13, ty)).toEqual(null); } } }); it("compiler-enum-3", function() { const schema = compile(` enum Foo { AAA = 'XA', BBB = 'XB', CCC = 'XC', DDD = 'XD', EEE = 'XE', } `); { expect(Array.from(schema.keys())).toEqual([ 'Foo', ]); } { const rhs: TypeAssertion = { name: 'Foo', typeName: 'Foo', kind: 'enum', values: [ ['AAA', 'XA'], ['BBB', 'XB'], ['CCC', 'XC'], ['DDD', 'XD'], ['EEE', 'XE'], ], }; // const ty = getType(schema, 'Foo'); for (const ty of [getType(deserialize(serialize(schema)), 'Foo'), getType(schema, 'Foo')]) { expect(ty).toEqual(rhs); expect(validate(-1, ty)).toEqual(null); expect(validate(0, ty)).toEqual(null); expect(validate(1, ty)).toEqual(null); expect(validate('XA', ty)).toEqual({value: 'XA'}); expect(validate('XB', ty)).toEqual({value: 'XB'}); expect(validate('XC', ty)).toEqual({value: 'XC'}); expect(validate('XD', ty)).toEqual({value: 'XD'}); expect(validate('XE', ty)).toEqual({value: 'XE'}); expect(validate('AAA', ty)).toEqual(null); expect(validate('AA', ty)).toEqual(null); expect(validate('', ty)).toEqual(null); } } }); it("compiler-enum-4", function() { const schema = compile(` enum Foo { AAA = 'XA', BBB, CCC, DDD = 10, EEE, FFF = 'XF', } `); { expect(Array.from(schema.keys())).toEqual([ 'Foo', ]); } { const rhs: TypeAssertion = { name: 'Foo', typeName: 'Foo', kind: 'enum', values: [ ['AAA', 'XA'], ['BBB', 0], ['CCC', 1], ['DDD', 10], ['EEE', 11], ['FFF', 'XF'], ], }; // const ty = getType(schema, 'Foo'); for (const ty of [getType(deserialize(serialize(schema)), 'Foo'), getType(schema, 'Foo')]) { expect(ty).toEqual(rhs); expect(validate(-1, ty)).toEqual(null); expect(validate(0, ty)).toEqual({value: 0}); expect(validate(1, ty)).toEqual({value: 1}); expect(validate(2, ty)).toEqual(null); expect(validate(9, ty)).toEqual(null); expect(validate(10, ty)).toEqual({value: 10}); expect(validate(11, ty)).toEqual({value: 11}); expect(validate(12, ty)).toEqual(null); expect(validate('XA', ty)).toEqual({value: 'XA'}); expect(validate('XB', ty)).toEqual(null); expect(validate('XC', ty)).toEqual(null); expect(validate('XD', ty)).toEqual(null); expect(validate('XE', ty)).toEqual(null); expect(validate('XF', ty)).toEqual({value: 'XF'}); expect(validate('AAA', ty)).toEqual(null); expect(validate('AA', ty)).toEqual(null); expect(validate('', ty)).toEqual(null); } } }); it("compiler-enum-4b", function() { const schema = compile(` const enum Foo { AAA = 'XA', BBB, CCC, DDD = 10, EEE, FFF = 'XF', } `); { expect(Array.from(schema.keys())).toEqual([ 'Foo', ]); } { const rhs: TypeAssertion = { name: 'Foo', typeName: 'Foo', kind: 'enum', values: [ ['AAA', 'XA'], ['BBB', 0], ['CCC', 1], ['DDD', 10], ['EEE', 11], ['FFF', 'XF'], ], isConst: true, }; // const ty = getType(schema, 'Foo'); for (const ty of [getType(deserialize(serialize(schema)), 'Foo'), getType(schema, 'Foo')]) { expect(ty).toEqual(rhs); expect(validate(-1, ty)).toEqual(null); expect(validate(0, ty)).toEqual({value: 0}); expect(validate(1, ty)).toEqual({value: 1}); expect(validate(2, ty)).toEqual(null); expect(validate(9, ty)).toEqual(null); expect(validate(10, ty)).toEqual({value: 10}); expect(validate(11, ty)).toEqual({value: 11}); expect(validate(12, ty)).toEqual(null); expect(validate('XA', ty)).toEqual({value: 'XA'}); expect(validate('XB', ty)).toEqual(null); expect(validate('XC', ty)).toEqual(null); expect(validate('XD', ty)).toEqual(null); expect(validate('XE', ty)).toEqual(null); expect(validate('XF', ty)).toEqual({value: 'XF'}); expect(validate('AAA', ty)).toEqual(null); expect(validate('AA', ty)).toEqual(null); expect(validate('', ty)).toEqual(null); } } }); it("compiler-enum-5", function() { const schema = compile(` enum Foo { AAA = 'XA', BBB, CCC, DDD = 'XD', EEE, FFF = 'XF', } `); { expect(Array.from(schema.keys())).toEqual([ 'Foo', ]); } { const rhs: TypeAssertion = { name: 'Foo', typeName: 'Foo', kind: 'enum', values: [ ['AAA', 'XA'], ['BBB', 0], ['CCC', 1], ['DDD', 'XD'], ['EEE', 2], ['FFF', 'XF'], ], }; // const ty = getType(schema, 'Foo'); for (const ty of [getType(deserialize(serialize(schema)), 'Foo'), getType(schema, 'Foo')]) { expect(ty).toEqual(rhs); expect(validate(-1, ty)).toEqual(null); expect(validate(0, ty)).toEqual({value: 0}); expect(validate(1, ty)).toEqual({value: 1}); expect(validate(2, ty)).toEqual({value: 2}); expect(validate(3, ty)).toEqual(null); expect(validate('XA', ty)).toEqual({value: 'XA'}); expect(validate('XB', ty)).toEqual(null); expect(validate('XC', ty)).toEqual(null); expect(validate('XD', ty)).toEqual({value: 'XD'}); expect(validate('XE', ty)).toEqual(null); expect(validate('XF', ty)).toEqual({value: 'XF'}); expect(validate('AAA', ty)).toEqual(null); expect(validate('AA', ty)).toEqual(null); expect(validate('', ty)).toEqual(null); } } }); it("compiler-enum-5b", function() { const schema = compile(` export const enum Foo { AAA = 'XA', BBB, CCC, DDD = 'XD', EEE, FFF = 'XF', } `); { expect(Array.from(schema.keys())).toEqual([ 'Foo', ]); } { const rhs: TypeAssertion = { name: 'Foo', typeName: 'Foo', kind: 'enum', values: [ ['AAA', 'XA'], ['BBB', 0], ['CCC', 1], ['DDD', 'XD'], ['EEE', 2], ['FFF', 'XF'], ], isConst: true, }; // const ty = getType(schema, 'Foo'); for (const ty of [getType(deserialize(serialize(schema)), 'Foo'), getType(schema, 'Foo')]) { expect(ty).toEqual(rhs); expect(validate(-1, ty)).toEqual(null); expect(validate(0, ty)).toEqual({value: 0}); expect(validate(1, ty)).toEqual({value: 1}); expect(validate(2, ty)).toEqual({value: 2}); expect(validate(3, ty)).toEqual(null); expect(validate('XA', ty)).toEqual({value: 'XA'}); expect(validate('XB', ty)).toEqual(null); expect(validate('XC', ty)).toEqual(null); expect(validate('XD', ty)).toEqual({value: 'XD'}); expect(validate('XE', ty)).toEqual(null); expect(validate('XF', ty)).toEqual({value: 'XF'}); expect(validate('AAA', ty)).toEqual(null); expect(validate('AA', ty)).toEqual(null); expect(validate('', ty)).toEqual(null); } } }); it("compiler-additional-props-1", function() { const schemas = [compile(` interface A { [propNames1: /^A+$/]: string; [propNames2: /^B+$/]: string; } interface C extends A { [propNames3: /^C+$/]: number; [propNames4: /^D+$/]: number; } `), compile(` interface C extends A { [propNames3: /^C+$/]: number; [propNames4: /^D+$/]: number; } interface A { [propNames1: /^A+$/]: string; [propNames2: /^B+$/]: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'A', 'C', ]); expect(Array.from(schemas[1].keys())).toEqual([ 'C', 'A', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [], additionalProps: [ [[/^A+$/], {kind: 'primitive', primitiveName: 'string'}, true], [[/^B+$/], {kind: 'primitive', primitiveName: 'string'}, true], [[/^C+$/], {kind: 'primitive', primitiveName: 'number'}], [[/^D+$/], {kind: 'primitive', primitiveName: 'number'}], ], baseTypes: [{ name: 'A', typeName: 'A', kind: 'object', members: [], additionalProps: [ [[/^A+$/], {kind: 'primitive', primitiveName: 'string'}], [[/^B+$/], {kind: 'primitive', primitiveName: 'string'}], ], }], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); expect(validate({}, ty)).toEqual({value: {}}); expect(validate({'A': ''}, ty)).toEqual({value: {'A': ''}}); expect(validate({'A': 0}, ty)).toEqual(null); expect(validate({'B': ''}, ty)).toEqual({value: {'B': ''}}); expect(validate({'B': 0}, ty)).toEqual(null); expect(validate({'C': ''}, ty)).toEqual(null); expect(validate({'C': 0}, ty)).toEqual({value: {'C': 0}}); { const ctx: Partial = {}; expect(validate({'D': ''}, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'TypeUnmatched', message: '"D" of "C" should be type "number".', dataPath: 'C:D', constraints: {}, value: '', }]); } { const ctx: Partial = {}; expect(validate({'D': 0}, ty, ctx)).toEqual({value: {'D': 0}}); } { const ctx: Partial = {}; expect(validate({'E': ''}, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"E" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } { const ctx: Partial = {}; expect(validate({'E': 0}, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"E" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } { const ctx: Partial = {}; expect(validate({0: ''}, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"0" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } { const ctx: Partial = { noAdditionalProps: true, }; expect(validate({0: ''}, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"0" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } { const ctx: Partial = {}; expect(validate({0: 0}, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"0" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } { const ctx: Partial = { noAdditionalProps: true, }; expect(validate({0: 0}, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"0" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } { const ctx: Partial = {}; expect(validate([], ty, ctx)).toEqual({value: []}); } { const ctx: Partial = { noAdditionalProps: true, }; expect(validate([], ty, ctx)).toEqual({value: []}); } { const ctx: Partial = {}; expect(validate([''], ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"0" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } { const ctx: Partial = { noAdditionalProps: true, }; expect(validate([''], ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"[number]" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } { const ctx: Partial = {}; expect(validate([0], ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"0" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } { const ctx: Partial = { noAdditionalProps: true, }; expect(validate([0], ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"[number]" of "C" are not matched to additional property patterns.', dataPath: 'C', constraints: {}, }]); } } } } }); it("compiler-additional-props-1z", function() { const schemas = [compile(` interface A { } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'A', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'A', typeName: 'A', kind: 'object', members: [], }; // const ty = getType(schema, 'A'); for (const ty of [getType(deserialize(serialize(schema)), 'A'), getType(schema, 'A')]) { expect(ty).toEqual(rhs); { const ctx: Partial = { noAdditionalProps: true, }; expect(validate([], ty, ctx)).toEqual({value: []}); } { const ctx: Partial = { noAdditionalProps: true, }; expect(validate([''], ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"[number]" of "A" are not matched to additional property patterns.', dataPath: 'A', constraints: {}, }]); } { const ctx: Partial = { noAdditionalProps: true, }; expect(validate([0], ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'AdditionalPropUnmatched', message: '"[number]" of "A" are not matched to additional property patterns.', dataPath: 'A', constraints: {}, }]); } } } } }); it("compiler-additional-props-2", function() { const schemas = [compile(` interface A { [propNames1: /^A+$/]: string; [propNames2: /^B+$/]: string; } interface C extends A { [propNames3: /^C+$/]: number; [propNames4: /^C+$/]: string; } `), compile(` interface C extends A { [propNames3: /^C+$/]: number; [propNames4: /^C+$/]: string; } interface A { [propNames1: /^A+$/]: string; [propNames2: /^B+$/]: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'A', 'C', ]); expect(Array.from(schemas[1].keys())).toEqual([ 'C', 'A', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [], additionalProps: [ [[/^A+$/], {kind: 'primitive', primitiveName: 'string'}, true], [[/^B+$/], {kind: 'primitive', primitiveName: 'string'}, true], [[/^C+$/], {kind: 'primitive', primitiveName: 'number'}], [[/^C+$/], {kind: 'primitive', primitiveName: 'string'}], ], baseTypes: [{ name: 'A', typeName: 'A', kind: 'object', members: [], additionalProps: [ [[/^A+$/], {kind: 'primitive', primitiveName: 'string'}], [[/^B+$/], {kind: 'primitive', primitiveName: 'string'}], ], }], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); expect(validate({}, ty)).toEqual({value: {}}); expect(validate({'A': ''}, ty)).toEqual({value: {'A': ''}}); expect(validate({'A': 0}, ty)).toEqual(null); expect(validate({'B': ''}, ty)).toEqual({value: {'B': ''}}); expect(validate({'B': 0}, ty)).toEqual(null); expect(validate({'C': ''}, ty)).toEqual({value: {'C': ''}}); expect(validate({'C': 0}, ty)).toEqual({value: {'C': 0}}); expect(validate({'D': ''}, ty)).toEqual(null); expect(validate({'D': 0}, ty)).toEqual(null); expect(validate({'E': ''}, ty)).toEqual(null); expect(validate({'E': 0}, ty)).toEqual(null); expect(validate({0: ''}, ty)).toEqual(null); expect(validate({0: 0}, ty)).toEqual(null); expect(validate([], ty)).toEqual({value: []}); expect(validate([''], ty)).toEqual(null); expect(validate([0], ty)).toEqual(null); } } } }); it("compiler-additional-props-3", function() { const schemas = [compile(` interface A { [propNames1: /^A+$/]: string; [propNames2: number | /^B+$/]: string; } interface C extends A { [propNames3: /^C+$/]: number; [propNames4: /^D+$/ | number]: number; } `), compile(` interface C extends A { [propNames3: /^C+$/]: number; [propNames4: /^D+$/ | number]: number; } interface A { [propNames1: /^A+$/]: string; [propNames2: number | /^B+$/]: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'A', 'C', ]); expect(Array.from(schemas[1].keys())).toEqual([ 'C', 'A', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [], additionalProps: [ [[/^A+$/], {kind: 'primitive', primitiveName: 'string'}, true], [['number', /^B+$/], {kind: 'primitive', primitiveName: 'string'}, true], [[/^C+$/], {kind: 'primitive', primitiveName: 'number'}], [[/^D+$/, 'number'], {kind: 'primitive', primitiveName: 'number'}], ], baseTypes: [{ name: 'A', typeName: 'A', kind: 'object', members: [], additionalProps: [ [[/^A+$/], {kind: 'primitive', primitiveName: 'string'}], [['number', /^B+$/], {kind: 'primitive', primitiveName: 'string'}], ], }], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); expect(validate({}, ty)).toEqual({value: {}}); expect(validate({'A': ''}, ty)).toEqual({value: {'A': ''}}); expect(validate({'A': 0}, ty)).toEqual(null); expect(validate({'B': ''}, ty)).toEqual({value: {'B': ''}}); expect(validate({'B': 0}, ty)).toEqual(null); expect(validate({'C': ''}, ty)).toEqual(null); expect(validate({'C': 0}, ty)).toEqual({value: {'C': 0}}); expect(validate({'D': ''}, ty)).toEqual(null); expect(validate({'D': 0}, ty)).toEqual({value: {'D': 0}}); expect(validate({'E': ''}, ty)).toEqual(null); expect(validate({'E': 0}, ty)).toEqual(null); expect(validate({0: ''}, ty)).toEqual({value: {'0': ''}}); expect(validate({0: 0}, ty)).toEqual({value: {'0': 0}}); expect(validate([], ty)).toEqual({value: []}); expect(validate([''], ty)).toEqual({value: ['']}); expect(validate([0], ty)).toEqual({value: [0]}); } } } }); it("compiler-additional-props-4", function() { const schemas = [compile(` interface A { [propNames1: /^A+$/]: string; [propNames2: /^B+$/]?: string; } interface C extends A { [propNames3: /^C+$/]: number; [propNames4: /^D+$/]: number; } `), compile(` interface C extends A { [propNames3: /^C+$/]: number; [propNames4: /^D+$/]: number; } interface A { [propNames1: /^A+$/]: string; [propNames2: /^B+$/]?: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'A', 'C', ]); expect(Array.from(schemas[1].keys())).toEqual([ 'C', 'A', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [], additionalProps: [ [[/^A+$/], {kind: 'primitive', primitiveName: 'string'}, true], [[/^B+$/], {kind: 'optional', optional: {kind: 'primitive', primitiveName: 'string'}}, true], [[/^C+$/], {kind: 'primitive', primitiveName: 'number'}], [[/^D+$/], {kind: 'primitive', primitiveName: 'number'}], ], baseTypes: [{ name: 'A', typeName: 'A', kind: 'object', members: [], additionalProps: [ [[/^A+$/], {kind: 'primitive', primitiveName: 'string'}], [[/^B+$/], {kind: 'optional', optional: {kind: 'primitive', primitiveName: 'string'}}], ], }], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); expect(validate({}, ty)).toEqual({value: {}}); expect(validate({'A': ''}, ty)).toEqual({value: {'A': ''}}); expect(validate({'A': 0}, ty)).toEqual(null); expect(validate({'B': ''}, ty)).toEqual({value: {'B': ''}}); expect(validate({'B': 0}, ty)).toEqual(null); expect(validate({'C': ''}, ty)).toEqual(null); expect(validate({'C': 0}, ty)).toEqual({value: {'C': 0}}); expect(validate({'D': ''}, ty)).toEqual(null); expect(validate({'D': 0}, ty)).toEqual({value: {'D': 0}}); expect(validate({'E': ''}, ty)).toEqual({value: {'E': ''}}); expect(validate({'E': 0}, ty)).toEqual({value: {'E': 0}}); expect(validate({0: ''}, ty)).toEqual({value: {'0': ''}}); expect(validate({0: 0}, ty)).toEqual({value: {'0': 0}}); expect(validate([], ty)).toEqual({value: []}); expect(validate([''], ty)).toEqual({value: ['']}); expect(validate([0], ty)).toEqual({value: [0]}); } } } }); it("compiler-additional-props-5a", function() { const schemas = [compile(` interface C { [propNames3: string]: number; [propNames4: number]: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'C', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [], additionalProps: [ [['string'], {kind: 'primitive', primitiveName: 'number'}], [['number'], {kind: 'primitive', primitiveName: 'string'}], ], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); expect(validate({}, ty)).toEqual({value: {}}); expect(validate({'A': ''}, ty)).toEqual(null); expect(validate({'A': 0}, ty)).toEqual({value: {'A': 0}}); expect(validate({'B': ''}, ty)).toEqual(null); expect(validate({'B': 0}, ty)).toEqual({value: {'B': 0}}); expect(validate({'C': ''}, ty)).toEqual(null); expect(validate({'C': 0}, ty)).toEqual({value: {'C': 0}}); expect(validate({0: ''}, ty)).toEqual({value: {'0': ''}}); // expect(validate({0: 0}, ty)).toEqual(null); // TODO: expect(validate([], ty)).toEqual({value: []}); expect(validate([''], ty)).toEqual({value: ['']}); // expect(validate([0], ty)).toEqual(null); // TODO: } } } }); it("compiler-additional-props-5b", function() { const schemas = [compile(` interface C { [propNames4: number]: string; [propNames3: string]: number; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'C', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [], additionalProps: [ [['number'], {kind: 'primitive', primitiveName: 'string'}], [['string'], {kind: 'primitive', primitiveName: 'number'}], ], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); expect(validate({}, ty)).toEqual({value: {}}); expect(validate({'A': ''}, ty)).toEqual(null); expect(validate({'A': 0}, ty)).toEqual({value: {'A': 0}}); expect(validate({'B': ''}, ty)).toEqual(null); expect(validate({'B': 0}, ty)).toEqual({value: {'B': 0}}); expect(validate({'C': ''}, ty)).toEqual(null); expect(validate({'C': 0}, ty)).toEqual({value: {'C': 0}}); expect(validate({0: ''}, ty)).toEqual({value: {'0': ''}}); // expect(validate({0: 0}, ty)).toEqual(null); // TODO: expect(validate([], ty)).toEqual({value: []}); expect(validate([''], ty)).toEqual({value: ['']}); // expect(validate([0], ty)).toEqual(null); // TODO: } } } }); it("compiler-additional-props-5c", function() { const schemas = [compile(` interface C { [propNames4: number]: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'C', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [], additionalProps: [ [['number'], {kind: 'primitive', primitiveName: 'string'}], ], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); expect(validate({}, ty)).toEqual({value: {}}); expect(validate({'A': ''}, ty)).toEqual(null); expect(validate({'A': 0}, ty)).toEqual(null); expect(validate({'B': ''}, ty)).toEqual(null); expect(validate({'B': 0}, ty)).toEqual(null); expect(validate({'C': ''}, ty)).toEqual(null); expect(validate({'C': 0}, ty)).toEqual(null); expect(validate({0: ''}, ty)).toEqual({value: {0: ''}}); expect(validate({0: 0}, ty)).toEqual(null); expect(validate([], ty)).toEqual({value: []}); expect(validate([''], ty)).toEqual({value: ['']}); expect(validate([0], ty)).toEqual(null); } } } }); it("compiler-additional-props-5d", function() { const schemas = [compile(` interface C { [propNames4: number | string]: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'C', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [], additionalProps: [ [['number', 'string'], {kind: 'primitive', primitiveName: 'string'}], ], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); expect(validate({}, ty)).toEqual({value: {}}); expect(validate({'A': ''}, ty)).toEqual({value: {'A': ''}}); expect(validate({'A': 0}, ty)).toEqual(null); expect(validate({'B': ''}, ty)).toEqual({value: {'B': ''}}); expect(validate({'B': 0}, ty)).toEqual(null); expect(validate({'C': ''}, ty)).toEqual({value: {'C': ''}}); expect(validate({'C': 0}, ty)).toEqual(null); expect(validate({0: ''}, ty)).toEqual({value: {0: ''}}); expect(validate({0: 0}, ty)).toEqual(null); expect(validate([], ty)).toEqual({value: []}); expect(validate([''], ty)).toEqual({value: ['']}); expect(validate([0], ty)).toEqual(null); } } } }); it("compiler-additional-props-6", function() { const schemas = [compile(` interface C { a?: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'C', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [ ['a', { name: 'a', kind: 'optional', optional: { kind: 'primitive', primitiveName: 'string', }, }], ], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); expect(validate({}, ty)).toEqual({value: {}}); expect(validate({'a': ''}, ty)).toEqual({value: {'a': ''}}); expect(validate({'a': 0}, ty)).toEqual(null); expect(validate({'A': ''}, ty)).toEqual({value: {'A': ''}}); expect(validate({'A': 0}, ty)).toEqual({value: {'A': 0}}); expect(validate({'B': ''}, ty)).toEqual({value: {'B': ''}}); expect(validate({'B': 0}, ty)).toEqual({value: {'B': 0}}); expect(validate({'C': ''}, ty)).toEqual({value: {'C': ''}}); expect(validate({'C': 0}, ty)).toEqual({value: {'C': 0}}); expect(validate({0: ''}, ty)).toEqual({value: {0: ''}}); expect(validate({0: 0}, ty)).toEqual({value: {0: 0}}); expect(validate([], ty)).toEqual({value: []}); expect(validate([''], ty)).toEqual({value: ['']}); expect(validate([0], ty)).toEqual({value: [0]}); } } } }); it("compiler-additional-props-6b", function() { const schemas = [compile(` interface C { a?: string; } `)]; { expect(Array.from(schemas[0].keys())).toEqual([ 'C', ]); } for (const schema of schemas) { { const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [ ['a', { name: 'a', kind: 'optional', optional: { kind: 'primitive', primitiveName: 'string', }, }], ], }; // const ty = getType(schema, 'C'); for (const ty of [getType(deserialize(serialize(schema)), 'C'), getType(schema, 'C')]) { expect(ty).toEqual(rhs); expect(validate({}, ty, {noAdditionalProps: true})).toEqual({value: {}}); expect(validate({'a': ''}, ty, {noAdditionalProps: true})).toEqual({value: {'a': ''}}); expect(validate({'a': 0}, ty, {noAdditionalProps: true})).toEqual(null); expect(validate({'A': ''}, ty, {noAdditionalProps: true})).toEqual(null); expect(validate({'A': 0}, ty, {noAdditionalProps: true})).toEqual(null); expect(validate({'B': ''}, ty, {noAdditionalProps: true})).toEqual(null); expect(validate({'B': 0}, ty, {noAdditionalProps: true})).toEqual(null); expect(validate({'C': ''}, ty, {noAdditionalProps: true})).toEqual(null); expect(validate({'C': 0}, ty, {noAdditionalProps: true})).toEqual(null); expect(validate({0: ''}, ty, {noAdditionalProps: true})).toEqual(null); expect(validate({0: 0}, ty, {noAdditionalProps: true})).toEqual(null); expect(validate([], ty, {noAdditionalProps: true})).toEqual({value: []}); expect(validate([''], ty, {noAdditionalProps: true})).toEqual(null); expect(validate([0], ty, {noAdditionalProps: true})).toEqual(null); } } } }); });