mirror of https://github.com/vuejs/core.git
refactor(compiler-vapor): use class for transform context
This commit is contained in:
parent
9b5d23c3e2
commit
784310d4dc
|
@ -58,37 +58,125 @@ export type StructuralDirectiveTransform = (
|
||||||
|
|
||||||
export type TransformOptions = HackOptions<BaseTransformOptions>
|
export type TransformOptions = HackOptions<BaseTransformOptions>
|
||||||
|
|
||||||
export interface TransformContext<T extends AllNode = AllNode> {
|
export class TransformContext<T extends AllNode = AllNode> {
|
||||||
node: T
|
parent: TransformContext<RootNode | ElementNode> | null = null
|
||||||
parent: TransformContext<RootNode | ElementNode> | null
|
|
||||||
root: TransformContext<RootNode>
|
root: TransformContext<RootNode>
|
||||||
index: number
|
index: number = 0
|
||||||
block: BlockIRNode
|
|
||||||
|
block: BlockIRNode = this.ir.block
|
||||||
options: Required<
|
options: Required<
|
||||||
Omit<TransformOptions, 'filename' | keyof CompilerCompatOptions>
|
Omit<TransformOptions, 'filename' | keyof CompilerCompatOptions>
|
||||||
>
|
>
|
||||||
|
|
||||||
template: string
|
template: string = ''
|
||||||
childrenTemplate: (string | null)[]
|
childrenTemplate: (string | null)[] = []
|
||||||
dynamic: IRDynamicInfo
|
dynamic: IRDynamicInfo = this.ir.block.dynamic
|
||||||
|
|
||||||
comment: CommentNode[]
|
inVOnce: boolean = false
|
||||||
|
inVFor: number = 0
|
||||||
|
|
||||||
inVOnce: boolean
|
comment: CommentNode[] = []
|
||||||
inVFor: number
|
component: Set<string> = this.ir.component
|
||||||
|
|
||||||
component: Set<string>
|
private globalId = 0
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private ir: RootIRNode,
|
||||||
|
public node: T,
|
||||||
|
options: TransformOptions = {},
|
||||||
|
) {
|
||||||
|
this.options = extend({}, defaultOptions, options)
|
||||||
|
this.root = this as TransformContext<RootNode>
|
||||||
|
}
|
||||||
|
|
||||||
|
enterBlock(
|
||||||
|
ir: TransformContext['block'],
|
||||||
|
isVFor: boolean = false,
|
||||||
|
): () => void {
|
||||||
|
const { block, template, dynamic, childrenTemplate } = this
|
||||||
|
this.block = ir
|
||||||
|
this.dynamic = ir.dynamic
|
||||||
|
this.template = ''
|
||||||
|
this.childrenTemplate = []
|
||||||
|
isVFor && this.inVFor++
|
||||||
|
return () => {
|
||||||
|
// exit
|
||||||
|
this.registerTemplate()
|
||||||
|
this.block = block
|
||||||
|
this.template = template
|
||||||
|
this.dynamic = dynamic
|
||||||
|
this.childrenTemplate = childrenTemplate
|
||||||
|
isVFor && this.inVFor--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
increaseId = () => this.globalId++
|
||||||
|
reference() {
|
||||||
|
if (this.dynamic.id !== undefined) return this.dynamic.id
|
||||||
|
this.dynamic.flags |= DynamicFlag.REFERENCED
|
||||||
|
return (this.dynamic.id = this.increaseId())
|
||||||
|
}
|
||||||
|
|
||||||
|
pushTemplate(content: string) {
|
||||||
|
const existing = this.ir.template.findIndex(
|
||||||
|
template => template === content,
|
||||||
|
)
|
||||||
|
if (existing !== -1) return existing
|
||||||
|
this.ir.template.push(content)
|
||||||
|
return this.ir.template.length - 1
|
||||||
|
}
|
||||||
|
registerTemplate() {
|
||||||
|
if (!this.template) return -1
|
||||||
|
const id = this.pushTemplate(this.template)
|
||||||
|
return (this.dynamic.template = id)
|
||||||
|
}
|
||||||
|
|
||||||
enterBlock(ir: TransformContext['block'], isVFor?: boolean): () => void
|
|
||||||
reference(): number
|
|
||||||
increaseId(): number
|
|
||||||
pushTemplate(template: string): number
|
|
||||||
registerTemplate(customTemplate?: string): number
|
|
||||||
registerEffect(
|
registerEffect(
|
||||||
expressions: SimpleExpressionNode[],
|
expressions: SimpleExpressionNode[],
|
||||||
...operation: OperationNode[]
|
...operations: OperationNode[]
|
||||||
): void
|
) {
|
||||||
registerOperation(...operations: OperationNode[]): void
|
expressions = expressions.filter(exp => !isConstantExpression(exp))
|
||||||
|
if (this.inVOnce || expressions.length === 0) {
|
||||||
|
return this.registerOperation(...operations)
|
||||||
|
}
|
||||||
|
const existing = this.block.effect.find(e =>
|
||||||
|
isSameExpression(e.expressions, expressions),
|
||||||
|
)
|
||||||
|
if (existing) {
|
||||||
|
existing.operations.push(...operations)
|
||||||
|
} else {
|
||||||
|
this.block.effect.push({
|
||||||
|
expressions,
|
||||||
|
operations,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSameExpression(
|
||||||
|
a: SimpleExpressionNode[],
|
||||||
|
b: SimpleExpressionNode[],
|
||||||
|
) {
|
||||||
|
if (a.length !== b.length) return false
|
||||||
|
return a.every((exp, i) => exp.content === b[i].content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registerOperation(...node: OperationNode[]) {
|
||||||
|
this.block.operation.push(...node)
|
||||||
|
}
|
||||||
|
|
||||||
|
create<T extends TemplateChildNode>(
|
||||||
|
node: T,
|
||||||
|
index: number,
|
||||||
|
): TransformContext<T> {
|
||||||
|
return Object.assign(Object.create(TransformContext.prototype), this, {
|
||||||
|
node,
|
||||||
|
parent: this as any,
|
||||||
|
index,
|
||||||
|
|
||||||
|
template: '',
|
||||||
|
childrenTemplate: [],
|
||||||
|
dynamic: genDefaultDynamic(),
|
||||||
|
} satisfies Partial<TransformContext<T>>)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
|
@ -115,97 +203,6 @@ const defaultOptions = {
|
||||||
onWarn: defaultOnWarn,
|
onWarn: defaultOnWarn,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO use class for better perf
|
|
||||||
function createRootContext(
|
|
||||||
root: RootIRNode,
|
|
||||||
node: RootNode,
|
|
||||||
options: TransformOptions = {},
|
|
||||||
): TransformContext<RootNode> {
|
|
||||||
let globalId = 0
|
|
||||||
|
|
||||||
const context: TransformContext<RootNode> = {
|
|
||||||
node,
|
|
||||||
parent: null,
|
|
||||||
index: 0,
|
|
||||||
root: null!, // set later
|
|
||||||
block: root.block,
|
|
||||||
enterBlock(ir, inVFor = false) {
|
|
||||||
const { block, template, dynamic, childrenTemplate } = this
|
|
||||||
this.block = ir
|
|
||||||
this.dynamic = ir.dynamic
|
|
||||||
this.template = ''
|
|
||||||
this.childrenTemplate = []
|
|
||||||
inVFor && this.inVFor++
|
|
||||||
return () => {
|
|
||||||
// exit
|
|
||||||
this.registerTemplate()
|
|
||||||
this.block = block
|
|
||||||
this.template = template
|
|
||||||
this.dynamic = dynamic
|
|
||||||
this.childrenTemplate = childrenTemplate
|
|
||||||
inVFor && this.inVFor--
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options: extend({}, defaultOptions, options),
|
|
||||||
dynamic: root.block.dynamic,
|
|
||||||
inVOnce: false,
|
|
||||||
inVFor: 0,
|
|
||||||
comment: [],
|
|
||||||
component: root.component,
|
|
||||||
|
|
||||||
increaseId: () => globalId++,
|
|
||||||
reference() {
|
|
||||||
if (this.dynamic.id !== undefined) return this.dynamic.id
|
|
||||||
this.dynamic.flags |= DynamicFlag.REFERENCED
|
|
||||||
return (this.dynamic.id = this.increaseId())
|
|
||||||
},
|
|
||||||
registerEffect(expressions, ...operations) {
|
|
||||||
expressions = expressions.filter(exp => !isConstantExpression(exp))
|
|
||||||
if (this.inVOnce || expressions.length === 0) {
|
|
||||||
return this.registerOperation(...operations)
|
|
||||||
}
|
|
||||||
const existing = this.block.effect.find(e =>
|
|
||||||
isSameExpression(e.expressions, expressions),
|
|
||||||
)
|
|
||||||
if (existing) {
|
|
||||||
existing.operations.push(...operations)
|
|
||||||
} else {
|
|
||||||
this.block.effect.push({
|
|
||||||
expressions,
|
|
||||||
operations,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSameExpression(
|
|
||||||
a: SimpleExpressionNode[],
|
|
||||||
b: SimpleExpressionNode[],
|
|
||||||
) {
|
|
||||||
if (a.length !== b.length) return false
|
|
||||||
return a.every((exp, i) => exp.content === b[i].content)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
template: '',
|
|
||||||
childrenTemplate: [],
|
|
||||||
pushTemplate(content) {
|
|
||||||
const existing = root.template.findIndex(template => template === content)
|
|
||||||
if (existing !== -1) return existing
|
|
||||||
root.template.push(content)
|
|
||||||
return root.template.length - 1
|
|
||||||
},
|
|
||||||
registerTemplate() {
|
|
||||||
if (!this.template) return -1
|
|
||||||
const id = this.pushTemplate(this.template)
|
|
||||||
return (this.dynamic.template = id)
|
|
||||||
},
|
|
||||||
registerOperation(...node) {
|
|
||||||
this.block.operation.push(...node)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
context.root = context
|
|
||||||
return context
|
|
||||||
}
|
|
||||||
|
|
||||||
// AST -> IR
|
// AST -> IR
|
||||||
export function transform(
|
export function transform(
|
||||||
root: RootNode,
|
root: RootNode,
|
||||||
|
@ -229,7 +226,7 @@ export function transform(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const context = createRootContext(ir, root, options)
|
const context = new TransformContext(ir, root, options)
|
||||||
|
|
||||||
transformNode(context)
|
transformNode(context)
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,6 @@ import {
|
||||||
transformNode,
|
transformNode,
|
||||||
} from '../transform'
|
} from '../transform'
|
||||||
import { DynamicFlag, type IRDynamicInfo, IRNodeTypes } from '../ir'
|
import { DynamicFlag, type IRDynamicInfo, IRNodeTypes } from '../ir'
|
||||||
import { extend } from '@vue/shared'
|
|
||||||
import { genDefaultDynamic } from './utils'
|
|
||||||
|
|
||||||
export const transformChildren: NodeTransform = (node, context) => {
|
export const transformChildren: NodeTransform = (node, context) => {
|
||||||
const isFragment =
|
const isFragment =
|
||||||
|
@ -102,13 +100,5 @@ function createContext<T extends TemplateChildNode>(
|
||||||
parent: TransformContext<RootNode | ElementNode>,
|
parent: TransformContext<RootNode | ElementNode>,
|
||||||
index: number,
|
index: number,
|
||||||
): TransformContext<T> {
|
): TransformContext<T> {
|
||||||
return extend({}, parent, {
|
return parent.create(node, index)
|
||||||
node,
|
|
||||||
parent,
|
|
||||||
index,
|
|
||||||
|
|
||||||
template: '',
|
|
||||||
childrenTemplate: [],
|
|
||||||
dynamic: genDefaultDynamic(),
|
|
||||||
} satisfies Partial<TransformContext<T>>) satisfies TransformContext<T>
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue