diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap
index 31378a265..7105dfe38 100644
--- a/packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap
+++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap
@@ -1,5 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`sfc props transform $$() escape 1`] = `
+"import { toRef as _toRef } from 'vue'
+
+export default {
+ props: ['foo'],
+ setup(__props) {
+const __props_bar = _toRef(__props, 'bar')
+const __props_foo = _toRef(__props, 'foo')
+
+
+ console.log((__props_foo))
+ console.log((__props_bar))
+ ({ foo: __props_foo, baz: __props_bar })
+
+return () => {}
+}
+
+}"
+`;
+
exports[`sfc props transform aliasing 1`] = `
"import { toDisplayString as _toDisplayString } from \\"vue\\"
diff --git a/packages/compiler-sfc/__tests__/compileScript.spec.ts b/packages/compiler-sfc/__tests__/compileScript.spec.ts
index 85b9f9a41..df2d99348 100644
--- a/packages/compiler-sfc/__tests__/compileScript.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileScript.spec.ts
@@ -36,7 +36,7 @@ describe('SFC compile
+ `)
+ expect(content).toMatch(`const __props_foo = _toRef(__props, 'foo')`)
+ expect(content).toMatch(`const __props_bar = _toRef(__props, 'bar')`)
+ expect(content).toMatch(`console.log((__props_foo))`)
+ expect(content).toMatch(`console.log((__props_bar))`)
+ expect(content).toMatch(`({ foo: __props_foo, baz: __props_bar })`)
+ assertCode(content)
+ })
+
describe('errors', () => {
test('should error on deep destructure', () => {
expect(() =>
diff --git a/packages/ref-transform/src/refTransform.ts b/packages/ref-transform/src/refTransform.ts
index a9972a2a2..1acdca74d 100644
--- a/packages/ref-transform/src/refTransform.ts
+++ b/packages/ref-transform/src/refTransform.ts
@@ -23,7 +23,7 @@ import { parse, ParserPlugin } from '@babel/parser'
import { hasOwn, isArray, isString } from '@vue/shared'
const TO_VAR_SYMBOL = '$'
-const TO_REF_SYMBOL = '$$'
+const ESCAPE_SYMBOL = '$$'
const shorthands = ['ref', 'computed', 'shallowRef', 'toRef', 'customRef']
const transformCheckRE = /[^\w]\$(?:\$|ref|computed|shallowRef)?\s*(\(|\<)/
@@ -420,30 +420,52 @@ export function transformAST(
const isProp = bindingType === 'prop'
if (isStaticProperty(parent) && parent.shorthand) {
// let binding used in a property shorthand
- // { foo } -> { foo: foo.value }
- // { prop } -> { prop: __prop.prop }
// skip for destructure patterns
if (
!(parent as any).inPattern ||
isInDestructureAssignment(parent, parentStack)
) {
if (isProp) {
- s.appendLeft(
- id.end! + offset,
- `: __props.${propsLocalToPublicMap[id.name]}`
- )
+ if (escapeScope) {
+ // prop binding in $$()
+ // { prop } -> { prop: __prop_prop }
+ registerEscapedPropBinding(id)
+ s.appendLeft(
+ id.end! + offset,
+ `: __props_${propsLocalToPublicMap[id.name]}`
+ )
+ } else {
+ // { prop } -> { prop: __prop.prop }
+ s.appendLeft(
+ id.end! + offset,
+ `: __props.${propsLocalToPublicMap[id.name]}`
+ )
+ }
} else {
+ // { foo } -> { foo: foo.value }
s.appendLeft(id.end! + offset, `: ${id.name}.value`)
}
}
} else {
if (isProp) {
- s.overwrite(
- id.start! + offset,
- id.end! + offset,
- `__props.${propsLocalToPublicMap[id.name]}`
- )
+ if (escapeScope) {
+ // x --> __props_x
+ registerEscapedPropBinding(id)
+ s.overwrite(
+ id.start! + offset,
+ id.end! + offset,
+ `__props_${propsLocalToPublicMap[id.name]}`
+ )
+ } else {
+ // x --> __props.x
+ s.overwrite(
+ id.start! + offset,
+ id.end! + offset,
+ `__props.${propsLocalToPublicMap[id.name]}`
+ )
+ }
} else {
+ // x --> x.value
s.appendLeft(id.end! + offset, '.value')
}
}
@@ -453,8 +475,25 @@ export function transformAST(
return false
}
+ const propBindingRefs: Record = {}
+ function registerEscapedPropBinding(id: Identifier) {
+ if (!propBindingRefs.hasOwnProperty(id.name)) {
+ propBindingRefs[id.name] = true
+ const publicKey = propsLocalToPublicMap[id.name]
+ s.prependRight(
+ offset,
+ `const __props_${publicKey} = ${helper(
+ `toRef`
+ )}(__props, '${publicKey}')\n`
+ )
+ }
+ }
+
// check root scope first
walkScope(ast, true)
+
+ // inside $$()
+ let escapeScope: CallExpression | undefined
;(walk as any)(ast, {
enter(node: Node, parent?: Node) {
parent && parentStack.push(parent)
@@ -488,6 +527,8 @@ export function transformAST(
if (
node.type === 'Identifier' &&
+ // if inside $$(), skip unless this is a destructured prop binding
+ !(escapeScope && rootScope[node.name] !== 'prop') &&
isReferencedIdentifier(node, parent!, parentStack) &&
!excludedIds.has(node)
) {
@@ -512,9 +553,9 @@ export function transformAST(
)
}
- if (callee === TO_REF_SYMBOL) {
+ if (callee === ESCAPE_SYMBOL) {
s.remove(node.callee.start! + offset, node.callee.end! + offset)
- return this.skip()
+ escapeScope = node
}
// TODO remove when out of experimental
@@ -543,6 +584,9 @@ export function transformAST(
scopeStack.pop()
currentScope = scopeStack[scopeStack.length - 1] || null
}
+ if (node === escapeScope) {
+ escapeScope = undefined
+ }
}
})