Skip to content

Commit d8f131a

Browse files
committed
fix(reactivity-transform): unwrap wrapper node
1 parent 3f703db commit d8f131a

File tree

7 files changed

+94
-32
lines changed

7 files changed

+94
-32
lines changed

packages/compiler-core/src/babelUtils.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,3 +422,17 @@ function isReferenced(node: Node, parent: Node, grandparent?: Node): boolean {
422422

423423
return true
424424
}
425+
426+
export const TS_NODE_TYPES = [
427+
'TSNonNullExpression', // foo!
428+
'TSAsExpression', // foo as number
429+
'TSTypeAssertion', // (<number>foo)
430+
'TSInstantiationExpression' // foo<string>
431+
]
432+
export function unwrapTSNode(node: Node): Node {
433+
if (TS_NODE_TYPES.includes(node.type)) {
434+
return unwrapTSNode((node as any).expression)
435+
} else {
436+
return node
437+
}
438+
}

packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,23 @@ return () => {}
188188
189189
}"
190190
`;
191+
192+
exports[`sfc props transform unwrap TS node 1`] = `
193+
"import { defineComponent as _defineComponent } from 'vue'
194+
import { toDisplayString as _toDisplayString } from "vue"
195+
196+
197+
export default /*#__PURE__*/_defineComponent({
198+
props: ['foo'],
199+
setup(__props) {
200+
201+
202+
console.log(__props.foo)
203+
204+
return (_ctx: any,_cache: any) => {
205+
return _toDisplayString(__props.foo)
206+
}
207+
}
208+
209+
})"
210+
`;

packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,23 @@ describe('sfc props transform', () => {
202202
})
203203
})
204204

205+
test('unwrap TS node', () => {
206+
const { content, bindings } = compile(`
207+
<script setup lang="ts">
208+
const { foo } = defineProps(['foo'])! as any
209+
console.log(foo)
210+
</script>
211+
<template>{{ foo }}</template>
212+
`)
213+
expect(content).not.toMatch(`const { foo } =`)
214+
expect(content).toMatch(`console.log(__props.foo)`)
215+
expect(content).toMatch(`_toDisplayString(__props.foo)`)
216+
assertCode(content)
217+
expect(bindings).toStrictEqual({
218+
foo: BindingTypes.PROPS
219+
})
220+
})
221+
205222
describe('errors', () => {
206223
test('should error on deep destructure', () => {
207224
expect(() =>

packages/compiler-sfc/src/compileScript.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import {
99
UNREF,
1010
SimpleExpressionNode,
1111
isFunctionType,
12-
walkIdentifiers
12+
walkIdentifiers,
13+
unwrapTSNode
1314
} from '@vue/compiler-dom'
1415
import { DEFAULT_FILENAME, SFCDescriptor, SFCScriptBlock } from './parse'
1516
import {
@@ -1184,16 +1185,17 @@ export function compileScript(
11841185
}
11851186

11861187
if (node.type === 'ExpressionStatement') {
1188+
const expr = unwrapTSNode(node.expression)
11871189
// process `defineProps` and `defineEmit(s)` calls
11881190
if (
1189-
processDefineProps(node.expression) ||
1190-
processDefineEmits(node.expression) ||
1191-
processWithDefaults(node.expression)
1191+
processDefineProps(expr) ||
1192+
processDefineEmits(expr) ||
1193+
processWithDefaults(expr)
11921194
) {
11931195
s.remove(node.start! + startOffset, node.end! + startOffset)
1194-
} else if (processDefineExpose(node.expression)) {
1196+
} else if (processDefineExpose(expr)) {
11951197
// defineExpose({}) -> expose({})
1196-
const callee = (node.expression as CallExpression).callee
1198+
const callee = (expr as CallExpression).callee
11971199
s.overwrite(
11981200
callee.start! + startOffset,
11991201
callee.end! + startOffset,
@@ -1207,12 +1209,13 @@ export function compileScript(
12071209
let left = total
12081210
for (let i = 0; i < total; i++) {
12091211
const decl = node.declarations[i]
1210-
if (decl.init) {
1212+
const init = decl.init && unwrapTSNode(decl.init)
1213+
if (init) {
12111214
// defineProps / defineEmits
12121215
const isDefineProps =
1213-
processDefineProps(decl.init, decl.id, node.kind) ||
1214-
processWithDefaults(decl.init, decl.id, node.kind)
1215-
const isDefineEmits = processDefineEmits(decl.init, decl.id)
1216+
processDefineProps(init, decl.id, node.kind) ||
1217+
processWithDefaults(init, decl.id, node.kind)
1218+
const isDefineEmits = processDefineEmits(init, decl.id)
12161219
if (isDefineProps || isDefineEmits) {
12171220
if (left === 1) {
12181221
s.remove(node.start! + startOffset, node.end! + startOffset)
@@ -1721,7 +1724,8 @@ function walkDeclaration(
17211724
if (node.type === 'VariableDeclaration') {
17221725
const isConst = node.kind === 'const'
17231726
// export const foo = ...
1724-
for (const { id, init } of node.declarations) {
1727+
for (const { id, init: _init } of node.declarations) {
1728+
const init = _init && unwrapTSNode(_init)
17251729
const isDefineCall = !!(
17261730
isConst &&
17271731
isCallOf(

packages/reactivity-transform/__tests__/__snapshots__/reactivityTransform.spec.ts.snap

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,15 @@ const props = defineProps<{msg: string; ids?: string[]}>()
280280
let ids = _ref([])"
281281
`;
282282
283+
exports[`should unwrap TS node 1`] = `
284+
"import { ref as _ref } from 'vue'
285+
286+
const bar = (ref(1))! as number
287+
const baz = (bar)! as Ref<number>
288+
const qux = (<number>_ref(10)!)
289+
"
290+
`;
291+
283292
exports[`using ref binding in property shorthand 1`] = `
284293
"import { ref as _ref } from 'vue'
285294

packages/reactivity-transform/__tests__/reactivityTransform.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,18 @@ test('should not overwrite current scope', () => {
489489
assertCode(code)
490490
})
491491

492+
test('should unwrap TS node', () => {
493+
const { code } = transform(
494+
`
495+
const bar = $(ref(1))! as number
496+
const baz = $$(bar)! as Ref<number>
497+
const qux = (<number>$ref(10)!)
498+
`,
499+
{ filename: 'foo.ts' }
500+
)
501+
assertCode(code)
502+
})
503+
492504
describe('errors', () => {
493505
test('$ref w/ destructure', () => {
494506
expect(() => transform(`let { a } = $ref(1)`)).toThrow(

packages/reactivity-transform/src/reactivityTransform.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import {
2222
isInDestructureAssignment,
2323
isReferencedIdentifier,
2424
isStaticProperty,
25-
walkFunctionParams
25+
unwrapTSNode,
26+
walkFunctionParams,
27+
TS_NODE_TYPES
2628
} from '@vue/compiler-core'
2729
import { parse, ParserPlugin } from '@babel/parser'
2830
import { hasOwn, isArray, isString, genPropsAccessExp } from '@vue/shared'
@@ -261,25 +263,11 @@ export function transformAST(
261263
return s.original.slice(node.start! + offset, node.end! + offset)
262264
}
263265

264-
const WRAPPER_NODE_TYPES = [
265-
'ParenthesizedExpression', // (foo)
266-
'TSNonNullExpression', // foo!
267-
'TSAsExpression', // foo as number
268-
'TSTypeAssertion', // (<number>foo)
269-
'TSInstantiationExpression' // foo<string>
270-
]
271266
function findUpParent() {
272267
return parentStack
273268
.slice()
274269
.reverse()
275-
.find(({ type }) => !WRAPPER_NODE_TYPES.includes(type))
276-
}
277-
function unwrapNode(node: Node): Node {
278-
if (WRAPPER_NODE_TYPES.includes(node.type)) {
279-
return unwrapNode((node as any).expression)
280-
} else {
281-
return node
282-
}
270+
.find(({ type }) => !TS_NODE_TYPES.includes(type))
283271
}
284272

285273
function walkScope(node: Program | BlockStatement, isRoot = false) {
@@ -318,7 +306,7 @@ export function transformAST(
318306
}
319307
for (const decl of stmt.declarations) {
320308
let refCall
321-
const init = decl.init ? unwrapNode(decl.init) : null
309+
const init = decl.init ? unwrapTSNode(decl.init) : null
322310
const isCall =
323311
init &&
324312
init.type === 'CallExpression' &&
@@ -327,7 +315,7 @@ export function transformAST(
327315
processRefDeclaration(refCall, decl.id, init, stmt.kind === 'const')
328316
} else {
329317
const isProps =
330-
isRoot && isCall && (decl as any).init.callee.name === 'defineProps'
318+
isRoot && isCall && (init.callee as Identifier).name === 'defineProps'
331319
for (const id of extractIdentifiers(decl.id)) {
332320
if (isProps) {
333321
// for defineProps destructure, only exclude them since they
@@ -677,7 +665,7 @@ export function transformAST(
677665
if (
678666
parent &&
679667
parent.type.startsWith('TS') &&
680-
!WRAPPER_NODE_TYPES.includes(parent.type)
668+
!TS_NODE_TYPES.includes(parent.type)
681669
) {
682670
return this.skip()
683671
}
@@ -775,8 +763,6 @@ export function transformAST(
775763
}
776764
})
777765

778-
console.log(s.toString())
779-
780766
return {
781767
rootRefs: Object.keys(rootScope).filter(key => {
782768
const binding = rootScope[key]

0 commit comments

Comments
 (0)