import _Ajv from "../ajv_jtd" ; import type { JTDSchemaType , SomeJTDSchemaType , JTDDataType } from "../../dist/jtd" ; import chai from "../chai" ; const should = chai . should ( ) ; /** type is true if T is identically E */ type TypeEquality < T , E > = [ T ] extends [ E ] ? ( [ E ] extends [ T ] ? true : false ) : false ; interface A { type : "a" ; a : number ; } interface B { type : "b" ; b ? : string ; } type MyData = A | B ; interface LinkedList { val : number ; next ? : LinkedList ; } const mySchema = { discriminator : "type" , mapping : { a : { properties : { a : { type : "float64" } } } , b : { optionalProperties : { b : { type : "string" } } } , } , } ; describe ( "JTDSchemaType" , ( ) => { it ( "validation should prove the data type" , ( ) => { const ajv = new _Ajv ( ) ; const validate = ajv . compile ( mySchema ) ; const validData = { type : "a" , a : 1 } ; if ( validate ( validData ) && validData . type === "a" ) { validData . a . should . equal ( 1 ) ; } should . not . exist ( validate . errors ) ; if ( ajv . validate ( mySchema , validData ) && validData . type === "a" ) { validData . a . should . equal ( 1 ) ; } should . not . exist ( ajv . errors ) ; } ) ; it ( "parser should return correct data type" , ( ) => { const ajv = new _Ajv ( ) ; const parse = ajv . compileParser ( mySchema ) ; const validJson = '{"type": "a", "a": 1}' ; const data = parse ( validJson ) ; if ( data !== undefined && data . type === "a" ) { data . a . should . equal ( 1 ) ; } should . not . exist ( parse . message ) ; } ) ; it ( "serializer should only accept correct data type" , ( ) => { const ajv = new _Ajv ( ) ; const serialize = ajv . compileSerializer ( mySchema ) ; const validData = { type : "a" as const , a : 1 } ; serialize ( validData ) . should . equal ( '{"type":"a","a":1}' ) ; const invalidData = { type : "a" as const , b : "test" } ; serialize ( invalidData ) ; } ) ; it ( "should typecheck number schemas" , ( ) => { const numf = { type : "float64" } ; const numi = { type : "int32" } ; const numl = { type : "int64" } ; const nums = { type : "int32" } ; const numNull = { type : "int32" , nullable : true } ; const numNotNull = { type : "float32" } ; void [ numf , numi , numl , nums , numNull , numNotNull ] ; } ) ; it ( "should typecheck boolean schemas" , ( ) => { const bool = { type : "boolean" } ; const boolTrue = { type : "boolean" } ; const boolNull = { type : "boolean" , nullable : true } ; void [ bool , boolTrue , boolNull ] ; } ) ; it ( "should typecheck string schemas" , ( ) => { const str = { type : "string" } ; const time = { type : "timestamp" } ; const strNull = { type : "string" , nullable : true } ; void [ str , time , strNull ] ; } ) ; it ( "should typecheck dates" , ( ) => { const time = { type : "timestamp" } ; const timeNull = { type : "timestamp" , nullable : true } ; void [ time , timeNull ] ; } ) ; it ( "should typecheck enumeration schemas" , ( ) => { const enumerate = { enum : [ "a" , "b" ] } ; const enumerateMissing = { enum : [ "a" , "b" ] } ; const enumerateNumber = { enum : [ "a" , "b" ] } ; const enumerateString = { type : "string" } ; const enumerateNull = { enum : [ "a" , "b" ] , nullable : true } ; void [ enumerate , enumerateMissing , enumerateNumber , enumerateString , enumerateNull ] ; } ) ; it ( "should typecheck elements schemas" , ( ) => { const elements = { elements : { type : "float64" } } ; const readonlyElements = { elements : { type : "float64" } } ; const tupleHomo = { elements : { type : "float64" } } ; const tupleHeteroNum = { elements : { type : "float64" } , } ; const tupleHeteroString = { elements : { type : "string" } , } ; const elemNull = { elements : { type : "float64" } , nullable : true } ; const unionElem = false ; const elemUnion = true ; void [ elements , readonlyElements , tupleHomo , tupleHeteroNum , tupleHeteroString , elemNull , unionElem , elemUnion , ] ; } ) ; it ( "should typecheck values schemas" , ( ) => { const values = { values : { type : "float64" } } ; const readonlyValues = { values : { type : "float64" } , } ; const valuesDefined = { values : { type : "float64" } } ; const valuesNull = { values : { type : "float64" } , nullable : true , } ; const unionValues = false ; const valuesUnion = true ; void [ values , readonlyValues , valuesDefined , valuesNull , unionValues , valuesUnion ] ; } ) ; it ( "should typecheck properties schemas" , ( ) => { const properties = { properties : { a : { type : "float64" } , b : { type : "string" } } , } ; const optionalProperties = { optionalProperties : { a : { type : "float64" } , b : { type : "string" } } , additionalProperties : false , } ; const mixedProperties = { properties : { a : { type : "float64" } } , optionalProperties : { b : { type : "string" } } , additionalProperties : true , } ; const fewerProperties = { properties : { a : { type : "float64" } } , } ; const propertiesNull = { properties : { a : { type : "float64" } , b : { type : "string" } } , nullable : true , } ; void [ properties , optionalProperties , mixedProperties , fewerProperties , propertiesNull ] ; } ) ; it ( "should typecheck discriminator schemas" , ( ) => { const union = { discriminator : "type" , mapping : { a : { properties : { a : { type : "float64" } } } , b : { optionalProperties : { b : { type : "string" } } , } , } , } ; const unionDuplicate = { discriminator : "type" , mapping : { a : { properties : { a : { type : "float64" } } } , b : { properties : { a : { type : "float64" } } } , } , } ; const unionMissing = { discriminator : "type" , mapping : { a : { properties : { a : { type : "float64" } } } , } , } ; type Mult = JTDSchemaType < ( A & { typ : "alpha" ; } ) | ( B & { typ : "beta" ; } ) > ; const multOne = { discriminator : "type" , mapping : { a : { properties : { a : { type : "float64" } , typ : { enum : [ "alpha" ] } } } , b : { properties : { typ : { enum : [ "beta" ] } } , optionalProperties : { b : { type : "string" } } , } , } , } ; const multTwo = { discriminator : "typ" , mapping : { alpha : { properties : { a : { type : "float64" } , type : { enum : [ "a" ] } } } , beta : { properties : { type : { enum : [ "b" ] } } , optionalProperties : { b : { type : "string" } } , } , } , } ; const unionNull = { discriminator : "type" , mapping : { a : { properties : { a : { type : "float64" } } } , b : { optionalProperties : { b : { type : "string" } } , } , } , nullable : true , } ; const noCommon = true ; void [ union , unionDuplicate , unionMissing , multOne , multTwo , unionNull , noCommon ] ; } ) ; it ( "should typecheck empty schemas" , ( ) => { const empty = { } ; const emptyUnknown = { nullable : true } ; const falseUnknown = { nullable : false } ; const emptyButFull = { } ; const emptyMeta = { metadata : { } } ; const emptyNull = true ; void [ empty , emptyUnknown , falseUnknown , emptyButFull , emptyMeta , emptyNull ] ; } ) ; it ( "should typecheck ref schemas" , ( ) => { const refs = { definitions : { num : { type : "float64" } , } , elements : { ref : "num" } , } ; const missingDef = { definitions : { } , elements : { ref : "num" } , } ; const missingType = { definitions : { } , elements : { ref : "num" } , } ; const nullRefs = { definitions : { num : { type : "float64" } , } , ref : "num" , nullable : true , } ; const refsNullOne = { definitions : { num : { type : "float64" , nullable : true } , } , ref : "num" , } ; const refsNullTwo = { definitions : { num : { type : "float64" , nullable : true } , } , ref : "num" , nullable : true , } ; void [ refs , missingDef , missingType , nullRefs , refsNullOne , refsNullTwo ] ; } ) ; it ( "should typecheck metadata schemas" , ( ) => { const meta = { type : "float32" , metadata : { key : "val" } } ; const emptyMeta = { metadata : { key : "val" } } ; const unknownMeta = { nullable : true , metadata : { key : "val" } } ; void [ meta , emptyMeta , unknownMeta ] ; } ) ; } ) ; describe ( "JTDDataType" , ( ) => { it ( "validation should prove the data type" , ( ) => { const ajv = new _Ajv ( ) ; const mySchema1 = { discriminator : "type" , mapping : { a : { properties : { a : { type : "float64" } } } , b : { optionalProperties : { b : { type : "string" } } } , } , } as const ; const validate = ajv . compile ( mySchema1 ) ; const validData = { type : "a" , a : 1 } ; if ( validate ( validData ) && validData . type === "a" ) { validData . a . should . equal ( 1 ) ; } should . not . exist ( validate . errors ) ; if ( ajv . validate ( mySchema1 , validData ) && validData . type === "a" ) { validData . a . should . equal ( 1 ) ; } should . not . exist ( ajv . errors ) ; } ) ; it ( "should typecheck number schemas" , ( ) => { const numSchema = { type : "float64" } as const ; const num = true ; void [ num ] ; } ) ; it ( "should typecheck boolean schemas" , ( ) => { const booleanSchema = { type : "boolean" } as const ; const bool = true ; void [ bool ] ; } ) ; it ( "should typecheck string schemas" , ( ) => { const strSchema = { type : "string" } as const ; const str = true ; void [ str ] ; } ) ; it ( "should typecheck timestamp schemas" , ( ) => { const timeSchema = { type : "timestamp" } as const ; const time = true ; void [ time ] ; } ) ; it ( "should typecheck enum schemas" , ( ) => { const enumSchema = { enum : [ "a" , "b" ] } as const ; const enumerated = true ; const enumStringSchema = { enum : [ "a" , "b" ] } ; const enumString = true ; const enumNumSchema = { enum : [ 3 ] } as const ; const enumNum = true ; void [ enumerated , enumString , enumNum ] ; } ) ; it ( "should typecheck elements schemas" , ( ) => { const elementsSchema = { elements : { type : "float64" } } as const ; const elem = true ; void [ elem ] ; } ) ; it ( "should typecheck properties schemas" , ( ) => { const bothPropsSchema = { properties : { a : { type : "float64" } } , optionalProperties : { b : { type : "string" } } , } as const ; const both = true ; const reqPropsSchema = { properties : { a : { type : "float64" } } } as const ; const req = true ; const optPropsSchema = { optionalProperties : { b : { type : "string" } } } as const ; const opt = true ; const noAddSchema = { optionalProperties : { b : { type : "string" } } , additionalProperties : false , } as const ; const noAdd = true ; const addSchema = { optionalProperties : { b : { type : "string" } } , additionalProperties : true , } as const ; const add = true ; const addVal = { b : "b" , additional : 6 } ; void [ both , req , opt , noAdd , add , addVal ] ; } ) ; it ( "should typecheck values schemas" , ( ) => { const valuesSchema = { values : { type : "float64" } } as const ; const values = true ; void [ values ] ; } ) ; it ( "should typecheck discriminator schemas" , ( ) => { const discriminatorSchema = { discriminator : "type" , mapping : { a : { properties : { a : { type : "float64" } } } , b : { optionalProperties : { b : { type : "string" } } } , } , } as const ; const disc = true ; void [ disc ] ; } ) ; it ( "should typecheck ref schemas" , ( ) => { const refSchema = { definitions : { num : { type : "float64" , nullable : true } } , ref : "num" , nullable : true , } as const ; const ref = true ; const llSchema = { definitions : { node : { properties : { val : { type : "float64" } } , optionalProperties : { next : { ref : "node" } } , } , } , ref : "node" , } as const ; const list = true ; void [ ref , list ] ; } ) ; it ( "should typecheck empty schemas" , ( ) => { const emptySchema = { metadata : { } } as const ; const empty = true ; void [ empty ] ; } ) ; } ) ; describe ( "SomeJTDSchemaType" , ( ) => { it ( "should allow setting unknowns" , ( ) => { const schema = { } ; void [ schema ] ; } ) ; } ) ;