@@ -21,7 +21,8 @@ const Mixed = AsMixin(
2121export class ObjectTsDsl extends Mixed {
2222 readonly '~dsl' = 'ObjectTsDsl' ;
2323
24- protected _props : Array < ObjectPropTsDsl > = [ ] ;
24+ protected _props = new Map < string , ObjectPropTsDsl > ( ) ;
25+ protected _spreadCounter = 0 ;
2526
2627 constructor ( ...props : Array < ObjectPropTsDsl > ) {
2728 super ( ) ;
@@ -30,63 +31,101 @@ export class ObjectTsDsl extends Mixed {
3031
3132 override analyze ( ctx : AnalysisContext ) : void {
3233 super . analyze ( ctx ) ;
33- for ( const prop of this . _props ) {
34+ for ( const prop of this . _props . values ( ) ) {
3435 ctx . analyze ( prop ) ;
3536 }
3637 }
3738
38- /** Adds a computed property (e.g. `{ [expr]: value }`). */
39- computed ( name : string , expr : ExprFn ) : this {
40- this . _props . push (
41- new ObjectPropTsDsl ( { kind : 'computed' , name } ) . value ( expr ) ,
42- ) ;
39+ /** Returns composite key for the property. */
40+ private _propKey ( prop : ObjectPropTsDsl ) : string {
41+ if ( prop . kind === 'spread' ) {
42+ return `spread:${ this . _spreadCounter ++ } ` ;
43+ }
44+ return `${ prop . kind } :${ prop . propName } ` ;
45+ }
46+
47+ /** Adds a computed property (e.g. `{ [expr]: value }`), or removes if null. */
48+ computed ( name : string , expr : ExprFn | null ) : this {
49+ if ( expr === null ) {
50+ this . _props . delete ( `computed:${ name } ` ) ;
51+ } else {
52+ this . _props . set (
53+ `computed:${ name } ` ,
54+ new ObjectPropTsDsl ( { kind : 'computed' , name } ) . value ( expr ) ,
55+ ) ;
56+ }
4357 return this ;
4458 }
4559
46- /** Adds a getter property (e.g. `{ get foo() { ... } }`). */
47- getter ( name : string , stmt : StmtFn ) : this {
48- this . _props . push ( new ObjectPropTsDsl ( { kind : 'getter' , name } ) . value ( stmt ) ) ;
60+ /** Adds a getter property (e.g. `{ get foo() { ... } }`), or removes if null. */
61+ getter ( name : string , stmt : StmtFn | null ) : this {
62+ if ( stmt === null ) {
63+ this . _props . delete ( `getter:${ name } ` ) ;
64+ } else {
65+ this . _props . set (
66+ `getter:${ name } ` ,
67+ new ObjectPropTsDsl ( { kind : 'getter' , name } ) . value ( stmt ) ,
68+ ) ;
69+ }
4970 return this ;
5071 }
5172
5273 /** Returns true if object has at least one property or spread. */
5374 hasProps ( ) : boolean {
54- return this . _props . length > 0 ;
75+ return this . _props . size > 0 ;
5576 }
5677
5778 /** Returns true if object has no properties or spreads. */
5879 get isEmpty ( ) : boolean {
59- return this . _props . length === 0 ;
80+ return this . _props . size === 0 ;
6081 }
6182
62- /** Adds a property assignment. */
63- prop ( name : string , expr : ExprFn ) : this {
64- this . _props . push ( new ObjectPropTsDsl ( { kind : 'prop' , name } ) . value ( expr ) ) ;
83+ /** Adds a property assignment, or removes if null. */
84+ prop ( name : string , expr : ExprFn | null ) : this {
85+ if ( expr === null ) {
86+ this . _props . delete ( `prop:${ name } ` ) ;
87+ } else {
88+ this . _props . set (
89+ `prop:${ name } ` ,
90+ new ObjectPropTsDsl ( { kind : 'prop' , name } ) . value ( expr ) ,
91+ ) ;
92+ }
6593 return this ;
6694 }
6795
6896 /** Adds multiple properties. */
6997 props ( ...props : ReadonlyArray < ObjectPropTsDsl > ) : this {
70- this . _props . push ( ...props ) ;
98+ for ( const prop of props ) {
99+ this . _props . set ( this . _propKey ( prop ) , prop ) ;
100+ }
71101 return this ;
72102 }
73103
74- /** Adds a setter property (e.g. `{ set foo(v) { ... } }`). */
75- setter ( name : string , stmt : StmtFn ) : this {
76- this . _props . push ( new ObjectPropTsDsl ( { kind : 'setter' , name } ) . value ( stmt ) ) ;
104+ /** Adds a setter property (e.g. `{ set foo(v) { ... } }`), or removes if null. */
105+ setter ( name : string , stmt : StmtFn | null ) : this {
106+ if ( stmt === null ) {
107+ this . _props . delete ( `setter:${ name } ` ) ;
108+ } else {
109+ this . _props . set (
110+ `setter:${ name } ` ,
111+ new ObjectPropTsDsl ( { kind : 'setter' , name } ) . value ( stmt ) ,
112+ ) ;
113+ }
77114 return this ;
78115 }
79116
80117 /** Adds a spread property (e.g. `{ ...options }`). */
81118 spread ( expr : ExprFn ) : this {
82- this . _props . push ( new ObjectPropTsDsl ( { kind : 'spread' } ) . value ( expr ) ) ;
119+ const key = `spread:${ this . _spreadCounter ++ } ` ;
120+ this . _props . set ( key , new ObjectPropTsDsl ( { kind : 'spread' } ) . value ( expr ) ) ;
83121 return this ;
84122 }
85123
86124 override toAst ( ) {
125+ const props = [ ...this . _props . values ( ) ] ;
87126 const node = ts . factory . createObjectLiteralExpression (
88- this . $node ( this . _props ) ,
89- this . $multiline ( this . _props . length ) ,
127+ this . $node ( props ) ,
128+ this . $multiline ( props . length ) ,
90129 ) ;
91130 return this . $hint ( node ) ;
92131 }
0 commit comments