fix(compiler): improve auto prefixing cases
This commit is contained in:
		
							parent
							
								
									262be6733c
								
							
						
					
					
						commit
						6377af483b
					
				@ -308,6 +308,59 @@ describe('compiler: expression transform', () => {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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', () => {
 | 
					  test('should not prefix an object property key', () => {
 | 
				
			||||||
    const node = parseWithExpressionTransform(
 | 
					    const node = parseWithExpressionTransform(
 | 
				
			||||||
      `{{ { foo: bar } }}`
 | 
					      `{{ { foo: bar } }}`
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ import {
 | 
				
			|||||||
  createCompoundExpression
 | 
					  createCompoundExpression
 | 
				
			||||||
} from '../ast'
 | 
					} from '../ast'
 | 
				
			||||||
import { Node, Function, Identifier, Property } from 'estree'
 | 
					import { Node, Function, Identifier, Property } from 'estree'
 | 
				
			||||||
import { advancePositionWithClone } from '../utils'
 | 
					import { advancePositionWithClone, isSimpleIdentifier } from '../utils'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const transformExpression: NodeTransform = (node, context) => {
 | 
					export const transformExpression: NodeTransform = (node, context) => {
 | 
				
			||||||
  if (node.type === NodeTypes.INTERPOLATION) {
 | 
					  if (node.type === NodeTypes.INTERPOLATION) {
 | 
				
			||||||
@ -31,19 +31,19 @@ export const transformExpression: NodeTransform = (node, context) => {
 | 
				
			|||||||
  } else if (node.type === NodeTypes.ELEMENT) {
 | 
					  } else if (node.type === NodeTypes.ELEMENT) {
 | 
				
			||||||
    // handle directives on element
 | 
					    // handle directives on element
 | 
				
			||||||
    for (let i = 0; i < node.props.length; i++) {
 | 
					    for (let i = 0; i < node.props.length; i++) {
 | 
				
			||||||
      const prop = node.props[i]
 | 
					      const dir = node.props[i]
 | 
				
			||||||
      if (prop.type === NodeTypes.DIRECTIVE) {
 | 
					      if (dir.type === NodeTypes.DIRECTIVE) {
 | 
				
			||||||
        const exp = prop.exp as SimpleExpressionNode | undefined
 | 
					        const exp = dir.exp as SimpleExpressionNode | undefined
 | 
				
			||||||
        const arg = prop.arg as SimpleExpressionNode | undefined
 | 
					        const arg = dir.arg as SimpleExpressionNode | undefined
 | 
				
			||||||
        if (exp) {
 | 
					        if (exp) {
 | 
				
			||||||
          prop.exp = processExpression(exp, context)
 | 
					          dir.exp = processExpression(exp, context, dir.name === 'slot')
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (arg && !arg.isStatic) {
 | 
					        if (arg && !arg.isStatic) {
 | 
				
			||||||
          if (prop.name === 'class') {
 | 
					          if (dir.name === 'class') {
 | 
				
			||||||
            // TODO special expression optimization for classes
 | 
					            // TODO special expression optimization for classes
 | 
				
			||||||
            prop.arg = processExpression(arg, context)
 | 
					            dir.arg = processExpression(arg, context)
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            prop.arg = processExpression(arg, context)
 | 
					            dir.arg = processExpression(arg, context)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -51,14 +51,6 @@ export const transformExpression: NodeTransform = (node, 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
 | 
					// cache node requires
 | 
				
			||||||
let _parseScript: typeof parseScript
 | 
					let _parseScript: typeof parseScript
 | 
				
			||||||
let _walk: typeof walk
 | 
					let _walk: typeof walk
 | 
				
			||||||
@ -74,14 +66,15 @@ interface PrefixMeta {
 | 
				
			|||||||
// tree-shaken from the browser build.
 | 
					// tree-shaken from the browser build.
 | 
				
			||||||
export function processExpression(
 | 
					export function processExpression(
 | 
				
			||||||
  node: SimpleExpressionNode,
 | 
					  node: SimpleExpressionNode,
 | 
				
			||||||
  context: TransformContext
 | 
					  context: TransformContext,
 | 
				
			||||||
 | 
					  asParams: boolean = false
 | 
				
			||||||
): ExpressionNode {
 | 
					): ExpressionNode {
 | 
				
			||||||
  if (!context.prefixIdentifiers) {
 | 
					  if (!context.prefixIdentifiers) {
 | 
				
			||||||
    return node
 | 
					    return node
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // fast path if expression is a simple identifier.
 | 
					  // fast path if expression is a simple identifier.
 | 
				
			||||||
  if (simpleIdRE.test(node.content)) {
 | 
					  if (isSimpleIdentifier(node.content)) {
 | 
				
			||||||
    if (!context.identifiers[node.content]) {
 | 
					    if (!context.identifiers[node.content]) {
 | 
				
			||||||
      node.content = `_ctx.${node.content}`
 | 
					      node.content = `_ctx.${node.content}`
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -95,8 +88,11 @@ export function processExpression(
 | 
				
			|||||||
  const walk = _walk || (_walk = require('estree-walker').walk)
 | 
					  const walk = _walk || (_walk = require('estree-walker').walk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let ast
 | 
					  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 {
 | 
					  try {
 | 
				
			||||||
    ast = parseScript(`(${node.content})`, { ranges: true }) as any
 | 
					    ast = parseScript(source, { ranges: true }) as any
 | 
				
			||||||
  } catch (e) {
 | 
					  } catch (e) {
 | 
				
			||||||
    context.onError(e)
 | 
					    context.onError(e)
 | 
				
			||||||
    return node
 | 
					    return node
 | 
				
			||||||
@ -132,8 +128,17 @@ export function processExpression(
 | 
				
			|||||||
        // so that we don't prefix them
 | 
					        // so that we don't prefix them
 | 
				
			||||||
        node.params.forEach(p =>
 | 
					        node.params.forEach(p =>
 | 
				
			||||||
          walk(p, {
 | 
					          walk(p, {
 | 
				
			||||||
            enter(child) {
 | 
					            enter(child, parent) {
 | 
				
			||||||
              if (child.type === 'Identifier') {
 | 
					              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
 | 
					                knownIds[child.name] = true
 | 
				
			||||||
                ;(
 | 
					                ;(
 | 
				
			||||||
                  (node as any)._scopeIds ||
 | 
					                  (node as any)._scopeIds ||
 | 
				
			||||||
@ -187,6 +192,12 @@ export function processExpression(
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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(
 | 
					const globals = new Set(
 | 
				
			||||||
  (
 | 
					  (
 | 
				
			||||||
    'Infinity,undefined,NaN,isFinite,isNaN,' +
 | 
					    'Infinity,undefined,NaN,isFinite,isNaN,' +
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user