1import { 2 BinaryExpression, Bundle, chainBundle, Expression, isElementAccessExpression, isExpression, isPropertyAccessExpression, 3 Node, setTextRange, SourceFile, SyntaxKind, TransformationContext, TransformFlags, visitEachChild, visitNode, 4 VisitResult, 5} from "../_namespaces/ts"; 6 7/** @internal */ 8export function transformES2016(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle { 9 const { 10 factory, 11 hoistVariableDeclaration 12 } = context; 13 14 return chainBundle(context, transformSourceFile); 15 16 function transformSourceFile(node: SourceFile) { 17 if (node.isDeclarationFile) { 18 return node; 19 } 20 21 return visitEachChild(node, visitor, context); 22 } 23 24 function visitor(node: Node): VisitResult<Node> { 25 if ((node.transformFlags & TransformFlags.ContainsES2016) === 0) { 26 return node; 27 } 28 switch (node.kind) { 29 case SyntaxKind.BinaryExpression: 30 return visitBinaryExpression(node as BinaryExpression); 31 default: 32 return visitEachChild(node, visitor, context); 33 } 34 } 35 36 function visitBinaryExpression(node: BinaryExpression): Expression { 37 switch (node.operatorToken.kind) { 38 case SyntaxKind.AsteriskAsteriskEqualsToken: 39 return visitExponentiationAssignmentExpression(node); 40 case SyntaxKind.AsteriskAsteriskToken: 41 return visitExponentiationExpression(node); 42 default: 43 return visitEachChild(node, visitor, context); 44 } 45 } 46 47 function visitExponentiationAssignmentExpression(node: BinaryExpression) { 48 let target: Expression; 49 let value: Expression; 50 const left = visitNode(node.left, visitor, isExpression); 51 const right = visitNode(node.right, visitor, isExpression); 52 if (isElementAccessExpression(left)) { 53 // Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)` 54 const expressionTemp = factory.createTempVariable(hoistVariableDeclaration); 55 const argumentExpressionTemp = factory.createTempVariable(hoistVariableDeclaration); 56 target = setTextRange( 57 factory.createElementAccessExpression( 58 setTextRange(factory.createAssignment(expressionTemp, left.expression), left.expression), 59 setTextRange(factory.createAssignment(argumentExpressionTemp, left.argumentExpression), left.argumentExpression) 60 ), 61 left 62 ); 63 value = setTextRange( 64 factory.createElementAccessExpression( 65 expressionTemp, 66 argumentExpressionTemp 67 ), 68 left 69 ); 70 } 71 else if (isPropertyAccessExpression(left)) { 72 // Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)` 73 const expressionTemp = factory.createTempVariable(hoistVariableDeclaration); 74 target = setTextRange( 75 factory.createPropertyAccessExpression( 76 setTextRange(factory.createAssignment(expressionTemp, left.expression), left.expression), 77 left.name 78 ), 79 left 80 ); 81 value = setTextRange( 82 factory.createPropertyAccessExpression( 83 expressionTemp, 84 left.name 85 ), 86 left 87 ); 88 } 89 else { 90 // Transforms `a **= b` into `a = Math.pow(a, b)` 91 target = left; 92 value = left; 93 } 94 return setTextRange( 95 factory.createAssignment( 96 target, 97 setTextRange(factory.createGlobalMethodCall("Math", "pow", [value, right]), node) 98 ), 99 node 100 ); 101 } 102 103 function visitExponentiationExpression(node: BinaryExpression) { 104 // Transforms `a ** b` into `Math.pow(a, b)` 105 const left = visitNode(node.left, visitor, isExpression); 106 const right = visitNode(node.right, visitor, isExpression); 107 return setTextRange(factory.createGlobalMethodCall("Math", "pow", [left, right]), node); 108 } 109} 110