2016-09-05 24 views
1

私は、一部のソースコードを解析してクラス参照を取得するために、TypeScriptコンパイラAPIを使用しています。TypeScriptソース解析:クラスデコレータ名を取得

クラス定義に対応するNodeオブジェクトにはdecoratorsの配列がありますが、各デコレータの名前を取得する方法が見つかりません。

私はあなたがデコレータ式で最初のトークンを取得することができ、これは、関数の宣言になります活字体のwiki

///<reference path="typings/node/node.d.ts" /> 

import * as 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 documention 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: DocEntry[] = []; 

    // Visit every sourceFile in the program  
    for (const sourceFile of program.getSourceFiles()) { 
     // Walk the tree to search for classes 
     ts.forEachChild(sourceFile, visit); 
    } 

    // print out the doc 
    fs.writeFileSync("classes.json", JSON.stringify(output, undefined, 4)); 

    return; 

    /** visit nodes finding exported classes */  
    function visit(node: ts.Node) { 
     // Only consider exported nodes 
     if (!isNodeExported(node)) { 
      return; 
     } 

     if (node.kind === ts.SyntaxKind.ClassDeclaration) { 
      // This is a top level class, get its symbol 
      let symbol = checker.getSymbolAtLocation((<ts.ClassDeclaration>node).name); 
      output.push(serializeClass(symbol)); 
      // No need to walk any further, class expressions/inner declarations 
      // cannot be exported 
     } 
     else if (node.kind === ts.SyntaxKind.ModuleDeclaration) { 
      // This is a namespace, visit its children 
      ts.forEachChild(node, visit); 
     } 
    } 

    /** Serialize a symbol into a json object */  
    function serializeSymbol(symbol: ts.Symbol): DocEntry { 
     return { 
      name: symbol.getName(), 
      documentation: ts.displayPartsToString(symbol.getDocumentationComment()), 
      type: checker.typeToString(checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration)) 
     }; 
    } 

    /** Serialize a class symbol infomration */ 
    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()) 
     }; 
    } 

    /** True if this is visible outside this file, false otherwise */ 
    function isNodeExported(node: ts.Node): boolean { 
     return (node.flags & ts.NodeFlags.Export) !== 0 || (node.parent && node.parent.kind === ts.SyntaxKind.SourceFile); 
    } 
} 

generateDocumentation(process.argv.slice(2), { 
    target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS 
}); 

答えて

1

からthis exampleを使用。関数からは、名前、パラメータ、docstringなどの情報を得ることができます。

私が例に拡張している:私は出力を得た

function MyDecorator(myParam: string) { 

} 

@MyDecorator("myVal") 
class MyTestClass { 

} 

[ 
    { 
     "name": "MyTestClass", 
     "documentation": "", 
     "type": "typeof MyTestClass", 
     "decorators": [ 
      { 
       "name": "MyDecorator", 
       "documentation": "", 
       "type": "(myParam: string) => void", 
       "constructors": [ 
        { 
         "parameters": [ 
          { 
           "name": "myParam", 
           "documentation": "", 
           "type": "string" 
          } 
         ], 
         "returnType": "void", 
         "documentation": "" 
        } 
       ] 
      } 
     ], 
     "constructors": [ 
      { 
       "parameters": [], 
       "returnType": "MyTestClass", 
       "documentation": "" 
      } 
     ] 
    } 
] 
+0

はあなたのKostyaをありがとう、このようなサンプルコードについて

///<reference path="typings/node/node.d.ts" /> import * as ts from "typescript"; import * as fs from "fs"; interface DocEntry { name?: string, fileName?: string, documentation?: string, type?: string, constructors?: DocEntry[], parameters?: DocEntry[], decorators?: DocEntry[], returnType?: string }; /** Generate documention 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: DocEntry[] = []; // Visit every sourceFile in the program for (const sourceFile of program.getSourceFiles()) { // Walk the tree to search for classes ts.forEachChild(sourceFile, visit); } // print out the doc fs.writeFileSync("classes.json", JSON.stringify(output, undefined, 4)); return; /** visit nodes finding exported classes */ function visit(node: ts.Node) { // Only consider exported nodes if (!isNodeExported(node)) { return; } if (node.kind === ts.SyntaxKind.ClassDeclaration) { // This is a top level class, get its symbol output.push(serializeClass((<ts.ClassDeclaration>node))); // No need to walk any further, class expressions/inner declarations // cannot be exported } else if (node.kind === ts.SyntaxKind.ModuleDeclaration) { // This is a namespace, visit its children ts.forEachChild(node, visit); } } /** Serialize a symbol into a json object */ function serializeSymbol(symbol: ts.Symbol): DocEntry { return { name: symbol.getName(), documentation: ts.displayPartsToString(symbol.getDocumentationComment()), type: checker.typeToString(checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration)) }; } /** Serialize a class symbol infomration */ function serializeClass(node: ts.ClassDeclaration) { let symbol = checker.getSymbolAtLocation(node.name); let details = serializeSymbol(symbol); // Get the construct signatures details.decorators = node.decorators.map(serializeDecorator); let constructorType = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration); details.constructors = constructorType.getConstructSignatures().map(serializeSignature); return details; } function serializeDecorator(decorator: ts.Decorator) { let symbol = checker.getSymbolAtLocation(decorator.expression.getFirstToken()); let decoratorType = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration); let details = serializeSymbol(symbol); details.constructors = decoratorType.getCallSignatures().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()) }; } /** True if this is visible outside this file, false otherwise */ function isNodeExported(node: ts.Node): boolean { return (node.flags & ts.NodeFlags.Export) !== 0 || (node.parent && node.parent.kind === ts.SyntaxKind.SourceFile); } } generateDocumentation(process.argv.slice(2), { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS }); 

そして今を – devoups

関連する問題