From 7007ffb2c796d6d56b9c8e278c54dc1cefd7b58f Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 31 Dec 2021 11:23:50 +0800 Subject: [PATCH] fix(reactivity-transform): should not rewrite for...in / for...of scope variables --- .../__tests__/reactivityTransform.spec.ts | 40 +++++++++-- .../src/reactivityTransform.ts | 68 +++++++++++-------- 2 files changed, 73 insertions(+), 35 deletions(-) diff --git a/packages/reactivity-transform/__tests__/reactivityTransform.spec.ts b/packages/reactivity-transform/__tests__/reactivityTransform.spec.ts index 5fffcd5d6d2..c3c90aae57e 100644 --- a/packages/reactivity-transform/__tests__/reactivityTransform.spec.ts +++ b/packages/reactivity-transform/__tests__/reactivityTransform.spec.ts @@ -127,15 +127,43 @@ test('accessing ref binding', () => { assertCode(code) }) -test('cases that should not append .value', () => { - const { code } = transform(` +describe('cases that should not append .value', () => { + test('member expression', () => { + const { code } = transform(` + let a = $ref(1) + console.log(b.a) + `) + expect(code).not.toMatch(`a.value`) + }) + + test('function argument', () => { + const { code } = transform(` + let a = $ref(1) + function get(a) { + return a + 1 + } + function get2({ a }) { + return a + 1 + } + function get3([a]) { + return a + 1 + } + `) + expect(code).not.toMatch(`a.value`) + }) + + test('for in/of loops', () => { + const { code } = transform(` let a = $ref(1) - console.log(b.a) - function get(a) { - return a + 1 + for (const [a, b] of arr) { + console.log(a) + } + for (let a in arr) { + console.log(a) } `) - expect(code).not.toMatch(`a.value`) + expect(code).not.toMatch(`a.value`) + }) }) test('mutating ref binding', () => { diff --git a/packages/reactivity-transform/src/reactivityTransform.ts b/packages/reactivity-transform/src/reactivityTransform.ts index f7a822ff508..706b09ec5ad 100644 --- a/packages/reactivity-transform/src/reactivityTransform.ts +++ b/packages/reactivity-transform/src/reactivityTransform.ts @@ -7,7 +7,8 @@ import { ArrayPattern, Program, VariableDeclarator, - Expression + Expression, + VariableDeclaration } from '@babel/types' import MagicString, { SourceMap } from 'magic-string' import { walk } from 'estree-walker' @@ -216,40 +217,49 @@ export function transformAST( function walkScope(node: Program | BlockStatement, isRoot = false) { for (const stmt of node.body) { if (stmt.type === 'VariableDeclaration') { - if (stmt.declare) continue - for (const decl of stmt.declarations) { - let refCall - const isCall = - decl.init && - decl.init.type === 'CallExpression' && - decl.init.callee.type === 'Identifier' - if ( - isCall && - (refCall = isRefCreationCall((decl as any).init.callee.name)) - ) { - processRefDeclaration(refCall, decl.id, decl.init as CallExpression) - } else { - const isProps = - isRoot && - isCall && - (decl as any).init.callee.name === 'defineProps' - for (const id of extractIdentifiers(decl.id)) { - if (isProps) { - // for defineProps destructure, only exclude them since they - // are already passed in as knownProps - excludedIds.add(id) - } else { - registerBinding(id) - } - } - } - } + walkVariableDeclaration(stmt, isRoot) } else if ( stmt.type === 'FunctionDeclaration' || stmt.type === 'ClassDeclaration' ) { if (stmt.declare || !stmt.id) continue registerBinding(stmt.id) + } else if ( + (stmt.type === 'ForOfStatement' || stmt.type === 'ForInStatement') && + stmt.left.type === 'VariableDeclaration' + ) { + walkVariableDeclaration(stmt.left) + } + } + } + + function walkVariableDeclaration(stmt: VariableDeclaration, isRoot = false) { + if (stmt.declare) { + return + } + for (const decl of stmt.declarations) { + let refCall + const isCall = + decl.init && + decl.init.type === 'CallExpression' && + decl.init.callee.type === 'Identifier' + if ( + isCall && + (refCall = isRefCreationCall((decl as any).init.callee.name)) + ) { + processRefDeclaration(refCall, decl.id, decl.init as CallExpression) + } else { + const isProps = + isRoot && isCall && (decl as any).init.callee.name === 'defineProps' + for (const id of extractIdentifiers(decl.id)) { + if (isProps) { + // for defineProps destructure, only exclude them since they + // are already passed in as knownProps + excludedIds.add(id) + } else { + registerBinding(id) + } + } } } }