Files

1.9 KiB

安全改写规则

这份文档只回答一个问题:当前节点是否“确定可还原”。

只有在答案明确为“是”时,才做 AST 替换。

可以直接替换的典型场景

  • 数组字面量下标访问,且下标是 NumericLiteral,数组内容本身也稳定。
  • 已建立最小解密环境后,调用参数全是数字字面量或纯字面量。
  • ['a', 'b', 'c'].join('')、String.fromCharCode(...)、split('').reverse().join('') 这类纯计算表达式。
  • 明确的字符串或数字别名链,例如 var a = 'x'; var b = a;。
  • 可以静态确认结果的恒真或恒假比较,例如 if ('a' === 'a')。

不要直接替换的高风险场景

  • 依赖 this、window、闭包外部变量或浏览器环境的调用。
  • 含 getter、setter、代理对象、动态属性访问、副作用函数调用的表达式。
  • 不能确认 binding 是否稳定的别名链。
  • 顺序很关键的逻辑表达式、逗号表达式、条件测试表达式。
  • 需要跨作用域推断执行结果的节点。

默认判断顺序

  1. 先看节点结果是否只依赖字面量和局部稳定绑定。
  2. 再看求值过程中是否存在副作用。
  3. 再看是否依赖执行顺序、宿主环境或外部状态。
  4. 任意一步无法确认,就不要替换。

常见误区

  • 不要把所有 CallExpression 都拿去局部求值。
  • 不要把 LogicalExpression 默认折叠成左值或右值,尤其是含函数调用时。
  • 不要把 StringLiteral、NumericLiteral、BooleanLiteral 再次纳入“循环 evaluate 并回写”的流程。
  • 不要为了追求完全还原而牺牲稳定性。

推荐做法

  • 先得到“结构可读、关键字符串已恢复、主控制流已展开”的结果。
  • 把不能静态确认的区域保留下来,等后续结合运行时证据再处理。
  • 每完成一批替换后重新 parse 一次,确保输出仍然稳定。