typescript - 从以编程方式创建的 AST 打印类型定义
问题描述
我正在尝试以编程方式为第三方库创建的定义创建一个打字稿 AST,并使用该 AST 为我们在库语法中的声明打印一组类型定义(一个 .d.ts 文件)。
依靠编译器 API 的文档,并挖掘 typescript 编译器的源文件,我相信我有一个基本正确的 AST。但是,我还没有找到一种方法来输出此 AST 的类型定义(对应于 .d.ts 文件),仅将 AST 打印为打字稿程序。
我的问题实际上是两个部分:
- 有没有办法从 AST 打印类型定义(输出 .d.ts 文件)?
- 如果是这样,有没有这样的例子?
解决方案
ts.transpileModule
复制和更改TypeScript 源函数中所做的工作以仅输出声明文件可能是最简单的。
例如:
export function transpileModuleDeclaration(sourceFile: ts.SourceFile, transpileOptions: ts.TranspileOptions) {
const diagnostics: ts.Diagnostic[] = [];
const options = transpileOptions.compilerOptions != null ? { ...transpileOptions.compilerOptions } : ts.getDefaultCompilerOptions();
options.isolatedModules = true;
// in this case we only want to emit the declaration file
options.emitDeclarationOnly = true;
options.declaration = true;
// this does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths.
options.suppressOutputPathCheck = true;
// Filename can be non-ts file.
options.allowNonTsExtensions = true;
// We are not returning a sourceFile for lib file when asked by the program,
// so pass --noLib to avoid reporting a file not found error.
options.noLib = true;
// Clear out other settings that would not be used in transpiling this module
options.lib = undefined;
options.types = undefined;
options.noEmit = undefined;
options.noEmitOnError = undefined;
options.paths = undefined;
options.rootDirs = undefined;
options.composite = undefined;
options.declarationDir = undefined;
options.out = undefined;
options.outFile = undefined;
// We are not doing a full typecheck, we are not resolving the whole context,
// so pass --noResolve to avoid reporting missing file errors.
options.noResolve = true;
// if jsx is specified then treat file as .tsx
const inputFileName = transpileOptions.fileName || (options.jsx ? "module.tsx" : "module.ts");
if (transpileOptions.moduleName) {
sourceFile.moduleName = transpileOptions.moduleName;
}
// Output
let outputText: string | undefined;
// Create a compilerHost object to allow the compiler to read and write files
const compilerHost: ts.CompilerHost = {
getSourceFile: (fileName) => fileName === inputFileName.replace(/\\/g, "/") ? sourceFile : undefined,
writeFile: (name, text) => {
outputText = text;
},
getDefaultLibFileName: () => "lib.d.ts",
useCaseSensitiveFileNames: () => false,
getCanonicalFileName: fileName => fileName,
getCurrentDirectory: () => "",
getNewLine: () => options.newLine == null || options.newLine === ts.NewLineKind.LineFeed ? "\n" : "\r\n",
fileExists: fileName => fileName === inputFileName,
readFile: () => "",
directoryExists: () => true,
getDirectories: () => []
};
const program = ts.createProgram([inputFileName], options, compilerHost);
if (transpileOptions.reportDiagnostics) {
diagnostics.push(...program.getSyntacticDiagnostics(sourceFile));
diagnostics.push(...program.getOptionsDiagnostics());
}
// Emit
program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ undefined, transpileOptions.transformers);
if (outputText === undefined)
throw new Error("Output generation failed.");
return { outputText, diagnostics };
}
然后使用它:
const file = ts.createSourceFile("test.ts", `function myFunc(a: number, b: number) {
return a + b;
}`, ts.ScriptTarget.Latest, true);
const result = transpileModuleDeclaration(file, {});
console.log(result.outputText);
输出:
declare function myFunc(a: number, b: number): number;
推荐阅读
- php - php mysql准备好的语句LIKE在Wordpress中不起作用
- python - 如何合并元组列表
- javascript - 使用 mocha-allure-reporter 和 Cypress 的 Allure 报告中不显示步骤
- c# - 更改第三方引用的 dll 属性(产品名称)
- javascript - JavaScript 的 Math.random 在循环中生成相同的数字
- wordpress - WordPress 页面更新
- c# - 播放器设置中的 Internet 访问已禁用
- google-maps - 是否可以在 PWA 应用程序中开发带有方向的离线地图应用程序?
- angular - 如何在 Angular 2 中设置反向代理
- python - 如何使用 .after 使画布文本在 Tkinter 中出现和消失