@@ -5,10 +5,6 @@ const t = require('@babel/types')
55const  ivm  =  require ( 'isolated-vm' ) 
66
77const  isolate  =  new  ivm . Isolate ( ) 
8- const  globalContext  =  isolate . createContextSync ( ) 
9- function  virtualGlobalEval ( jsStr )  { 
10-   return  globalContext . evalSync ( String ( jsStr ) ) 
11- } 
128
139const  collect_id  =  { 
1410  arrowFunc : null , 
@@ -148,6 +144,120 @@ const deMinifyArrow = {
148144  } , 
149145} 
150146
147+ function  checkArrayName ( path )  { 
148+   if  ( path . key  !==  'argument' )  { 
149+     return  null 
150+   } 
151+   const  ret_path  =  path . parentPath 
152+   if  ( ! ret_path . isReturnStatement ( )  ||  ret_path . key  !==  0 )  { 
153+     return  null 
154+   } 
155+   const  array_fn_path  =  ret_path . getFunctionParent ( ) 
156+   const  array_fn_name  =  array_fn_path . node . id ?. name 
157+   if  ( ! array_fn_name )  { 
158+     return  null 
159+   } 
160+   const  binding  =  array_fn_path . parentPath . scope . bindings [ array_fn_name ] 
161+   if  ( binding . references  !==  1 )  { 
162+     return  null 
163+   } 
164+   let  ref  =  binding . referencePaths [ 0 ] 
165+   while  ( ref  &&  ! ref . isAssignmentExpression ( ) )  { 
166+     ref  =  ref . parentPath 
167+   } 
168+   if  ( ! ref )  { 
169+     return  null 
170+   } 
171+   const  array_name  =  ref . node . left ?. name 
172+   if  ( ! array_name )  { 
173+     return  null 
174+   } 
175+   return  { 
176+     func_name : array_fn_name , 
177+     func_path : array_fn_path , 
178+     array_name : array_name , 
179+     array_path : ref , 
180+   } 
181+ } 
182+ 
183+ function  parseArrayWarp ( vm ,  path )  { 
184+   let  func  =  path . getFunctionParent ( path ) 
185+   let  name  =  null 
186+   let  binding  =  null 
187+   if  ( func . isArrowFunctionExpression ( ) )  { 
188+     func  =  func . parentPath 
189+     name  =  func . node . id . name 
190+     binding  =  func . scope . getBinding ( name ) 
191+   }  else  { 
192+     name  =  func . node . id . name 
193+     binding  =  func . parentPath . scope . getBinding ( name ) 
194+   } 
195+   console . log ( `Process array warp function: ${ name }  ` ) 
196+   vm . evalSync ( generator ( func . node ) . code ) 
197+   for  ( const  ref  of  binding . referencePaths )  { 
198+     const  call  =  ref . parentPath 
199+     if  ( ref . key  !==  'callee' )  { 
200+       console . warn ( `Unexpected ref of array warp function: ${ call }  ` ) 
201+       continue 
202+     } 
203+     const  ret  =  vm . evalSync ( generator ( call . node ) . code ) 
204+     if  ( typeof  ret  ===  'string' )  { 
205+       call . replaceWith ( t . stringLiteral ( ret ) ) 
206+     }  else  { 
207+       call . replaceWithSourceString ( ret ) 
208+     } 
209+   } 
210+   binding . scope . crawl ( ) 
211+   binding  =  binding . scope . getBinding ( name ) 
212+   if  ( ! binding . references )  { 
213+     func . remove ( ) 
214+   } 
215+ } 
216+ 
217+ /** 
218+  * Template: 
219+  * ```javascript 
220+  * var arrayName = getArrayFn() 
221+  * function getArrayFn (){ 
222+  *   return [...arrayExpression] 
223+  * } 
224+  * ``` 
225+  */ 
226+ const  deDuplicateLiteral  =  { 
227+   ArrayExpression ( path )  { 
228+     let  obj  =  checkArrayName ( path ) 
229+     if  ( ! obj )  { 
230+       return 
231+     } 
232+     console . log ( `Find arrayName: ${ obj . array_name }  ` ) 
233+     let  decl_node  =  t . variableDeclarator ( 
234+       obj . array_path . node . left , 
235+       obj . array_path . node . right 
236+     ) 
237+     decl_node  =  t . variableDeclaration ( 'var' ,  [ decl_node ] ) 
238+     const  code  =  [ generator ( obj . func_path . node ) . code ,  generator ( decl_node ) . code ] 
239+     let  binding  =  obj . array_path . scope . getBinding ( obj . array_name ) 
240+     for  ( const  ref  of  binding . referencePaths )  { 
241+       const  vm  =  isolate . createContextSync ( ) 
242+       vm . evalSync ( code [ 0 ] ) 
243+       vm . evalSync ( code [ 1 ] ) 
244+       parseArrayWarp ( vm ,  ref ) 
245+     } 
246+     binding . scope . crawl ( ) 
247+     binding  =  binding . scope . bindings [ obj . array_name ] 
248+     if  ( ! binding . references )  { 
249+       obj . array_path . remove ( ) 
250+       binding . path . remove ( ) 
251+     } 
252+     binding  =  obj . func_path . parentPath . scope . getBinding ( obj . func_name ) 
253+     binding . scope . crawl ( ) 
254+     binding  =  binding . scope . getBinding ( obj . func_name ) 
255+     if  ( ! binding . references )  { 
256+       obj . func_path . remove ( ) 
257+     } 
258+   } , 
259+ } 
260+ 
151261function  checkFuncLen ( path )  { 
152262  if  ( path . node ?. name  !==  'configurable'  ||  path . key  !==  'key' )  { 
153263    return  null 
@@ -222,6 +332,8 @@ module.exports = function (code) {
222332  traverse ( ast ,  deAntiTooling ) 
223333  // Minify 
224334  traverse ( ast ,  deMinifyArrow ) 
335+   // DuplicateLiteralsRemoval 
336+   traverse ( ast ,  deDuplicateLiteral ) 
225337  // Stack 
226338  traverse ( ast ,  deStackFuncLen ) 
227339  code  =  generator ( ast ,  { 
0 commit comments