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'
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)
-import { NOOP, extend, genPropsAccessExp, isGloballyAllowed } from '@vue/shared'
+import {
+ NOOP,
+ extend,
+ genPropsAccessExp,
+ isGloballyAllowed,
+ isString,
+} from '@vue/shared'
import {
BindingTypes,
NewlineType,
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
-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,
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`
// 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) {
(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
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)}]`
}
// 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