原理
使用typescript把源代码读成ast,然后修改ast结构,然后将ast重新还原成js代码,最后将js代码重新写入文件。
具体步骤
将需要修改的代码以字符串的形式读进来
var file = fs.readFileSync(path, 'utf-8');
使用ts提供的一系列工具函数来生成和修改ast
const ts = require('typescript')
关键的转换代码
function transformTS(source, transformer) {
const sourceFile = ts.createSourceFile(
'test.ts', source, ts.ScriptTarget.ES2015, true, ts.ScriptKind.TS
);
const printer = ts.createPrinter();
const result = ts.transform(
sourceFile, [transformer]
);
const transformedSourceFile = result.transformed[0];
const newContent = printer.printFile(transformedSourceFile)
result.dispose()
return newContent
}
这个函数主要是接受一个源代码字符串,可以是任意的js代码或者ts代码,还接受一个transformer,用来对生成的ast(抽象语法树)进行遍历,根据需要在对应的位置插入或修改。
一个transformer是一个函数,要写成下面这样的格式提供给ts.transform函数
const transformer = (context) => {
return (rootNode) => {
function visit(node) {
node = ts.visitEachChild(node, visit, context);
if (ts.isArrowFunction(node)) {
console.log(node.body.statements);
let newLine = ts.createExpressionStatement(
ts.createCall(
ts.createPropertyAccess(
ts.createIdentifier('router'), 'get'), undefined,
[
ts.createLiteral(`/${namespace}/${pageName}`),
ts.createPropertyAccess(ts.createIdentifier('controller'),
ts.createPropertyAccess(ts.createIdentifier(namespace), pageName))
]))
node.body.statements = node.body.statements.concat(newLine);
}
return node;
}
return ts.visitNode(rootNode, visit);
}
}
这个函数主要是遍历ast的node节点,对于匹配的节点进行编辑操作,这个例子中遍历节点,在ts.isClassDelaration(node)
这里判断是不是类声明,如果是的话就给这个类添加一个新的成员方法node.members = node.members.concat(createControllerMethod(pageName))
。
将代码转换之后并没有执行写入操作,需要将修改后的代码重新写入
fs.writeFileSync('app/router.ts', result);
网友评论