@@ -58,37 +58,125 @@ export type StructuralDirectiveTransform = (
58
58
59
59
export type TransformOptions = HackOptions < BaseTransformOptions >
60
60
61
- export interface TransformContext < T extends AllNode = AllNode > {
62
- node : T
63
- parent : TransformContext < RootNode | ElementNode > | null
61
+ export class TransformContext < T extends AllNode = AllNode > {
62
+ parent : TransformContext < RootNode | ElementNode > | null = null
64
63
root : TransformContext < RootNode >
65
- index : number
66
- block : BlockIRNode
64
+ index : number = 0
65
+
66
+ block : BlockIRNode = this . ir . block
67
67
options : Required <
68
68
Omit < TransformOptions , 'filename' | keyof CompilerCompatOptions >
69
69
>
70
70
71
- template : string
72
- childrenTemplate : ( string | null ) [ ]
73
- dynamic : IRDynamicInfo
71
+ template : string = ''
72
+ childrenTemplate : ( string | null ) [ ] = [ ]
73
+ dynamic : IRDynamicInfo = this . ir . block . dynamic
74
+
75
+ inVOnce : boolean = false
76
+ inVFor : number = 0
77
+
78
+ comment : CommentNode [ ] = [ ]
79
+ component : Set < string > = this . ir . component
80
+
81
+ private globalId = 0
82
+
83
+ constructor (
84
+ private ir : RootIRNode ,
85
+ public node : T ,
86
+ options : TransformOptions = { } ,
87
+ ) {
88
+ this . options = extend ( { } , defaultOptions , options )
89
+ this . root = this as TransformContext < RootNode >
90
+ }
74
91
75
- comment : CommentNode [ ]
92
+ enterBlock (
93
+ ir : TransformContext [ 'block' ] ,
94
+ isVFor : boolean = false ,
95
+ ) : ( ) => void {
96
+ const { block, template, dynamic, childrenTemplate } = this
97
+ this . block = ir
98
+ this . dynamic = ir . dynamic
99
+ this . template = ''
100
+ this . childrenTemplate = [ ]
101
+ isVFor && this . inVFor ++
102
+ return ( ) => {
103
+ // exit
104
+ this . registerTemplate ( )
105
+ this . block = block
106
+ this . template = template
107
+ this . dynamic = dynamic
108
+ this . childrenTemplate = childrenTemplate
109
+ isVFor && this . inVFor --
110
+ }
111
+ }
76
112
77
- inVOnce : boolean
78
- inVFor : number
113
+ increaseId = ( ) => this . globalId ++
114
+ reference ( ) {
115
+ if ( this . dynamic . id !== undefined ) return this . dynamic . id
116
+ this . dynamic . flags |= DynamicFlag . REFERENCED
117
+ return ( this . dynamic . id = this . increaseId ( ) )
118
+ }
79
119
80
- component : Set < string >
120
+ pushTemplate ( content : string ) {
121
+ const existing = this . ir . template . findIndex (
122
+ template => template === content ,
123
+ )
124
+ if ( existing !== - 1 ) return existing
125
+ this . ir . template . push ( content )
126
+ return this . ir . template . length - 1
127
+ }
128
+ registerTemplate ( ) {
129
+ if ( ! this . template ) return - 1
130
+ const id = this . pushTemplate ( this . template )
131
+ return ( this . dynamic . template = id )
132
+ }
81
133
82
- enterBlock ( ir : TransformContext [ 'block' ] , isVFor ?: boolean ) : ( ) => void
83
- reference ( ) : number
84
- increaseId ( ) : number
85
- pushTemplate ( template : string ) : number
86
- registerTemplate ( customTemplate ?: string ) : number
87
134
registerEffect (
88
135
expressions : SimpleExpressionNode [ ] ,
89
- ...operation : OperationNode [ ]
90
- ) : void
91
- registerOperation ( ...operations : OperationNode [ ] ) : void
136
+ ...operations : OperationNode [ ]
137
+ ) {
138
+ expressions = expressions . filter ( exp => ! isConstantExpression ( exp ) )
139
+ if ( this . inVOnce || expressions . length === 0 ) {
140
+ return this . registerOperation ( ...operations )
141
+ }
142
+ const existing = this . block . effect . find ( e =>
143
+ isSameExpression ( e . expressions , expressions ) ,
144
+ )
145
+ if ( existing ) {
146
+ existing . operations . push ( ...operations )
147
+ } else {
148
+ this . block . effect . push ( {
149
+ expressions,
150
+ operations,
151
+ } )
152
+ }
153
+
154
+ function isSameExpression (
155
+ a : SimpleExpressionNode [ ] ,
156
+ b : SimpleExpressionNode [ ] ,
157
+ ) {
158
+ if ( a . length !== b . length ) return false
159
+ return a . every ( ( exp , i ) => exp . content === b [ i ] . content )
160
+ }
161
+ }
162
+ registerOperation ( ...node : OperationNode [ ] ) {
163
+ this . block . operation . push ( ...node )
164
+ }
165
+
166
+ create < T extends TemplateChildNode > (
167
+ node : T ,
168
+ index : number ,
169
+ ) : TransformContext < T > {
170
+ return Object . assign ( Object . create ( TransformContext . prototype ) , this , {
171
+ node,
172
+ parent : this as any ,
173
+ index,
174
+
175
+ template : '' ,
176
+ childrenTemplate : [ ] ,
177
+ dynamic : genDefaultDynamic ( ) ,
178
+ } satisfies Partial < TransformContext < T > > )
179
+ }
92
180
}
93
181
94
182
const defaultOptions = {
@@ -115,97 +203,6 @@ const defaultOptions = {
115
203
onWarn : defaultOnWarn ,
116
204
}
117
205
118
- // TODO use class for better perf
119
- function createRootContext (
120
- root : RootIRNode ,
121
- node : RootNode ,
122
- options : TransformOptions = { } ,
123
- ) : TransformContext < RootNode > {
124
- let globalId = 0
125
-
126
- const context : TransformContext < RootNode > = {
127
- node,
128
- parent : null ,
129
- index : 0 ,
130
- root : null ! , // set later
131
- block : root . block ,
132
- enterBlock ( ir , inVFor = false ) {
133
- const { block, template, dynamic, childrenTemplate } = this
134
- this . block = ir
135
- this . dynamic = ir . dynamic
136
- this . template = ''
137
- this . childrenTemplate = [ ]
138
- inVFor && this . inVFor ++
139
- return ( ) => {
140
- // exit
141
- this . registerTemplate ( )
142
- this . block = block
143
- this . template = template
144
- this . dynamic = dynamic
145
- this . childrenTemplate = childrenTemplate
146
- inVFor && this . inVFor --
147
- }
148
- } ,
149
- options : extend ( { } , defaultOptions , options ) ,
150
- dynamic : root . block . dynamic ,
151
- inVOnce : false ,
152
- inVFor : 0 ,
153
- comment : [ ] ,
154
- component : root . component ,
155
-
156
- increaseId : ( ) => globalId ++ ,
157
- reference ( ) {
158
- if ( this . dynamic . id !== undefined ) return this . dynamic . id
159
- this . dynamic . flags |= DynamicFlag . REFERENCED
160
- return ( this . dynamic . id = this . increaseId ( ) )
161
- } ,
162
- registerEffect ( expressions , ...operations ) {
163
- expressions = expressions . filter ( exp => ! isConstantExpression ( exp ) )
164
- if ( this . inVOnce || expressions . length === 0 ) {
165
- return this . registerOperation ( ...operations )
166
- }
167
- const existing = this . block . effect . find ( e =>
168
- isSameExpression ( e . expressions , expressions ) ,
169
- )
170
- if ( existing ) {
171
- existing . operations . push ( ...operations )
172
- } else {
173
- this . block . effect . push ( {
174
- expressions,
175
- operations,
176
- } )
177
- }
178
-
179
- function isSameExpression (
180
- a : SimpleExpressionNode [ ] ,
181
- b : SimpleExpressionNode [ ] ,
182
- ) {
183
- if ( a . length !== b . length ) return false
184
- return a . every ( ( exp , i ) => exp . content === b [ i ] . content )
185
- }
186
- } ,
187
-
188
- template : '' ,
189
- childrenTemplate : [ ] ,
190
- pushTemplate ( content ) {
191
- const existing = root . template . findIndex ( template => template === content )
192
- if ( existing !== - 1 ) return existing
193
- root . template . push ( content )
194
- return root . template . length - 1
195
- } ,
196
- registerTemplate ( ) {
197
- if ( ! this . template ) return - 1
198
- const id = this . pushTemplate ( this . template )
199
- return ( this . dynamic . template = id )
200
- } ,
201
- registerOperation ( ...node ) {
202
- this . block . operation . push ( ...node )
203
- } ,
204
- }
205
- context . root = context
206
- return context
207
- }
208
-
209
206
// AST -> IR
210
207
export function transform (
211
208
root : RootNode ,
@@ -229,7 +226,7 @@ export function transform(
229
226
} ,
230
227
}
231
228
232
- const context = createRootContext ( ir , root , options )
229
+ const context = new TransformContext ( ir , root , options )
233
230
234
231
transformNode ( context )
235
232
0 commit comments