LoginSignup
10
11

More than 5 years have passed since last update.

ScalaでTypeScriptをコンパイルできるtypescript4sを作りました。

Last updated at Posted at 2014-05-17

Introduction

元々、typescript4jというTypeScriptをコンパイルできるJavaライブラリがあることを知り興味が湧いたのだが、
型定義ファイルの参照 /// <reference path="typings/jquery/jquery.d.ts" /> があると
コンパイルに失敗するらしく、調べてみた。

試してみるといくつか条件がありそうだったが、
相対パスで指定した型定義ファイルの位置を特定するのがうまくいかない場合があるようだった。
compiler.compile(new File("/Users/zaneli/ws/typescript4j/example.ts"), new File('output.js'));
のように第一引数に指定するtsファイルパスを絶対パスで指定し、
かつその中で参照されている型定義ファイルも同一ディレクトリに配置されている場合には
コンパイルできることが確認できたが、
それ以外の場合には参照しようとしているファイルパスの解決に失敗しているようだった。

typescript4jは内部でtypescript-compileを使用してTypeScriptファイルをコンパイルしており、
(これ以上あまり真面目に調べなかったけど)typescript-compile側で一手間必要なのかな、と思い
それを使わない形でコンパイルしてみたらどうなるかと試してみたのがきっかけ。

結論から言うと、TypeScript公式のコンパイラに使用されている tsc.js を使用することで
型定義ファイルの件については特に何か回避コードを入れるでもなく解決できたようだ。

Work procedure

TypeScript公式ソースコードをダウンロード(最新のリリースブランチっぽい release-1.0.2 を選択した)し、
bin/ディレクトリの tsc.js をScala(JVM)上で動かすためにRhinoを使用した。

動かしてみたところ、プロパティが無い、undefinedのメソッドが呼べないなどのエラーが色々出たので
tsc.js を読みつつトライ&エラーを繰り返す。

TypeScript.EnvironmentTypeScript.IO というオブジェクトを
WSH(Windows Script Host)の場合、node.jsの場合でそれぞれ作成しているようだったが、
Rhinoで動かしているのでどちらのオブジェクトも作成できず、
これらのオブジェクトのプロパティを参照しようとしてエラーが発生しているようだ。
TypeScript4sEnvironment, TypeScript4sIO というobjectを作り、Scalaのメソッドで補う形を取った。
それをTypeScriptCompiler.jsCodesで設定するようにしている。

実行の都度渡されるコンパイル引数は、本当はTypeScript.IOのプロパティのひとつだが、
TypeScript4sIOのこれ以外の値は実行の都度変わるものではないので、
今回はこれのみこんな感じts4sargsという変数に設定することにした。

また、コンパイル時にデフォルトライブラリ lib.d.ts が必要だったので、
これもダウンロードしたソースコードから持ってきた。
tsc.js 実行パスを取得し、その同一ディレクトリにある lib.d.ts を使う、という形で参照していたが、
jarに固めた場合これではうまくいかないだろうと思い、強引なやり方だがこんな感じで読み取った lib.d.ts の内容を渡すようにした。

他、色々無理やりだったり実装がイケてなかったりする箇所があるが、
とりあえず当初やりたかった事ができたので一旦 GitHub に上げた。

Todo

TypeScriptCompiler.jsCodes の設定方法に無理やり感があるので、もっとスマートにしたい。
理想としては、jsコードの上書きは

TypeScriptCompiler.scala
scope.put("TypeScript.Environment", scope, TypeScript4sEnvironment)
scope.put("TypeScript.IO", scope, new TypeScript4sIO(args))
val jsCodes = """
  var batch = new TypeScript.BatchCompiler(TypeScript.IO);
  batch.batchCompile();"""
cx.evaluateString(scope, jsCodes, "compile.js", 1, null)

これだけで済むように TypeScript4sEnvironmentTypeScript4sIO を作り替えたい。
(が、現状上手いやり方が分からなかった…)


コンパイル引数の指定組み立てが冗長でScalaっぽくない気がするので
もっとスッキリさせたい。どうやったら綺麗になるかなー…。


TypeScript.EnvironmentTypeScript.IO の実装が適当(とりあえず動かして、失敗したら付け足す)なので、ちゃんと tsc.js を読んで必要な物を実装する。
コンパイル時に出しているログとかも Scala の logger を呼び出すようにしたい。


Javaの文字列をJavaScriptの文字列に変換するために、空文字を足すといういかにもな回避コードを入れているが、
Rhinoに変換メソッドみたいなのがあるんじゃないかな、と思っているので探してみたい。
Context.javaToJS(javaString) とか new NativeString(javaString) みたいな感じで。
何故こんな変換が必要だったかというと、tsc.jsでString.replace()を呼んでいる箇所があるのだが、
Javaの文字列のままだと replace(char oldChar, char newChar)replace(CharSequence target, CharSequence replacement)
どっちを呼んでいるのか曖昧で分からんとエラーが出たため。
また、String.length もJavaの文字列では呼べないため、
length の値で String.substring を呼んで長さに合わずエラーになる箇所もあり、
現状2箇所でこの回避コードを入れている。
(そもそもJavaからJavaScriptへの変換なんてしなくても対応可能ならそちらを選択したい…)

GitHub Repository

10
11
1

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
10
11