在 UglifyJS 中转换 AST
Transform AST in 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 格式提升变量声明,因此我遵循相同的规则。
我正在使用 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 格式提升变量声明,因此我遵循相同的规则。