@@ -72,6 +72,8 @@ function createVisitor (options) {
7272 const targetModules = new Set ( config . modules ) ;
7373 const targetVariables = new Set ( config . variables ) ;
7474
75+ const nodeUpdates = new WeakMap ( ) ;
76+
7577 function isAssertionModuleName ( lit ) {
7678 return isLiteral ( lit ) && targetModules . has ( lit . value ) ;
7779 }
@@ -170,105 +172,153 @@ function createVisitor (options) {
170172 return isAssertionFunction ( callee ) || isAssertionMethod ( callee ) || isConsoleAssert ( callee ) ;
171173 }
172174
173- const nodeToRemove = new WeakSet ( ) ;
175+ function removeNode ( node ) {
176+ nodeUpdates . set ( node , null ) ;
177+ }
178+
179+ function replaceNode ( node , replacement ) {
180+ nodeUpdates . set ( node , replacement ) ;
181+ }
182+
183+ function createNoopExpression ( ) {
184+ return {
185+ type : 'UnaryExpression' ,
186+ operator : 'void' ,
187+ prefix : true ,
188+ argument : {
189+ type : 'Literal' ,
190+ value : 0 ,
191+ raw : '0'
192+ }
193+ } ;
194+ }
195+
196+ function createNoopStatement ( ) {
197+ return {
198+ type : 'BlockStatement' ,
199+ body : [ ]
200+ } ;
201+ }
202+
203+ function unassertImportDeclaration ( currentNode , parentNode ) {
204+ const source = currentNode . source ;
205+ if ( ! ( isAssertionModuleName ( source ) ) ) {
206+ return ;
207+ }
208+ // remove current ImportDeclaration
209+ removeNode ( currentNode ) ;
210+ this . skip ( ) ;
211+ // register local identifier(s) as assertion variable
212+ registerAssertionVariables ( currentNode ) ;
213+ }
214+
215+ function unassertVariableDeclarator ( currentNode , parentNode ) {
216+ if ( isRemovalTargetRequire ( currentNode . id , currentNode . init ) ) {
217+ if ( parentNode . declarations . length === 1 ) {
218+ // remove parent VariableDeclaration
219+ removeNode ( parentNode ) ;
220+ } else {
221+ // single var pattern
222+ // remove current VariableDeclarator
223+ removeNode ( currentNode ) ;
224+ }
225+ this . skip ( ) ;
226+ // register local identifier(s) as assertion variable
227+ registerAssertionVariables ( currentNode . id ) ;
228+ }
229+ }
230+
231+ function unassertAssignmentExpression ( currentNode , parentNode ) {
232+ if ( currentNode . operator !== '=' ) {
233+ return ;
234+ }
235+ if ( ! isExpressionStatement ( parentNode ) ) {
236+ return ;
237+ }
238+ if ( isRemovalTargetRequire ( currentNode . left , currentNode . right ) ) {
239+ // remove parent ExpressionStatement
240+ removeNode ( parentNode ) ;
241+ this . skip ( ) ;
242+ // register local identifier(s) as assertion variable
243+ registerAssertionVariables ( currentNode . left ) ;
244+ }
245+ }
246+
247+ function unassertCallExpression ( currentNode , parentNode ) {
248+ const callee = currentNode . callee ;
249+ if ( ! isRemovalTargetAssertion ( callee ) ) {
250+ return ;
251+ }
252+
253+ switch ( parentNode . type ) {
254+ case 'ExpressionStatement' : {
255+ // remove parent ExpressionStatement
256+ removeNode ( parentNode ) ;
257+ this . skip ( ) ;
258+ break ;
259+ }
260+ case 'SequenceExpression' : {
261+ // replace the asserstion with essentially nothing
262+ replaceNode ( currentNode , createNoopExpression ( ) ) ;
263+ break ;
264+ }
265+ }
266+ }
267+
268+ function unassertAwaitExpression ( currentNode , parentNode ) {
269+ const childNode = currentNode . argument ;
270+ if ( isExpressionStatement ( parentNode ) && isCallExpression ( childNode ) ) {
271+ const callee = childNode . callee ;
272+ if ( isRemovalTargetAssertion ( callee ) ) {
273+ // remove parent ExpressionStatement
274+ removeNode ( parentNode ) ;
275+ this . skip ( ) ;
276+ }
277+ }
278+ }
174279
175280 return {
176281 enter : function ( currentNode , parentNode ) {
177282 switch ( currentNode . type ) {
178283 case 'ImportDeclaration' : {
179- const source = currentNode . source ;
180- if ( ! ( isAssertionModuleName ( source ) ) ) {
181- return ;
182- }
183- // remove current ImportDeclaration
184- nodeToRemove . add ( currentNode ) ;
185- this . skip ( ) ;
186- // register local identifier(s) as assertion variable
187- registerAssertionVariables ( currentNode ) ;
284+ unassertImportDeclaration . bind ( this ) ( currentNode , parentNode ) ;
188285 break ;
189286 }
190287 case 'VariableDeclarator' : {
191- if ( isRemovalTargetRequire ( currentNode . id , currentNode . init ) ) {
192- if ( parentNode . declarations . length === 1 ) {
193- // remove parent VariableDeclaration
194- nodeToRemove . add ( parentNode ) ;
195- } else {
196- // single var pattern
197- // remove current VariableDeclarator
198- nodeToRemove . add ( currentNode ) ;
199- }
200- this . skip ( ) ;
201- // register local identifier(s) as assertion variable
202- registerAssertionVariables ( currentNode . id ) ;
203- }
288+ unassertVariableDeclarator . bind ( this ) ( currentNode , parentNode ) ;
204289 break ;
205290 }
206291 case 'AssignmentExpression' : {
207- if ( currentNode . operator !== '=' ) {
208- return ;
209- }
210- if ( ! isExpressionStatement ( parentNode ) ) {
211- return ;
212- }
213- if ( isRemovalTargetRequire ( currentNode . left , currentNode . right ) ) {
214- // remove parent ExpressionStatement
215- nodeToRemove . add ( parentNode ) ;
216- this . skip ( ) ;
217- // register local identifier(s) as assertion variable
218- registerAssertionVariables ( currentNode . left ) ;
219- }
292+ unassertAssignmentExpression . bind ( this ) ( currentNode , parentNode ) ;
220293 break ;
221294 }
222295 case 'CallExpression' : {
223- if ( ! isExpressionStatement ( parentNode ) ) {
224- return ;
225- }
226- const callee = currentNode . callee ;
227- if ( isRemovalTargetAssertion ( callee ) ) {
228- // remove parent ExpressionStatement
229- nodeToRemove . add ( parentNode ) ;
230- this . skip ( ) ;
231- }
296+ unassertCallExpression . bind ( this ) ( currentNode , parentNode ) ;
232297 break ;
233298 }
234299 case 'AwaitExpression' : {
235- const childNode = currentNode . argument ;
236- if ( isExpressionStatement ( parentNode ) && isCallExpression ( childNode ) ) {
237- const callee = childNode . callee ;
238- if ( isRemovalTargetAssertion ( callee ) ) {
239- // remove parent ExpressionStatement
240- nodeToRemove . add ( parentNode ) ;
241- this . skip ( ) ;
242- }
243- }
300+ unassertAwaitExpression . bind ( this ) ( currentNode , parentNode ) ;
244301 break ;
245302 }
246303 }
247304 } ,
248305 leave : function ( currentNode , parentNode ) {
249- switch ( currentNode . type ) {
250- case 'ImportDeclaration' :
251- case 'VariableDeclarator' :
252- case 'VariableDeclaration' :
253- case 'ExpressionStatement' :
254- break ;
255- default :
256- return undefined ;
306+ const update = nodeUpdates . get ( currentNode ) ;
307+ if ( update === undefined ) {
308+ return undefined ;
257309 }
258- if ( nodeToRemove . has ( currentNode ) ) {
310+ if ( update === null ) {
259311 if ( isExpressionStatement ( currentNode ) ) {
260312 const path = this . path ( ) ;
261313 const key = path [ path . length - 1 ] ;
262314 if ( isNonBlockChildOfParentNode ( currentNode , parentNode , key ) ) {
263- return {
264- type : 'BlockStatement' ,
265- body : [ ]
266- } ;
315+ return createNoopStatement ( ) ;
267316 }
268317 }
269318 this . remove ( ) ;
319+ return undefined ;
270320 }
271- return undefined ;
321+ return update ;
272322 }
273323 } ;
274324}
0 commit comments