import { BaseTypes , IteratableGenericObject , IteratorReturnValue , SchemaPair , SchemaProps , } from './types' ; type mapperFunction = ( value : BaseTypes ) => BaseTypes ; interface mappersInterface { toJSON : { readonly [ key ] : mapperFunction ; } ; fromJSON : { readonly [ key ] : mapperFunction ; } ; } const mappers = { toJSON : { uint32 : value => value as number , sint32 : value => value as number , uint64 : value => ( value as BigInt ) . toString ( ) , sint64 : value => ( value as BigInt ) . toString ( ) , string : value => value as string , bytes : value => ( value as Buffer ) . toString ( 'hex' ) , boolean : value => value as boolean , } , fromJSON : { uint32 : value => value as number , sint32 : value => value as number , uint64 : value => BigInt ( value ) , sint64 : value => BigInt ( value ) , string : value => value as string , bytes : value => Buffer . from ( value as string , 'hex' ) , boolean : value => value as boolean , } , } ; const findObjectByPath = ( message , pathArr ) : SchemaProps | undefined => { let result = message ; for ( let i = 0 ; i < pathArr . length ; i += 1 ) { if ( ! result . properties && ! result . items ) { return undefined ; } if ( result . properties ) { result = result . properties [ pathArr [ i ] ] ; } else if ( result . items ) { const x = ( result . items as SchemaProps ) . properties as SchemaPair ; result = x [ pathArr [ i ] ] ; } } return result ; } ; const isObject = ( item ) : boolean => typeof item === 'object' && item !== null && ! Array . isArray ( item ) && ! Buffer . isBuffer ( item ) ; export const iterator = function iterator ( this ) : { next : ( ) => { done : boolean ; value : IteratorReturnValue ; } ; } { let index = 0 ; const properties = Object . keys ( this ) ; let Done = false ; return { next : ( ) : { done : boolean ; value : IteratorReturnValue ; } => { Done = index >= properties . length ; const obj = { done : Done , value : { value : this [ properties [ index ] ] , key : properties [ index ] } , } ; index += 1 ; return obj ; } , } ; } ; export const recursiveTypeCast = ( mode , object , schema , dataPath ) : void => { for ( const { key , value } of object ) { if ( isObject ( value ) ) { dataPath . push ( key ) ; ( value as IteratableGenericObject ) [ Symbol . iterator ] = iterator ; recursiveTypeCast ( mode , value , schema , dataPath ) ; dataPath . pop ( ) ; delete ( value as IteratableGenericObject ) [ ( Symbol . iterator as unknown ) as string ] ; } else if ( Array . isArray ( value ) ) { dataPath . push ( key ) ; const schemaProp = findObjectByPath ( schema , dataPath ) ; if ( schemaProp ?. items ?. type === 'object' ) { for ( let i = 0 ; i < value . length ; i += 1 ) { const arrayObject = value [ i ] ; ( arrayObject as IteratableGenericObject ) [ Symbol . iterator ] = iterator ; recursiveTypeCast ( mode , arrayObject , schema , dataPath ) ; delete arrayObject [ Symbol . iterator ] ; } } else { for ( let i = 0 ; i < value . length ; i += 1 ) { if ( schemaProp === undefined || schemaProp . items === undefined ) { delete object [ key ] ; dataPath . pop ( ) ; continue ; } ( object [ key ] as any ) [ i ] = mappers [ mode ] [ schemaProp . items . dataType ] ( value [ i ] ) ; } } dataPath . pop ( ) ; } else { dataPath . push ( key ) ; const schemaProp = findObjectByPath ( schema , dataPath ) ; if ( schemaProp === undefined ) { delete object [ key ] ; dataPath . pop ( ) ; continue ; } object [ key ] = mappers [ mode ] [ ( schemaProp . dataType as unknown ) as string ] ( value ) ; delete object [ ( Symbol . iterator as unknown ) as string ] ; dataPath . pop ( ) ; } } delete object [ ( Symbol . iterator as unknown ) as string ] ; } ;