是否可以使用打字稿编译器 API 将评论作为 AST 中的节点获取?
Is it possible to get comments as nodes in the AST using the typescript compiler API?
我想从打字稿源文件中提取注释,最好带有行号。我试过这样做:
var program = ts.createProgram(files, {
target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS, removeComments: false
});
ts.forEachChild(sourceFile, visit);
function visit(node) {
if (node.kind == ts.SyntaxKind.SingleLineCommentTrivia){
//print something
}
ts.forEachChild(node, visit);
}
事实上,当我打印所有节点的文本时,我可以看到评论被完全丢弃了。我用来测试的输入源码是:
//test comment
declare namespace myLib {
//another comment
function makeGreeting(s: string): string;
let numberOfGreetings: number;
}
无法以节点形式获取注释,但仍然可以从源文件中获取注释。要使用的函数是 getLeadingCommentRanges(text: string, pos: number)
.
我是这样使用的:
for(var sourceFile of program.getSourceFiles()){
ts.forEachChild(sourceFile, visit);
}
function visit(node: ts.Node){
const commentRanges = ts.getLeadingCommentRanges(
sourceFile.getFullText(),
node.getFullStart());
if (commentRange?.length)
const commentStrings:string[] =
commentRanges.map(r=>sourceFile.getFullText().slice(r.pos,r.end))
}
注意:sourceFile.getFullText()
不会跳过前导评论,sourceFile.getText()
会跳过前导评论。在上面的用例中使用 .getText
是 apparently a common source of errors.
如果您使用 jsDoc 风格的注释,例如
export const myConst = {
/**
* My property description
*/
myProp: 'test prop',
};
可以在树遍历期间检索评论内容。
例如 extractWithComment
将 return
{
name: 'myProp',
comment: 'My property description',
type: 'string'
}
import * as ts from 'typescript';
export function extractWithComment(fileNames: string[], options: ts.CompilerOptions): void {
const program = ts.createProgram(fileNames, options);
const checker: ts.TypeChecker = program.getTypeChecker();
for (const sourceFile of program.getSourceFiles()) {
if (!sourceFile.isDeclarationFile) {
ts.forEachChild(sourceFile, visit);
}
}
function visit(node: ts.Node) {
const count = node.getChildCount()
if (count > 0) {
ts.forEachChild(node, visit);
}
if (ts.isPropertyAssignment(node) && node.name) {
const symbol = checker.getSymbolAtLocation(node.name);
if (symbol) {
return serializeSymbol(symbol)
}
}
}
function serializeSymbol(symbol: ts.Symbol) {
return {
name: symbol.getName(),
comment: ts.displayPartsToString(symbol.getDocumentationComment(checker)),
type: checker.typeToString(
checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration!)
),
};
}
}
我想从打字稿源文件中提取注释,最好带有行号。我试过这样做:
var program = ts.createProgram(files, {
target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS, removeComments: false
});
ts.forEachChild(sourceFile, visit);
function visit(node) {
if (node.kind == ts.SyntaxKind.SingleLineCommentTrivia){
//print something
}
ts.forEachChild(node, visit);
}
事实上,当我打印所有节点的文本时,我可以看到评论被完全丢弃了。我用来测试的输入源码是:
//test comment
declare namespace myLib {
//another comment
function makeGreeting(s: string): string;
let numberOfGreetings: number;
}
无法以节点形式获取注释,但仍然可以从源文件中获取注释。要使用的函数是 getLeadingCommentRanges(text: string, pos: number)
.
我是这样使用的:
for(var sourceFile of program.getSourceFiles()){
ts.forEachChild(sourceFile, visit);
}
function visit(node: ts.Node){
const commentRanges = ts.getLeadingCommentRanges(
sourceFile.getFullText(),
node.getFullStart());
if (commentRange?.length)
const commentStrings:string[] =
commentRanges.map(r=>sourceFile.getFullText().slice(r.pos,r.end))
}
注意:sourceFile.getFullText()
不会跳过前导评论,sourceFile.getText()
会跳过前导评论。在上面的用例中使用 .getText
是 apparently a common source of errors.
如果您使用 jsDoc 风格的注释,例如
export const myConst = {
/**
* My property description
*/
myProp: 'test prop',
};
可以在树遍历期间检索评论内容。
例如 extractWithComment
将 return
{
name: 'myProp',
comment: 'My property description',
type: 'string'
}
import * as ts from 'typescript';
export function extractWithComment(fileNames: string[], options: ts.CompilerOptions): void {
const program = ts.createProgram(fileNames, options);
const checker: ts.TypeChecker = program.getTypeChecker();
for (const sourceFile of program.getSourceFiles()) {
if (!sourceFile.isDeclarationFile) {
ts.forEachChild(sourceFile, visit);
}
}
function visit(node: ts.Node) {
const count = node.getChildCount()
if (count > 0) {
ts.forEachChild(node, visit);
}
if (ts.isPropertyAssignment(node) && node.name) {
const symbol = checker.getSymbolAtLocation(node.name);
if (symbol) {
return serializeSymbol(symbol)
}
}
}
function serializeSymbol(symbol: ts.Symbol) {
return {
name: symbol.getName(),
comment: ts.displayPartsToString(symbol.getDocumentationComment(checker)),
type: checker.typeToString(
checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration!)
),
};
}
}