• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import {
2    AssignmentExpression, BinaryExpression, Bundle, chainBundle, getNonAssignmentOperatorForCompoundAssignment,
3    isAccessExpression, isExpression, isLeftHandSideExpression, isLogicalOrCoalescingAssignmentExpression,
4    isPropertyAccessExpression, isSimpleCopiableExpression, LogicalOrCoalescingAssignmentOperator, Node,
5    skipParentheses, SourceFile, SyntaxKind, Token, TransformationContext, TransformFlags, visitEachChild, visitNode,
6    VisitResult,
7} from "../_namespaces/ts";
8
9/** @internal */
10export function transformES2021(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle {
11    const {
12        hoistVariableDeclaration,
13        factory
14    } = context;
15    return chainBundle(context, transformSourceFile);
16
17    function transformSourceFile(node: SourceFile) {
18        if (node.isDeclarationFile) {
19            return node;
20        }
21
22        return visitEachChild(node, visitor, context);
23    }
24
25    function visitor(node: Node): VisitResult<Node> {
26        if ((node.transformFlags & TransformFlags.ContainsES2021) === 0) {
27            return node;
28        }
29        switch (node.kind) {
30            case SyntaxKind.BinaryExpression:
31                const binaryExpression = node as BinaryExpression;
32                if (isLogicalOrCoalescingAssignmentExpression(binaryExpression)) {
33                    return transformLogicalAssignment(binaryExpression);
34                }
35            // falls through
36            default:
37                return visitEachChild(node, visitor, context);
38        }
39    }
40
41    function transformLogicalAssignment(binaryExpression: AssignmentExpression<Token<LogicalOrCoalescingAssignmentOperator>>): VisitResult<Node> {
42        const operator = binaryExpression.operatorToken;
43        const nonAssignmentOperator = getNonAssignmentOperatorForCompoundAssignment(operator.kind);
44        let left = skipParentheses(visitNode(binaryExpression.left, visitor, isLeftHandSideExpression));
45        let assignmentTarget = left;
46        const right = skipParentheses(visitNode(binaryExpression.right, visitor, isExpression));
47
48        if (isAccessExpression(left)) {
49            const propertyAccessTargetSimpleCopiable = isSimpleCopiableExpression(left.expression);
50            const propertyAccessTarget = propertyAccessTargetSimpleCopiable ? left.expression :
51                factory.createTempVariable(hoistVariableDeclaration);
52            const propertyAccessTargetAssignment = propertyAccessTargetSimpleCopiable ? left.expression : factory.createAssignment(
53                propertyAccessTarget,
54                left.expression
55            );
56
57            if (isPropertyAccessExpression(left)) {
58                assignmentTarget = factory.createPropertyAccessExpression(
59                    propertyAccessTarget,
60                    left.name
61                );
62                left = factory.createPropertyAccessExpression(
63                    propertyAccessTargetAssignment,
64                    left.name
65                );
66            }
67            else {
68                const elementAccessArgumentSimpleCopiable = isSimpleCopiableExpression(left.argumentExpression);
69                const elementAccessArgument = elementAccessArgumentSimpleCopiable ? left.argumentExpression :
70                    factory.createTempVariable(hoistVariableDeclaration);
71
72                assignmentTarget = factory.createElementAccessExpression(
73                    propertyAccessTarget,
74                    elementAccessArgument
75                );
76                left = factory.createElementAccessExpression(
77                    propertyAccessTargetAssignment,
78                    elementAccessArgumentSimpleCopiable ? left.argumentExpression : factory.createAssignment(
79                        elementAccessArgument,
80                        left.argumentExpression
81                    )
82                );
83            }
84        }
85
86        return factory.createBinaryExpression(
87            left,
88            nonAssignmentOperator,
89            factory.createParenthesizedExpression(
90                factory.createAssignment(
91                    assignmentTarget,
92                    right
93                )
94            )
95        );
96    }
97}
98