diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts index 319aac9e4..193a0f5da 100644 --- a/packages/compiler-vapor/src/generate.ts +++ b/packages/compiler-vapor/src/generate.ts @@ -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 = new Set() - identifiers: Record = Object.create(null) + identifiers: Record = + Object.create(null) seenInlineHandlerNames: Record = Object.create(null) block: BlockIRNode - withId(fn: () => T, map: Record): T { + withId( + fn: () => T, + map: Record, + ): T { const { identifiers } = this const ids = Object.keys(map) diff --git a/packages/compiler-vapor/src/generators/expression.ts b/packages/compiler-vapor/src/generators/expression.ts index 6ece58fa8..e128ccfbe 100644 --- a/packages/compiler-vapor/src/generators/expression.ts +++ b/packages/compiler-vapor/src/generators/expression.ts @@ -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 diff --git a/packages/compiler-vapor/src/generators/for.ts b/packages/compiler-vapor/src/generators/for.ts index 9e4278995..af429c0e6 100644 --- a/packages/compiler-vapor/src/generators/for.ts +++ b/packages/compiler-vapor/src/generators/for.ts @@ -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 = {} + const idMap: Record = {} - 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() + const map = new Map() 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