ts compiler api
# ts compiler api
# ast
借助该api可以遍历ts文件的ast树做一些事情,例如代码检查。
[文档](Using the Compiler API · microsoft/TypeScript Wiki · GitHub (opens new window))
import { readFileSync } from "fs";
import * as ts from "typescript";
export function delint(sourceFile: ts.SourceFile) {
delintNode(sourceFile);
function delintNode(node: ts.Node) {
switch (node.kind) {
case ts.SyntaxKind.ForStatement:
case ts.SyntaxKind.ForInStatement:
case ts.SyntaxKind.WhileStatement:
case ts.SyntaxKind.DoStatement:
if ((node as ts.IterationStatement).statement.kind !== ts.SyntaxKind.Block) {
report(
node,
'A looping statement\'s contents should be wrapped in a block body.'
);
}
break;
case ts.SyntaxKind.IfStatement:
const ifStatement = node as ts.IfStatement;
if (ifStatement.thenStatement.kind !== ts.SyntaxKind.Block) {
report(ifStatement.thenStatement, 'An if statement\'s contents should be wrapped in a block body.');
}
if (
ifStatement.elseStatement &&
ifStatement.elseStatement.kind !== ts.SyntaxKind.Block &&
ifStatement.elseStatement.kind !== ts.SyntaxKind.IfStatement
) {
report(
ifStatement.elseStatement,
'An else statement\'s contents should be wrapped in a block body.'
);
}
break;
case ts.SyntaxKind.BinaryExpression:
const op = (node as ts.BinaryExpression).operatorToken.kind;
if (op === ts.SyntaxKind.EqualsEqualsToken || op === ts.SyntaxKind.ExclamationEqualsToken) {
report(node, 'Use \'===\' and \'!==\'.');
}
break;
}
ts.forEachChild(node, delintNode);
}
function report(node: ts.Node, message: string) {
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
console.log(`${sourceFile.fileName} (${line + 1},${character + 1}): ${message}`);
}
}
const fileNames = process.argv.slice(2);
fileNames.forEach(fileName => {
// Parse a file
const sourceFile = ts.createSourceFile(
fileName,
readFileSync(fileName).toString(),
ts.ScriptTarget.ES2015,
/*setParentNodes */ true
);
// delint it
delint(sourceFile);
});