]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix: exclude compund expression type
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Tue, 5 Dec 2023 09:13:25 +0000 (17:13 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Tue, 5 Dec 2023 16:17:16 +0000 (00:17 +0800)
packages/compiler-vapor/src/generate.ts
packages/compiler-vapor/src/ir.ts
packages/compiler-vapor/src/transform.ts
packages/compiler-vapor/src/transforms/transformElement.ts
packages/compiler-vapor/src/transforms/transformInterpolation.ts
packages/compiler-vapor/src/transforms/vOn.ts

index 4cd284e84a969867892a2aef3d93d55d74631d77..2718801d1df9272dcb3c641b97c45fde237f0a68 100644 (file)
@@ -6,7 +6,6 @@ import {
   NewlineType,
   advancePositionWithMutation,
   locStub,
-  NodeTypes,
   BindingTypes,
   isSimpleIdentifier,
   createSimpleExpression,
@@ -14,12 +13,19 @@ import {
 import {
   type IRDynamicChildren,
   type RootIRNode,
+  type SetPropIRNode,
+  type IRExpression,
+  type OperationNode,
+  type VaporHelper,
+  type SetEventIRNode,
+  type WithDirectiveIRNode,
+  type SetTextIRNode,
   IRNodeTypes,
-  OperationNode,
-  VaporHelper,
-  IRExpression,
-  SetEventIRNode,
-  WithDirectiveIRNode,
+  SetHtmlIRNode,
+  CreateTextNodeIRNode,
+  InsertNodeIRNode,
+  PrependNodeIRNode,
+  AppendNodeIRNode,
 } from './ir'
 import { SourceMapGenerator } from 'source-map-js'
 import { camelize, isString } from '@vue/shared'
@@ -307,80 +313,6 @@ export function generate(
   }
 }
 
-function genOperation(oper: OperationNode, context: CodegenContext) {
-  const { vaporHelper, push, pushWithNewline } = context
-  // TODO: cache old value
-  switch (oper.type) {
-    case IRNodeTypes.SET_PROP: {
-      pushWithNewline(`${vaporHelper('setAttr')}(n${oper.element}, `)
-      genExpression(oper.name, context)
-      push(`, undefined, `)
-      genExpression(oper.value, context)
-      push(')')
-      return
-    }
-
-    case IRNodeTypes.SET_TEXT: {
-      pushWithNewline(`${vaporHelper('setText')}(n${oper.element}, undefined, `)
-      genExpression(oper.value, context)
-      push(')')
-      return
-    }
-
-    case IRNodeTypes.SET_EVENT: {
-      return genSetEvent(oper, context)
-    }
-
-    case IRNodeTypes.SET_HTML: {
-      pushWithNewline(`${vaporHelper('setHtml')}(n${oper.element}, undefined, `)
-      genExpression(oper.value, context)
-      push(')')
-      return
-    }
-
-    case IRNodeTypes.CREATE_TEXT_NODE: {
-      pushWithNewline(`const n${oper.id} = ${vaporHelper('createTextNode')}(`)
-      genExpression(oper.value, context)
-      push(')')
-      return
-    }
-
-    case IRNodeTypes.INSERT_NODE: {
-      const elements = ([] as number[]).concat(oper.element)
-      let element = elements.map((el) => `n${el}`).join(', ')
-      if (elements.length > 1) element = `[${element}]`
-      pushWithNewline(
-        `${vaporHelper('insert')}(${element}, n${
-          oper.parent
-        }${`, n${oper.anchor}`})`,
-      )
-      return
-    }
-    case IRNodeTypes.PREPEND_NODE: {
-      pushWithNewline(
-        `${vaporHelper('prepend')}(n${oper.parent}, ${oper.elements
-          .map((el) => `n${el}`)
-          .join(', ')})`,
-      )
-      return
-    }
-    case IRNodeTypes.APPEND_NODE: {
-      pushWithNewline(
-        `${vaporHelper('append')}(n${oper.parent}, ${oper.elements
-          .map((el) => `n${el}`)
-          .join(', ')})`,
-      )
-      return
-    }
-    case IRNodeTypes.WITH_DIRECTIVE: {
-      // generated, skip
-      return
-    }
-    default:
-      return checkNever(oper)
-  }
-}
-
 function genChildren(children: IRDynamicChildren) {
   let code = ''
   // TODO
@@ -407,49 +339,94 @@ function genChildren(children: IRDynamicChildren) {
   return `{${code}}`
 }
 
-// TODO: other types (not only string)
-function genArrayExpression(elements: string[]) {
-  return `[${elements.map((it) => JSON.stringify(it)).join(', ')}]`
+function genOperation(oper: OperationNode, context: CodegenContext) {
+  // TODO: cache old value
+  switch (oper.type) {
+    case IRNodeTypes.SET_PROP:
+      return genSetProp(oper, context)
+    case IRNodeTypes.SET_TEXT:
+      return genSetText(oper, context)
+    case IRNodeTypes.SET_EVENT:
+      return genSetEvent(oper, context)
+    case IRNodeTypes.SET_HTML:
+      return genSetHtml(oper, context)
+    case IRNodeTypes.CREATE_TEXT_NODE:
+      return genCreateTextNode(oper, context)
+    case IRNodeTypes.INSERT_NODE:
+      return genInsertNode(oper, context)
+    case IRNodeTypes.PREPEND_NODE:
+      return genPrependNode(oper, context)
+    case IRNodeTypes.APPEND_NODE:
+      return genAppendNode(oper, context)
+    case IRNodeTypes.WITH_DIRECTIVE:
+      // generated, skip
+      return
+    default:
+      return checkNever(oper)
+  }
 }
 
-function genExpression(
-  exp: IRExpression,
-  {
-    inline,
-    prefixIdentifiers,
-    bindingMetadata,
-    vaporHelper,
-    push,
-  }: CodegenContext,
-  { unref = true }: { unref?: boolean } = {},
-) {
-  if (isString(exp)) return push(exp)
+function genSetProp(oper: SetPropIRNode, context: CodegenContext) {
+  const { push, pushWithNewline, vaporHelper } = context
+  pushWithNewline(`${vaporHelper('setAttr')}(n${oper.element}, `)
+  genExpression(oper.name, context)
+  push(`, undefined, `)
+  genExpression(oper.value, context)
+  push(')')
+}
 
-  // TODO NodeTypes.COMPOUND_EXPRESSION
-  if (exp.type === NodeTypes.COMPOUND_EXPRESSION) return
+function genSetText(oper: SetTextIRNode, context: CodegenContext) {
+  const { push, pushWithNewline, vaporHelper } = context
+  pushWithNewline(`${vaporHelper('setText')}(n${oper.element}, undefined, `)
+  genExpression(oper.value, context)
+  push(')')
+}
 
-  let { content } = exp
-  let name: string | undefined
+function genSetHtml(oper: SetHtmlIRNode, context: CodegenContext) {
+  const { push, pushWithNewline, vaporHelper } = context
+  pushWithNewline(`${vaporHelper('setHtml')}(n${oper.element}, undefined, `)
+  genExpression(oper.value, context)
+  push(')')
+}
 
-  if (exp.isStatic) {
-    content = JSON.stringify(content)
-  } else {
-    if (unref)
-      switch (bindingMetadata[content]) {
-        case BindingTypes.SETUP_REF:
-          content += '.value'
-          break
-        case BindingTypes.SETUP_MAYBE_REF:
-          content = `${vaporHelper('unref')}(${content})`
-          break
-      }
-    if (prefixIdentifiers && !inline) {
-      if (isSimpleIdentifier(content)) name = content
-      content = `_ctx.${content}`
-    }
-  }
+function genCreateTextNode(
+  oper: CreateTextNodeIRNode,
+  context: CodegenContext,
+) {
+  const { push, pushWithNewline, vaporHelper } = context
+  pushWithNewline(`const n${oper.id} = ${vaporHelper('createTextNode')}(`)
+  genExpression(oper.value, context)
+  push(')')
+}
 
-  push(content, NewlineType.None, exp.loc, name)
+function genInsertNode(oper: InsertNodeIRNode, context: CodegenContext) {
+  const { pushWithNewline, vaporHelper } = context
+  const elements = ([] as number[]).concat(oper.element)
+  let element = elements.map((el) => `n${el}`).join(', ')
+  if (elements.length > 1) element = `[${element}]`
+  pushWithNewline(
+    `${vaporHelper('insert')}(${element}, n${
+      oper.parent
+    }${`, n${oper.anchor}`})`,
+  )
+}
+
+function genPrependNode(oper: PrependNodeIRNode, context: CodegenContext) {
+  const { pushWithNewline, vaporHelper } = context
+  pushWithNewline(
+    `${vaporHelper('prepend')}(n${oper.parent}, ${oper.elements
+      .map((el) => `n${el}`)
+      .join(', ')})`,
+  )
+}
+
+function genAppendNode(oper: AppendNodeIRNode, context: CodegenContext) {
+  const { pushWithNewline, vaporHelper } = context
+  pushWithNewline(
+    `${vaporHelper('append')}(n${oper.parent}, ${oper.elements
+      .map((el) => `n${el}`)
+      .join(', ')})`,
+  )
 }
 
 function genSetEvent(oper: SetEventIRNode, context: CodegenContext) {
@@ -500,3 +477,43 @@ function genWithDirective(oper: WithDirectiveIRNode, context: CodegenContext) {
   push(']])')
   return
 }
+
+// TODO: other types (not only string)
+function genArrayExpression(elements: string[]) {
+  return `[${elements.map((it) => JSON.stringify(it)).join(', ')}]`
+}
+
+function genExpression(
+  exp: IRExpression,
+  {
+    inline,
+    prefixIdentifiers,
+    bindingMetadata,
+    vaporHelper,
+    push,
+  }: CodegenContext,
+) {
+  if (isString(exp)) return push(exp)
+
+  let { content } = exp
+  let name: string | undefined
+
+  if (exp.isStatic) {
+    content = JSON.stringify(content)
+  } else {
+    switch (bindingMetadata[content]) {
+      case BindingTypes.SETUP_REF:
+        content += '.value'
+        break
+      case BindingTypes.SETUP_MAYBE_REF:
+        content = `${vaporHelper('unref')}(${content})`
+        break
+    }
+    if (prefixIdentifiers && !inline) {
+      if (isSimpleIdentifier(content)) name = content
+      content = `_ctx.${content}`
+    }
+  }
+
+  push(content, NewlineType.None, exp.loc, name)
+}
index 0ed0ebfb3f1db7f19c5306b4a75bbb138b721432..78ddc6ec8857828493093e0193b42802b5674dbd 100644 (file)
@@ -1,6 +1,7 @@
 import type {
-  ExpressionNode,
+  DirectiveNode,
   RootNode,
+  SimpleExpressionNode,
   SourceLocation,
 } from '@vue/compiler-dom'
 import type { Prettify } from '@vue/shared'
@@ -145,7 +146,7 @@ export interface IRDynamicInfo {
 }
 export type IRDynamicChildren = Record<number, IRDynamicInfo>
 
-export type IRExpression = ExpressionNode | string
+export type IRExpression = SimpleExpressionNode | string
 export interface IREffect {
   // TODO multi-expression effect
   expressions: IRExpression[]
@@ -164,3 +165,11 @@ export type HackOptions<T> = Prettify<
     }
   >
 >
+
+export type HackDirectiveNode = Overwrite<
+  DirectiveNode,
+  {
+    exp: SimpleExpressionNode | undefined
+    arg: SimpleExpressionNode | undefined
+  }
+>
index 2132fcf43c1f0dc00011063072d5f99f108e5a8b..ce0b373c2acdd2abd7cd5a37cce75666fa972f1e 100644 (file)
@@ -9,7 +9,6 @@ import {
   NodeTypes,
   defaultOnError,
   defaultOnWarn,
-  DirectiveNode,
 } from '@vue/compiler-dom'
 import { EMPTY_OBJ, NOOP, isArray } from '@vue/shared'
 import {
@@ -19,7 +18,7 @@ import {
   type IRExpression,
   IRNodeTypes,
 } from './ir'
-import type { HackOptions } from './ir'
+import type { HackDirectiveNode, HackOptions } from './ir'
 
 export type NodeTransform = (
   node: RootNode | TemplateChildNode,
@@ -27,7 +26,7 @@ export type NodeTransform = (
 ) => void | (() => void) | (() => void)[]
 
 export type DirectiveTransform = (
-  dir: DirectiveNode,
+  dir: HackDirectiveNode,
   node: ElementNode,
   context: TransformContext<ElementNode>,
   // a platform specific compiler can import the base transform and augment
index 9ac60cd9ba67799f8d02e249dc7d39312db178b5..6a3615b73ec334788c901c784ddfbdc73ae3d325 100644 (file)
@@ -1,7 +1,6 @@
 import {
   type ElementNode,
   type AttributeNode,
-  type DirectiveNode,
   NodeTypes,
   ErrorCodes,
   createCompilerError,
@@ -9,7 +8,7 @@ import {
 } from '@vue/compiler-dom'
 import { isBuiltInDirective, isVoidTag } from '@vue/shared'
 import { NodeTransform, TransformContext } from '../transform'
-import { IRNodeTypes } from '../ir'
+import { HackDirectiveNode, IRNodeTypes } from '../ir'
 
 export const transformElement: NodeTransform = (node, ctx) => {
   return function postTransformElement() {
@@ -53,17 +52,16 @@ function buildProps(
   isComponent: boolean,
 ) {
   for (const prop of props) {
-    transformProp(prop, node, context)
+    transformProp(prop as HackDirectiveNode | AttributeNode, node, context)
   }
 }
 
 function transformProp(
-  prop: DirectiveNode | AttributeNode,
+  prop: HackDirectiveNode | AttributeNode,
   node: ElementNode,
   context: TransformContext<ElementNode>,
 ): void {
   const { name } = prop
-
   if (prop.type === NodeTypes.ATTRIBUTE) {
     context.template += ` ${name}`
     if (prop.value) context.template += `="${prop.value.content}"`
@@ -79,17 +77,14 @@ function transformProp(
       type: IRNodeTypes.WITH_DIRECTIVE,
       element: context.reference(),
       name,
-      binding: prop.exp,
+      binding: exp,
       loc: prop.loc,
     })
   }
 
   switch (name) {
     case 'bind': {
-      if (
-        !exp ||
-        (exp.type === NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim())
-      ) {
+      if (!exp || !exp.content.trim()) {
         context.options.onError(
           createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
         )
index 4bd51a571750fd782f7a997988de4ccc8713c6ed..dd7537aeccc813c5a8c8f631c6403939dd23963a 100644 (file)
@@ -1,11 +1,11 @@
-import { NodeTypes } from '@vue/compiler-dom'
+import { NodeTypes, SimpleExpressionNode } from '@vue/compiler-dom'
 import { NodeTransform } from '../transform'
 import { IRNodeTypes } from '../ir'
 
 export const transformInterpolation: NodeTransform = (node, ctx) => {
   if (node.type !== NodeTypes.INTERPOLATION) return
 
-  const expr = node.content
+  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
index a8ed5fd7d58eb16c680b198e9fbaf4bd380e9aba..0183138ef1b5468fa60813df42c8d68541ba182c 100644 (file)
@@ -25,9 +25,6 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
   } else if (exp === undefined) {
     // TODO X_V_ON_NO_EXPRESSION error
     return
-  } else if (arg.type === NodeTypes.COMPOUND_EXPRESSION) {
-    // TODO
-    return
   }
 
   const handlerKey = `on${arg.content}`