feat(compiler): better warning for invalid expressions in function/browser mode

fix #1266
This commit is contained in:
Evan You
2020-06-11 16:31:51 -04:00
parent 10bb34bb86
commit e29f0b3fc2
7 changed files with 159 additions and 1 deletions

View File

@@ -25,6 +25,7 @@ import {
import { isGloballyWhitelisted, makeMap } from '@vue/shared'
import { createCompilerError, ErrorCodes } from '../errors'
import { Node, Function, Identifier, ObjectProperty } from '@babel/types'
import { validateBrowserExpression } from '../validateExpression'
const isLiteralWhitelisted = /*#__PURE__*/ makeMap('true,false,null,this')
@@ -84,6 +85,12 @@ export function processExpression(
// v-on handler values may contain multiple statements
asRawStatements = false
): ExpressionNode {
if (__DEV__ && __BROWSER__) {
// simple in-browser validation (same logic in 2.x)
validateBrowserExpression(node, context, asParams, asRawStatements)
return node
}
if (!context.prefixIdentifiers || !node.content.trim()) {
return node
}

View File

@@ -41,6 +41,7 @@ import {
FRAGMENT
} from '../runtimeHelpers'
import { processExpression } from './transformExpression'
import { validateBrowserExpression } from '../validateExpression'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
export const transformFor = createStructuralDirectiveTransform(
@@ -243,6 +244,9 @@ export function parseForExpression(
context
)
}
if (__DEV__ && __BROWSER__) {
validateBrowserExpression(result.source as SimpleExpressionNode, context)
}
let valueContent = LHS.trim()
.replace(stripParensRE, '')
@@ -261,6 +265,13 @@ export function parseForExpression(
if (!__BROWSER__ && context.prefixIdentifiers) {
result.key = processExpression(result.key, context, true)
}
if (__DEV__ && __BROWSER__) {
validateBrowserExpression(
result.key as SimpleExpressionNode,
context,
true
)
}
}
if (iteratorMatch[2]) {
@@ -280,6 +291,13 @@ export function parseForExpression(
if (!__BROWSER__ && context.prefixIdentifiers) {
result.index = processExpression(result.index, context, true)
}
if (__DEV__ && __BROWSER__) {
validateBrowserExpression(
result.index as SimpleExpressionNode,
context,
true
)
}
}
}
}
@@ -289,6 +307,13 @@ export function parseForExpression(
if (!__BROWSER__ && context.prefixIdentifiers) {
result.value = processExpression(result.value, context, true)
}
if (__DEV__ && __BROWSER__) {
validateBrowserExpression(
result.value as SimpleExpressionNode,
context,
true
)
}
}
return result

View File

@@ -22,6 +22,7 @@ import {
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { processExpression } from './transformExpression'
import { validateBrowserExpression } from '../validateExpression'
import {
CREATE_BLOCK,
FRAGMENT,
@@ -93,6 +94,10 @@ export function processIf(
dir.exp = processExpression(dir.exp as SimpleExpressionNode, context)
}
if (__DEV__ && __BROWSER__ && dir.exp) {
validateBrowserExpression(dir.exp as SimpleExpressionNode, context)
}
if (dir.name === 'if') {
const branch = createIfBranch(node, dir)
const ifNode: IfNode = {

View File

@@ -11,6 +11,7 @@ import {
import { capitalize, camelize } from '@vue/shared'
import { createCompilerError, ErrorCodes } from '../errors'
import { processExpression } from './transformExpression'
import { validateBrowserExpression } from '../validateExpression'
import { isMemberExpression, hasScopeRef } from '../utils'
const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/
@@ -89,6 +90,15 @@ export const transformOn: DirectiveTransform = (
}
}
if (__DEV__ && __BROWSER__) {
validateBrowserExpression(
exp as SimpleExpressionNode,
context,
false,
hasMultipleStatements
)
}
if (isInlineStatement || (isCacheable && isMemberExp)) {
// wrap inline statement in a function expression
exp = createCompoundExpression([

View File

@@ -0,0 +1,49 @@
import { NodeTransform, TransformContext } from '../transform'
import { NodeTypes, SimpleExpressionNode } from '../ast'
/**
* When using the runtime compiler in function mode, some expressions will
* become invalid (e.g. using keyworkds like `class` in expressions) so we need
* to detect them.
*
* This transform is browser-only and dev-only.
*/
export const validateExpression: NodeTransform = (node, context) => {
if (node.type === NodeTypes.INTERPOLATION) {
validateBrowserExpression(node.content as SimpleExpressionNode, context)
} else if (node.type === NodeTypes.ELEMENT) {
// handle directives on element
for (let i = 0; i < node.props.length; i++) {
const dir = node.props[i]
// do not process for v-on & v-for since they are special handled
if (dir.type === NodeTypes.DIRECTIVE && dir.name !== 'for') {
const exp = dir.exp
const arg = dir.arg
// do not process exp if this is v-on:arg - we need special handling
// for wrapping inline statements.
if (
exp &&
exp.type === NodeTypes.SIMPLE_EXPRESSION &&
!(dir.name === 'on' && arg)
) {
validateBrowserExpression(
exp,
context,
// slot args must be processed as function params
dir.name === 'slot'
)
}
if (arg && arg.type === NodeTypes.SIMPLE_EXPRESSION && !arg.isStatic) {
validateBrowserExpression(arg, context)
}
}
}
}
}
export function validateBrowserExpression(
node: SimpleExpressionNode,
context: TransformContext,
asParams = false,
asRawStatements = false
) {}