LoginSignup
35
32

More than 5 years have passed since last update.

TypeScriptのASTを使ってコードを解析しよう

Posted at

TypeScriptのASTを操作する方法が、GitHubのWikiに公開されていました。これを使えば,TypeScriptのコードを解析することができます。

準備

TypeScriptのインストール

npm install typescriptを実行しTypeScriptを取得します。

tsconfig.jsonを設定する(Atomを利用している場合)

./node_modules/typescript/bin/typescript.d.tsをfilesGlobに追加することで、TypeScriptのASTのAPIのコード補完が可能となります(./node_modules/typescript/bin以下のd.tsファイルを追加すると、Atomが重くなりコード補完は使い物になりません)

tsconfig.json
{
    "version": "1.4.1",
    "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "declaration": false,
        "noImplicitAny": false,
        "removeComments": true,
        "noLib": false
    },
    "filesGlob": [
        "./**/*.ts",
        "!./node_modules/**/*.ts",
        "./node_modules/typescript/bin/typescript.d.ts"
    ],
    "files": [
        "./index.ts",
        "./typings/node/node.d.ts",
        "./node_modules/typescript/bin/typescript.d.ts"
    ]
}

AST解析の進め方

ASTの解析はVisitorパターンを使って、ASTのNodeの種類ごとに、解析を進めていきます。
サンプルプログラムでは、クラスの一覧を標準出力に出力します。

1. typescript を import する

import * as ts from 'typescript' でtypescritをインポートします

2. 解析対象のソースを準備する

解析対象のソースを準備します。本来はfileから読み込むべきですが、ファイル操作のコードを省略するために、変数として用意します。

let source = `
 class Sample{

 }

 class Sample2{

 }
`;

3. SourceFile を生成する

TypeScriptのASTのエントリポイントは、ソースコードをParseして得られるSourceFileから開始します。

let sourceFile = ts.createSourceFile(
          /*ファイル名*/       'sample.ts', 
          /*ソース*/           source, 
          /*ターゲット*/       ts.ScriptTarget.ES6, 
         /*setParentNodes */  true);

4. Visitor パターンを実装する

TypeScriptのAPIにts.forEachChild用意されており、これを使うことでVisitorパターンを実装することができます.

下記のサンプルはClassの宣言を見つけるためのVisitorパターンの実装です。node.kindとts.SyntaxKindを比較することで、Nodeの種類を特定することができます。

ts.forEachChild(sourceFile, each);

function each(node: ts.Node) {
    switch (node.kind) {
        case ts.SyntaxKind.ClassDeclaration:
            classDeclaration(<ts.ClassDeclaration>node);
            break;
        default:
            next();

    }

    function next()   {
            ts.forEachChild(node, each);
    }

}

5. クラス宣言の場合のコールバックメソッドを作成する

クラス宣言の場合のコールバックメソッドでコンソールにクラス名を出力します。

function classDeclaration(node: ts.ClassDeclaration) {
  console.log(node.name.text);
}

動作確認

作成したコードを実行すると、解析対象のソースにある2つのクラス名がコンソールに出力されます

$ node index.js 
Sample
Sample2

まとめ

TypeScriptにASTを操作するためAPIが用意されているので、Visitorパターンを利用すれば、ソースコードの解析は簡単に実現できます。しかし、ソースコードを書き換える処理を実装しようとすると、falafelに比べて、APIが足りないので面倒な実装をしなければなりません。ソースコードを書き換えは、次回の記事に書こうと思います。

開発したソース

index.ts
import * as ts from 'typescript'

let source = `
 class Sample{

 }

 class Sample2{

 }
`;

let sourceFile = ts.createSourceFile('sample.ts', source, ts.ScriptTarget.ES6, /*setParentNodes */ true);

ts.forEachChild(sourceFile, each);

function each(node: ts.Node) {
    switch (node.kind) {
        case ts.SyntaxKind.ClassDeclaration:
            classDeclaration(<ts.ClassDeclaration>node);
            break;
        default:
            next();

    }

    function next()   {
            ts.forEachChild(node, each);
    }

}

function classDeclaration(node: ts.ClassDeclaration) {
  console.log(node.name.text);
}

35
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
32