使用TypeScript Compiler API为函数添加前置注释
用TypeScript Compiler API给函数自动添加注释的正确姿势
踩过这个坑的人来给你支个招:直接修改SourceFile.statements的方式只能处理顶层函数,而且TypeScript的AST节点本质是不可变对象,硬改容易出各种奇怪的问题。更靠谱的做法是用官方的Transformer API来遍历并修改AST,既能覆盖所有函数(包括嵌套的),又能保证代码生成的正确性。
完整实现代码
下面是可以直接跑的示例,会给所有函数(函数声明、函数表达式、箭头函数)添加统一的注释:
import * as ts from 'typescript'; import * as fs from 'fs'; // 配置编译选项 const compilerOptions: ts.CompilerOptions = { target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.CommonJS, }; // 要处理的源文件路径 const inputFilePath = './your-input-file.ts'; const outputFilePath = './your-output-file.js'; // 创建Program实例 const program = ts.createProgram([inputFilePath], compilerOptions); const sourceFile = program.getSourceFiles().find(file => !file.isDeclarationFile)!; // 定义Transformer:遍历AST并添加注释 function addFunctionCommentsTransformer(context: ts.TransformationContext): ts.Transformer<ts.SourceFile> { return (node: ts.SourceFile) => { // 递归遍历所有节点的访问器 const visitor: ts.Visitor = (node) => { // 匹配所有类型的函数节点 if ( ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) ) { // 给函数节点添加前置注释 // 第一个参数是目标节点,第二个是注释类型,第三个是注释内容,第四个是是否换行 ts.addSyntheticLeadingComment( node, ts.SyntaxKind.MultiLineCommentTrivia, `* 自动生成的函数注释:${node.name?.getText() || '匿名函数'} *`, true ); } // 继续遍历子节点 return ts.visitEachChild(node, visitor, context); }; return ts.visitNode(node, visitor); }; } // 执行转换并生成输出代码 const result = ts.transform(sourceFile, [addFunctionCommentsTransformer]); const transformedSourceFile = result.transformed[0]; // 将转换后的AST输出为JS代码 const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); const outputCode = printer.printFile(transformedSourceFile); // 写入文件 fs.writeFileSync(outputFilePath, outputCode); // 清理资源 result.dispose();
关键细节说明
为什么不用直接修改statements?
- TS的AST节点是只读设计的,直接赋值
srcFile.statements = ...会绕过类型检查,可能导致后续遍历或打印时出错。 - 这种方式只能处理顶层的函数声明,没法处理嵌套在if语句、类、其他函数内部的函数,覆盖范围有限。
- TS的AST节点是只读设计的,直接赋值
Transformer API的优势
- 官方提供的标准修改AST的方式,完全兼容TS的类型系统。
- 递归遍历能覆盖所有层级的函数节点,不管是顶层还是嵌套的。
- 用
addSyntheticLeadingComment添加的注释会被正确解析并输出到最终的JS文件里。
自定义注释内容
你可以根据函数的元信息(比如参数、返回值)来生成更个性化的注释,比如:const paramNames = node.parameters.map(p => p.name.getText()).join(', '); ts.addSyntheticLeadingComment( node, ts.SyntaxKind.MultiLineCommentTrivia, `* 函数:${node.name?.getText() || '匿名函数'} *\n* 参数:${paramNames} *`, true );
内容的提问来源于stack exchange,提问作者Radu Szasz
相关产品推荐
相关产品推荐

