refactor(compiler): further extract babel ast utilities
This commit is contained in:
parent
62f752552a
commit
73f8cae465
231
packages/compiler-core/src/babelUtils.ts
Normal file
231
packages/compiler-core/src/babelUtils.ts
Normal file
@ -0,0 +1,231 @@
|
||||
import {
|
||||
Identifier,
|
||||
Node,
|
||||
isReferenced,
|
||||
Function,
|
||||
ObjectProperty
|
||||
} from '@babel/types'
|
||||
import { walk } from 'estree-walker'
|
||||
|
||||
export function walkIdentifiers(
|
||||
root: Node,
|
||||
onIdentifier: (
|
||||
node: Identifier,
|
||||
parent: Node,
|
||||
parentStack: Node[],
|
||||
isReference: boolean,
|
||||
isLocal: boolean
|
||||
) => void,
|
||||
onNode?: (node: Node, parent: Node, parentStack: Node[]) => void | boolean,
|
||||
parentStack: Node[] = [],
|
||||
knownIds: Record<string, number> = Object.create(null),
|
||||
includeAll = false
|
||||
) {
|
||||
const rootExp =
|
||||
root.type === 'Program' &&
|
||||
root.body[0].type === 'ExpressionStatement' &&
|
||||
root.body[0].expression
|
||||
|
||||
;(walk as any)(root, {
|
||||
enter(node: Node & { scopeIds?: Set<string> }, parent: Node | undefined) {
|
||||
parent && parentStack.push(parent)
|
||||
if (
|
||||
parent &&
|
||||
parent.type.startsWith('TS') &&
|
||||
parent.type !== 'TSAsExpression' &&
|
||||
parent.type !== 'TSNonNullExpression' &&
|
||||
parent.type !== 'TSTypeAssertion'
|
||||
) {
|
||||
return this.skip()
|
||||
}
|
||||
if (onNode && onNode(node, parent!, parentStack) === false) {
|
||||
return this.skip()
|
||||
}
|
||||
if (node.type === 'Identifier') {
|
||||
const isLocal = !!knownIds[node.name]
|
||||
const isRefed = isReferencedIdentifier(node, parent!, parentStack)
|
||||
if (includeAll || (isRefed && !isLocal)) {
|
||||
onIdentifier(node, parent!, parentStack, isRefed, isLocal)
|
||||
}
|
||||
} else if (isFunctionType(node)) {
|
||||
// walk function expressions and add its arguments to known identifiers
|
||||
// so that we don't prefix them
|
||||
for (const p of node.params) {
|
||||
;(walk as any)(p, {
|
||||
enter(child: Node, parent: Node) {
|
||||
if (
|
||||
child.type === 'Identifier' &&
|
||||
// do not record as scope variable if is a destructured key
|
||||
!isStaticPropertyKey(child, parent) &&
|
||||
// do not record if this is a default value
|
||||
// assignment of a destructured variable
|
||||
!(
|
||||
parent &&
|
||||
parent.type === 'AssignmentPattern' &&
|
||||
parent.right === child
|
||||
)
|
||||
) {
|
||||
markScopeIdentifier(node, child, knownIds)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} else if (node.type === 'BlockStatement') {
|
||||
// #3445 record block-level local variables
|
||||
for (const stmt of node.body) {
|
||||
if (stmt.type === 'VariableDeclaration') {
|
||||
for (const decl of stmt.declarations) {
|
||||
for (const id of extractIdentifiers(decl.id)) {
|
||||
markScopeIdentifier(node, id, knownIds)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
node.type === 'ObjectProperty' &&
|
||||
parent!.type === 'ObjectPattern'
|
||||
) {
|
||||
// mark property in destructure pattern
|
||||
;(node as any).inPattern = true
|
||||
}
|
||||
},
|
||||
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | undefined) {
|
||||
parent && parentStack.pop()
|
||||
if (node !== rootExp && node.scopeIds) {
|
||||
node.scopeIds.forEach((id: string) => {
|
||||
knownIds[id]--
|
||||
if (knownIds[id] === 0) {
|
||||
delete knownIds[id]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function isReferencedIdentifier(
|
||||
id: Identifier,
|
||||
parent: Node | null,
|
||||
parentStack: Node[]
|
||||
) {
|
||||
if (!parent) {
|
||||
return true
|
||||
}
|
||||
|
||||
// is a special keyword but parsed as identifier
|
||||
if (id.name === 'arguments') {
|
||||
return false
|
||||
}
|
||||
|
||||
if (isReferenced(id, parent)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// babel's isReferenced check returns false for ids being assigned to, so we
|
||||
// need to cover those cases here
|
||||
switch (parent.type) {
|
||||
case 'AssignmentExpression':
|
||||
case 'AssignmentPattern':
|
||||
return true
|
||||
case 'ObjectPattern':
|
||||
case 'ArrayPattern':
|
||||
return isInDestructureAssignment(parent, parentStack)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export function isInDestructureAssignment(
|
||||
parent: Node,
|
||||
parentStack: Node[]
|
||||
): boolean {
|
||||
if (
|
||||
parent &&
|
||||
(parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')
|
||||
) {
|
||||
let i = parentStack.length
|
||||
while (i--) {
|
||||
const p = parentStack[i]
|
||||
if (p.type === 'AssignmentExpression') {
|
||||
return true
|
||||
} else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function extractIdentifiers(
|
||||
param: Node,
|
||||
nodes: Identifier[] = []
|
||||
): Identifier[] {
|
||||
switch (param.type) {
|
||||
case 'Identifier':
|
||||
nodes.push(param)
|
||||
break
|
||||
|
||||
case 'MemberExpression':
|
||||
let object: any = param
|
||||
while (object.type === 'MemberExpression') {
|
||||
object = object.object
|
||||
}
|
||||
nodes.push(object)
|
||||
break
|
||||
|
||||
case 'ObjectPattern':
|
||||
param.properties.forEach(prop => {
|
||||
if (prop.type === 'RestElement') {
|
||||
extractIdentifiers(prop.argument, nodes)
|
||||
} else {
|
||||
extractIdentifiers(prop.value, nodes)
|
||||
}
|
||||
})
|
||||
break
|
||||
|
||||
case 'ArrayPattern':
|
||||
param.elements.forEach(element => {
|
||||
if (element) extractIdentifiers(element, nodes)
|
||||
})
|
||||
break
|
||||
|
||||
case 'RestElement':
|
||||
extractIdentifiers(param.argument, nodes)
|
||||
break
|
||||
|
||||
case 'AssignmentPattern':
|
||||
extractIdentifiers(param.left, nodes)
|
||||
break
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
function markScopeIdentifier(
|
||||
node: Node & { scopeIds?: Set<string> },
|
||||
child: Identifier,
|
||||
knownIds: Record<string, number>
|
||||
) {
|
||||
const { name } = child
|
||||
if (node.scopeIds && node.scopeIds.has(name)) {
|
||||
return
|
||||
}
|
||||
if (name in knownIds) {
|
||||
knownIds[name]++
|
||||
} else {
|
||||
knownIds[name] = 1
|
||||
}
|
||||
;(node.scopeIds || (node.scopeIds = new Set())).add(name)
|
||||
}
|
||||
|
||||
export const isFunctionType = (node: Node): node is Function => {
|
||||
return /Function(?:Expression|Declaration)$|Method$/.test(node.type)
|
||||
}
|
||||
|
||||
export const isStaticProperty = (node: Node): node is ObjectProperty =>
|
||||
node &&
|
||||
(node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&
|
||||
!node.computed
|
||||
|
||||
export const isStaticPropertyKey = (node: Node, parent: Node) =>
|
||||
isStaticProperty(parent) && parent.key === node
|
@ -31,6 +31,7 @@ export {
|
||||
|
||||
export * from './ast'
|
||||
export * from './utils'
|
||||
export * from './babelUtils'
|
||||
export * from './runtimeHelpers'
|
||||
|
||||
export { getBaseTransformPreset, TransformPreset } from './compile'
|
||||
|
@ -17,18 +17,19 @@ import {
|
||||
createCompoundExpression,
|
||||
ConstantTypes
|
||||
} from '../ast'
|
||||
import {
|
||||
isInDestructureAssignment,
|
||||
isStaticProperty,
|
||||
isStaticPropertyKey,
|
||||
walkIdentifiers
|
||||
} from '../babelUtils'
|
||||
import { advancePositionWithClone, isSimpleIdentifier } from '../utils'
|
||||
import {
|
||||
isGloballyWhitelisted,
|
||||
makeMap,
|
||||
babelParserDefaultPlugins,
|
||||
hasOwn,
|
||||
isString,
|
||||
isReferencedIdentifier,
|
||||
isInDestructureAssignment,
|
||||
isStaticProperty,
|
||||
isStaticPropertyKey,
|
||||
isFunctionType
|
||||
isString
|
||||
} from '@vue/shared'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import {
|
||||
@ -39,7 +40,6 @@ import {
|
||||
} from '@babel/types'
|
||||
import { validateBrowserExpression } from '../validateExpression'
|
||||
import { parse } from '@babel/parser'
|
||||
import { walk } from 'estree-walker'
|
||||
import { IS_REF, UNREF } from '../runtimeHelpers'
|
||||
import { BindingTypes } from '../options'
|
||||
|
||||
@ -245,89 +245,49 @@ export function processExpression(
|
||||
return node
|
||||
}
|
||||
|
||||
const ids: (Identifier & PrefixMeta)[] = []
|
||||
const knownIds = Object.create(context.identifiers)
|
||||
const isDuplicate = (node: Node & PrefixMeta): boolean =>
|
||||
ids.some(id => id.start === node.start)
|
||||
type QualifiedId = Identifier & PrefixMeta
|
||||
|
||||
const ids: QualifiedId[] = []
|
||||
const parentStack: Node[] = []
|
||||
const knownIds: Record<string, number> = Object.create(context.identifiers)
|
||||
|
||||
// walk the AST and look for identifiers that need to be prefixed.
|
||||
;(walk as any)(ast, {
|
||||
enter(node: Node & PrefixMeta, parent: Node | undefined) {
|
||||
parent && parentStack.push(parent)
|
||||
if (node.type === 'Identifier') {
|
||||
if (!isDuplicate(node)) {
|
||||
// v2 wrapped filter call
|
||||
if (__COMPAT__ && node.name.startsWith('_filter_')) {
|
||||
return
|
||||
}
|
||||
walkIdentifiers(
|
||||
ast,
|
||||
(node, parent, _, isReferenced, isLocal) => {
|
||||
if (isStaticPropertyKey(node, parent!)) {
|
||||
return
|
||||
}
|
||||
// v2 wrapped filter call
|
||||
if (__COMPAT__ && node.name.startsWith('_filter_')) {
|
||||
return
|
||||
}
|
||||
|
||||
const needPrefix = shouldPrefix(node, parent!, parentStack)
|
||||
if (!knownIds[node.name] && needPrefix) {
|
||||
if (isStaticProperty(parent!) && parent.shorthand) {
|
||||
// property shorthand like { foo }, we need to add the key since
|
||||
// we rewrite the value
|
||||
node.prefix = `${node.name}: `
|
||||
}
|
||||
node.name = rewriteIdentifier(node.name, parent, node)
|
||||
ids.push(node)
|
||||
} else if (!isStaticPropertyKey(node, parent!)) {
|
||||
// The identifier is considered constant unless it's pointing to a
|
||||
// scope variable (a v-for alias, or a v-slot prop)
|
||||
if (!(needPrefix && knownIds[node.name]) && !bailConstant) {
|
||||
node.isConstant = true
|
||||
}
|
||||
// also generate sub-expressions for other identifiers for better
|
||||
// source map support. (except for property keys which are static)
|
||||
ids.push(node)
|
||||
}
|
||||
const needPrefix = isReferenced && canPrefix(node)
|
||||
if (needPrefix && !isLocal) {
|
||||
if (isStaticProperty(parent!) && parent.shorthand) {
|
||||
// property shorthand like { foo }, we need to add the key since
|
||||
// we rewrite the value
|
||||
;(node as QualifiedId).prefix = `${node.name}: `
|
||||
}
|
||||
} else if (isFunctionType(node)) {
|
||||
// walk function expressions and add its arguments to known identifiers
|
||||
// so that we don't prefix them
|
||||
node.params.forEach(p =>
|
||||
(walk as any)(p, {
|
||||
enter(child: Node, parent: Node) {
|
||||
if (
|
||||
child.type === 'Identifier' &&
|
||||
// do not record as scope variable if is a destructured key
|
||||
!isStaticPropertyKey(child, parent) &&
|
||||
// do not record if this is a default value
|
||||
// assignment of a destructured variable
|
||||
!(
|
||||
parent &&
|
||||
parent.type === 'AssignmentPattern' &&
|
||||
parent.right === child
|
||||
)
|
||||
) {
|
||||
const { name } = child
|
||||
if (node.scopeIds && node.scopeIds.has(name)) {
|
||||
return
|
||||
}
|
||||
if (name in knownIds) {
|
||||
knownIds[name]++
|
||||
} else {
|
||||
knownIds[name] = 1
|
||||
}
|
||||
;(node.scopeIds || (node.scopeIds = new Set())).add(name)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
node.name = rewriteIdentifier(node.name, parent, node)
|
||||
ids.push(node as QualifiedId)
|
||||
} else {
|
||||
// The identifier is considered constant unless it's pointing to a
|
||||
// local scope variable (a v-for alias, or a v-slot prop)
|
||||
if (!(needPrefix && isLocal) && !bailConstant) {
|
||||
;(node as QualifiedId).isConstant = true
|
||||
}
|
||||
// also generate sub-expressions for other identifiers for better
|
||||
// source map support. (except for property keys which are static)
|
||||
ids.push(node as QualifiedId)
|
||||
}
|
||||
},
|
||||
leave(node: Node & PrefixMeta, parent: Node | undefined) {
|
||||
parent && parentStack.pop()
|
||||
if (node !== ast.body[0].expression && node.scopeIds) {
|
||||
node.scopeIds.forEach((id: string) => {
|
||||
knownIds[id]--
|
||||
if (knownIds[id] === 0) {
|
||||
delete knownIds[id]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
undefined,
|
||||
parentStack,
|
||||
knownIds,
|
||||
// invoke on ALL identifiers
|
||||
true
|
||||
)
|
||||
|
||||
// We break up the compound expression into an array of strings and sub
|
||||
// expressions (for identifiers that have been prefixed). In codegen, if
|
||||
@ -375,7 +335,7 @@ export function processExpression(
|
||||
return ret
|
||||
}
|
||||
|
||||
function shouldPrefix(id: Identifier, parent: Node, parentStack: Node[]) {
|
||||
function canPrefix(id: Identifier) {
|
||||
// skip whitelisted globals
|
||||
if (isGloballyWhitelisted(id.name)) {
|
||||
return false
|
||||
@ -384,7 +344,7 @@ function shouldPrefix(id: Identifier, parent: Node, parentStack: Node[]) {
|
||||
if (id.name === 'require') {
|
||||
return false
|
||||
}
|
||||
return isReferencedIdentifier(id, parent, parentStack)
|
||||
return true
|
||||
}
|
||||
|
||||
function stringifyExpression(exp: ExpressionNode | string): string {
|
||||
|
@ -8,7 +8,10 @@ import {
|
||||
transform,
|
||||
parserOptions,
|
||||
UNREF,
|
||||
SimpleExpressionNode
|
||||
SimpleExpressionNode,
|
||||
isFunctionType,
|
||||
isStaticProperty,
|
||||
walkIdentifiers
|
||||
} from '@vue/compiler-dom'
|
||||
import {
|
||||
ScriptSetupTextRanges,
|
||||
@ -22,10 +25,6 @@ import {
|
||||
camelize,
|
||||
capitalize,
|
||||
generateCodeFrame,
|
||||
isFunctionType,
|
||||
isReferencedIdentifier,
|
||||
isStaticProperty,
|
||||
isStaticPropertyKey,
|
||||
makeMap
|
||||
} from '@vue/shared'
|
||||
import {
|
||||
@ -1154,9 +1153,7 @@ export function compileScript(
|
||||
}
|
||||
|
||||
for (const node of scriptSetupAst) {
|
||||
if (node.type !== 'ImportDeclaration') {
|
||||
walkIdentifiers(node, onIdent, onNode)
|
||||
}
|
||||
walkIdentifiers(node, onIdent, onNode)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1774,116 +1771,6 @@ function genRuntimeEmits(emits: Set<string>) {
|
||||
: ``
|
||||
}
|
||||
|
||||
function markScopeIdentifier(
|
||||
node: Node & { scopeIds?: Set<string> },
|
||||
child: Identifier,
|
||||
knownIds: Record<string, number>
|
||||
) {
|
||||
const { name } = child
|
||||
if (node.scopeIds && node.scopeIds.has(name)) {
|
||||
return
|
||||
}
|
||||
if (name in knownIds) {
|
||||
knownIds[name]++
|
||||
} else {
|
||||
knownIds[name] = 1
|
||||
}
|
||||
;(node.scopeIds || (node.scopeIds = new Set())).add(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk an AST and find identifiers that are variable references.
|
||||
* This is largely the same logic with `transformExpressions` in compiler-core
|
||||
* but with some subtle differences as this needs to handle a wider range of
|
||||
* possible syntax.
|
||||
*/
|
||||
export function walkIdentifiers(
|
||||
root: Node,
|
||||
onIdentifier: (node: Identifier, parent: Node, parentStack: Node[]) => void,
|
||||
onNode?: (node: Node, parent: Node, parentStack: Node[]) => void | boolean
|
||||
) {
|
||||
const parentStack: Node[] = []
|
||||
const knownIds: Record<string, number> = Object.create(null)
|
||||
;(walk as any)(root, {
|
||||
enter(node: Node & { scopeIds?: Set<string> }, parent: Node | undefined) {
|
||||
parent && parentStack.push(parent)
|
||||
if (
|
||||
parent &&
|
||||
parent.type.startsWith('TS') &&
|
||||
parent.type !== 'TSAsExpression' &&
|
||||
parent.type !== 'TSNonNullExpression' &&
|
||||
parent.type !== 'TSTypeAssertion'
|
||||
) {
|
||||
return this.skip()
|
||||
}
|
||||
if (onNode && onNode(node, parent!, parentStack) === false) {
|
||||
return this.skip()
|
||||
}
|
||||
if (node.type === 'Identifier') {
|
||||
if (
|
||||
!knownIds[node.name] &&
|
||||
isReferencedIdentifier(node, parent!, parentStack)
|
||||
) {
|
||||
onIdentifier(node, parent!, parentStack)
|
||||
}
|
||||
} else if (isFunctionType(node)) {
|
||||
// #3445
|
||||
// should not rewrite local variables sharing a name with a top-level ref
|
||||
if (node.body.type === 'BlockStatement') {
|
||||
node.body.body.forEach(p => {
|
||||
if (p.type === 'VariableDeclaration') {
|
||||
for (const decl of p.declarations) {
|
||||
extractIdentifiers(decl.id).forEach(id => {
|
||||
markScopeIdentifier(node, id, knownIds)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// walk function expressions and add its arguments to known identifiers
|
||||
// so that we don't prefix them
|
||||
node.params.forEach(p =>
|
||||
(walk as any)(p, {
|
||||
enter(child: Node, parent: Node) {
|
||||
if (
|
||||
child.type === 'Identifier' &&
|
||||
// do not record as scope variable if is a destructured key
|
||||
!isStaticPropertyKey(child, parent) &&
|
||||
// do not record if this is a default value
|
||||
// assignment of a destructured variable
|
||||
!(
|
||||
parent &&
|
||||
parent.type === 'AssignmentPattern' &&
|
||||
parent.right === child
|
||||
)
|
||||
) {
|
||||
markScopeIdentifier(node, child, knownIds)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
} else if (
|
||||
node.type === 'ObjectProperty' &&
|
||||
parent!.type === 'ObjectPattern'
|
||||
) {
|
||||
// mark property in destructure pattern
|
||||
;(node as any).inPattern = true
|
||||
}
|
||||
},
|
||||
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | undefined) {
|
||||
parent && parentStack.pop()
|
||||
if (node.scopeIds) {
|
||||
node.scopeIds.forEach((id: string) => {
|
||||
knownIds[id]--
|
||||
if (knownIds[id] === 0) {
|
||||
delete knownIds[id]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function isCallOf(
|
||||
node: Node | null | undefined,
|
||||
test: string | ((id: string) => boolean)
|
||||
@ -2077,51 +1964,6 @@ function getObjectOrArrayExpressionKeys(value: Node): string[] {
|
||||
return []
|
||||
}
|
||||
|
||||
function extractIdentifiers(
|
||||
param: Node,
|
||||
nodes: Identifier[] = []
|
||||
): Identifier[] {
|
||||
switch (param.type) {
|
||||
case 'Identifier':
|
||||
nodes.push(param)
|
||||
break
|
||||
|
||||
case 'MemberExpression':
|
||||
let object: any = param
|
||||
while (object.type === 'MemberExpression') {
|
||||
object = object.object
|
||||
}
|
||||
nodes.push(object)
|
||||
break
|
||||
|
||||
case 'ObjectPattern':
|
||||
param.properties.forEach(prop => {
|
||||
if (prop.type === 'RestElement') {
|
||||
extractIdentifiers(prop.argument, nodes)
|
||||
} else {
|
||||
extractIdentifiers(prop.value, nodes)
|
||||
}
|
||||
})
|
||||
break
|
||||
|
||||
case 'ArrayPattern':
|
||||
param.elements.forEach(element => {
|
||||
if (element) extractIdentifiers(element, nodes)
|
||||
})
|
||||
break
|
||||
|
||||
case 'RestElement':
|
||||
extractIdentifiers(param.argument, nodes)
|
||||
break
|
||||
|
||||
case 'AssignmentPattern':
|
||||
extractIdentifiers(param.left, nodes)
|
||||
break
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
function toTextRange(node: Node): TextRange {
|
||||
return {
|
||||
start: node.start!,
|
||||
|
@ -4,11 +4,10 @@ export { compileTemplate } from './compileTemplate'
|
||||
export { compileStyle, compileStyleAsync } from './compileStyle'
|
||||
export { compileScript } from './compileScript'
|
||||
export { rewriteDefault } from './rewriteDefault'
|
||||
export { generateCodeFrame } from '@vue/compiler-core'
|
||||
export { generateCodeFrame, walkIdentifiers } from '@vue/compiler-core'
|
||||
|
||||
// Utilities
|
||||
export { parse as babelParse } from '@babel/parser'
|
||||
export { walkIdentifiers } from './compileScript'
|
||||
import MagicString from 'magic-string'
|
||||
export { MagicString }
|
||||
export { walk } from 'estree-walker'
|
||||
|
@ -1,72 +0,0 @@
|
||||
import {
|
||||
Identifier,
|
||||
Node,
|
||||
isReferenced,
|
||||
Function,
|
||||
ObjectProperty
|
||||
} from '@babel/types'
|
||||
|
||||
export function isReferencedIdentifier(
|
||||
id: Identifier,
|
||||
parent: Node | null,
|
||||
parentStack: Node[]
|
||||
) {
|
||||
if (!parent) {
|
||||
return true
|
||||
}
|
||||
|
||||
// is a special keyword but parsed as identifier
|
||||
if (id.name === 'arguments') {
|
||||
return false
|
||||
}
|
||||
|
||||
if (isReferenced(id, parent)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// babel's isReferenced check returns false for ids being assigned to, so we
|
||||
// need to cover those cases here
|
||||
switch (parent.type) {
|
||||
case 'AssignmentExpression':
|
||||
case 'AssignmentPattern':
|
||||
return true
|
||||
case 'ObjectPattern':
|
||||
case 'ArrayPattern':
|
||||
return isInDestructureAssignment(parent, parentStack)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export function isInDestructureAssignment(
|
||||
parent: Node,
|
||||
parentStack: Node[]
|
||||
): boolean {
|
||||
if (
|
||||
parent &&
|
||||
(parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')
|
||||
) {
|
||||
let i = parentStack.length
|
||||
while (i--) {
|
||||
const p = parentStack[i]
|
||||
if (p.type === 'AssignmentExpression') {
|
||||
return true
|
||||
} else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export const isFunctionType = (node: Node): node is Function => {
|
||||
return /Function(?:Expression|Declaration)$|Method$/.test(node.type)
|
||||
}
|
||||
|
||||
export const isStaticProperty = (node: Node): node is ObjectProperty =>
|
||||
node &&
|
||||
(node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&
|
||||
!node.computed
|
||||
|
||||
export const isStaticPropertyKey = (node: Node, parent: Node) =>
|
||||
isStaticProperty(parent) && parent.key === node
|
@ -12,7 +12,6 @@ export * from './domAttrConfig'
|
||||
export * from './escapeHtml'
|
||||
export * from './looseEqual'
|
||||
export * from './toDisplayString'
|
||||
export * from './astUtils'
|
||||
|
||||
/**
|
||||
* List of @babel/parser plugins that are used for template expression
|
||||
|
Loading…
Reference in New Issue
Block a user