Ver código fonte

fix: exclude compund expression type

三咲智子 Kevin Deng 2 anos atrás
pai
commit
3474e06542

+ 134 - 117
packages/compiler-vapor/src/generate.ts

@@ -6,7 +6,6 @@ import {
   NewlineType,
   NewlineType,
   advancePositionWithMutation,
   advancePositionWithMutation,
   locStub,
   locStub,
-  NodeTypes,
   BindingTypes,
   BindingTypes,
   isSimpleIdentifier,
   isSimpleIdentifier,
   createSimpleExpression,
   createSimpleExpression,
@@ -14,12 +13,19 @@ import {
 import {
 import {
   type IRDynamicChildren,
   type IRDynamicChildren,
   type RootIRNode,
   type RootIRNode,
+  type SetPropIRNode,
+  type IRExpression,
+  type OperationNode,
+  type VaporHelper,
+  type SetEventIRNode,
+  type WithDirectiveIRNode,
+  type SetTextIRNode,
   IRNodeTypes,
   IRNodeTypes,
-  OperationNode,
-  VaporHelper,
-  IRExpression,
-  SetEventIRNode,
-  WithDirectiveIRNode,
+  SetHtmlIRNode,
+  CreateTextNodeIRNode,
+  InsertNodeIRNode,
+  PrependNodeIRNode,
+  AppendNodeIRNode,
 } from './ir'
 } from './ir'
 import { SourceMapGenerator } from 'source-map-js'
 import { SourceMapGenerator } from 'source-map-js'
 import { camelize, isString } from '@vue/shared'
 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) {
 function genChildren(children: IRDynamicChildren) {
   let code = ''
   let code = ''
   // TODO
   // TODO
@@ -407,49 +339,94 @@ function genChildren(children: IRDynamicChildren) {
   return `{${code}}`
   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) {
 function genSetEvent(oper: SetEventIRNode, context: CodegenContext) {
@@ -500,3 +477,43 @@ function genWithDirective(oper: WithDirectiveIRNode, context: CodegenContext) {
   push(']])')
   push(']])')
   return
   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)
+}

+ 11 - 2
packages/compiler-vapor/src/ir.ts

@@ -1,6 +1,7 @@
 import type {
 import type {
-  ExpressionNode,
+  DirectiveNode,
   RootNode,
   RootNode,
+  SimpleExpressionNode,
   SourceLocation,
   SourceLocation,
 } from '@vue/compiler-dom'
 } from '@vue/compiler-dom'
 import type { Prettify } from '@vue/shared'
 import type { Prettify } from '@vue/shared'
@@ -145,7 +146,7 @@ export interface IRDynamicInfo {
 }
 }
 export type IRDynamicChildren = Record<number, IRDynamicInfo>
 export type IRDynamicChildren = Record<number, IRDynamicInfo>
 
 
-export type IRExpression = ExpressionNode | string
+export type IRExpression = SimpleExpressionNode | string
 export interface IREffect {
 export interface IREffect {
   // TODO multi-expression effect
   // TODO multi-expression effect
   expressions: IRExpression[]
   expressions: IRExpression[]
@@ -164,3 +165,11 @@ export type HackOptions<T> = Prettify<
     }
     }
   >
   >
 >
 >
+
+export type HackDirectiveNode = Overwrite<
+  DirectiveNode,
+  {
+    exp: SimpleExpressionNode | undefined
+    arg: SimpleExpressionNode | undefined
+  }
+>

+ 2 - 3
packages/compiler-vapor/src/transform.ts

@@ -9,7 +9,6 @@ import {
   NodeTypes,
   NodeTypes,
   defaultOnError,
   defaultOnError,
   defaultOnWarn,
   defaultOnWarn,
-  DirectiveNode,
 } from '@vue/compiler-dom'
 } from '@vue/compiler-dom'
 import { EMPTY_OBJ, NOOP, isArray } from '@vue/shared'
 import { EMPTY_OBJ, NOOP, isArray } from '@vue/shared'
 import {
 import {
@@ -19,7 +18,7 @@ import {
   type IRExpression,
   type IRExpression,
   IRNodeTypes,
   IRNodeTypes,
 } from './ir'
 } from './ir'
-import type { HackOptions } from './ir'
+import type { HackDirectiveNode, HackOptions } from './ir'
 
 
 export type NodeTransform = (
 export type NodeTransform = (
   node: RootNode | TemplateChildNode,
   node: RootNode | TemplateChildNode,
@@ -27,7 +26,7 @@ export type NodeTransform = (
 ) => void | (() => void) | (() => void)[]
 ) => void | (() => void) | (() => void)[]
 
 
 export type DirectiveTransform = (
 export type DirectiveTransform = (
-  dir: DirectiveNode,
+  dir: HackDirectiveNode,
   node: ElementNode,
   node: ElementNode,
   context: TransformContext<ElementNode>,
   context: TransformContext<ElementNode>,
   // a platform specific compiler can import the base transform and augment
   // a platform specific compiler can import the base transform and augment

+ 5 - 10
packages/compiler-vapor/src/transforms/transformElement.ts

@@ -1,7 +1,6 @@
 import {
 import {
   type ElementNode,
   type ElementNode,
   type AttributeNode,
   type AttributeNode,
-  type DirectiveNode,
   NodeTypes,
   NodeTypes,
   ErrorCodes,
   ErrorCodes,
   createCompilerError,
   createCompilerError,
@@ -9,7 +8,7 @@ import {
 } from '@vue/compiler-dom'
 } from '@vue/compiler-dom'
 import { isBuiltInDirective, isVoidTag } from '@vue/shared'
 import { isBuiltInDirective, isVoidTag } from '@vue/shared'
 import { NodeTransform, TransformContext } from '../transform'
 import { NodeTransform, TransformContext } from '../transform'
-import { IRNodeTypes } from '../ir'
+import { HackDirectiveNode, IRNodeTypes } from '../ir'
 
 
 export const transformElement: NodeTransform = (node, ctx) => {
 export const transformElement: NodeTransform = (node, ctx) => {
   return function postTransformElement() {
   return function postTransformElement() {
@@ -53,17 +52,16 @@ function buildProps(
   isComponent: boolean,
   isComponent: boolean,
 ) {
 ) {
   for (const prop of props) {
   for (const prop of props) {
-    transformProp(prop, node, context)
+    transformProp(prop as HackDirectiveNode | AttributeNode, node, context)
   }
   }
 }
 }
 
 
 function transformProp(
 function transformProp(
-  prop: DirectiveNode | AttributeNode,
+  prop: HackDirectiveNode | AttributeNode,
   node: ElementNode,
   node: ElementNode,
   context: TransformContext<ElementNode>,
   context: TransformContext<ElementNode>,
 ): void {
 ): void {
   const { name } = prop
   const { name } = prop
-
   if (prop.type === NodeTypes.ATTRIBUTE) {
   if (prop.type === NodeTypes.ATTRIBUTE) {
     context.template += ` ${name}`
     context.template += ` ${name}`
     if (prop.value) context.template += `="${prop.value.content}"`
     if (prop.value) context.template += `="${prop.value.content}"`
@@ -79,17 +77,14 @@ function transformProp(
       type: IRNodeTypes.WITH_DIRECTIVE,
       type: IRNodeTypes.WITH_DIRECTIVE,
       element: context.reference(),
       element: context.reference(),
       name,
       name,
-      binding: prop.exp,
+      binding: exp,
       loc: prop.loc,
       loc: prop.loc,
     })
     })
   }
   }
 
 
   switch (name) {
   switch (name) {
     case 'bind': {
     case 'bind': {
-      if (
-        !exp ||
-        (exp.type === NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim())
-      ) {
+      if (!exp || !exp.content.trim()) {
         context.options.onError(
         context.options.onError(
           createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
           createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
         )
         )

+ 2 - 2
packages/compiler-vapor/src/transforms/transformInterpolation.ts

@@ -1,11 +1,11 @@
-import { NodeTypes } from '@vue/compiler-dom'
+import { NodeTypes, SimpleExpressionNode } from '@vue/compiler-dom'
 import { NodeTransform } from '../transform'
 import { NodeTransform } from '../transform'
 import { IRNodeTypes } from '../ir'
 import { IRNodeTypes } from '../ir'
 
 
 export const transformInterpolation: NodeTransform = (node, ctx) => {
 export const transformInterpolation: NodeTransform = (node, ctx) => {
   if (node.type !== NodeTypes.INTERPOLATION) return
   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 parentChildren = ctx.parent ? ctx.parent.node.children : []
   const isFirst = ctx.index === 0
   const isFirst = ctx.index === 0
   const isLast = ctx.index === parentChildren.length - 1
   const isLast = ctx.index === parentChildren.length - 1

+ 0 - 3
packages/compiler-vapor/src/transforms/vOn.ts

@@ -25,9 +25,6 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
   } else if (exp === undefined) {
   } else if (exp === undefined) {
     // TODO X_V_ON_NO_EXPRESSION error
     // TODO X_V_ON_NO_EXPRESSION error
     return
     return
-  } else if (arg.type === NodeTypes.COMPOUND_EXPRESSION) {
-    // TODO
-    return
   }
   }
 
 
   const handlerKey = `on${arg.content}`
   const handlerKey = `on${arg.content}`