@@ -69,6 +69,8 @@ function createVisitor (options) {
69
69
const targetModules = new Set ( config . modules ) ;
70
70
const targetVariables = new Set ( config . variables ) ;
71
71
72
+ const nodeUpdates = new WeakMap ( ) ;
73
+
72
74
function isAssertionModuleName ( lit ) {
73
75
return isLiteral ( lit ) && targetModules . has ( lit . value ) ;
74
76
}
@@ -167,105 +169,152 @@ function createVisitor (options) {
167
169
return isAssertionFunction ( callee ) || isAssertionMethod ( callee ) || isConsoleAssert ( callee ) ;
168
170
}
169
171
170
- const nodeToRemove = new WeakSet ( ) ;
172
+ function removeNode ( node ) {
173
+ nodeUpdates . set ( node , null ) ;
174
+ }
175
+
176
+ function replaceNode ( node , replacement ) {
177
+ nodeUpdates . set ( node , replacement ) ;
178
+ }
179
+
180
+ function createNoopExpression ( ) {
181
+ return {
182
+ type : 'UnaryExpression' ,
183
+ operator : 'void' ,
184
+ prefix : true ,
185
+ argument : {
186
+ type : 'Literal' ,
187
+ value : 0 ,
188
+ raw : '0'
189
+ }
190
+ } ;
191
+ }
192
+
193
+ function createNoopBlock ( ) {
194
+ return {
195
+ type : 'BlockStatement' ,
196
+ body : [ ]
197
+ } ;
198
+ }
199
+
200
+ function unassertImportDeclaration ( currentNode , parentNode ) {
201
+ const source = currentNode . source ;
202
+ if ( ! ( isAssertionModuleName ( source ) ) ) {
203
+ return ;
204
+ }
205
+ // remove current ImportDeclaration
206
+ removeNode ( currentNode ) ;
207
+ this . skip ( ) ;
208
+ // register local identifier(s) as assertion variable
209
+ registerAssertionVariables ( currentNode ) ;
210
+ }
211
+
212
+ function unassertVariableDeclarator ( currentNode , parentNode ) {
213
+ if ( isRemovalTargetRequire ( currentNode . id , currentNode . init ) ) {
214
+ if ( parentNode . declarations . length === 1 ) {
215
+ // remove parent VariableDeclaration
216
+ removeNode ( parentNode ) ;
217
+ } else {
218
+ // single var pattern
219
+ // remove current VariableDeclarator
220
+ removeNode ( currentNode ) ;
221
+ }
222
+ this . skip ( ) ;
223
+ // register local identifier(s) as assertion variable
224
+ registerAssertionVariables ( currentNode . id ) ;
225
+ }
226
+ }
227
+
228
+ function unassertAssignmentExpression ( currentNode , parentNode ) {
229
+ if ( currentNode . operator !== '=' ) {
230
+ return ;
231
+ }
232
+ if ( ! isExpressionStatement ( parentNode ) ) {
233
+ return ;
234
+ }
235
+ if ( isRemovalTargetRequire ( currentNode . left , currentNode . right ) ) {
236
+ // remove parent ExpressionStatement
237
+ removeNode ( parentNode ) ;
238
+ this . skip ( ) ;
239
+ // register local identifier(s) as assertion variable
240
+ registerAssertionVariables ( currentNode . left ) ;
241
+ }
242
+ }
243
+
244
+ function unassertCallExpression ( currentNode , parentNode ) {
245
+ const callee = currentNode . callee ;
246
+ if ( ! isRemovalTargetAssertion ( callee ) ) {
247
+ return ;
248
+ }
249
+
250
+ switch ( parentNode . type ) {
251
+ case 'ExpressionStatement' : {
252
+ // remove parent ExpressionStatement
253
+ removeNode ( parentNode ) ;
254
+ this . skip ( ) ;
255
+ break ;
256
+ }
257
+ case 'SequenceExpression' : {
258
+ // replace the asserstion with essentially nothing
259
+ replaceNode ( currentNode , createNoopExpression ( ) ) ;
260
+ break ;
261
+ }
262
+ }
263
+ }
264
+ function unassertAwaitExpression ( currentNode , parentNode ) {
265
+ const childNode = currentNode . argument ;
266
+ if ( isExpressionStatement ( parentNode ) && isCallExpression ( childNode ) ) {
267
+ const callee = childNode . callee ;
268
+ if ( isRemovalTargetAssertion ( callee ) ) {
269
+ // remove parent ExpressionStatement
270
+ removeNode ( parentNode ) ;
271
+ this . skip ( ) ;
272
+ }
273
+ }
274
+ }
171
275
172
276
return {
173
277
enter : function ( currentNode , parentNode ) {
174
278
switch ( currentNode . type ) {
175
279
case 'ImportDeclaration' : {
176
- const source = currentNode . source ;
177
- if ( ! ( isAssertionModuleName ( source ) ) ) {
178
- return ;
179
- }
180
- // remove current ImportDeclaration
181
- nodeToRemove . add ( currentNode ) ;
182
- this . skip ( ) ;
183
- // register local identifier(s) as assertion variable
184
- registerAssertionVariables ( currentNode ) ;
280
+ unassertImportDeclaration . bind ( this ) ( currentNode , parentNode ) ;
185
281
break ;
186
282
}
187
283
case 'VariableDeclarator' : {
188
- if ( isRemovalTargetRequire ( currentNode . id , currentNode . init ) ) {
189
- if ( parentNode . declarations . length === 1 ) {
190
- // remove parent VariableDeclaration
191
- nodeToRemove . add ( parentNode ) ;
192
- } else {
193
- // single var pattern
194
- // remove current VariableDeclarator
195
- nodeToRemove . add ( currentNode ) ;
196
- }
197
- this . skip ( ) ;
198
- // register local identifier(s) as assertion variable
199
- registerAssertionVariables ( currentNode . id ) ;
200
- }
284
+ unassertVariableDeclarator . bind ( this ) ( currentNode , parentNode ) ;
201
285
break ;
202
286
}
203
287
case 'AssignmentExpression' : {
204
- if ( currentNode . operator !== '=' ) {
205
- return ;
206
- }
207
- if ( ! isExpressionStatement ( parentNode ) ) {
208
- return ;
209
- }
210
- if ( isRemovalTargetRequire ( currentNode . left , currentNode . right ) ) {
211
- // remove parent ExpressionStatement
212
- nodeToRemove . add ( parentNode ) ;
213
- this . skip ( ) ;
214
- // register local identifier(s) as assertion variable
215
- registerAssertionVariables ( currentNode . left ) ;
216
- }
288
+ unassertAssignmentExpression . bind ( this ) ( currentNode , parentNode ) ;
217
289
break ;
218
290
}
219
291
case 'CallExpression' : {
220
- if ( ! isExpressionStatement ( parentNode ) ) {
221
- return ;
222
- }
223
- const callee = currentNode . callee ;
224
- if ( isRemovalTargetAssertion ( callee ) ) {
225
- // remove parent ExpressionStatement
226
- nodeToRemove . add ( parentNode ) ;
227
- this . skip ( ) ;
228
- }
292
+ unassertCallExpression . bind ( this ) ( currentNode , parentNode ) ;
229
293
break ;
230
294
}
231
295
case 'AwaitExpression' : {
232
- const childNode = currentNode . argument ;
233
- if ( isExpressionStatement ( parentNode ) && isCallExpression ( childNode ) ) {
234
- const callee = childNode . callee ;
235
- if ( isRemovalTargetAssertion ( callee ) ) {
236
- // remove parent ExpressionStatement
237
- nodeToRemove . add ( parentNode ) ;
238
- this . skip ( ) ;
239
- }
240
- }
296
+ unassertAwaitExpression . bind ( this ) ( currentNode , parentNode ) ;
241
297
break ;
242
298
}
243
299
}
244
300
} ,
245
301
leave : function ( currentNode , parentNode ) {
246
- switch ( currentNode . type ) {
247
- case 'ImportDeclaration' :
248
- case 'VariableDeclarator' :
249
- case 'VariableDeclaration' :
250
- case 'ExpressionStatement' :
251
- break ;
252
- default :
253
- return undefined ;
302
+ const update = nodeUpdates . get ( currentNode ) ;
303
+ if ( update === undefined ) {
304
+ return undefined ;
254
305
}
255
- if ( nodeToRemove . has ( currentNode ) ) {
306
+ if ( update === null ) {
256
307
if ( isExpressionStatement ( currentNode ) ) {
257
308
const path = this . path ( ) ;
258
309
const key = path [ path . length - 1 ] ;
259
310
if ( isNonBlockChildOfParentNode ( currentNode , parentNode , key ) ) {
260
- return {
261
- type : 'BlockStatement' ,
262
- body : [ ]
263
- } ;
311
+ return createNoopBlock ( ) ;
264
312
}
265
313
}
266
314
this . remove ( ) ;
315
+ return undefined ;
267
316
}
268
- return undefined ;
317
+ return update ;
269
318
}
270
319
} ;
271
320
}
0 commit comments