TypeScript のパースに Babel を使う

TypeScript のパースに Babel を使う

ソースコードのふりがな生成で TypeScript にもふりがなを振れないかと思って調べたメモ

TypeScript
MS を中心に開発しているオープンソースな言語
通常は tsc (TypeScript Compiler)でコンパイル(→JavaScript)する

Babel 7 からBabel が TypeScript をパースできるようになった
babe-plugin-transform-typescript
babel-preset-typescript も提供されている
オプションによって typescript , jsxPragma , TSX のプラグインが入ったり入らなかったりする
とくに jsxPragma などが必要なければ babel-plugin-transform-typescript だけ入れれば良い
babel-preset-es2015 のように「たくさんのプラグインをまとめたもの」ではない

TypeScript をサポートしよう
babel-types に TypeScript の型定義の実装がある
TS~ から始まる型定義がたくさんある
よく見たら @types/babel-types に全部入ってた!?
全部コピーしたつもりだったのに、抜けていたらしい
これをふりがな生成の Visitor 関数リストに追加すれば辞書を作れる
とりあえずパースできれば一応 TypeScript でも動くことにはなる
その場合は enum とかアノテーションとかが無視されるはず

teramotodaiki Babel が TypeScript をサポートするまでのプロセスが面白い
Issue の流れを軽く読んだ感じだと、キッカケは@drosenwasser(TypeScript Program Manager)達とのやりとり
それとは別の流れとして、 ESLint チームはこれまで独自に TypeScript サポートを行ってきた
TypeScript → typescript-eslint-parser → ESTree → ESLint ルールで構文チェック、という流れ
TSLint というのもあるのだが、そっちは微妙らしい
TypeScriptのLinterはTSLintがデファクトだが、TSLintはESLintと比べて実装されているルールがだいぶ少なかったり、同じルールでも名前が違ったりする。
この手のツールは時代を追っかけながらコミットし続けて行く必要があるので、注目度の高さがツールのクオリティに直結するのだろう。ESLint の方が歴史も長く利用者も圧倒的に多い
つまり TypeScript の構文エラーを見つけるために、TypeScript のパーサの実装が進められていた
#320 で@JamesHenry(MVP of TypeScript)が typescript-eslint-parser について言及している
... just wanted to note in advance that it would be great to avoid duplicating the efforts we have already made on https://github.com/eslint/typescript-eslint-parser, ...
@JamesHenryは ESLint のコミッターでもあり、パーサの実装について Slack にまとめたとも発言している
Babel 6 以前で Babylon は ESTree を読んだり書いたりできなかった(?)
@danezがそれをできるようにした(?)
このPRによって typescript-eslint-parser と連携できるようになり、Babel の骨子を保ったまま、TypeScript のサポートが可能になった(たぶん)
teramotodaiki 「これがオープンソース言語の力か…!!」と実感する出来事
「我々のチームはメンテするリソースを持っていない」と言いながらもこれだけのことを半年足らずでやってのける
むしろリソースの限られた戦い方をしているからこそ Babel はスケールしたのかも知れない


babel-types に書いてあった名前を全部 Visitor 関数に突っ込んでみた
謎のランタイムエラーが出た
real-example.js

/Users/teramotodaiki/github/transform-jp/node_modules/babel-traverse/lib/path/context.js:57

Rejected promise returned by test. Reason:

TypeError {
message: `enter(path, state) {␊
const { line, column } = path.node.loc.start;␊
set(state, line, column, '別の場所からとってこい');␊
} is not iterable!`,
}

NodePath._call (node_modules/babel-traverse/lib/path/context.js:57:135)
NodePath.call (node_modules/babel-traverse/lib/path/context.js:48:17)
NodePath.visit (node_modules/babel-traverse/lib/path/context.js:105:12)
TraversalContext.visitQueue (node_modules/babel-traverse/lib/context.js:150:16)
TraversalContext.visitMultiple (node_modules/babel-traverse/lib/context.js:103:17)
TraversalContext.visit (node_modules/babel-traverse/lib/context.js:190:19)
Function.traverse.node (node_modules/babel-traverse/lib/index.js:114:17)
NodePath.visit (node_modules/babel-traverse/lib/path/context.js:115:19)
TraversalContext.visitQueue (node_modules/babel-traverse/lib/context.js:150:16)
Powered by Helpfeel