feat(experimental): support ref transform for sfc normal <script>

This commit is contained in:
Evan You
2021-08-23 16:00:46 -04:00
parent f173cf0026
commit 06051c4bf2
8 changed files with 226 additions and 74 deletions

View File

@@ -136,6 +136,9 @@ exports[`nested scopes 1`] = `
b.value++ // outer b
c++ // outer c
let bar = _ref(0)
bar.value++ // outer bar
function foo({ a }) {
a++ // inner a
b.value++ // inner b
@@ -143,10 +146,11 @@ exports[`nested scopes 1`] = `
c.value++ // inner c
let d = _ref(0)
const bar = (c) => {
function bar(c) {
c++ // nested c
d.value++ // nested d
}
bar() // inner bar
if (true) {
let a = _ref(0)

View File

@@ -279,6 +279,9 @@ test('nested scopes', () => {
b++ // outer b
c++ // outer c
let bar = $ref(0)
bar++ // outer bar
function foo({ a }) {
a++ // inner a
b++ // inner b
@@ -286,10 +289,11 @@ test('nested scopes', () => {
c++ // inner c
let d = $ref(0)
const bar = (c) => {
function bar(c) {
c++ // nested c
d++ // nested d
}
bar() // inner bar
if (true) {
let a = $ref(0)
@@ -299,7 +303,7 @@ test('nested scopes', () => {
return $$({ a, b, c, d })
}
`)
expect(rootVars).toStrictEqual(['a', 'b'])
expect(rootVars).toStrictEqual(['a', 'b', 'bar'])
expect(code).toMatch('a.value++ // outer a')
expect(code).toMatch('b.value++ // outer b')
@@ -314,6 +318,10 @@ test('nested scopes', () => {
expect(code).toMatch(`a.value++ // if block a`) // if block
expect(code).toMatch(`bar.value++ // outer bar`)
// inner bar shadowed by function declaration
expect(code).toMatch(`bar() // inner bar`)
expect(code).toMatch(`return ({ a, b, c, d })`)
assertCode(code)
})

View File

@@ -1,7 +1,6 @@
import {
Node,
Identifier,
VariableDeclarator,
BlockStatement,
CallExpression,
ObjectPattern,
@@ -30,14 +29,6 @@ export function shouldTransform(src: string): boolean {
return transformCheckRE.test(src)
}
export interface ReactiveDeclarator {
node: VariableDeclarator
statement: VariableDeclaration
ids: Identifier[]
isPattern: boolean
isRoot: boolean
}
type Scope = Record<string, boolean>
export interface RefTransformOptions {
@@ -105,18 +96,26 @@ export function transform(
export function transformAST(
ast: Node,
s: MagicString,
offset = 0
offset = 0,
knownRootVars?: string[]
): {
rootVars: string[]
importedHelpers: string[]
} {
const importedHelpers = new Set<string>()
const blockStack: BlockStatement[] = []
let currentBlock: BlockStatement | null = null
const rootScope: Scope = {}
const blockToScopeMap = new WeakMap<BlockStatement, Scope>()
const excludedIds = new Set<Identifier>()
const parentStack: Node[] = []
if (knownRootVars) {
for (const key of knownRootVars) {
rootScope[key] = true
}
}
const error = (msg: string, node: Node) => {
const e = new Error(msg)
;(e as any).node = node
@@ -130,7 +129,6 @@ export function transformAST(
const registerBinding = (id: Identifier, isRef = false) => {
excludedIds.add(id)
const currentBlock = blockStack[blockStack.length - 1]
if (currentBlock) {
const currentScope = blockToScopeMap.get(currentBlock)
if (!currentScope) {
@@ -145,13 +143,16 @@ export function transformAST(
const registerRefBinding = (id: Identifier) => registerBinding(id, true)
if (ast.type === 'Program') {
walkBlockDeclarations(ast, registerBinding)
}
// 1st pass: detect macro callsites and register ref bindings
;(walk as any)(ast, {
enter(node: Node, parent?: Node) {
parent && parentStack.push(parent)
if (node.type === 'BlockStatement') {
blockStack.push(node)
blockStack.push((currentBlock = node))
walkBlockDeclarations(node, registerBinding)
if (parent && isFunctionType(parent)) {
walkFunctionParams(parent, registerBinding)
@@ -213,6 +214,7 @@ export function transformAST(
parent && parentStack.pop()
if (node.type === 'BlockStatement') {
blockStack.pop()
currentBlock = blockStack[blockStack.length - 1] || null
}
}
})
@@ -356,7 +358,7 @@ export function transformAST(
}
return {
rootVars: Object.keys(rootScope),
rootVars: Object.keys(rootScope).filter(key => rootScope[key]),
importedHelpers: [...importedHelpers]
}
}