@@ -11,7 +11,222 @@ type optionalChainTransformer struct {
11
11
}
12
12
13
13
func (ch * optionalChainTransformer ) visit (node * ast.Node ) * ast.Node {
14
- return node // !!!
14
+ if node .SubtreeFacts ()& ast .SubtreeContainsOptionalChaining == 0 {
15
+ return node
16
+ }
17
+ switch node .Kind {
18
+ case ast .KindCallExpression :
19
+ return ch .visitCallExpression (node .AsCallExpression (), false )
20
+ case ast .KindPropertyAccessExpression ,
21
+ ast .KindElementAccessExpression :
22
+ if node .Flags & ast .NodeFlagsOptionalChain != 0 {
23
+ return ch .visitOptionalExpression (node , false , false )
24
+ }
25
+ return ch .Visitor ().VisitEachChild (node )
26
+ case ast .KindDeleteExpression :
27
+ return ch .visitDeleteExpression (node .AsDeleteExpression ())
28
+ default :
29
+ return ch .Visitor ().VisitEachChild (node )
30
+ }
31
+ }
32
+
33
+ func (ch * optionalChainTransformer ) visitCallExpression (node * ast.CallExpression , captureThisArg bool ) * ast.Node {
34
+ if node .Flags & ast .NodeFlagsOptionalChain != 0 {
35
+ // If `node` is an optional chain, then it is the outermost chain of an optional expression.
36
+ return ch .visitOptionalExpression (node .AsNode (), captureThisArg , false )
37
+ }
38
+ if ast .IsParenthesizedExpression (node .Expression ) {
39
+ unwrapped := ast .SkipParentheses (node .Expression )
40
+ if unwrapped .Flags & ast .NodeFlagsOptionalChain != 0 {
41
+ // capture thisArg for calls of parenthesized optional chains like `(foo?.bar)()`
42
+ expression := ch .visitParenthesizedExpression (node .Expression .AsParenthesizedExpression (), true , false )
43
+ args := ch .Visitor ().VisitNodes (node .Arguments )
44
+ if ast .IsSyntheticReferenceExpression (expression ) {
45
+ res := ch .Factory ().NewFunctionCallCall (expression .AsSyntheticReferenceExpression ().Expression , expression .AsSyntheticReferenceExpression ().ThisArg , args .Nodes )
46
+ res .Loc = node .Loc
47
+ ch .EmitContext ().SetOriginal (res , node .AsNode ())
48
+ return res
49
+ }
50
+ return ch .Factory ().UpdateCallExpression (node , expression , nil , nil , args )
51
+ }
52
+ }
53
+ return ch .Visitor ().VisitEachChild (node .AsNode ())
54
+ }
55
+
56
+ func (ch * optionalChainTransformer ) visitParenthesizedExpression (node * ast.ParenthesizedExpression , captureThisArg bool , isDelete bool ) * ast.Node {
57
+ expr := ch .visitNonOptionalExpression (node .Expression , captureThisArg , isDelete )
58
+ if ast .IsSyntheticReferenceExpression (expr ) {
59
+ // `(a.b)` -> { expression `((_a = a).b)`, thisArg: `_a` }
60
+ // `(a[b])` -> { expression `((_a = a)[b])`, thisArg: `_a` }
61
+ synth := expr .AsSyntheticReferenceExpression ()
62
+ res := ch .Factory ().NewSyntheticReferenceExpression (ch .Factory ().UpdateParenthesizedExpression (node , synth .Expression ), synth .ThisArg )
63
+ ch .EmitContext ().SetOriginal (res , node .AsNode ())
64
+ return res
65
+ }
66
+ return ch .Factory ().UpdateParenthesizedExpression (node , expr )
67
+ }
68
+
69
+ func (ch * optionalChainTransformer ) visitPropertyOrElementAccessExpression (node * ast.Expression , captureThisArg bool , isDelete bool ) * ast.Expression {
70
+ if node .Flags & ast .NodeFlagsOptionalChain != 0 {
71
+ // If `node` is an optional chain, then it is the outermost chain of an optional expression.
72
+ return ch .visitOptionalExpression (node .AsNode (), captureThisArg , isDelete )
73
+ }
74
+ expression := ch .Visitor ().VisitNode (node .Expression ())
75
+ // Debug.assertNotNode(expression, isSyntheticReference); // !!!
76
+
77
+ var thisArg * ast.Expression
78
+ if captureThisArg {
79
+ if ! transformers .IsSimpleCopiableExpression (expression ) {
80
+ thisArg = ch .Factory ().NewTempVariable ()
81
+ ch .EmitContext ().AddVariableDeclaration (thisArg )
82
+ expression = ch .Factory ().NewAssignmentExpression (thisArg , expression )
83
+ } else {
84
+ thisArg = expression
85
+ }
86
+ }
87
+
88
+ if node .Kind == ast .KindPropertyAccessExpression {
89
+ p := node .AsPropertyAccessExpression ()
90
+ expression = ch .Factory ().UpdatePropertyAccessExpression (p , expression , nil , ch .Visitor ().VisitNode (p .Name ()))
91
+ } else {
92
+ p := node .AsElementAccessExpression ()
93
+ expression = ch .Factory ().UpdateElementAccessExpression (p , expression , nil , ch .Visitor ().VisitNode (p .AsElementAccessExpression ().ArgumentExpression ))
94
+ }
95
+
96
+ if thisArg != nil {
97
+ res := ch .Factory ().NewSyntheticReferenceExpression (expression , thisArg )
98
+ ch .EmitContext ().SetOriginal (res , node .AsNode ())
99
+ return res
100
+ }
101
+ return expression
102
+ }
103
+
104
+ func (ch * optionalChainTransformer ) visitDeleteExpression (node * ast.DeleteExpression ) * ast.Node {
105
+ unwrapped := ast .SkipParentheses (node .Expression )
106
+ if unwrapped .Flags & ast .NodeFlagsOptionalChain != 0 {
107
+ return ch .visitNonOptionalExpression (node .Expression , false , true )
108
+ }
109
+ return ch .Visitor ().VisitEachChild (node .AsNode ())
110
+ }
111
+
112
+ func (ch * optionalChainTransformer ) visitNonOptionalExpression (node * ast.Expression , captureThisArg bool , isDelete bool ) * ast.Expression {
113
+ switch node .Kind {
114
+ case ast .KindParenthesizedExpression :
115
+ return ch .visitParenthesizedExpression (node .AsParenthesizedExpression (), captureThisArg , isDelete )
116
+ case ast .KindElementAccessExpression , ast .KindPropertyAccessExpression :
117
+ return ch .visitPropertyOrElementAccessExpression (node , captureThisArg , isDelete )
118
+ case ast .KindCallExpression :
119
+ return ch .visitCallExpression (node .AsCallExpression (), captureThisArg )
120
+ default :
121
+ return ch .Visitor ().VisitNode (node .AsNode ())
122
+ }
123
+ }
124
+
125
+ type flattenResult struct {
126
+ expression * ast.Expression
127
+ chain []* ast.Node
128
+ }
129
+
130
+ func flattenChain (chain * ast.Node ) flattenResult {
131
+ // Debug.assertNotNode(chain, isNonNullChain); // !!!
132
+ links := []* ast.Node {chain }
133
+ for ! ast .IsTaggedTemplateExpression (chain ) && chain .QuestionDotToken () == nil {
134
+ chain = ast .SkipPartiallyEmittedExpressions (chain .Expression ())
135
+ // Debug.assertNotNode(chain, isNonNullChain); // !!!
136
+ links = append ([]* ast.Node {chain }, links ... )
137
+ }
138
+ return flattenResult {chain .Expression (), links }
139
+ }
140
+
141
+ func isCallChain (node * ast.Node ) bool {
142
+ return ast .IsCallExpression (node ) && node .Flags & ast .NodeFlagsOptionalChain != 0
143
+ }
144
+
145
+ func (ch * optionalChainTransformer ) visitOptionalExpression (node * ast.Node , captureThisArg bool , isDelete bool ) * ast.Node {
146
+ r := flattenChain (node )
147
+ expression := r .expression
148
+ chain := r .chain
149
+ left := ch .visitNonOptionalExpression (ast .SkipPartiallyEmittedExpressions (expression ), isCallChain (chain [0 ]), false )
150
+ var leftThisArg * ast.Expression
151
+ capturedLeft := left
152
+ if ast .IsSyntheticReferenceExpression (left ) {
153
+ leftThisArg = left .AsSyntheticReferenceExpression ().ThisArg
154
+ capturedLeft = left .AsSyntheticReferenceExpression ().Expression
155
+ }
156
+ leftExpression := ch .Factory ().RestoreOuterExpressions (expression , capturedLeft , ast .OEKPartiallyEmittedExpressions )
157
+ if ! transformers .IsSimpleCopiableExpression (capturedLeft ) {
158
+ capturedLeft = ch .Factory ().NewTempVariable ()
159
+ ch .EmitContext ().AddVariableDeclaration (capturedLeft )
160
+ leftExpression = ch .Factory ().NewAssignmentExpression (capturedLeft , leftExpression )
161
+ }
162
+ rightExpression := capturedLeft
163
+ var thisArg * ast.Expression
164
+
165
+ for i , segment := range chain {
166
+ switch segment .Kind {
167
+ case ast .KindElementAccessExpression , ast .KindPropertyAccessExpression :
168
+ if i == len (chain )- 1 && captureThisArg {
169
+ if ! transformers .IsSimpleCopiableExpression (rightExpression ) {
170
+ thisArg = ch .Factory ().NewTempVariable ()
171
+ ch .EmitContext ().AddVariableDeclaration (thisArg )
172
+ rightExpression = ch .Factory ().NewAssignmentExpression (thisArg , rightExpression )
173
+ } else {
174
+ thisArg = rightExpression
175
+ }
176
+ }
177
+ if segment .Kind == ast .KindElementAccessExpression {
178
+ rightExpression = ch .Factory ().NewElementAccessExpression (rightExpression , nil , ch .Visitor ().VisitNode (segment .AsElementAccessExpression ().ArgumentExpression ), ast .NodeFlagsNone )
179
+ } else {
180
+ rightExpression = ch .Factory ().NewPropertyAccessExpression (rightExpression , nil , ch .Visitor ().VisitNode (segment .AsPropertyAccessExpression ().Name ()), ast .NodeFlagsNone )
181
+ }
182
+ case ast .KindCallExpression :
183
+ if i == 0 && leftThisArg != nil {
184
+ if ! ch .EmitContext ().HasAutoGenerateInfo (leftThisArg ) {
185
+ leftThisArg = leftThisArg .Clone (ch .Factory ())
186
+ ch .EmitContext ().AddEmitFlags (leftThisArg , printer .EFNoComments )
187
+ }
188
+ callThisArg := leftThisArg
189
+ if leftThisArg .Kind == ast .KindSuperKeyword {
190
+ callThisArg = ch .Factory ().NewThisExpression ()
191
+ }
192
+ rightExpression = ch .Factory ().NewFunctionCallCall (rightExpression , callThisArg , ch .Visitor ().VisitNodes (segment .ArgumentList ()).Nodes )
193
+ } else {
194
+ rightExpression = ch .Factory ().NewCallExpression (
195
+ rightExpression ,
196
+ nil ,
197
+ nil ,
198
+ ch .Visitor ().VisitNodes (segment .ArgumentList ()),
199
+ ast .NodeFlagsNone ,
200
+ )
201
+ }
202
+ }
203
+ ch .EmitContext ().SetOriginal (rightExpression , segment )
204
+ }
205
+
206
+ var target * ast.Node
207
+ if isDelete {
208
+ target = ch .Factory ().NewConditionalExpression (
209
+ createNotNullCondition (ch .EmitContext (), leftExpression , capturedLeft , true ),
210
+ ch .Factory ().NewToken (ast .KindQuestionToken ),
211
+ ch .Factory ().NewTrueExpression (),
212
+ ch .Factory ().NewToken (ast .KindColonToken ),
213
+ ch .Factory ().NewDeleteExpression (rightExpression ),
214
+ )
215
+ } else {
216
+ target = ch .Factory ().NewConditionalExpression (
217
+ createNotNullCondition (ch .EmitContext (), leftExpression , capturedLeft , true ),
218
+ ch .Factory ().NewToken (ast .KindQuestionToken ),
219
+ ch .Factory ().NewVoidZeroExpression (),
220
+ ch .Factory ().NewToken (ast .KindColonToken ),
221
+ rightExpression ,
222
+ )
223
+ }
224
+ target .Loc = node .Loc
225
+ if thisArg != nil {
226
+ target = ch .Factory ().NewSyntheticReferenceExpression (target , thisArg )
227
+ }
228
+ ch .EmitContext ().SetOriginal (target , node .AsNode ())
229
+ return target
15
230
}
16
231
17
232
func newOptionalChainTransformer (emitContext * printer.EmitContext ) * transformers.Transformer {
0 commit comments