Skip to content

Commit

Permalink
feat(ref-transform): support using $ macros as function param default…
Browse files Browse the repository at this point in the history
… value initializer
  • Loading branch information
yyx990803 committed Sep 17, 2021
1 parent ebe00f6 commit 380b119
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 36 deletions.
7 changes: 2 additions & 5 deletions packages/compiler-core/src/babelUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,15 @@ export function isInDestructureAssignment(
return false
}

export function walkFunctionParams(
node: Function,
onIdent: (id: Identifier) => void
) {
function walkFunctionParams(node: Function, onIdent: (id: Identifier) => void) {
for (const p of node.params) {
for (const id of extractIdentifiers(p)) {
onIdent(id)
}
}
}

export function walkBlockDeclarations(
function walkBlockDeclarations(
block: BlockStatement | Program,
onIdent: (node: Identifier) => void
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,29 @@ const c = _shallowRef(__c);
"
`;

exports[`as function param default value (arrow fn, no block) 1`] = `
"import { shallowRef as _shallowRef, ref as _ref } from 'vue'
const foo = (m, n = (m), { x: __x, y: __y } = (useMouse()), z = _ref(0)) => {
const x = _shallowRef(__x);
const y = _shallowRef(__y);
return ({ m, n, x, y, z })
}
"
`;

exports[`as function param default value 1`] = `
"import { shallowRef as _shallowRef, ref as _ref } from 'vue'
function foo(m, n = (m), { x: __x, y: __y } = (useMouse()), z = _ref(0)) {
const x = _shallowRef(__x);
const y = _shallowRef(__y);
console.log(m, n.value, x.value, y.value, z.value)
return ({ m, n, x, y, z })
}
"
`;

exports[`handle TS casting syntax 1`] = `
"import { ref as _ref } from 'vue'
Expand Down
31 changes: 31 additions & 0 deletions packages/ref-transform/__tests__/refTransform.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,37 @@ test('nested destructure', () => {
assertCode(code)
})

test('as function param default value', () => {
const { code } = transform(`
function foo(m, n = $(m), { x, y } = $(useMouse()), z = $ref(0)) {
console.log(m, n, x, y, z)
return $$({ m, n, x, y, z })
}
`)
expect(code).toMatch(
`function foo(m, n = (m), { x: __x, y: __y } = (useMouse()), z = _ref(0))`
)
expect(code).toMatch(`const x = _shallowRef(__x)`)
expect(code).toMatch(`const y = _shallowRef(__y)`)
expect(code).toMatch(`console.log(m, n.value, x.value, y.value, z.value)`)
expect(code).toMatch(`return ({ m, n, x, y, z })`)
assertCode(code)
})

test('as function param default value (arrow fn, no block)', () => {
const { code } = transform(`
const foo = (m, n = $(m), { x, y } = $(useMouse()), z = $ref(0)) => $$({ m, n, x, y, z })
`)
expect(code).toMatch(
`const foo = (m, n = (m), { x: __x, y: __y } = (useMouse()), z = _ref(0))`
)
expect(code).toMatch(`const x = _shallowRef(__x)`)
expect(code).toMatch(`const y = _shallowRef(__y)`)
// should convert it to a function with block body and return statement
expect(code).toMatch(`return ({ m, n, x, y, z })`)
assertCode(code)
})

test('$$', () => {
const { code } = transform(`
let a = $ref(1)
Expand Down
135 changes: 104 additions & 31 deletions packages/ref-transform/src/refTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import {
BlockStatement,
CallExpression,
ObjectPattern,
VariableDeclaration,
ArrayPattern,
Program,
VariableDeclarator
Function,
LVal
} from '@babel/types'
import MagicString, { SourceMap } from 'magic-string'
import { walk } from 'estree-walker'
Expand All @@ -16,8 +16,7 @@ import {
isFunctionType,
isInDestructureAssignment,
isReferencedIdentifier,
isStaticProperty,
walkFunctionParams
isStaticProperty
} from '@vue/compiler-core'
import { parse, ParserPlugin } from '@babel/parser'
import { babelParserDefaultPlugins, hasOwn } from '@vue/shared'
Expand Down Expand Up @@ -155,13 +154,19 @@ export function transformAST(
decl.init &&
decl.init.type === 'CallExpression' &&
decl.init.callee.type === 'Identifier' &&
(toVarCall = isToVarCall(decl.init.callee.name))
(toVarCall = isToVarCallString(decl.init.callee.name))
) {
if (stmt.kind !== 'let') {
error(
`${toVarCall}() bindings can only be declared with let`,
decl.init
)
}
processRefDeclaration(
toVarCall,
decl.init as CallExpression,
decl.id,
stmt
stmt.end! + offset
)
} else {
for (const id of extractIdentifiers(decl.id)) {
Expand All @@ -179,16 +184,49 @@ export function transformAST(
}
}

function walkFunctionParams(node: Function) {
let hasConverted = false
for (const param of node.params) {
let varCall
if (
param.type === 'AssignmentPattern' &&
(varCall = isToVarCall(param.right))
) {
// determine destructure statements append point
let appendPoint
if (node.body.type === 'BlockStatement') {
appendPoint = node.body.start! + offset + 1
} else {
appendPoint = node.body.start! + offset
// foo = () => 123 ---> foo = () => {return 123}
if (!hasConverted) {
hasConverted = true
s.prependLeft(appendPoint, '{')
s.prependRight(appendPoint, '\nreturn ')
s.appendLeft(node.body.end! + offset, '\n}')
}
}
processRefDeclaration(
varCall,
param.right as CallExpression,
param.left,
appendPoint
)
} else {
for (const id of extractIdentifiers(param)) {
registerBinding(id)
}
}
}
}

function processRefDeclaration(
method: string,
call: CallExpression,
id: VariableDeclarator['id'],
statement: VariableDeclaration
id: LVal,
appendPoint: number
) {
excludedIds.add(call.callee as Identifier)
if (statement.kind !== 'let') {
error(`${method}() bindings can only be declared with let`, call)
}
if (method === TO_VAR_SYMBOL) {
// $
// remove macro
Expand All @@ -197,9 +235,9 @@ export function transformAST(
// single variable
registerRefBinding(id)
} else if (id.type === 'ObjectPattern') {
processRefObjectPattern(id, statement)
processRefObjectPattern(id, appendPoint)
} else if (id.type === 'ArrayPattern') {
processRefArrayPattern(id, statement)
processRefArrayPattern(id, appendPoint)
}
} else {
// shorthands
Expand All @@ -219,7 +257,7 @@ export function transformAST(

function processRefObjectPattern(
pattern: ObjectPattern,
statement: VariableDeclaration
appendPoint: number
) {
for (const p of pattern.properties) {
let nameId: Identifier | undefined
Expand All @@ -244,9 +282,9 @@ export function transformAST(
nameId = p.value
s.prependRight(nameId.start! + offset, `__`)
} else if (p.value.type === 'ObjectPattern') {
processRefObjectPattern(p.value, statement)
processRefObjectPattern(p.value, appendPoint)
} else if (p.value.type === 'ArrayPattern') {
processRefArrayPattern(p.value, statement)
processRefArrayPattern(p.value, appendPoint)
} else if (p.value.type === 'AssignmentPattern') {
// { foo: bar = 1 } --> { foo: __bar = 1 }
nameId = p.value.left as Identifier
Expand All @@ -262,17 +300,14 @@ export function transformAST(
registerRefBinding(nameId)
// append binding declarations after the parent statement
s.appendLeft(
statement.end! + offset,
appendPoint,
`\nconst ${nameId.name} = ${helper('shallowRef')}(__${nameId.name});`
)
}
}
}

function processRefArrayPattern(
pattern: ArrayPattern,
statement: VariableDeclaration
) {
function processRefArrayPattern(pattern: ArrayPattern, appendPoint: number) {
for (const e of pattern.elements) {
if (!e) continue
let nameId: Identifier | undefined
Expand All @@ -286,17 +321,17 @@ export function transformAST(
// [...a] --> [...__a]
nameId = e.argument as Identifier
} else if (e.type === 'ObjectPattern') {
processRefObjectPattern(e, statement)
processRefObjectPattern(e, appendPoint)
} else if (e.type === 'ArrayPattern') {
processRefArrayPattern(e, statement)
processRefArrayPattern(e, appendPoint)
}
if (nameId) {
registerRefBinding(nameId)
// prefix original
s.prependRight(nameId.start! + offset, `__`)
// append binding declarations after the parent statement
s.appendLeft(
statement.end! + offset,
appendPoint,
`\nconst ${nameId.name} = ${helper('shallowRef')}(__${nameId.name});`
)
}
Expand Down Expand Up @@ -339,7 +374,7 @@ export function transformAST(
// function scopes
if (isFunctionType(node)) {
scopeStack.push((currentScope = {}))
walkFunctionParams(node, registerBinding)
walkFunctionParams(node)
if (node.body.type === 'BlockStatement') {
walkScope(node.body)
}
Expand Down Expand Up @@ -379,18 +414,30 @@ export function transformAST(

if (node.type === 'CallExpression' && node.callee.type === 'Identifier') {
const callee = node.callee.name

const toVarCall = isToVarCall(callee)
if (toVarCall && (!parent || parent.type !== 'VariableDeclarator')) {
const toVarCall = isToVarCallString(callee)
if (
toVarCall &&
(!parent ||
(parent.type !== 'VariableDeclarator' &&
!isParamDefaultInitializer(node, parent, parentStack)))
) {
return error(
`${toVarCall} can only be used as the initializer of ` +
`a variable declaration.`,
`a variable declaration or a function parameter.`,
node
)
}

if (callee === TO_REF_SYMBOL) {
s.remove(node.callee.start! + offset, node.callee.end! + offset)
const call = s.slice(
node.callee.start! + offset,
node.callee.end! + offset
)
s.overwrite(
node.callee.start! + offset,
node.callee.end! + offset,
call.replace(/\$\$$/, '')
)
return this.skip()
}

Expand Down Expand Up @@ -429,7 +476,15 @@ export function transformAST(
}
}

function isToVarCall(callee: string): string | false {
function isToVarCall(node: Node) {
return (
node.type === 'CallExpression' &&
node.callee.type === 'Identifier' &&
isToVarCallString(node.callee.name)
)
}

function isToVarCallString(callee: string): string | false {
if (callee === TO_VAR_SYMBOL) {
return TO_VAR_SYMBOL
}
Expand All @@ -439,6 +494,24 @@ function isToVarCall(callee: string): string | false {
return false
}

function isParamDefaultInitializer(
node: Node,
parent: Node,
parentStack: Node[]
): boolean {
if (parent.type !== 'AssignmentPattern') {
return false
}
if (node !== parent.right) {
return false
}
const grandParent = parentStack[parentStack.length - 2]
if (!isFunctionType(grandParent)) {
return false
}
return grandParent.params.includes(parent)
}

const RFC_LINK = `https://github.com/vuejs/rfcs/discussions/369`
const hasWarned: Record<string, boolean> = {}

Expand Down

0 comments on commit 380b119

Please sign in to comment.