2015-07-05 32 views
2

我正在使用UglifyJS來解析,縮小和轉換JS代碼。我的目標之一是通過插入新的變量定義來轉換AST。例如:在UglifyJS中轉換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獲得插入的正確位置。誰能分享一些見解?一些代碼示例會更好!

+0

變量聲明是函數作用域的,解釋器應該將它們提升到函數的開始位置,所以只要它在正確的範圍內,注入新聲明的位置並不重要。希望這是一個有用的信息。另外,這聽起來像是一個在javascript uglification中變形的實驗.....是一個好人。 – Catalyst

回答

1

下面是我解決這個問題的方法。

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; 

醜化吊在其AST格式變量聲明,所以我遵循相同的規則。