import { TypeAssertion, ObjectAssertion, AdditionalPropsMember, ValidationContext, ErrorMessages } from '../types'; import { validate, getType } from '../validator'; import { compile } from '../compiler'; import { serialize, deserialize } from '../serializer'; describe("compiler-7", function() { const myMessages: ErrorMessages = { invalidDefinition: ':invalidDefinition: %{name} %{parentType}', required: ':required: %{name} %{parentType}', typeUnmatched: ':typeUnmatched: %{name} %{parentType} %{expectedType}', additionalPropUnmatched: ':additionalPropUnmatched %{name} %{parentType}', repeatQtyUnmatched: ':repeatQtyUnmatched: %{name} %{parentType} %{repeatQty}', sequenceUnmatched: ':sequenceUnmatched: %{name} %{parentType}', valueRangeUnmatched: ':valueRangeUnmatched: %{name} %{parentType} %{minValue} %{maxValue}', valuePatternUnmatched: ':valuePatternUnmatched: %{name} %{parentType} %{pattern}', valueLengthUnmatched: ':valueLengthUnmatched: %{name} %{parentType} %{minLength} %{maxLength}', valueUnmatched: ':valueUnmatched: %{name} %{parentType} %{expectedValue}', }; function mkmsgobj(s: string): ErrorMessages { const m: ErrorMessages = { invalidDefinition: s + myMessages.invalidDefinition, required: s + myMessages.required, typeUnmatched: s + myMessages.typeUnmatched, repeatQtyUnmatched: s + myMessages.repeatQtyUnmatched, sequenceUnmatched: s + myMessages.sequenceUnmatched, valueRangeUnmatched: s + myMessages.valueRangeUnmatched, valuePatternUnmatched: s + myMessages.valuePatternUnmatched, valueLengthUnmatched: s + myMessages.valueLengthUnmatched, valueUnmatched: s + myMessages.valueUnmatched, }; return m; } function mkmsg(s: string): string { return JSON.stringify(mkmsgobj(s)); } it("compiler-error-reporting-5", function() { const schema = compile(` @msg(${mkmsg('A')}) interface A { @msg(${mkmsg('A.a1')}) a1: string; @msg('MSG_A.a2') a2?: number; /** Comment A.a3 */ @msg('MSG_A.a3') a3: string[]; /** Comment A.a4 */ @msg('MSG_A.a4') [propNames: string]: any; } /** Comment B */ @msg('MSG_B') interface B { @msg('MSG_B.b1') b1: boolean; /** Comment B.b2 */ @msg('MSG_B.b2') b2: A; } @msg(${mkmsg('C')}) interface C extends A { @msg('MSG_C.c1') c1: string; } /** Comment D */ @msg(${mkmsg('D')}) type D = string; /** Comment E */ @msg(${mkmsg('E')}) enum E { P, Q, R, } interface F { @msg(${mkmsg('F.f1')}) f1: B; @msg('MSG_F.f2') f2?: A; } `); { expect(Array.from(schema.keys())).toEqual([ 'A', 'B', 'C', 'D', 'E', 'F', ]); } { const ty = getType(schema, 'A'); expect(false).toEqual(schema.get('A')?.exported as any); const rhs: TypeAssertion = { name: 'A', typeName: 'A', kind: 'object', members: [ ['a1', { name: 'a1', kind: 'primitive', primitiveName: 'string', messages: mkmsgobj('A.a1'), }], ['a2', { name: 'a2', kind: 'optional', optional: { kind: 'primitive', primitiveName: 'number', message: 'MSG_A.a2', }, message: 'MSG_A.a2', }], ['a3', { name: 'a3', kind: 'repeated', min: null, max: null, repeated: { kind: 'primitive', primitiveName: 'string', }, message: 'MSG_A.a3', }, false, 'Comment A.a3'], ], additionalProps: [ [['string'], { kind: 'any', message: 'MSG_A.a4', }, false, 'Comment A.a4'], ], messages: mkmsgobj('A'), }; expect(ty).toEqual(rhs); } { const ty = getType(schema, 'B'); expect(false).toEqual(schema.get('B')?.exported as any); const rhs: TypeAssertion = { name: 'B', typeName: 'B', kind: 'object', members: [ ['b1', { name: 'b1', kind: 'primitive', primitiveName: 'boolean', message: 'MSG_B.b1', }], ['b2', { name: 'b2', typeName: 'A', kind: 'object', members: [...(getType(schema, 'A') as ObjectAssertion).members], additionalProps: [...((getType(schema, 'A') as ObjectAssertion).additionalProps as AdditionalPropsMember[])], message: 'MSG_B.b2', // NOTE: 'messages' is overwritten by 'B.b2's 'message'. Only one of 'message' or 'messages' can be set. }, false, 'Comment B.b2'], ], message: 'MSG_B', docComment: 'Comment B', }; expect(ty).toEqual(rhs); } { const ty = getType(schema, 'C'); expect(false).toEqual(schema.get('C')?.exported as any); const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [ ['c1', { name: 'c1', kind: 'primitive', primitiveName: 'string', message: 'MSG_C.c1', }], ['a1', { name: 'a1', kind: 'primitive', primitiveName: 'string', messages: mkmsgobj('A.a1'), }, true], ['a2', { name: 'a2', kind: 'optional', optional: { kind: 'primitive', primitiveName: 'number', message: 'MSG_A.a2', }, message: 'MSG_A.a2', }, true], ['a3', { name: 'a3', kind: 'repeated', min: null, max: null, repeated: { kind: 'primitive', primitiveName: 'string', }, message: 'MSG_A.a3', }, true, 'Comment A.a3'], ], baseTypes: [ getType(schema, 'A') as any, ], additionalProps: [ [['string'], { kind: 'any', message: 'MSG_A.a4', }, true, 'Comment A.a4'] ], messages: mkmsgobj('C'), }; expect(ty).toEqual(rhs); } { const ty = getType(schema, 'D'); expect(false).toEqual(schema.get('D')?.exported as any); const rhs: TypeAssertion = { name: 'D', typeName: 'D', kind: 'primitive', primitiveName: 'string', messages: mkmsgobj('D'), docComment: 'Comment D', }; expect(ty).toEqual(rhs); } { const ty = getType(schema, 'E'); expect(false).toEqual(schema.get('E')?.exported as any); const rhs: TypeAssertion = { name: 'E', typeName: 'E', kind: 'enum', values: [ ['P', 0], ['Q', 1], ['R', 2], ], messages: mkmsgobj('E'), docComment: 'Comment E', }; expect(ty).toEqual(rhs); } { const ty = getType(schema, 'F'); expect(false).toEqual(schema.get('F')?.exported as any); const rhs: TypeAssertion = { name: 'F', typeName: 'F', kind: 'object', members: [ ['f1', { name: 'f1', typeName: 'B', kind: 'object', members: [...(getType(schema, 'B') as ObjectAssertion).members], messages: mkmsgobj('F.f1'), // NOTE: 'messages' is overwritten by 'B.b2's 'message'. Only one of 'message' or 'messages' can be set. docComment: 'Comment B', }], ['f2', { name: 'f2', typeName: 'A', kind: 'optional', optional: { name: 'A', typeName: 'A', kind: 'object', members: [...(getType(schema, 'A') as ObjectAssertion).members], additionalProps: [...((getType(schema, 'A') as ObjectAssertion).additionalProps as AdditionalPropsMember[])], message: 'MSG_F.f2', }, message: 'MSG_F.f2', }], ], }; expect(ty).toEqual(rhs); } }); it("compiler-error-reporting-6", function() { const schema = compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: string; @msg('MSG_A.a2') a2?: number; /** Comment A.a3 */ @msg('MSG_A.a3') a3: string[]; /** Comment A.a4 */ @msg('MSG_A.a4') [propNames: string]: any; } /** Comment B */ @msg('MSG_B') export interface B { @msg('MSG_B.b1') b1: boolean; /** Comment B.b2 */ @msg('MSG_B.b2') b2: A; } @msg(${mkmsg('C')}) export interface C extends A { @msg('MSG_C.c1') c1: string; } /** Comment D */ @msg(${mkmsg('D')}) export type D = string; /** Comment E */ @msg(${mkmsg('E')}) export enum E { P, Q, R, } export interface F { @msg(${mkmsg('F.f1')}) f1: B; @msg('MSG_F.f2') f2?: A; } `); { expect(Array.from(schema.keys())).toEqual([ 'A', 'B', 'C', 'D', 'E', 'F', ]); } { const ty = getType(schema, 'A'); expect(true).toEqual(schema.get('A')?.exported as any); const rhs: TypeAssertion = { name: 'A', typeName: 'A', kind: 'object', members: [ ['a1', { name: 'a1', kind: 'primitive', primitiveName: 'string', messages: mkmsgobj('A.a1'), }], ['a2', { name: 'a2', kind: 'optional', optional: { kind: 'primitive', primitiveName: 'number', message: 'MSG_A.a2', }, message: 'MSG_A.a2', }], ['a3', { name: 'a3', kind: 'repeated', min: null, max: null, repeated: { kind: 'primitive', primitiveName: 'string', }, message: 'MSG_A.a3', }, false, 'Comment A.a3'], ], additionalProps: [ [['string'], { kind: 'any', message: 'MSG_A.a4', }, false, 'Comment A.a4'], ], messages: mkmsgobj('A'), }; expect(ty).toEqual(rhs); } { const ty = getType(schema, 'B'); expect(true).toEqual(schema.get('B')?.exported as any); const rhs: TypeAssertion = { name: 'B', typeName: 'B', kind: 'object', members: [ ['b1', { name: 'b1', kind: 'primitive', primitiveName: 'boolean', message: 'MSG_B.b1', }], ['b2', { name: 'b2', typeName: 'A', kind: 'object', members: [...(getType(schema, 'A') as ObjectAssertion).members], additionalProps: [...((getType(schema, 'A') as ObjectAssertion).additionalProps as AdditionalPropsMember[])], message: 'MSG_B.b2', // NOTE: 'messages' is overwritten by 'B.b2's 'message'. Only one of 'message' or 'messages' can be set. }, false, 'Comment B.b2'], ], message: 'MSG_B', docComment: 'Comment B', }; expect(ty).toEqual(rhs); } { const ty = getType(schema, 'C'); expect(true).toEqual(schema.get('C')?.exported as any); const rhs: TypeAssertion = { name: 'C', typeName: 'C', kind: 'object', members: [ ['c1', { name: 'c1', kind: 'primitive', primitiveName: 'string', message: 'MSG_C.c1', }], ['a1', { name: 'a1', kind: 'primitive', primitiveName: 'string', messages: mkmsgobj('A.a1'), }, true], ['a2', { name: 'a2', kind: 'optional', optional: { kind: 'primitive', primitiveName: 'number', message: 'MSG_A.a2', }, message: 'MSG_A.a2', }, true], ['a3', { name: 'a3', kind: 'repeated', min: null, max: null, repeated: { kind: 'primitive', primitiveName: 'string', }, message: 'MSG_A.a3', }, true, 'Comment A.a3'], ], baseTypes: [ getType(schema, 'A') as any, ], additionalProps: [ [['string'], { kind: 'any', message: 'MSG_A.a4', }, true, 'Comment A.a4'] ], messages: mkmsgobj('C'), }; expect(ty).toEqual(rhs); } { const ty = getType(schema, 'D'); expect(true).toEqual(schema.get('D')?.exported as any); const rhs: TypeAssertion = { name: 'D', typeName: 'D', kind: 'primitive', primitiveName: 'string', messages: mkmsgobj('D'), docComment: 'Comment D', }; expect(ty).toEqual(rhs); } { const ty = getType(schema, 'E'); expect(true).toEqual(schema.get('E')?.exported as any); const rhs: TypeAssertion = { name: 'E', typeName: 'E', kind: 'enum', values: [ ['P', 0], ['Q', 1], ['R', 2], ], messages: mkmsgobj('E'), docComment: 'Comment E', }; expect(ty).toEqual(rhs); } { const ty = getType(schema, 'F'); expect(true).toEqual(schema.get('F')?.exported as any); const rhs: TypeAssertion = { name: 'F', typeName: 'F', kind: 'object', members: [ ['f1', { name: 'f1', typeName: 'B', kind: 'object', members: [...(getType(schema, 'B') as ObjectAssertion).members], messages: mkmsgobj('F.f1'), // NOTE: 'messages' is overwritten by 'B.b2's 'message'. Only one of 'message' or 'messages' can be set. docComment: 'Comment B', }], ['f2', { name: 'f2', typeName: 'A', kind: 'optional', optional: { name: 'A', typeName: 'A', kind: 'object', members: [...(getType(schema, 'A') as ObjectAssertion).members], additionalProps: [...((getType(schema, 'A') as ObjectAssertion).additionalProps as AdditionalPropsMember[])], message: 'MSG_F.f2', }, message: 'MSG_F.f2', }], ], }; expect(ty).toEqual(rhs); } }); it("compiler-error-reporting-reporter-1-1", function() { const schema = compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: string; } `); const ctx: Partial = { checkAll: true, schema, }; expect(validate({}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'Required', message: 'A.a1:required: a1 A', dataPath: 'A:a1', constraints: {}, }]); }); it("compiler-error-reporting-reporter-1-2", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: string; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: string; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: 1}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'TypeUnmatched', message: 'A.a1:typeUnmatched: a1 A string', dataPath: 'A:a1', constraints: {}, value: 1, }]); } }); it("compiler-error-reporting-reporter-1-2b", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: string; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: string; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: [1]}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'TypeUnmatched', message: 'A.a1:typeUnmatched: a1 A string', dataPath: 'A:a1', constraints: {}, }]); } }); it("compiler-error-reporting-reporter-1-2c", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: string[]; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: string[]; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: '1'}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'TypeUnmatched', message: 'A.a1:typeUnmatched: a1 A (repeated string)', dataPath: 'A:a1', constraints: {}, value: '1', }]); } }); it("compiler-error-reporting-reporter-1-2d", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: string[]; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: string[]; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: [1]}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'TypeUnmatched', message: '"repeated item of a1" of "A" should be type "string".', // TODO: dataPath: 'A:a1.(0:repeated)', constraints: {}, value: 1, }]); } }); it("compiler-error-reporting-reporter-1-2e", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: [string]; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: [string]; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: '1'}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'TypeUnmatched', message: 'A.a1:typeUnmatched: a1 A (sequence)', dataPath: 'A:a1', constraints: {}, value: '1', }]); } }); it("compiler-error-reporting-reporter-1-2f", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: [string]; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: [string]; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: [1]}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'TypeUnmatched', message: '"sequence item of a1" of "A" should be type "string".', // TODO: dataPath: 'A:a1.(0:sequence)', constraints: {}, value: 1, }]); } }); it("compiler-error-reporting-reporter-1-3", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) @range(3, 5) a1: number; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) @range(3, 5) a1?: number; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: 1}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'ValueRangeUnmatched', message: 'A.a1:valueRangeUnmatched: a1 A 3 5', dataPath: 'A:a1', constraints: {minValue: 3, maxValue: 5}, value: 1, }]); } }); it("compiler-error-reporting-reporter-1-4", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) @minLength(3) @maxLength(5) a1: string; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) @minLength(3) @maxLength(5) a1?: string; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: '1'}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'ValueLengthUnmatched', message: 'A.a1:valueLengthUnmatched: a1 A 3 5', dataPath: 'A:a1', constraints: {minLength: 3, maxLength: 5}, value: '1', }]); } }); it("compiler-error-reporting-reporter-1-5", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) @match(/^[0-9]+$/) a1: string; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) @match(/^[0-9]+$/) a1?: string; } `)]; for (const schema of schemas) { for (const ty of [getType(deserialize(serialize(schema)), 'A'), getType(schema, 'A')]) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: 'A'}, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'ValuePatternUnmatched', message: 'A.a1:valuePatternUnmatched: a1 A /^[0-9]+$/', dataPath: 'A:a1', constraints: {pattern: '/^[0-9]+$/'}, value: 'A', }]); } } }); it("compiler-error-reporting-reporter-1-5b", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) @match(/^[0-9]+$/gi) a1: string; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) @match(/^[0-9]+$/gi) a1?: string; } `)]; for (const schema of schemas) { for (const ty of [getType(deserialize(serialize(schema)), 'A'), getType(schema, 'A')]) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: 'A'}, ty, ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'ValuePatternUnmatched', message: 'A.a1:valuePatternUnmatched: a1 A /^[0-9]+$/gi', dataPath: 'A:a1', constraints: {pattern: '/^[0-9]+$/gi'}, value: 'A', }]); } } }); it("compiler-error-reporting-reporter-1-6", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: 5; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: 5; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: 4}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'ValueUnmatched', message: 'A.a1:valueUnmatched: a1 A 5', dataPath: 'A:a1', constraints: {}, value: 4, }]); } }); it("compiler-error-reporting-reporter-1-7a", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: [...]; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: [...]; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: [1]}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'TypeUnmatched', // TODO: expect SequenceUnmatched? message: '"sequence item of a1" of "A" should be type "string".', // TODO: custom error message is ignored dataPath: 'A:a1.(0:sequence)', constraints: {min: 3, max: 5}, }]); } }); it("compiler-error-reporting-reporter-1-7b", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: [...]; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: [...]; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: ['1', '2']}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'RepeatQtyUnmatched', message: '"sequence item of a1" of "A" should repeat 3..5 times.', // TODO: custom error message is ignored dataPath: 'A:a1.(2:sequence)', constraints: {min: 3, max: 5}, }]); } }); it("compiler-error-reporting-reporter-1-7c", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: [string?]; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: [string?]; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: [1]}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'SequenceUnmatched', message: 'A.a1:sequenceUnmatched: a1 A', dataPath: 'A:a1', constraints: {}, }]); } }); it("compiler-error-reporting-reporter-1-7d", function() { const schemas = [compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1: [string?]; } `), compile(` @msg(${mkmsg('A')}) export interface A { @msg(${mkmsg('A.a1')}) a1?: [string?]; } `)]; for (const schema of schemas) { const ctx: Partial = { checkAll: true, schema, }; expect(validate({a1: ['1', '2']}, getType(schema, 'A'), ctx)).toEqual(null); expect(ctx.errors).toEqual([{ code: 'RepeatQtyUnmatched', message: '"sequence item of a1" of "A" should repeat 0..1 times.', // TODO: custom error message is ignored dataPath: 'A:a1.(2:sequence)', constraints: {}, }]); } }); });