import { isSimpleType , SimpleType } from "../simple-type" ; const TYPE_REF_PREFIX = "__REF__" ; function isTypeRef ( value ) { return typeof value === "string" && value . startsWith ( TYPE_REF_PREFIX ) ; } export type SerializedSimpleTypeWithRef < ST = SimpleType > = { [ key in keyof ST ] : ST [ key ] extends SimpleType ? string : SerializedSimpleTypeWithRef < ST [ key ] > ; } ; export interface SerializedSimpleType { typeMap : Record < number , SerializedSimpleTypeWithRef > ; type : number ; } param serializedSimpleType export function deserializeSimpleType ( serializedSimpleType ) { const { typeMap } = serializedSimpleType ; const deserializedTypeMap = new Map < number , SimpleType > ( ) ; for ( const typeId of Object . keys ( typeMap ) ) { deserializedTypeMap . set ( Number ( typeId ) , { } as never ) ; } for ( const [ typeId , serializedType ] of Object . entries ( typeMap ) ) { const deserializedType = convertObject ( serializedType , obj => { if ( isTypeRef ( obj ) ) { const typeId = Number ( obj . replace ( TYPE_REF_PREFIX , "" ) ) ; return deserializedTypeMap . get ( typeId ) ! ; } } ) ; Object . assign ( deserializedTypeMap . get ( Number ( typeId ) ) , deserializedType ) ; } return deserializedTypeMap . get ( serializedSimpleType . type ) ! ; } param simpleType export function serializeSimpleType ( simpleType ) { const typeMap = { } ; const typeMapReverse = new WeakMap < SimpleType , number > ( ) ; let id = 0 ; const mainTypeId = serializeTypeInternal ( simpleType , { assignIdToType : type => { if ( typeMapReverse . has ( type ) ) { return typeMapReverse . get ( type ) ! ; } const assignedId = id ++ ; typeMapReverse . set ( type , assignedId ) ; return assignedId ; } , getIdFromType : type => { return typeMapReverse . get ( type ) ; } , emitType : ( id , simpleTypeWithRef ) => { typeMap [ id ] = simpleTypeWithRef ; return id ++ ; } } ) ; return { type : mainTypeId , typeMap } ; } function serializeTypeInternal ( simpleType , { emitType , getIdFromType , assignIdToType } ) { const existingId = getIdFromType ( simpleType ) ; if ( existingId != null ) { return existingId ; } const id = assignIdToType ( simpleType ) ; const serializedType = convertObject < SimpleType , SerializedSimpleTypeWithRef > ( { ... simpleType } , obj => { if ( isSimpleType ( obj ) ) { const id = serializeTypeInternal ( obj , { emitType , getIdFromType , assignIdToType } ) ; return `${ TYPE_REF_PREFIX }${ id }` ; } } ) ; emitType ( id , serializedType ) ; return id ; } function convertObject < T , U > ( input , convert ) { let outer = true ; function convertObjectInner ( obj ) { if ( Array . isArray ( obj ) ) { return obj . map ( o => convertObjectInner ( o ) ) ; } if ( ! outer ) { const convertedObj = convert ( obj ) ; if ( convertedObj != null ) { return convertedObj ; } } outer = false ; if ( typeof obj === "object" && obj != null ) { const newObj = { } ; for ( const [ key , value ] of Object . entries ( obj ) ) { newObj [ key ] = convertObjectInner ( value ) ; } return newObj ; } return obj ; } return convertObjectInner ( input ) as U ; }