@@ -58,37 +58,125 @@ export type StructuralDirectiveTransform = (
5858
5959export type TransformOptions = HackOptions < BaseTransformOptions >
6060
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
6463 root : TransformContext < RootNode >
65- index : number
66- block : BlockIRNode
64+ index : number = 0
65+
66+ block : BlockIRNode = this . ir . block
6767 options : Required <
6868 Omit < TransformOptions , 'filename' | keyof CompilerCompatOptions >
6969 >
7070
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+ }
7491
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+ }
76112
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+ }
79119
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+ }
81133
82- enterBlock ( ir : TransformContext [ 'block' ] , isVFor ?: boolean ) : ( ) => void
83- reference ( ) : number
84- increaseId ( ) : number
85- pushTemplate ( template : string ) : number
86- registerTemplate ( customTemplate ?: string ) : number
87134 registerEffect (
88135 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+ }
92180}
93181
94182const defaultOptions = {
@@ -115,97 +203,6 @@ const defaultOptions = {
115203 onWarn : defaultOnWarn ,
116204}
117205
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-
209206// AST -> IR
210207export function transform (
211208 root : RootNode ,
@@ -229,7 +226,7 @@ export function transform(
229226 } ,
230227 }
231228
232- const context = createRootContext ( ir , root , options )
229+ const context = new TransformContext ( ir , root , options )
233230
234231 transformNode ( context )
235232
0 commit comments