javascript - 在 UglifyJS 中转换 AST

标签 javascript transform abstract-syntax-tree uglifyjs

我正在使用 UglifyJS 来解析、缩小和转换 JS 代码。我的目标之一是通过插入新的变量定义来转换 AST。例如:

var x;
var y;
x = 1;
y = x;
x = 3;

我想插入一个新的变量定义“var _x”到一个随机的位置,比如在语句“y = x”之前。转换后的代码应该是这样的:

var x;
var y;
x = 1;
var _x = x;
y = _x;
_x = 3;

我在 UglifyJS 中尝试过 TreeTransformer。将符号引用更新为新的 (x -> _x) 没有问题。但是我不清楚如何使用 TreeTransformer 获得正确的插入位置。谁能分享一些见解?一些代码示例会更好!

最佳答案

这是我解决这个问题的方法。

var _ = require('lodash');
var path = require('path');
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
var UglifyJS = require('uglify-js');

fs.readFileAsync(path.join(__dirname, 'source.js'), 'utf8').then(function (file) {
  var topLevel = UglifyJS.parse(file);

  var transformed = topLevel.transform(new UglifyJS.TreeTransformer(function (node, descend) {
    if (node instanceof UglifyJS.AST_Toplevel) {
      node = node.clone();

      // Add new variable declaration
      node.body.unshift(new UglifyJS.AST_Var({
        definitions: [
          new UglifyJS.AST_VarDef({
            name: new UglifyJS.AST_SymbolVar({
              name: '_x'
            })
          })
        ]
      }));

      // Replace existing assignment statement with new statements
      var index = _(node.body).findIndex(function (node) {
        return node instanceof UglifyJS.AST_SimpleStatement &&
          node.body instanceof UglifyJS.AST_Assign &&
          node.body.left instanceof UglifyJS.AST_SymbolRef &&
          node.body.left.name === 'y';
      });
      var assignmentStatement = node.body[index].clone();
      node.body.splice(
        index,
        1,
        new UglifyJS.AST_SimpleStatement({
          body: new UglifyJS.AST_Assign({
            left: new UglifyJS.AST_SymbolRef({name: '_x'}),
            operator: '=',
            right: new UglifyJS.AST_SymbolRef({name: 'x'})
          })
        }),
        new UglifyJS.AST_SimpleStatement({
          body: new UglifyJS.AST_Assign({
            left: assignmentStatement.body.left.clone(),
            operator: assignmentStatement.body.operator,
            right: new UglifyJS.AST_SymbolRef({name: '_x'})
          })
        })
      );

      descend(node, this);
      return node;
    }

    node = node.clone();
    descend(node, this);
    return node;
  }));

  var result = transformed.print_to_string({beautify: true});
  return fs.writeFileAsync(path.join(__dirname, 'output.js'), result);
});

这是输出:

var _x;

var x;

var y;

x = 1;

_x = x;

y = _x;

x = 3;

Uglify 以其 AST 格式提升变量声明,因此我遵循相同的规则。

关于javascript - 在 UglifyJS 中转换 AST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31227598/

相关文章:

javascript - 将流式输入与 map 功能结合使用

ios - 在横向模式下应用变换/旋转后获取 ImageView 精确帧

css - 将 CSS 转换应用于显示为 :block, 的元素会向页面添加大量滚动

javascript - 尝试替换元素时整个 div 被替换

javascript - 多个元素上的航路点 - 更新标题

objective-c - iOS 将 UIView 平行于 X-Z 平面对齐

Python 节点转换器 : how to remove nodes?

javascript - 如何将自定义 AST 转换为 JS 代码

c++ - 将解析树转换为 AST(抽象语法树)C++

javascript - react native onChange 事件的名称类型值未定义