Skip to content

Commit 784310d

Browse files
committed
refactor(compiler-vapor): use class for transform context
1 parent 9b5d23c commit 784310d

File tree

2 files changed

+110
-123
lines changed

2 files changed

+110
-123
lines changed

packages/compiler-vapor/src/transform.ts

Lines changed: 109 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -58,37 +58,125 @@ export type StructuralDirectiveTransform = (
5858

5959
export 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

94182
const 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
210207
export 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

packages/compiler-vapor/src/transforms/transformChildren.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import {
1111
transformNode,
1212
} from '../transform'
1313
import { DynamicFlag, type IRDynamicInfo, IRNodeTypes } from '../ir'
14-
import { extend } from '@vue/shared'
15-
import { genDefaultDynamic } from './utils'
1614

1715
export const transformChildren: NodeTransform = (node, context) => {
1816
const isFragment =
@@ -102,13 +100,5 @@ function createContext<T extends TemplateChildNode>(
102100
parent: TransformContext<RootNode | ElementNode>,
103101
index: number,
104102
): TransformContext<T> {
105-
return extend({}, parent, {
106-
node,
107-
parent,
108-
index,
109-
110-
template: '',
111-
childrenTemplate: [],
112-
dynamic: genDefaultDynamic(),
113-
} satisfies Partial<TransformContext<T>>) satisfies TransformContext<T>
103+
return parent.create(node, index)
114104
}

0 commit comments

Comments
 (0)