2015-07-05 6 views
2

Я использую UglifyJS для синтаксического анализа, преобразования и преобразования JS-кодов. Одна из моих целей - преобразовать AST, вставив новые определения переменных. Например:Преобразование AST в UglifyJS

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

Я хочу, чтобы вставить новую переменную определение «переменная _x» в любом положении, например, перед оператором «у = х». Преобразованный код должен быть таким:

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

Я пробовал TreeTransformer в UglifyJS. Обновление ссылки на символ для новой (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; 

уродовать тали объявления переменных в своем формате АСТ, так что я следовать тому же правилу.

Смежные вопросы