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