})
})
+ test('should prefix default value of a function expression param', () => {
+ const node = parseWithExpressionTransform(
+ `{{ (foo = baz) => foo + bar }}`
+ ) as InterpolationNode
+ expect(node.content).toMatchObject({
+ type: NodeTypes.COMPOUND_EXPRESSION,
+ children: [
+ `(`,
+ { content: `foo` },
+ ` = `,
+ { content: `_ctx.baz` },
+ `) => `,
+ { content: `foo` },
+ ` + `,
+ { content: `_ctx.bar` }
+ ]
+ })
+ })
+
+ test('should not prefix function param destructuring', () => {
+ const node = parseWithExpressionTransform(
+ `{{ ({ foo }) => foo + bar }}`
+ ) as InterpolationNode
+ expect(node.content).toMatchObject({
+ type: NodeTypes.COMPOUND_EXPRESSION,
+ children: [
+ `({ foo }) => `,
+ { content: `foo` },
+ ` + `,
+ { content: `_ctx.bar` }
+ ]
+ })
+ })
+
+ test('should prefix default value of function param destructuring', () => {
+ const node = parseWithExpressionTransform(
+ `{{ ({ foo = bar }) => foo + bar }}`
+ ) as InterpolationNode
+ expect(node.content).toMatchObject({
+ type: NodeTypes.COMPOUND_EXPRESSION,
+ children: [
+ `({ `,
+ { content: `foo` },
+ ` = `,
+ { content: `_ctx.bar` },
+ ` }) => `,
+ { content: `foo` },
+ ` + `,
+ { content: `_ctx.bar` }
+ ]
+ })
+ })
+
test('should not prefix an object property key', () => {
const node = parseWithExpressionTransform(
`{{ { foo: bar } }}`
createCompoundExpression
} from '../ast'
import { Node, Function, Identifier, Property } from 'estree'
-import { advancePositionWithClone } from '../utils'
+import { advancePositionWithClone, isSimpleIdentifier } from '../utils'
export const transformExpression: NodeTransform = (node, context) => {
if (node.type === NodeTypes.INTERPOLATION) {
} else if (node.type === NodeTypes.ELEMENT) {
// handle directives on element
for (let i = 0; i < node.props.length; i++) {
- const prop = node.props[i]
- if (prop.type === NodeTypes.DIRECTIVE) {
- const exp = prop.exp as SimpleExpressionNode | undefined
- const arg = prop.arg as SimpleExpressionNode | undefined
+ const dir = node.props[i]
+ if (dir.type === NodeTypes.DIRECTIVE) {
+ const exp = dir.exp as SimpleExpressionNode | undefined
+ const arg = dir.arg as SimpleExpressionNode | undefined
if (exp) {
- prop.exp = processExpression(exp, context)
+ dir.exp = processExpression(exp, context, dir.name === 'slot')
}
if (arg && !arg.isStatic) {
- if (prop.name === 'class') {
+ if (dir.name === 'class') {
// TODO special expression optimization for classes
- prop.arg = processExpression(arg, context)
+ dir.arg = processExpression(arg, context)
} else {
- prop.arg = processExpression(arg, context)
+ dir.arg = processExpression(arg, context)
}
}
}
}
}
-const simpleIdRE = /^[a-zA-Z$_][\w$]*$/
-
-const isFunction = (node: Node): node is Function =>
- /Function(Expression|Declaration)$/.test(node.type)
-
-const isPropertyKey = (node: Node, parent: Node) =>
- parent.type === 'Property' && parent.key === node && !parent.computed
-
// cache node requires
let _parseScript: typeof parseScript
let _walk: typeof walk
// tree-shaken from the browser build.
export function processExpression(
node: SimpleExpressionNode,
- context: TransformContext
+ context: TransformContext,
+ asParams: boolean = false
): ExpressionNode {
if (!context.prefixIdentifiers) {
return node
}
// fast path if expression is a simple identifier.
- if (simpleIdRE.test(node.content)) {
+ if (isSimpleIdentifier(node.content)) {
if (!context.identifiers[node.content]) {
node.content = `_ctx.${node.content}`
}
const walk = _walk || (_walk = require('estree-walker').walk)
let ast
+ // if the expression is supposed to be used in a function params position
+ // we need to parse it differently.
+ const source = `(${node.content})${asParams ? `=>{}` : ``}`
try {
- ast = parseScript(`(${node.content})`, { ranges: true }) as any
+ ast = parseScript(source, { ranges: true }) as any
} catch (e) {
context.onError(e)
return node
// so that we don't prefix them
node.params.forEach(p =>
walk(p, {
- enter(child) {
- if (child.type === 'Identifier') {
+ enter(child, parent) {
+ if (
+ child.type === 'Identifier' &&
+ !// do not keep as scope variable if this is a default value
+ // assignment of a param
+ (
+ parent &&
+ parent.type === 'AssignmentPattern' &&
+ parent.right === child
+ )
+ ) {
knownIds[child.name] = true
;(
(node as any)._scopeIds ||
}
}
+const isFunction = (node: Node): node is Function =>
+ /Function(Expression|Declaration)$/.test(node.type)
+
+const isPropertyKey = (node: Node, parent: Node) =>
+ parent.type === 'Property' && parent.key === node && !parent.computed
+
const globals = new Set(
(
'Infinity,undefined,NaN,isFinite,isNaN,' +