import { Buildable } from "./buildable" ; import { ignore , paramMetadataKey , ignoreMetadataKey } from "../decorations/params" ; import { BuildingTree } from "./building-tree" ; import { Reflection as Reflect } from '@abraham/reflection' ; export class BuildableTree implements Buildable { constructor ( private readonly _name ? ) { } build ( depth ? ) { depth = depth ?? 0 ; const target = this . targetObject ?? this ; const defaultParamKeys = Reflect . getMetadata ( paramMetadataKey , target ) ?? [ ] ; const ignoreFeildKeys = Reflect . getMetadata ( ignoreMetadataKey , target ) ?? [ ] ; const result = new Map < any , PropertyDescriptor > ( ) ; for ( let key of Object . keys ( target ) ) { if ( ignoreFeildKeys . includes ( key ) ) { } else { result . set ( key , Object . getOwnPropertyDescriptor ( target , key ) ) ; } } const tree = new BuildingTree ( { name : this . name , depth : depth , extensions : this . extensions , overrideSnippet : this . overridenSnippet , comments : this . comments } ) ; function registerOnParam ( key , value ) { const isDefault = checkIfDefault ( key ) ; if ( isDefault ) { tree . pushDefaultArgument ( value ) ; } else { tree . pushNamedArgument ( key , value ) ; } } /**
         * returns false if named
         * returns true if default argument
         */ function checkIfDefault ( key ) { if ( key . includes ( "__default__" ) ) { return true ; } if ( defaultParamKeys . includes ( key ) ) { return true ; } return false ; } let keys = Array . from ( result . keys ( ) ) ; for ( const key of keys ) { const fieldM = result . get ( key ) ; const field = fieldM . value ; if ( field === undefined ) { } else { switch ( typeof ( field ) ) { case "string" : registerOnParam ( key , `"${ field }"` ) ; break ; case "boolean" : registerOnParam ( key , `${ field }` ) ; case "number" : registerOnParam ( key , `${ field }` ) ; break ; case "object" : if ( field == null ) { registerOnParam ( key , `null` ) ; } else if ( field == undefined ) { } else if ( Array . isArray ( field ) ) { const builds = [ ] ; field . forEach ( ( f ) => { switch ( typeof ( f ) ) { case "string" : builds . push ( `"${ f }"` ) ; break ; case "number" : builds . push ( `${ f }` ) ; break ; } try { builds . push ( ( f as any ) . build ( depth + 1 ) . lookup ( ) ) ; } catch ( e ) { } } ) ; tree . pushNamedArray ( key , builds ) ; } else { trySingleFieldBuild ( key , field ) ; } break ; } } } param key param field function trySingleFieldBuild ( key , field ) { try { registerOnParam ( key , field . build ( depth + 1 ) . lookup ( ) ) ; } catch ( e ) { console . error ( key , "of type" , typeof field , "does not support build()" ) ; console . error ( "failed object is " , field ) ; console . error ( e ) ; } } return tree . build ( ) ; } param name @ ignore ( ) private _factoryName : string = null ; @ ignore ( ) private get _factoryExtended ( ) : boolean { return this . _factoryName !== null ; } extendWithFactory ( name ) { this . _factoryName = name ; return this ; } @ ignore ( ) private extensions : Array < BuildableTree > = [ ] ; extendWithExtensionFunction < T > ( name , args ) { const extension = new BuildableTree ( name ) . overrideArguments < this > ( args ) ; this . extensions . push ( extension ) ; return this ; } extendWithAccessor < T extends BuildableTree > ( accessor ) { const extension = Snippet . fromStatic < T > ( accessor ) ; this . extensions . push ( extension ) ; return extension as T ; } @ ignore ( ) private targetObject : BuildableTree ; overrideTarget ( target ) { this . targetObject = target ; return this ; } @ ignore ( ) private overridenSnippet : Snippet ; overrideSnippet ( snippet ) { this . overridenSnippet = Snippet . fromStatic ( snippet ) as any ; return this ; } overrideArguments < T > ( args ) { const target = < BuildableTree > { ... args } ; return this . overrideTarget ( target ) ; } @ ignore ( ) comments = Array < string > ( ) ; addComment ( comment ) { this . comments . push ( comment ) ; return this ; } get name ( ) : string { if ( this . _name ) { return this . _name ; } if ( this . _factoryExtended ) { return `${ this . constructor . name }.${ this . _factoryName }` ; } return this . constructor . name ; } } export class Snippet extends BuildableTree { _defaultSnippet : string ; constructor ( defaultSnippet ? ) { super ( ) ; this . _defaultSnippet = defaultSnippet ; } static fromStatic < T extends BuildableTree > ( snippet ) { return new Snippet ( snippet ) as any as T ; } build ( depth ? ) { return new SnippetBuildingTree ( this . _defaultSnippet ) ; } lookup ( ) { return this . _defaultSnippet ; } get name ( ) : string { return this . constructor . name ; } } export class EnumClass extends Snippet { } export class EnumField extends Snippet { } export class SnippetBuildingTree extends BuildingTree { snippet : string ; constructor ( snippet ) { super ( ) ; this . snippet = snippet ; } build ( ) { return this ; } lookup ( ) { return this . snippet ; } }