这里只列举出 visitor 的内容,其他配置参考原理篇

字符串还原

1
2
3
4
5
6
7
8
9
const visitor = {
StringLiteral(path) {
// 以下方法均可
// path.node.extra.raw = path.node.rawValue
// path.node.extra.raw = '"' + path.node.value + '"'
// delete path.node.extra
delete path.node.extra.raw
}
}

效果:

1
2
console['\u006c\u006f\u0067']('\u0048\u0065\u006c\u006c\u006f\u0020\u0077\u006f\u0072\u006c\u0064\u0021');
const name = "\x68\x65\x6c\x6c\x6f";
1
2
console["log"]("Hello world!");
const name = "hello";

表达式还原

1
2
3
4
5
6
7
const visitor = {
"UnaryExpression|BinaryExpression|CallExpression|ConditionalExpression"(path) {
const {confident, value} = path.evaluate();
if (value == Infinity || value == -Infinity) return;
confident && path.replaceInline(types.valueToNode(value))
}
}

效果:

1
2
3
4
5
6
7
const a = !![]+!![]+!![];
const b = Math.floor(12.34 * 2.12)
const c = 10 >> 3 << 1
const d = String(21.3 + 14 * 1.32)
const e = parseInt("1.893" + "45.9088")
const f = parseFloat("23.2334" + "21.89112")
const g = 20 < 18 ? '未成年' : '成年'
1
2
3
4
5
6
7
const a = 3;
const b = 26;
const c = 2;
const d = "39.78";
const e = parseInt("1.89345.9088");
const f = parseFloat("23.233421.89112");
const g = "\u6210\u5E74";

删除无用变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const visitor = {
VariableDeclarator(path){
const binding = path.scope.getBinding(path.node.id.name);

// 如标识符被修改过,则不能进行删除动作。
if (!binding || binding.constantViolations.length > 0) {
return;
}

// 未被引用
if (!binding.referenced) {
path.remove();
}

// 被引用次数为0
// if (binding.references === 0) {
// path.remove();
// }

// 长度为0,变量没有被引用过
// if (binding.referencePaths.length === 0) {
// path.remove();
// }
}
}

效果:

1
2
3
4
5
6
const a = 1;
const b = a * 2;
const c = 2;
const d = b + 1;
const e = 3;
console.log(d)
1
2
3
4
const a = 1;
const b = a * 2;
const d = b + 1;
console.log(d);

删除冗余代码(僵尸代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 去除无用的判断语句

const visitor = {
IfStatement(path) {
let { consequent, alternate } = path.node;
let testPath = path.get("test");
// console.log("test path", testPath);
// console.log(typeof testPath);
const evaluateTest = testPath.evaluateTruthy();
console.log("evaluateTest", evaluateTest);

if (evaluateTest === true) {
if (types.isBlockStatement(consequent)) {
consequent = consequent.body;
}
path.replaceWithMultiple(consequent);
} else if (evaluateTest === false) {
if (alternate != null) {
if (types.isBlockStatement(alternate)) {
alternate = alternate.body;
}
path.replaceWithMultiple(alternate);
} else {
path.remove();
}
}
}
}

反控制流平坦

1