Просмотр исходного кода

refactor(compiler-vapor): use class for transform context

三咲智子 Kevin Deng 2 лет назад
Родитель
Сommit
784310d4dc

+ 109 - 112
packages/compiler-vapor/src/transform.ts

@@ -58,37 +58,125 @@ export type StructuralDirectiveTransform = (
 
 export type TransformOptions = HackOptions<BaseTransformOptions>
 
-export interface TransformContext<T extends AllNode = AllNode> {
-  node: T
-  parent: TransformContext<RootNode | ElementNode> | null
+export class TransformContext<T extends AllNode = AllNode> {
+  parent: TransformContext<RootNode | ElementNode> | null = null
   root: TransformContext<RootNode>
-  index: number
-  block: BlockIRNode
+  index: number = 0
+
+  block: BlockIRNode = this.ir.block
   options: Required<
     Omit<TransformOptions, 'filename' | keyof CompilerCompatOptions>
   >
 
-  template: string
-  childrenTemplate: (string | null)[]
-  dynamic: IRDynamicInfo
+  template: string = ''
+  childrenTemplate: (string | null)[] = []
+  dynamic: IRDynamicInfo = this.ir.block.dynamic
+
+  inVOnce: boolean = false
+  inVFor: number = 0
+
+  comment: CommentNode[] = []
+  component: Set<string> = this.ir.component
+
+  private globalId = 0
+
+  constructor(
+    private ir: RootIRNode,
+    public node: T,
+    options: TransformOptions = {},
+  ) {
+    this.options = extend({}, defaultOptions, options)
+    this.root = this as TransformContext<RootNode>
+  }
 
-  comment: CommentNode[]
+  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--
+    }
+  }
 
-  inVOnce: boolean
-  inVFor: number
+  increaseId = () => this.globalId++
+  reference() {
+    if (this.dynamic.id !== undefined) return this.dynamic.id
+    this.dynamic.flags |= DynamicFlag.REFERENCED
+    return (this.dynamic.id = this.increaseId())
+  }
 
-  component: Set<string>
+  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(
     expressions: SimpleExpressionNode[],
-    ...operation: OperationNode[]
-  ): void
-  registerOperation(...operations: OperationNode[]): void
+    ...operations: OperationNode[]
+  ) {
+    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 = {
@@ -115,97 +203,6 @@ const defaultOptions = {
   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
 export function transform(
   root: RootNode,
@@ -229,7 +226,7 @@ export function transform(
     },
   }
 
-  const context = createRootContext(ir, root, options)
+  const context = new TransformContext(ir, root, options)
 
   transformNode(context)
 

+ 1 - 11
packages/compiler-vapor/src/transforms/transformChildren.ts

@@ -11,8 +11,6 @@ import {
   transformNode,
 } from '../transform'
 import { DynamicFlag, type IRDynamicInfo, IRNodeTypes } from '../ir'
-import { extend } from '@vue/shared'
-import { genDefaultDynamic } from './utils'
 
 export const transformChildren: NodeTransform = (node, context) => {
   const isFragment =
@@ -102,13 +100,5 @@ function createContext<T extends TemplateChildNode>(
   parent: TransformContext<RootNode | ElementNode>,
   index: number,
 ): TransformContext<T> {
-  return extend({}, parent, {
-    node,
-    parent,
-    index,
-
-    template: '',
-    childrenTemplate: [],
-    dynamic: genDefaultDynamic(),
-  } satisfies Partial<TransformContext<T>>) satisfies TransformContext<T>
+  return parent.create(node, index)
 }