fix(reactivity-transform): should not rewrite for...in / for...of scope variables

This commit is contained in:
Evan You 2021-12-31 11:23:50 +08:00
parent dd70003cc3
commit 7007ffb2c7
2 changed files with 73 additions and 35 deletions

View File

@ -127,15 +127,43 @@ test('accessing ref binding', () => {
assertCode(code) assertCode(code)
}) })
test('cases that should not append .value', () => { describe('cases that should not append .value', () => {
const { code } = transform(` 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) let a = $ref(1)
console.log(b.a) for (const [a, b] of arr) {
function get(a) { console.log(a)
return a + 1 }
for (let a in arr) {
console.log(a)
} }
`) `)
expect(code).not.toMatch(`a.value`) expect(code).not.toMatch(`a.value`)
})
}) })
test('mutating ref binding', () => { test('mutating ref binding', () => {

View File

@ -7,7 +7,8 @@ import {
ArrayPattern, ArrayPattern,
Program, Program,
VariableDeclarator, VariableDeclarator,
Expression Expression,
VariableDeclaration
} from '@babel/types' } from '@babel/types'
import MagicString, { SourceMap } from 'magic-string' import MagicString, { SourceMap } from 'magic-string'
import { walk } from 'estree-walker' import { walk } from 'estree-walker'
@ -216,40 +217,49 @@ export function transformAST(
function walkScope(node: Program | BlockStatement, isRoot = false) { function walkScope(node: Program | BlockStatement, isRoot = false) {
for (const stmt of node.body) { for (const stmt of node.body) {
if (stmt.type === 'VariableDeclaration') { if (stmt.type === 'VariableDeclaration') {
if (stmt.declare) continue walkVariableDeclaration(stmt, isRoot)
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)
}
}
}
}
} else if ( } else if (
stmt.type === 'FunctionDeclaration' || stmt.type === 'FunctionDeclaration' ||
stmt.type === 'ClassDeclaration' stmt.type === 'ClassDeclaration'
) { ) {
if (stmt.declare || !stmt.id) continue if (stmt.declare || !stmt.id) continue
registerBinding(stmt.id) 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)
}
}
} }
} }
} }