]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip(compiler-vapor): support expressions in idMap
authorEvan You <evan@vuejs.org>
Thu, 30 Jan 2025 12:45:44 +0000 (20:45 +0800)
committerEvan You <evan@vuejs.org>
Thu, 30 Jan 2025 12:45:44 +0000 (20:45 +0800)
packages/compiler-vapor/src/generate.ts
packages/compiler-vapor/src/generators/expression.ts
packages/compiler-vapor/src/generators/for.ts

index 319aac9e48289bf4f53f4d08a2f4bcc9d41dfe9e..193a0f5da777be3f443ac9aa2480870aad6a3d34 100644 (file)
@@ -1,6 +1,7 @@
 import type {
   CodegenOptions as BaseCodegenOptions,
   BaseCodegenResult,
+  SimpleExpressionNode,
 } from '@vue/compiler-dom'
 import type { BlockIRNode, CoreHelper, RootIRNode, VaporHelper } from './ir'
 import { extend, remove } from '@vue/shared'
@@ -32,12 +33,16 @@ export class CodegenContext {
 
   delegates: Set<string> = new Set<string>()
 
-  identifiers: Record<string, string[]> = Object.create(null)
+  identifiers: Record<string, (string | SimpleExpressionNode)[]> =
+    Object.create(null)
 
   seenInlineHandlerNames: Record<string, number> = Object.create(null)
 
   block: BlockIRNode
-  withId<T>(fn: () => T, map: Record<string, string | null>): T {
+  withId<T>(
+    fn: () => T,
+    map: Record<string, string | SimpleExpressionNode | null>,
+  ): T {
     const { identifiers } = this
     const ids = Object.keys(map)
 
index 6ece58fa80f9b31f504ba9574f8276ade6794a7e..e128ccfbe8520866d7875a6af594d227263ca9b8 100644 (file)
@@ -1,4 +1,10 @@
-import { NOOP, extend, genPropsAccessExp, isGloballyAllowed } from '@vue/shared'
+import {
+  NOOP,
+  extend,
+  genPropsAccessExp,
+  isGloballyAllowed,
+  isString,
+} from '@vue/shared'
 import {
   BindingTypes,
   NewlineType,
@@ -110,19 +116,26 @@ export function genExpression(
 
 function genIdentifier(
   raw: string,
-  { options, helper, identifiers }: CodegenContext,
+  context: CodegenContext,
   loc?: SourceLocation,
   assignment?: string,
   id?: Identifier,
   parent?: Node,
   parentStack?: Node[],
 ): CodeFragment[] {
+  const { options, helper, identifiers } = context
   const { inline, bindingMetadata } = options
   let name: string | undefined = raw
 
   const idMap = identifiers[raw]
   if (idMap && idMap.length) {
-    return [[idMap[0], NewlineType.None, loc]]
+    const replacement = idMap[0]
+    if (isString(replacement)) {
+      return [[replacement, NewlineType.None, loc]]
+    } else {
+      // replacement is an expression - process it again
+      return genExpression(replacement, context, assignment)
+    }
   }
 
   let prefix: string | undefined
index 9e42789958f19adbfe3cc5797da4b04afd5eda8a..af429c0e673d4c596fc07f00ed976f9c8e4ef66a 100644 (file)
@@ -1,10 +1,15 @@
-import { type SimpleExpressionNode, walkIdentifiers } from '@vue/compiler-dom'
+import {
+  type SimpleExpressionNode,
+  createSimpleExpression,
+  walkIdentifiers,
+} from '@vue/compiler-dom'
 import { genBlock } from './block'
 import { genExpression } from './expression'
 import type { CodegenContext } from '../generate'
 import type { ForIRNode } from '../ir'
 import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils'
 import type { Identifier } from '@babel/types'
+import { parseExpression } from '@babel/parser'
 
 export function genFor(
   oper: ForIRNode,
@@ -23,10 +28,19 @@ export function genFor(
 
   const [depth, exitScope] = context.enterScope()
   const propsName = `_ctx${depth}`
-  const idMap: Record<string, string | null> = {}
+  const idMap: Record<string, string | SimpleExpressionNode | null> = {}
 
-  idToPathMap.forEach((path, id) => {
-    idMap[id] = `${propsName}[0].value${path}`
+  idToPathMap.forEach((pathInfo, id) => {
+    const path = `${propsName}[0].value${pathInfo ? pathInfo.path : ''}`
+    if (pathInfo && pathInfo.dynamic) {
+      const node = (idMap[id] = createSimpleExpression(path))
+      const plugins = context.options.expressionPlugins
+      node.ast = parseExpression(`(${path})`, {
+        plugins: plugins ? [...plugins, 'typescript'] : ['typescript'],
+      })
+    } else {
+      idMap[id] = path
+    }
   })
   if (rawKey) idMap[rawKey] = `${propsName}[1].value`
   if (rawIndex) idMap[rawIndex] = `${propsName}[2].value`
@@ -54,7 +68,7 @@ export function genFor(
   // construct a id -> accessor path map.
   // e.g. `{ x: { y: [z] }}` -> `Map{ 'z' => '.x.y[0]' }`
   function parseValueDestructure() {
-    const map = new Map<string, string>()
+    const map = new Map<string, { path: string; dynamic: boolean } | null>()
     if (value) {
       rawValue = value && value.content
       if (value.ast) {
@@ -63,6 +77,7 @@ export function genFor(
           (id, _, parentStack, ___, isLocal) => {
             if (isLocal) {
               let path = ''
+              let isDynamic = false
               for (let i = 0; i < parentStack.length; i++) {
                 const parent = parentStack[i]
                 const child = parentStack[i + 1] || id
@@ -71,10 +86,10 @@ export function genFor(
                   parent.value === child
                 ) {
                   if (parent.computed && parent.key.type !== 'StringLiteral') {
-                    // TODO need to process this
+                    isDynamic = true
                     path += `[${value.content.slice(
-                      parent.key.start!,
-                      parent.key.end!,
+                      parent.key.start! - 1,
+                      parent.key.end! - 1,
                     )}]`
                   } else if (parent.key.type === 'StringLiteral') {
                     path += `[${JSON.stringify(parent.key.value)}]`
@@ -88,13 +103,13 @@ export function genFor(
                 }
                 // TODO handle rest spread
               }
-              map.set(id.name, path)
+              map.set(id.name, { path, dynamic: isDynamic })
             }
           },
           true,
         )
       } else {
-        map.set(rawValue, '')
+        map.set(rawValue, null)
       }
     }
     return map