• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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