@@ -42,24 +42,25 @@ function safeDeleteNode(name, path) {
42
42
binding = path . scope . getBinding ( name )
43
43
}
44
44
if ( ! binding ) {
45
- return
45
+ return false
46
46
}
47
47
binding . scope . crawl ( )
48
48
binding = binding . scope . getBinding ( name )
49
49
if ( binding . references ) {
50
- return
50
+ return false
51
51
}
52
52
for ( const item of binding . constantViolations ) {
53
53
item . remove ( )
54
54
}
55
55
const decl = binding . path
56
56
if ( decl . removed ) {
57
- return
57
+ return true
58
58
}
59
59
if ( ! decl . isVariableDeclarator ( ) && ! decl . isFunctionDeclaration ( ) ) {
60
- return
60
+ return true
61
61
}
62
62
binding . path . remove ( )
63
+ return true
63
64
}
64
65
65
66
function deAntiToolingCheckFunc ( path ) {
@@ -845,9 +846,6 @@ function insertDepItemVar(deps, name, path) {
845
846
*/
846
847
function findGlobalFn ( path ) {
847
848
const glo_fn_name = path . node . id ?. name
848
- if ( path . parentPath . getFunctionParent ( ) ) {
849
- return null
850
- }
851
849
if ( ! glo_fn_name ) {
852
850
return null
853
851
}
@@ -1197,7 +1195,10 @@ const deStringConcealing = {
1197
1195
FunctionDeclaration ( path ) {
1198
1196
const obj = findGlobalFn ( path )
1199
1197
if ( ! obj ) {
1200
- return
1198
+ return null
1199
+ }
1200
+ if ( obj . glo_fn_path . parentPath . getFunctionParent ( ) ) {
1201
+ return null
1201
1202
}
1202
1203
findGlobalFnRef ( obj )
1203
1204
if ( ! findBufferToString ( obj ) ) {
@@ -1239,6 +1240,26 @@ function tryStringConcealingPlace(path) {
1239
1240
}
1240
1241
1241
1242
const deStringConcealingPlace = {
1243
+ StringLiteral ( path ) {
1244
+ if ( path . key !== 'right' || ! path . parentPath . isAssignmentExpression ( ) ) {
1245
+ return
1246
+ }
1247
+ const name = safeGetName ( path . parentPath . get ( 'left' ) )
1248
+ if ( ! name ) {
1249
+ return
1250
+ }
1251
+ const binding = path . scope . getBinding ( name )
1252
+ if ( binding . constantViolations . length !== 1 ) {
1253
+ return
1254
+ }
1255
+ for ( const ref of binding . referencePaths ) {
1256
+ if ( ref . node . start < path . node . start ) {
1257
+ continue
1258
+ }
1259
+ ref . replaceWith ( path . node )
1260
+ }
1261
+ safeDeleteNode ( name , path . parentPath )
1262
+ } ,
1242
1263
ArrayExpression ( path ) {
1243
1264
let valid = true
1244
1265
if ( path . node . elements . length === 0 ) {
@@ -1414,6 +1435,125 @@ const deOpaquePredicates = {
1414
1435
} ,
1415
1436
}
1416
1437
1438
+ function findGlobalVar ( glo_name , glo_path ) {
1439
+ let tmp_path = glo_path . parentPath . getFunctionParent ( )
1440
+ if (
1441
+ ! tmp_path ||
1442
+ ! tmp_path . parentPath . isMemberExpression ( ) ||
1443
+ ! tmp_path . parentPath . parentPath . isCallExpression ( )
1444
+ ) {
1445
+ return null
1446
+ }
1447
+ const tmp_body = tmp_path . node . body . body
1448
+ tmp_path = tmp_path . parentPath . parentPath
1449
+ const ret_node = tmp_body [ tmp_body . length - 1 ]
1450
+ if (
1451
+ ! t . isReturnStatement ( ret_node ) ||
1452
+ ! t . isAssignmentExpression ( ret_node . argument )
1453
+ ) {
1454
+ return null
1455
+ }
1456
+ const code = generator ( ret_node . argument . right ) . code
1457
+ const template = `${ glo_name } call(this)`
1458
+ if ( ! checkPattern ( code , template ) ) {
1459
+ return null
1460
+ }
1461
+ const glo_var = ret_node . argument . left . name
1462
+ const binding = glo_path . scope . getBinding ( glo_var )
1463
+ for ( const ref of binding . referencePaths ) {
1464
+ if (
1465
+ ! ref . parentPath . isMemberExpression ( ) ||
1466
+ ! ref . parentPath . parentPath . isReturnStatement ( )
1467
+ ) {
1468
+ continue
1469
+ }
1470
+ const func_path = ref . getFunctionParent ( )
1471
+ const func_name = func_path . node . id . name
1472
+ return {
1473
+ glo_var : glo_var ,
1474
+ tmp_path : tmp_path ,
1475
+ glo_fn_name : func_name ,
1476
+ glo_fn_path : func_path ,
1477
+ }
1478
+ }
1479
+ return null
1480
+ }
1481
+
1482
+ function getGlobalConcealingNames ( glo_fn_path ) {
1483
+ const obj = { }
1484
+ glo_fn_path . traverse ( {
1485
+ SwitchCase ( path ) {
1486
+ const key = parseInt ( generator ( path . node . test ) . code )
1487
+ let consequent = path . node . consequent [ 0 ]
1488
+ if ( t . isReturnStatement ( consequent ) ) {
1489
+ obj [ key ] = consequent . argument . property . value
1490
+ } else {
1491
+ if ( t . isExpressionStatement ( consequent ) ) {
1492
+ consequent = consequent . expression
1493
+ }
1494
+ obj [ key ] = consequent . right . left . value
1495
+ }
1496
+ } ,
1497
+ } )
1498
+ return obj
1499
+ }
1500
+
1501
+ /**
1502
+ * Hide the global vars found by module GlobalAnalysis
1503
+ *
1504
+ * Template:
1505
+ * ```javascript
1506
+ * // Add to head:
1507
+ * var globalVar, tempVar = function () {
1508
+ * getGlobalVariableFnName = createGetGlobalTemplate()
1509
+ * return globalVar = getGlobalVariableFnName.call(this)
1510
+ * }["call"]()
1511
+ * // Add to foot:
1512
+ * function globalFn (indexParamName) {
1513
+ * var returnName
1514
+ * switch (indexParamName) {
1515
+ * case state_x: {
1516
+ * return globalVar[name]
1517
+ * }
1518
+ * case state_y: {
1519
+ * returnName = name || globalVar[name]
1520
+ * break
1521
+ * }
1522
+ * }
1523
+ * return globalVar[returnName]
1524
+ * }
1525
+ * // References:
1526
+ * // name -> globalFn(state)
1527
+ * ```
1528
+ */
1529
+ const deGlobalConcealing = {
1530
+ FunctionDeclaration ( path ) {
1531
+ const glo_obj = findGlobalFn ( path )
1532
+ if ( ! glo_obj ) {
1533
+ return null
1534
+ }
1535
+ const obj = findGlobalVar ( glo_obj . glo_fn_name , glo_obj . glo_fn_path )
1536
+ if ( ! obj ) {
1537
+ return null
1538
+ }
1539
+ console . log ( `[GlobalConcealing] globalVar: ${ obj . glo_var } ` )
1540
+ const glo_vars = getGlobalConcealingNames ( obj . glo_fn_path )
1541
+ console . log ( `[GlobalConcealing] globalFn: ${ obj . glo_fn_name } ` )
1542
+ let binding = obj . glo_fn_path . parentPath . scope . getBinding ( obj . glo_fn_name )
1543
+ for ( const ref of binding . referencePaths ) {
1544
+ const repl_path = ref . parentPath
1545
+ if ( ref . key !== 'callee' || ! repl_path . isCallExpression ( ) ) {
1546
+ continue
1547
+ }
1548
+ const key = parseInt ( generator ( repl_path . node . arguments [ 0 ] ) . code )
1549
+ repl_path . replaceWith ( t . identifier ( glo_vars [ key ] ) )
1550
+ }
1551
+ if ( safeDeleteNode ( obj . glo_fn_name , obj . glo_fn_path ) ) {
1552
+ obj . tmp_path . remove ( )
1553
+ }
1554
+ } ,
1555
+ }
1556
+
1417
1557
module . exports = function ( code ) {
1418
1558
let ast
1419
1559
try {
@@ -1442,6 +1582,8 @@ module.exports = function (code) {
1442
1582
traverse ( ast , deOpaquePredicates )
1443
1583
traverse ( ast , calculateConstantExp )
1444
1584
traverse ( ast , pruneIfBranch )
1585
+ // GlobalConcealing
1586
+ traverse ( ast , deGlobalConcealing )
1445
1587
code = generator ( ast , {
1446
1588
comments : false ,
1447
1589
jsescOption : { minimal : true } ,
0 commit comments