diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap index 518c2a5fe..454e50e9c 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap @@ -32,3 +32,25 @@ export function render(_ctx, $props, $emit, $attrs, $slots) { return n0 }" `; + +exports[`compiler: expression > update expression 1`] = ` +"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template("
", true) + +export function render(_ctx) { + const n1 = t0() + const n0 = _child(n1) + const x1 = _child(n1) + _renderEffect(() => { + const _String = String + const _foo = _ctx.foo + + _setText(n0, _toDisplayString(_String(_foo.id++)) + " " + _toDisplayString(_foo) + " " + _toDisplayString(_ctx.bar)) + _setText(x1, _toDisplayString(_String(_foo.id++)) + " " + _toDisplayString(_foo) + " " + _toDisplayString(_ctx.bar)) + _setProp(n1, "id", _String(_foo.id++)) + _setProp(n1, "foo", _foo) + _setProp(n1, "bar", _ctx.bar++) + }) + return n1 +}" +`; diff --git a/packages/compiler-vapor/__tests__/transforms/expression.spec.ts b/packages/compiler-vapor/__tests__/transforms/expression.spec.ts index c97decd9d..5983bde67 100644 --- a/packages/compiler-vapor/__tests__/transforms/expression.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/expression.spec.ts @@ -1,9 +1,15 @@ import { BindingTypes } from '@vue/compiler-dom' -import { transformChildren, transformText } from '../../src' +import { + transformChildren, + transformElement, + transformText, + transformVBind, +} from '../../src' import { makeCompile } from './_utils' const compileWithExpression = makeCompile({ - nodeTransforms: [transformChildren, transformText], + nodeTransforms: [transformElement, transformChildren, transformText], + directiveTransforms: { bind: transformVBind }, }) describe('compiler: expression', () => { @@ -31,4 +37,14 @@ describe('compiler: expression', () => { expect(code).toMatchSnapshot() expect(code).contains(`$props['bar']`) }) + + test('update expression', () => { + const { code } = compileWithExpression(` +
+ {{ String(foo.id++) }} {{ foo }} {{ bar }} +
+ `) + expect(code).toMatchSnapshot() + expect(code).contains(`_String(_foo.id++)`) + }) }) diff --git a/packages/compiler-vapor/src/generators/expression.ts b/packages/compiler-vapor/src/generators/expression.ts index eab50c625..1baa85535 100644 --- a/packages/compiler-vapor/src/generators/expression.ts +++ b/packages/compiler-vapor/src/generators/expression.ts @@ -244,8 +244,13 @@ export function processExpressions( expressions: SimpleExpressionNode[], ): DeclarationResult { // analyze variables - const { seenVariable, variableToExpMap, expToVariableMap, seenIdentifier } = - analyzeExpressions(expressions) + const { + seenVariable, + variableToExpMap, + expToVariableMap, + seenIdentifier, + updatedVariable, + } = analyzeExpressions(expressions) // process repeated identifiers and member expressions // e.g., `foo[baz]` will be transformed into `foo_baz` @@ -255,6 +260,7 @@ export function processExpressions( variableToExpMap, expToVariableMap, seenIdentifier, + updatedVariable, ) // process duplicate expressions after identifier and member expression handling. @@ -263,6 +269,8 @@ export function processExpressions( context, expressions, varDeclarations, + updatedVariable, + expToVariableMap, ) return genDeclarations([...varDeclarations, ...expDeclarations], context) @@ -273,11 +281,13 @@ function analyzeExpressions(expressions: SimpleExpressionNode[]) { const variableToExpMap = new Map>() const expToVariableMap = new Map() const seenIdentifier = new Set() + const updatedVariable = new Set() const registerVariable = ( name: string, exp: SimpleExpressionNode, isIdentifier: boolean, + parentStack: Node[] = [], ) => { if (isIdentifier) seenIdentifier.add(name) seenVariable[name] = (seenVariable[name] || 0) + 1 @@ -286,6 +296,8 @@ function analyzeExpressions(expressions: SimpleExpressionNode[]) { (variableToExpMap.get(name) || new Set()).add(exp), ) expToVariableMap.set(exp, (expToVariableMap.get(exp) || []).concat(name)) + if (parentStack.some(p => p.type === 'UpdateExpression')) + updatedVariable.add(name) } for (const exp of expressions) { @@ -299,14 +311,20 @@ function analyzeExpressions(expressions: SimpleExpressionNode[]) { const memberExp = extractMemberExpression(parent, name => { registerVariable(name, exp, true) }) - registerVariable(memberExp, exp, false) + registerVariable(memberExp, exp, false, parentStack) } else if (!parentStack.some(isMemberExpression)) { - registerVariable(currentNode.name, exp, true) + registerVariable(currentNode.name, exp, true, parentStack) } }) } - return { seenVariable, seenIdentifier, variableToExpMap, expToVariableMap } + return { + seenVariable, + seenIdentifier, + variableToExpMap, + expToVariableMap, + updatedVariable, + } } function processRepeatedVariables( @@ -315,9 +333,11 @@ function processRepeatedVariables( variableToExpMap: Map>, expToVariableMap: Map, seenIdentifier: Set, + updatedVariable: Set, ): DeclarationValue[] { const declarations: DeclarationValue[] = [] for (const [name, exps] of variableToExpMap) { + if (updatedVariable.has(name)) continue if (seenVariable[name] > 1 && exps.size > 0) { const isIdentifier = seenIdentifier.has(name) const varName = isIdentifier ? name : genVarName(name) @@ -409,12 +429,19 @@ function processRepeatedExpressions( context: CodegenContext, expressions: SimpleExpressionNode[], varDeclarations: DeclarationValue[], + updatedVariable: Set, + expToVariableMap: Map, ): DeclarationValue[] { const declarations: DeclarationValue[] = [] const seenExp = expressions.reduce( (acc, exp) => { + const variables = expToVariableMap.get(exp) // only handle expressions that are not identifiers - if (exp.ast && exp.ast.type !== 'Identifier') { + if ( + exp.ast && + exp.ast.type !== 'Identifier' && + !(variables && variables.some(v => updatedVariable.has(v))) + ) { acc[exp.content] = (acc[exp.content] || 0) + 1 } return acc