import reflect , { useCache } from "@plumier/reflect" ; import { Class } from "./types" ; import { Converter , defaultConverters } from './converter' ; export interface PrimitiveNode { kind : "Primitive" ; type : Class ; converter : Converter ; } export interface ObjectNode { kind : "Object" ; type : Class ; properties : Map < string , SuperNode > ; } export interface ArrayNode { kind : "Array" ; type : Class ; element : SuperNode ; } export type SuperNode = PrimitiveNode | ObjectNode | ArrayNode ; function primitiveNode ( type ) { return { kind : "Primitive" , type , converter : defaultConverters . get ( type ) ! } ; } function arrayNode ( type ) { let defer ; return { kind : "Array" , type : type [ 0 ] , get element ( ) { return defer || ( defer = getAst ( type [ 0 ] ) ) ; } } ; } function objectNode ( type ) { let defer ; return { kind : "Object" , type , get properties ( ) { if ( defer ) return defer ; else { const meta = reflect ( type ) ; return defer = new Map ( meta . properties . map ( x => ( < [ string , ObjectNode ] > [ x . name , transformer ( x . type ) ] ) ) ) ; } } } ; } function transformer ( type ) { if ( type === Boolean || type === Number || type === Date || type === String ) return primitiveNode ( type ) ; else if ( Array . isArray ( type ) ) return arrayNode ( type ) ; else return objectNode ( type ) ; } const astCache = new Map < Class , SuperNode > ( ) ; const arrayAstCache = new Map < Class , SuperNode > ( ) ; const transformArray = useCache ( arrayAstCache , transformer , ( type ) => type [ 0 ] ) ; const transformAll = useCache ( astCache , transformer , ( type ) => type ) ; function getAst ( type ) { const cachedTransformer = Array . isArray ( type ) ? transformArray : transformAll ; return cachedTransformer ( type ) ; } export { getAst } ;