【发布时间】:2021-03-28 17:06:23
【问题描述】:
我希望使用 Typescript 编译器收集类、属性和方法信息。
我正在使用 nodejs,并希望根据我的服务器端类定义使用这些信息来构建客户端表单等。
我在使用堆栈溢出作为开始时取得了很好的进展,例如: Correct way of getting type for a variable declaration in a typescript AST? 但想进一步扩展以获取 classes.json 文件中当前缺少的 Method 参数信息,如下所示。任何建议,将不胜感激。我的代码:
import ts from 'typescript';
import * as fs from "fs";
interface DocEntry {
name?: string;
fileName?: string;
documentation?: string;
type?: string;
constructors?: DocEntry[];
parameters?: DocEntry[];
returnType?: string;
}
/** Generate documentation for all classes in a set of .ts files */
function generateDocumentation(
fileNames: string[],
options: ts.CompilerOptions
): void {
// Build a program using the set of root file names in fileNames
let program = ts.createProgram(fileNames, options);
// Get the checker, we will use it to find more about classes
let checker = program.getTypeChecker();
let output = {
component: [],
fields: [],
methods: []
};
// Visit every sourceFile in the program
for (const sourceFile of program.getSourceFiles()) {
if (!sourceFile.isDeclarationFile) {
// Walk the tree to search for classes
ts.forEachChild(sourceFile, visit);
}
}
// print out the definitions
fs.writeFileSync("classes.json", JSON.stringify(output, undefined, 4));
return;
/** visit nodes */
function visit(node: ts.Node) {
if (ts.isClassDeclaration(node) && node.name) {
// This is a top level class, get its symbol
let symbol = checker.getSymbolAtLocation(node.name);
if (symbol) {
const details = serializeClass(symbol);
output.component.push(details);
}
ts.forEachChild(node, visit);
}
else if (ts.isPropertyDeclaration(node)) {
const x = 0;
let symbol = checker.getSymbolAtLocation(node.name);
if (symbol) {
output.fields.push(serializeClass(symbol));
}
} else if (ts.isMethodDeclaration(node)) {
const x = 0;
let symbol = checker.getSymbolAtLocation(node.name);
if (symbol) {
output.methods.push(serializeClass(symbol));
}
}
}
/** Serialize a symbol into a json object */
function serializeSymbol(symbol: ts.Symbol): DocEntry {
return {
name: symbol.getName(),
documentation: ts.displayPartsToString(symbol.getDocumentationComment(checker)),
type: checker.typeToString(
checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration!)
)
};
}
/** Serialize a class symbol information */
function serializeClass(symbol: ts.Symbol) {
let details = serializeSymbol(symbol);
// Get the construct signatures
let constructorType = checker.getTypeOfSymbolAtLocation(
symbol,
symbol.valueDeclaration!
);
details.constructors = constructorType
.getConstructSignatures()
.map(serializeSignature);
return details;
}
/** Serialize a signature (call or construct) */
function serializeSignature(signature: ts.Signature) {
return {
parameters: signature.parameters.map(serializeSymbol),
returnType: checker.typeToString(signature.getReturnType()),
documentation: ts.displayPartsToString(signature.getDocumentationComment(checker))
};
}
}
generateDocumentation(["source1.ts"], {
target: ts.ScriptTarget.ES5,
module: ts.ModuleKind.CommonJS
});
目标源文件source1.ts:
* Documentation for C
*/
class C {
/**bg2 is very cool*/
bg2: number = 2;
bg4: number = 4;
bgA: string = "A";
/**
* constructor documentation
* @param a my parameter documentation
* @param b another parameter documentation
*/
constructor(a: string, b: C) {
}
/** MethodA is an A type Method*/
methodA(myarga1: string): number {
return 22;
}
/** definitely a B grade Method
* @param myargb1 is very argumentative*/
methodB(myargb1: string): string {
return "abc";
}
}
生成的 JSON 文件 classes.json:
{
"component": [
{
"name": "C",
"documentation": "Documentation for C",
"type": "typeof C",
"constructors": [
{
"parameters": [
{
"name": "a",
"documentation": "my parameter documentation",
"type": "string"
},
{
"name": "b",
"documentation": "another parameter documentation",
"type": "C"
}
],
"returnType": "C",
"documentation": "constructor documentation"
}
]
}
],
"fields": [
{
"name": "bg2",
"documentation": "bg2 is very cool",
"type": "number",
"constructors": []
},
{
"name": "bg4",
"documentation": "",
"type": "number",
"constructors": []
},
{
"name": "bgA",
"documentation": "",
"type": "string",
"constructors": []
}
],
"methods": [
{
"name": "methodA",
"documentation": "MethodA is an A type Method",
"type": "(myarga1: string) => number",
"constructors": []
},
{
"name": "methodB",
"documentation": "definitely a B grade Method",
"type": "(myargb1: string) => string",
"constructors": []
}
]
}
【问题讨论】:
标签: typescript class methods properties abstract-syntax-tree