]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(compiler-vapor): extract imports & unify context name
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Wed, 31 Jan 2024 10:00:16 +0000 (18:00 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Wed, 31 Jan 2024 10:00:16 +0000 (18:00 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap
packages/compiler-vapor/src/generate.ts
packages/compiler-vapor/src/generators/block.ts
packages/compiler-vapor/src/generators/operation.ts
packages/compiler-vapor/src/transform.ts
packages/compiler-vapor/src/transforms/transformElement.ts
packages/compiler-vapor/src/transforms/transformInterpolation.ts

index efbe8477bb673b5d0c5d7e95ec5cfdf40783b8cc..31c80866d7a9c986b7511a7d5527fa23c2e883e8 100644 (file)
@@ -44,6 +44,7 @@ export function render(_ctx) {
 
 exports[`compiler v-bind > .camel modifier w/ dynamic arg 1`] = `
 "import { camelize as _camelize } from 'vue';
+import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
 
 export function render(_ctx) {
   const t0 = _template("<div></div>")
index 52be485aaaf179451356811acbe50fca6dded543..1753f163a62f813e037865858776ccc9c39e211f 100644 (file)
@@ -20,6 +20,7 @@ interface CodegenOptions extends BaseCodegenOptions {
 
 export type CodeFragment =
   | typeof NEWLINE
+  | typeof LF
   | typeof INDENT_START
   | typeof INDENT_END
   | string
@@ -131,6 +132,8 @@ export interface VaporCodegenResult extends BaseCodegenResult {
 }
 
 export const NEWLINE = Symbol(__DEV__ ? `newline` : ``)
+/** increase offset but don't push actual code */
+export const LF = Symbol(__DEV__ ? `line feed` : ``)
 export const INDENT_START = Symbol(__DEV__ ? `indent start` : ``)
 export const INDENT_END = Symbol(__DEV__ ? `indent end` : ``)
 
@@ -139,25 +142,22 @@ export function generate(
   ir: RootIRNode,
   options: CodegenOptions = {},
 ): VaporCodegenResult {
-  const ctx = new CodegenContext(ir, options)
-  const { push, helpers, vaporHelpers } = ctx
+  const context = new CodegenContext(ir, options)
+  const { push, helpers, vaporHelpers } = context
 
   const functionName = 'render'
   const isSetupInlined = !!options.inline
   if (isSetupInlined) {
     push(`(() => {`)
   } else {
-    push(
-      // placeholder for preamble
-      NEWLINE,
-      NEWLINE,
-      `export function ${functionName}(_ctx) {`,
-    )
+    push(NEWLINE, `export function ${functionName}(_ctx) {`)
   }
 
   push(INDENT_START)
-  ir.template.forEach((template, i) => push(...genTemplate(template, i, ctx)))
-  push(...genBlockFunctionContent(ir, ctx))
+  ir.template.forEach((template, i) =>
+    push(...genTemplate(template, i, context)),
+  )
+  push(...genBlockFunctionContent(ir, context))
   push(INDENT_END, NEWLINE)
 
   if (isSetupInlined) {
@@ -166,18 +166,9 @@ export function generate(
     push('}')
   }
 
-  let preamble = ''
-  if (vaporHelpers.size)
-    // TODO: extract import codegen
-    preamble = `import { ${[...vaporHelpers]
-      .map(h => `${h} as _${h}`)
-      .join(', ')} } from 'vue/vapor';`
-  if (helpers.size)
-    preamble = `import { ${[...helpers]
-      .map(h => `${h} as _${h}`)
-      .join(', ')} } from 'vue';`
+  const preamble = genHelperImports(context)
+  let codegen = genCodeFragment(context)
 
-  let codegen = genCodeFragment(ctx)
   if (!isSetupInlined) {
     codegen = preamble + codegen
   }
@@ -186,7 +177,7 @@ export function generate(
     code: codegen,
     ast: ir,
     preamble,
-    map: ctx.map ? ctx.map.toJSON() : undefined,
+    map: context.map ? context.map.toJSON() : undefined,
     helpers,
     vaporHelpers,
   }
@@ -208,6 +199,11 @@ function genCodeFragment(context: CodegenContext) {
     } else if (frag === INDENT_END) {
       indentLevel--
       continue
+    } else if (frag === LF) {
+      pos.line++
+      pos.column = 0
+      pos.offset++
+      continue
     }
 
     if (isString(frag)) frag = [frag]
@@ -282,3 +278,20 @@ export function buildCodeFragment(...frag: CodeFragment[]) {
   const push = frag.push.bind(frag)
   return [frag, push] as const
 }
+
+function genHelperImports({ helpers, vaporHelpers, code }: CodegenContext) {
+  let imports = ''
+  if (helpers.size) {
+    code.unshift(LF)
+    imports += `import { ${[...helpers]
+      .map(h => `${h} as _${h}`)
+      .join(', ')} } from 'vue';\n`
+  }
+  if (vaporHelpers.size) {
+    code.unshift(LF)
+    imports += `import { ${[...vaporHelpers]
+      .map(h => `${h} as _${h}`)
+      .join(', ')} } from 'vue/vapor';\n`
+  }
+  return imports
+}
index 9c57ca98d9a2de99af6b10d5b49057cbd862f82d..ddae02f025467eec65f518c6be56fb0e257b96be 100644 (file)
@@ -37,10 +37,10 @@ export function genBlockFunction(
 
 export function genBlockFunctionContent(
   ir: BlockFunctionIRNode | RootIRNode,
-  ctx: CodegenContext,
+  context: CodegenContext,
   returnValue?: () => CodeFragment[],
 ): CodeFragment[] {
-  const { vaporHelper } = ctx
+  const { vaporHelper } = context
   const [frag, push] = buildCodeFragment(
     NEWLINE,
     `const n${ir.dynamic.id} = t${ir.templateIndex}()`,
@@ -59,11 +59,11 @@ export function genBlockFunctionContent(
       oper.type === IRNodeTypes.WITH_DIRECTIVE,
   )
   for (const directives of groupDirective(directiveOps)) {
-    push(...genWithDirective(directives, ctx))
+    push(...genWithDirective(directives, context))
   }
 
-  push(...genOperations(ir.operation, ctx))
-  push(...genEffects(ir.effect, ctx))
+  push(...genOperations(ir.operation, context))
+  push(...genEffects(ir.effect, context))
 
   push(
     NEWLINE,
index 4d66f11cedc449cfa4ef2b569f497ddb864cc5f5..d1d5575702f56cfbfc3e6a69797ed2ae896943c6 100644 (file)
@@ -17,10 +17,10 @@ import { genSetProp } from './prop'
 import { genSetRef } from './ref'
 import { genCreateTextNode, genSetText } from './text'
 
-export function genOperations(opers: OperationNode[], ctx: CodegenContext) {
+export function genOperations(opers: OperationNode[], context: CodegenContext) {
   const [frag, push] = buildCodeFragment()
   for (const operation of opers) {
-    push(...genOperation(operation, ctx))
+    push(...genOperation(operation, context))
   }
   return frag
 }
index 3bd7ada2be59767753b2367252444c53a3dbd230..132dad3278e2218baf832451845c6ddb4eb3ce53 100644 (file)
@@ -117,7 +117,7 @@ function createRootContext(
 ): TransformContext<RootNode> {
   let globalId = 0
 
-  const ctx: TransformContext<RootNode> = {
+  const context: TransformContext<RootNode> = {
     node,
     parent: null,
     index: 0,
@@ -210,9 +210,9 @@ function createRootContext(
       this.block.operation.push(...node)
     },
   }
-  ctx.root = ctx
-  ctx.reference()
-  return ctx
+  context.root = context
+  context.reference()
+  return context
 }
 
 function createContext<T extends TemplateChildNode>(
@@ -220,7 +220,7 @@ function createContext<T extends TemplateChildNode>(
   parent: TransformContext<ParentNode>,
   index: number,
 ): TransformContext<T> {
-  const ctx: TransformContext<T> = extend({}, parent, {
+  return extend({}, parent, {
     node,
     parent,
     index,
@@ -228,8 +228,7 @@ function createContext<T extends TemplateChildNode>(
     template: '',
     childrenTemplate: [],
     dynamic: genDefaultDynamic(),
-  } satisfies Partial<TransformContext<T>>)
-  return ctx
+  } satisfies Partial<TransformContext<T>>) satisfies TransformContext<T>
 }
 
 // AST -> IR
@@ -250,10 +249,10 @@ export function transform(
     operation: [],
   }
 
-  const ctx = createRootContext(ir, root, options)
+  const context = createRootContext(ir, root, options)
 
-  transformNode(ctx)
-  ctx.registerTemplate()
+  transformNode(context)
+  context.registerTemplate()
 
   return ir
 }
@@ -311,17 +310,17 @@ function transformNode(
     context.template += context.childrenTemplate.filter(Boolean).join('')
 }
 
-function transformChildren(ctx: TransformContext<RootNode | ElementNode>) {
-  const { children } = ctx.node
+function transformChildren(context: TransformContext<RootNode | ElementNode>) {
+  const { children } = context.node
 
   for (const [i, child] of children.entries()) {
-    const childContext = createContext(child, ctx, i)
+    const childContext = createContext(child, context, i)
     transformNode(childContext)
-    ctx.childrenTemplate.push(childContext.template)
-    ctx.dynamic.children[i] = childContext.dynamic
+    context.childrenTemplate.push(childContext.template)
+    context.dynamic.children[i] = childContext.dynamic
   }
 
-  processDynamicChildren(ctx)
+  processDynamicChildren(context)
 }
 
 function processDynamicChildren(
index aafda37358620ccb8b4b1c7f1cb772cd02bf2352..a44626b75b8956afbfba1b41f36bc9e07e776c70 100644 (file)
@@ -8,9 +8,9 @@ import { isBuiltInDirective, isReservedProp, isVoidTag } from '@vue/shared'
 import type { NodeTransform, TransformContext } from '../transform'
 import { IRNodeTypes, type VaporDirectiveNode } from '../ir'
 
-export const transformElement: NodeTransform = (node, ctx) => {
+export const transformElement: NodeTransform = (node, context) => {
   return function postTransformElement() {
-    node = ctx.node
+    node = context.node
 
     if (
       !(
@@ -25,20 +25,20 @@ export const transformElement: NodeTransform = (node, ctx) => {
     const { tag, props } = node
     const isComponent = node.tagType === ElementTypes.COMPONENT
 
-    ctx.template += `<${tag}`
+    context.template += `<${tag}`
     if (props.length) {
       buildProps(
         node,
-        ctx as TransformContext<ElementNode>,
+        context as TransformContext<ElementNode>,
         undefined,
         isComponent,
       )
     }
-    ctx.template += `>` + ctx.childrenTemplate.join('')
+    context.template += `>` + context.childrenTemplate.join('')
 
     // TODO remove unnecessary close tag, e.g. if it's the last element of the template
     if (!isVoidTag(tag)) {
-      ctx.template += `</${tag}>`
+      context.template += `</${tag}>`
     }
   }
 }
index 255ff6763aafedfc608225193d654d1c71a1269a..f3d55dab912ffe3d13751d0f515b385dc012de0b 100644 (file)
@@ -2,19 +2,19 @@ import { NodeTypes, type SimpleExpressionNode } from '@vue/compiler-dom'
 import type { NodeTransform } from '../transform'
 import { DynamicFlag, IRNodeTypes } from '../ir'
 
-export const transformInterpolation: NodeTransform = (node, ctx) => {
+export const transformInterpolation: NodeTransform = (node, context) => {
   if (node.type !== NodeTypes.INTERPOLATION) return
 
   const expr = node.content as SimpleExpressionNode
-  const parentChildren = ctx.parent ? ctx.parent.node.children : []
-  const isFirst = ctx.index === 0
-  const isLast = ctx.index === parentChildren.length - 1
-  const isRoot = ctx.parent === ctx.root
+  const parentChildren = context.parent ? context.parent.node.children : []
+  const isFirst = context.index === 0
+  const isLast = context.index === parentChildren.length - 1
+  const isRoot = context.parent === context.root
 
   if (isFirst && isLast && !isRoot) {
-    const parent = ctx.parent!
+    const parent = context.parent!
     const parentId = parent.reference()
-    ctx.registerEffect(
+    context.registerEffect(
       [expr],
       [
         {
@@ -25,13 +25,13 @@ export const transformInterpolation: NodeTransform = (node, ctx) => {
       ],
     )
   } else {
-    const id = ctx.reference()
-    ctx.dynamic.flags |= DynamicFlag.INSERT | DynamicFlag.NON_TEMPLATE
-    ctx.registerOperation({
+    const id = context.reference()
+    context.dynamic.flags |= DynamicFlag.INSERT | DynamicFlag.NON_TEMPLATE
+    context.registerOperation({
       type: IRNodeTypes.CREATE_TEXT_NODE,
       id,
     })
-    ctx.registerEffect(
+    context.registerEffect(
       [expr],
       [
         {