tynder
Version:
TypeScript friendly Data validator for JavaScript.
1,219 lines (1,201 loc) • 61.4 kB
text/typescript
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<any>(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<B, 'b' | 'c'>;
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<any>(v, ty, {schema, noAdditionalProps: true})).toEqual({value: v});
}
{
const ctx: Partial<ValidationContext> = {
checkAll: true,
noAdditionalProps: true,
schema,
};
const v = {
a: '',
b: 0,
c: false,
};
expect(validate<any>(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<B, 'a' | 'c'>;
`), compile(`
type C = Pick<B, 'a' | 'c'>;
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<any>(v, ty, {schema, noAdditionalProps: true})).toEqual({value: v});
}
{
const ctx: Partial<ValidationContext> = {
checkAll: true,
noAdditionalProps: true,
schema,
};
const v = {
a: '',
b: 0,
c: false,
d: BigInt(5),
};
expect(validate<any>(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<B>;
`), compile(`
type C = Partial<B>;
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<any>(v, ty, {schema, noAdditionalProps: true})).toEqual({value: v});
}
{
const v = {
a: '',
b: 0,
c: false,
d: BigInt(5),
};
expect(validate<any>(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<number>(-1, ty)).toEqual(null);
expect(validate<number>(0, ty)).toEqual({value: 0});
expect(validate<number>(1, ty)).toEqual({value: 1});
expect(validate<number>(2, ty)).toEqual({value: 2});
expect(validate<number>(3, ty)).toEqual({value: 3});
expect(validate<number>(4, ty)).toEqual({value: 4});
expect(validate<number>(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<number>(-1, ty)).toEqual(null);
expect(validate<number>(0, ty)).toEqual(null);
expect(validate<number>(1, ty)).toEqual(null);
expect(validate<number>(2, ty)).toEqual({value: 2});
expect(validate<number>(3, ty)).toEqual({value: 3});
expect(validate<number>(4, ty)).toEqual(null);
expect(validate<number>(9, ty)).toEqual(null);
expect(validate<number>(10, ty)).toEqual({value: 10});
expect(validate<number>(11, ty)).toEqual({value: 11});
expect(validate<number>(12, ty)).toEqual({value: 12});
expect(validate<number>(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<number>(-1, ty)).toEqual(null);
expect(validate<number>(0, ty)).toEqual(null);
expect(validate<number>(1, ty)).toEqual(null);
expect(validate<string>('XA', ty)).toEqual({value: 'XA'});
expect(validate<string>('XB', ty)).toEqual({value: 'XB'});
expect(validate<string>('XC', ty)).toEqual({value: 'XC'});
expect(validate<string>('XD', ty)).toEqual({value: 'XD'});
expect(validate<string>('XE', ty)).toEqual({value: 'XE'});
expect(validate<number>('AAA', ty)).toEqual(null);
expect(validate<number>('AA', ty)).toEqual(null);
expect(validate<number>('', 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<number>(-1, ty)).toEqual(null);
expect(validate<number>(0, ty)).toEqual({value: 0});
expect(validate<number>(1, ty)).toEqual({value: 1});
expect(validate<number>(2, ty)).toEqual(null);
expect(validate<number>(9, ty)).toEqual(null);
expect(validate<number>(10, ty)).toEqual({value: 10});
expect(validate<number>(11, ty)).toEqual({value: 11});
expect(validate<number>(12, ty)).toEqual(null);
expect(validate<string>('XA', ty)).toEqual({value: 'XA'});
expect(validate<number>('XB', ty)).toEqual(null);
expect(validate<number>('XC', ty)).toEqual(null);
expect(validate<number>('XD', ty)).toEqual(null);
expect(validate<number>('XE', ty)).toEqual(null);
expect(validate<string>('XF', ty)).toEqual({value: 'XF'});
expect(validate<number>('AAA', ty)).toEqual(null);
expect(validate<number>('AA', ty)).toEqual(null);
expect(validate<number>('', 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<number>(-1, ty)).toEqual(null);
expect(validate<number>(0, ty)).toEqual({value: 0});
expect(validate<number>(1, ty)).toEqual({value: 1});
expect(validate<number>(2, ty)).toEqual(null);
expect(validate<number>(9, ty)).toEqual(null);
expect(validate<number>(10, ty)).toEqual({value: 10});
expect(validate<number>(11, ty)).toEqual({value: 11});
expect(validate<number>(12, ty)).toEqual(null);
expect(validate<string>('XA', ty)).toEqual({value: 'XA'});
expect(validate<number>('XB', ty)).toEqual(null);
expect(validate<number>('XC', ty)).toEqual(null);
expect(validate<number>('XD', ty)).toEqual(null);
expect(validate<number>('XE', ty)).toEqual(null);
expect(validate<string>('XF', ty)).toEqual({value: 'XF'});
expect(validate<number>('AAA', ty)).toEqual(null);
expect(validate<number>('AA', ty)).toEqual(null);
expect(validate<number>('', 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<number>(-1, ty)).toEqual(null);
expect(validate<number>(0, ty)).toEqual({value: 0});
expect(validate<number>(1, ty)).toEqual({value: 1});
expect(validate<number>(2, ty)).toEqual({value: 2});
expect(validate<number>(3, ty)).toEqual(null);
expect(validate<string>('XA', ty)).toEqual({value: 'XA'});
expect(validate<number>('XB', ty)).toEqual(null);
expect(validate<number>('XC', ty)).toEqual(null);
expect(validate<string>('XD', ty)).toEqual({value: 'XD'});
expect(validate<number>('XE', ty)).toEqual(null);
expect(validate<string>('XF', ty)).toEqual({value: 'XF'});
expect(validate<number>('AAA', ty)).toEqual(null);
expect(validate<number>('AA', ty)).toEqual(null);
expect(validate<number>('', 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<number>(-1, ty)).toEqual(null);
expect(validate<number>(0, ty)).toEqual({value: 0});
expect(validate<number>(1, ty)).toEqual({value: 1});
expect(validate<number>(2, ty)).toEqual({value: 2});
expect(validate<number>(3, ty)).toEqual(null);
expect(validate<string>('XA', ty)).toEqual({value: 'XA'});
expect(validate<number>('XB', ty)).toEqual(null);
expect(validate<number>('XC', ty)).toEqual(null);
expect(validate<string>('XD', ty)).toEqual({value: 'XD'});
expect(validate<number>('XE', ty)).toEqual(null);
expect(validate<string>('XF', ty)).toEqual({value: 'XF'});
expect(validate<number>('AAA', ty)).toEqual(null);
expect(validate<number>('AA', ty)).toEqual(null);
expect(validate<number>('', 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<any>({}, ty)).toEqual({value: {}});
expect(validate<any>({'A': ''}, ty)).toEqual({value: {'A': ''}});
expect(validate<any>({'A': 0}, ty)).toEqual(null);
expect(validate<any>({'B': ''}, ty)).toEqual({value: {'B': ''}});
expect(validate<any>({'B': 0}, ty)).toEqual(null);
expect(validate<any>({'C': ''}, ty)).toEqual(null);
expect(validate<any>({'C': 0}, ty)).toEqual({value: {'C': 0}});
{
const ctx: Partial<ValidationContext> = {};
expect(validate<any>({'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<ValidationContext> = {};
expect(validate<any>({'D': 0}, ty, ctx)).toEqual({value: {'D': 0}});
}
{
const ctx: Partial<ValidationContext> = {};
expect(validate<any>({'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<ValidationContext> = {};
expect(validate<any>({'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<ValidationContext> = {};
expect(validate<any>({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<ValidationContext> = {
noAdditionalProps: true,
};
expect(validate<any>({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<ValidationContext> = {};
expect(validate<any>({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<ValidationContext> = {
noAdditionalProps: true,
};
expect(validate<any>({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<ValidationContext> = {};
expect(validate<any>([], ty, ctx)).toEqual({value: []});
}
{
const ctx: Partial<ValidationContext> = {
noAdditionalProps: true,
};
expect(validate<any>([], ty, ctx)).toEqual({value: []});
}
{
const ctx: Partial<ValidationContext> = {};
expect(validate<any>([''], 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<ValidationContext> = {
noAdditionalProps: true,
};
expect(validate<any>([''], 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<ValidationContext> = {};
expect(validate<any>([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<ValidationContext> = {
noAdditionalProps: true,
};
expect(validate<any>([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<ValidationContext> = {
noAdditionalProps: true,
};
expect(validate<any>([], ty, ctx)).toEqual({value: []});
}
{
const ctx: Partial<ValidationContext> = {
noAdditionalProps: true,
};
expect(validate<any>([''], 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<ValidationContext> = {
noAdditionalProps: true,
};
expect(validate<any>([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<any>({}, ty)).toEqual({value: {}});
expect(validate<any>({'A': ''}, ty)).toEqual({value: {'A': ''}});
expect(validate<any>({'A': 0}, ty)).toEqual(null);
expect(validate<any>({'B': ''}, ty)).toEqual({value: {'B': ''}});
expect(validate<any>({'B': 0}, ty)).toEqual(null);
expect(validate<any>({'C': ''}, ty)).toEqual({value: {'C': ''}});
expect(validate<any>({'C': 0}, ty)).toEqual({value: {'C': 0}});
expect(validate<any>({'D': ''}, ty)).toEqual(null);
expect(validate<any>({'D': 0}, ty)).toEqual(null);
expect(validate<any>({'E': ''}, ty)).toEqual(null);
expect(validate<any>({'E': 0}, ty)).toEqual(null);
expect(validate<any>({0: ''}, ty)).toEqual(null);
expect(validate<any>({0: 0}, ty)).toEqual(null);
expect(validate<any>([], ty)).toEqual({value: []});
expect(validate<any>([''], ty)).toEqual(null);
expect(validate<any>([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<any>({}, ty)).toEqual({value: {}});
expect(validate<any>({'A': ''}, ty)).toEqual({value: {'A': ''}});
expect(validate<any>({'A': 0}, ty)).toEqual(null);
expect(validate<any>({'B': ''}, ty)).toEqual({value: {'B': ''}});
expect(validate<any>({'B': 0}, ty)).toEqual(null);
expect(validate<any>({'C': ''}, ty)).toEqual(null);
expect(validate<any>({'C': 0}, ty)).toEqual({value: {'C': 0}});
expect(validate<any>({'D': ''}, ty)).toEqual(null);
expect(validate<any>({'D': 0}, ty)).toEqual({value: {'D': 0}});
expect(validate<any>({'E': ''}, ty)).toEqual(null);
expect(validate<any>({'E': 0}, ty)).toEqual(null);
expect(validate<any>({0: ''}, ty)).toEqual({value: {'0': ''}});
expect(validate<any>({0: 0}, ty)).toEqual({value: {'0': 0}});
expect(validate<any>([], ty)).toEqual({value: []});
expect(validate<any>([''], ty)).toEqual({value: ['']});
expect(validate<any>([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<any>({}, ty)).toEqual({value: {}});
expect(validate<any>({'A': ''}, ty)).toEqual({value: {'A': ''}});
expect(validate<any>({'A': 0}, ty)).toEqual(null);
expect(validate<any>({'B': ''}, ty)).toEqual({value: {'B': ''}});
expect(validate<any>({'B': 0}, ty)).toEqual(null);
expect(validate<any>({'C': ''}, ty)).toEqual(null);
expect(validate<any>({'C': 0}, ty)).toEqual({value: {'C': 0}});
expect(validate<any>({'D': ''}, ty)).toEqual(null);
expect(validate<any>({'D': 0}, ty)).toEqual({value: {'D': 0}});
expect(validate<any>({'E': ''}, ty)).toEqual({value: {'E': ''}});
expect(validate<any>({'E': 0}, ty)).toEqual({value: {'E': 0}});
expect(validate<any>({0: ''}, ty)).toEqual({value: {'0': ''}});
expect(validate<any>({0: 0}, ty)).toEqual({value: {'0': 0}});
expect(validate<any>([], ty)).toEqual({value: []});
expect(validate<any>([''], ty)).toEqual({value: ['']});
expect(validate<any>([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<any>({}, ty)).toEqual({value: {}});
expect(validate<any>({'A': ''}, ty)).toEqual(null);
expect(validate<any>({'A': 0}, ty)).toEqual({value: {'A': 0}});
expect(validate<any>({'B': ''}, ty)).toEqual(null);
exp