import { BuildableTree } from "./buildable-tree" ; import { endsWithSemicolon , exportDuplicatedCommas } from "../utils" ; import { Buildable } from "./buildable" ; import { Snippet } from "./buildable-tree" ; export class BuildingTree implements Buildable { readonly defaultArguments : Array < string > = Array < string > ( ) ; readonly namedArguments : Map < string , string > = new Map ( ) ; readonly name : string ; readonly depth : number ; readonly extensions : Array < BuildableTree > ; readonly overrideSnippet ? : Snippet ; readonly comments : Array < string > ; pushDefaultArgument ( value ) { this . defaultArguments . push ( value ) ; } pushNamedArgument ( key , value ) { this . namedArguments . set ( key , value ) ; } param key param array pushNamedArray ( key , array ) { let content = "" ; array . forEach ( ( el ) => { content += `${ el },\n` ; } ) ; const code = `[\n${ content }]` ; this . namedArguments . set ( key , code ) ; } param containerName param depth param extensions constructor ( props ? ) { this . name = props ?. name ; this . depth = props ?. depth ; this . extensions = props ?. extensions ; this . overrideSnippet = props ?. overrideSnippet ; this . comments = props ?. comments ; } get isRootTree ( ) { return this . depth == 0 ; } get hasExtension ( ) { return this . extensions && this . extensions . length >= 1 ; } get isSnippetOverriden ( ) : boolean { return this . overrideSnippet !== undefined ; } code : string ; build ( ) { if ( this . isSnippetOverriden ) { const comment = buildComments ( this . overrideSnippet . comments , { forceSingleLine : true , } ) ; this . code = `${ this . overrideSnippet . build ( ) . lookup ( { withComma : false } ) }${ comment }` ; } else { const comment = buildComments ( this . comments ) ; let kvContents = "" ; this . defaultArguments . forEach ( ( v ) => { kvContents += `${ v },\n` ; } ) ; this . namedArguments . forEach ( ( v , k ) => { kvContents += `${ k }: ${ v },\n` ; } ) ; /**
             * the code with constructor and it's parameter.
             * usually in this format.
             * ```dart
             * Text('label', align: TextAlign.left)
             * Button.flat(label: Text('label'))
             * ```
             */ this . code = `${ comment }${ this . name }(
    ${ kvContents }
)` ; } /**
         * add extension if exists.
         * e.g.
         * ```dart
         * Theme.of(context).textTheme.headline1
         * .copyWith(color: Colors.white) // this part "copyWith"
         * ```
         */ if ( this . hasExtension ) { this . extensions . forEach ( ( ext ) => { this . code = this . code + `.${ ext . build ( ) . lookup ( ) }` ; } ) ; } this . code = `${ exportDuplicatedCommas ( this . code ) }` ; return this ; } finalize ( ) { if ( this . isRootTree ) { if ( ! endsWithSemicolon ( this . code ) ) { this . code += ";" ; } } this . format ( ) ; return this . lookup ( ) ; } format ( ) { return this . lookup ( ) ; } lookup ( options ? ) { if ( options ?. withComma && canAddComma ( this . code ) ) { return addComma ( { code : this . code , safetyCheck : true } ) ; } return this . code ; } } function canAddComma ( code ) { const trimmed = code . trimEnd ( ) ; if ( trimmed . endsWith ( ";" ) ) { return false ; } if ( trimmed . endsWith ( "," ) ) { return false ; } if ( trimmed . endsWith ( ")" ) ) { return true ; } return false ; } function addComma ( { code , safetyCheck = false , } ) { function add ( ) { code = code + "," ; } if ( safetyCheck ) { if ( canAddComma ( code ) ) { add ( ) ; } } else { add ( ) ; } return code ; } function buildComments ( comments , options ? ) { const empty = "" ; if ( comments ) { const rawComment = comments . join ( "\n" ) ; if ( rawComment . length == 0 ) { return empty ; } if ( options ?. forceSingleLine ) { return `/*${ rawComment }*/` ; } let finalComment = "" ; comments . forEach ( ( v , i ) => { const linebreak = i === 0 ? "" : "\n" ; finalComment += linebreak + `/// ` + v ; } ) ; return finalComment + "\n" ; } return empty ; }