Help us understand the problem. What is going on with this article?

TypeScriptのAST・コンパイラAPIとお付き合い

More than 3 years have passed since last update.

TypeScriptのAST・コンパイラAPIとお付き合い

by sisisin
1 / 17

はじめに

こちらはGotanda.js #6 in OisixのLT資料になります


自己紹介

  • twitter: @_sisisin
  • github: @sisisin
  • 普段触ってる技術
    • 仕事では主にAngular1系+TypeScriptでSPA開発
    • 個人では主にReact,Angular2系,Node.js.最近はちょろっとRuby

ASTとは

  • Abstract Syntax Tree(抽象構文木)のこと
  • コードをパースして木構造の集合として扱えるように出来る
  • 詳しくはazuさんの資料が参考になります(http://azu.github.io/slide/JSojisan/)
  • 気軽にASTを試すならAST explorerおすすめ

TypeScriptとAST

  • TypeScriptのコンパイラの内部ではTypeScriptのソースコードを変換するためにASTを利用している
  • 今回はそのコンパイラAPIでASTを取り扱う方法を紹介

コンパイラAPIの概要

  • コンパイラAPIではソースファイル = AST Nodeとして扱うことが出来、そのソースファイルノードの集合として1つのプロジェクトを構成している
  • それぞれNode, Programという型がtypescript.d.tsに定義されている
    • なお、ソースファイルはNode型を継承したSourceFileという型が定義されている
    • ソースファイルだけでなく、全てのAST NodeはNode型を継承したinterfaceが定義されている
  • プロジェクトに対しての操作などを行うAPIはCompilerHostに定義されている
    • この辺使わなかったのでよくわかってません><

実際にTypeScriptのプロジェクトを読み込んでみる


動作環境

TypeScript1.8

*2系で試すときはbreaking change入ってるかもなので注意


準備

  • npm init -y && npm i -S typescript
  • 下記のようなファイルを用意
index.ts
import * as ts from 'typescript';

簡単!


  • 型定義ファイルも含まれているのでそのままTypeScriptで書けてGood
    • (というか型定義ファイルなしではやってられない
  • もちろんトランスパイルしないと動かないので、実行する際は$(npm bin)/tscを実行してからnode index.jsと叩いてやる

使う

  • ts.createProgram()を利用してProgramを作成する
    • 第一引数に対象のファイル名配列、第二引数にコンパイラオプションを渡す
      • コンパイラオプションはtsconfig.jsonまるっと渡しても良い
    • 対象のTypeScriptプロジェクトを取り扱えるメソッド郡を持ったObjectが返ってくる
      • 返り値はクラスのインスタンスではなく生のJSオブジェクトっぽいのでややこしい言い回しになった

  • Program.getSourceFiles()を利用してSourceFileを取得する
    • SourceFileのインスタンスの配列が返ってくる
    • こいつはProgramと違ってクラスのインスタンスっぽい(SourceFileObjectクラス)
    • SourceFileはファイル名とかが含まれたNodeになっている

  • ts.forEachChild()を利用して、AST Nodeを走査する
    • 走査対象のNodeがもつ子Node全てに処理を行う関数
      • なお、孫以下は走査されない
    • 第一引数に走査対象Nodeを渡し、第二引数にコールバック関数を渡す
    • コールバック関数の引数はNodeのインスタンス
      • 更に子のNodeを探索する場合はこのコールバック内でさらにts.forEachChild()を呼ぶ形になる

  • Node.kindを用いてAST Nodeの種類によって処理を分岐する
    • Node.kindにはts.SyntaxKindのenum値が格納されている
    • SyntaxKindの種類によって扱えるプロパティが違うので、その場合はキャストする
      • 例えばts.SyntaxKind.VariableStatementの場合はVariableStatement.declarationListというプロパティを持っていたりする
    • TypeScriptのコードがどのSyntaxKindにパースされるかはenumの定義見て察する必要がありそうだった
      • ドキュメント・・・
    • AST explorerで試しながら探してみると非常に捗るのでおすすめ

サンプルコード

クラス定義をコンソールに表示するプログラムのサンプルコードはこんな感じ

index.ts
import * as ts from 'typescript';

const files = ['sample/s1.ts', 'sample/d/s2.ts'];
const tsconfig = require('../sample/tsconfig.json');
const program = ts.createProgram(files, tsconfig);

for (const sourceFile of program.getSourceFiles()) {
  if (sourceFile.fileName.substr(-5) === '.d.ts') continue;
  ts.forEachChild(sourceFile, visit);
}

function visit(node: ts.Node) {
  if (node.kind === ts.SyntaxKind.ClassDeclaration) {
    console.log((<ts.ClassDeclaration>node).name.text);
  }
  ts.forEachChild(node, visit);
}


終わりに

  • 簡単にTypeScriptのコンパイラAPIを用いたASTの扱い方を紹介しました
  • 以上の知識があれば最低限TypeScriptのAST使ってみることは出来ると思います
  • 正規表現に限界を感じたりしたら是非

※後者2つの記事ではTypeScript1.4を使ってますが、1.8でもそのまま使えました

opt
"INNOVATION AGENCY" を標榜するインターネット広告代理店。エンジニア組織 "Opt Techonologies" を中心にアドテクetc...に取り組んでいます。
https://opt-technologies.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした