ラベル TypeScript の投稿を表示しています。 すべての投稿を表示
ラベル TypeScript の投稿を表示しています。 すべての投稿を表示

2012年12月24日月曜日

Sublime Text 2 で TypeScript の開発環境を整える

このエントリは Sublime Text 2 Advent Calendar 2012 用です。

---

TypeScript については公式サイトなどを見てください。

Sublime Text 2 で TypeScript を開発するためのこまごましたチップスをブログに書いてきたので、一旦まとめたいと思います。


1. TypeScript ファイル(.ts)をシンタックスハイライトするようにする

「Y.A.M の雑記帳 - Sublime Text 2 に TypeScript の syntax highlighting を入れる」 を見よう!


2. TypeScript の補完がでるようにする

「Y.A.M の雑記料 - Sublime Text 2 で TypeScript の補完を出すプラグイン作った」 を見よう!

補完は以下のコマンドで出ます(標準機能)。

Linux : alt + /
Mac : command + space


3. TypeScript ファイルをビルドできるようにする

「Y.A.M の雑記帳 - Sublime Text 2 で TypeScript をビルドする」 を見よう!

ビルドは以下のコマンドで実行できます。

Linux : ctrl + b
Mac : command + b


4. ファイル保存時に自動でビルドさせる

「Y.A.M の雑記帳 - Sublime Text 2 でファイル保存時に自動でビルドさせる」 を見よう!


5. ctrl + / (Mac は command + /)でコメントをトグルさせる

「Y.A.M の雑記帳 - Sublime Text 2 で .ts ファイルでも Ctrl + / でコメントをトグルできるようにする」 を見よう!


6. TypeScript 用のスニペットを作る

JavaScript 用にあらかじめ用意されているスニペットがいくつかあります。

([Preferences] - [Browse packages...])/JavaScript/ の中をみると .sublime-snippet ファイルがこれだけあります。
  • for-()-{}.sublime-snippet
  • for-()-{}-(faster).sublime-snippet
  • function.sublime-snippet
  • function-(fun).sublime-snippet
  • Get-Elements.sublime-snippet
  • if.sublime-snippet
  • if-___-else.sublime-snippet
  • Object-key-key-value.sublime-snippet
  • Object-Method.sublime-snippet
  • Object-Value-JS.sublime-snippet
  • Prototype-(proto).sublime-snippet
  • setTimeout-function.sublime-snippet


例えば、for-()-{}.sublime-snippet の中身は次のようになっています。

for source.js for (…) {…}

scope で指定されている拡張子のファイルで、tabTrigger で指定されている単語の後に Tab を押すと、content で指定されているスニペットに置き換わります。Tab を押したときに候補が複数ある場合は、補完候補ウィンドウに description が表示されます。

tabTrigger に for を指定しているスニペットが
・for-()-{}.sublime-snippet
・for-()-{}-(faster).sublime-snippet
の2つあるため、次のように候補が2つ表示されます。



上部の候補を選ぶと次のように for 文のスニペットに置き換わります。



これらの補完を TypeScript でも使えるようにしてみます。

・for

せっかくなので、TypeScript の特徴である型情報を付加して、var i を var i : number にします。 scope タグを source.ts にするのを忘れずに。 このファイルを ([Preferences] - [Browse packages...])/TypeScript/ に置きます。

TypeScript/for-()-{}.sublime-snippet
<snippet> <content><![CDATA[for (var ${20:i} : number = 0; ${20:i} < ${1:Things}.length; ${20:i}++) { ${100:${1:Things}[${20:i}]}$0; }]]></content> <tabTrigger>for</tabTrigger> <scope>source.ts</scope> <description>for (…) {…}</description> </snippet>
他のも TypeScript 用にします。

TypeScript/for-()-{}-(faster).sublime-snippet
<snippet> <content><![CDATA[for (var ${20:i} : number = ${1:Things}.length - 1; ${20:i} >= 0; ${20:i}--) { ${100:${1:Things}[${20:i}]}$0; }]]></content> <tabTrigger>for</tabTrigger> <scope>source.ts</scope> <description>for (…) {…} (Improved Native For-Loop)</description> </snippet>

・function

TypeScript では無名関数は
(x) => x*x;
のように記述するので、function.sublime-snippet は次のようにしました。

TypeScript/function.sublime-snippet
<snippet> <content><![CDATA[($1) => {${0:$TM_SELECTED_TEXT}};]]></content> <tabTrigger>f</tabTrigger> <scope>source.ts</scope> <description>Anonymous Function</description> </snippet>

TypeScript/function-(fun).sublime-snippet
<snippet> <content><![CDATA[function ${1:function_name} (${2:argument} : ${3:type}) : ${4:return_type} { ${0:// body...} }]]></content> <tabTrigger>fun</tabTrigger> <scope>source.ts</scope> <description>Function</description> </snippet>

・get elements

TypeScript/Get-Elements.sublime-snippet <snippet> <content><![CDATA[getElement${1/(T)|.*/(?1:s)/}By${1:T}${1/(T)|(I)|.*/(?1:agName)(?2:d)/}('$2')]]></content> <tabTrigger>get</tabTrigger> <scope>source.ts</scope> <description>Get Elements</description> </snippet>

・if

TypeScript/if.sublime-snippet
<snippet> <content><![CDATA[if (${1:true}) { ${0:$TM_SELECTED_TEXT} }]]></content> <tabTrigger>if</tabTrigger> <scope>source.ts</scope> <description>if</description> </snippet>

TypeScript/if-___-else.sublime-snippet
<snippet> <content><![CDATA[if (${1:true}) { ${2:$TM_SELECTED_TEXT} } else { ${3:$TM_SELECTED_TEXT} }]]></content> <tabTrigger>ife</tabTrigger> <scope>source.ts</scope> <description>if … else</description> </snippet>

Object-key-key-value.sublime-snippet, Object-Method.sublime-snippet, Object-Value-JS.sublime-snippet は JavaScript でもうまく動いていないのでスキップ。


・function

TypeScript/setTimeout-function.sublime-snippet
<snippet> <content><![CDATA[setTimeout(function() {$0}${2:}, ${1:10});]]></content> <tabTrigger>timeout</tabTrigger> <scope>source.ts</scope> <description>setTimeout function</description> </snippet>


TypeScript では、class や module が使えます。
これら用のスニペットも用意しましょう(これらに置き換えるので Prototype-(proto).sublime-snippet はスキップ)

・class

"class" + tab

TypeScript/class.sublime-snippet
<snippet> <content><![CDATA[class ${1:className} extends ${2:superClass} implements ${3:interface} { ${4:varName} : ${5:varType}; ${6:funcName}(${7:arg} : ${8:argType}) : ${9:returnType} { ${10} } constructor(${11:arg} : ${12:argType}) { ${13:super();} } static ${21:varName} : ${22:varType}; static ${23:funcName}(${24:arg} : ${25:argType}) : ${26:returnType} { ${27} } }]]></content> <tabTrigger>class</tabTrigger> <scope>source.ts</scope> <description>class</description> </snippet>

・module

"module" + tab

TypeScript/module.sublime-snippet
<snippet> <content><![CDATA[module ${1:moduleName} { ${0:$TM_SELECTED_TEXT} }]]></content> <tabTrigger>module</tabTrigger> <scope>source.ts</scope> <description>module</description> </snippet>

・interface

"interface" + tab

TypeScript/interface.sublime-snippet
<snippet> <content><![CDATA[interface ${1:interface-name} { ${0:$TM_SELECTED_TEXT} }]]></content> <tabTrigger>interface</tabTrigger> <scope>source.ts</scope> <description>interface</description> </snippet>

・Index Signature

"index" + tab

var dic : { [index : string] : type; } = {};

TypeScript/index-signature.sublime-snippet
<snippet> <content><![CDATA[var dic : { [index : ${1:string}] : ${2:type}; } = {};]]></content> <tabTrigger>index</tabTrigger> <scope>source.ts</scope> <description>Index Signature</description> </snippet>

・reference

"reference" + tab

/// <reference path="…"/>

TypeScript/reference.sublime-snippet
]]> reference source.ts reference

その他に以下も用意してみました。

・Array

"array" + tab

var array : type[] = [];

TypeScript/array.sublime-snippet <snippet> <content><![CDATA[var array : ${0:type}[] = [];]]></content> <tabTrigger>array</tabTrigger> <scope>source.ts</scope> <description>Array</description> </snippet>

これで
  • array
  • class
  • for
  • function
  • get
  • if
  • index
  • interface
  • module
  • reference
  • timeout
でスニペット補完がでます。

ここから全部のファイルをコピーするのは面倒だと思うので、TypeScript フォルダを zip にしました。
ここからどうぞ TypeScript.zip



2012年12月19日水曜日

Sublime Text 2 で .ts ファイルでも Ctrl + / でコメントをトグルできるようにする

JavaScript の設定をそのまま流用します。

([Preferences] - [Browse Packages...]) /JavaScript/Comments.tmPreferences



([Preferences] - [Browse Packages...]) /TypeScript/

にコピー。

開いて、

<key>scope</key>
<string>source.js, source.json</string>



<key>scope</key>
<string>source.ts</string>

に変更し、Sublime Text 2 を再起動。これだけ!


2012年12月12日水曜日

モダンな TypeScript テスト環境

「これが現代のテスト環境や、どやぁ。」 と @vvakame が用意してくれました。 https://github.com/vvakame/typescript-project-sample

初心者の私にはたくさんのライブラリ(フレームワーク?)が入っててよくわからなかったので、それぞれの立ち位置を教えてもらったのでまとめておきます。


PhantomJS

PhantomJS は JavaScript の API も利用できる headless な WebKit です。実際の描画処理を行わないので速いという特徴があります。また、DOM 操作、CSS セレクタ、JSON、Canvas、SVG などいくつかの web 標準をネイティブでサポートしています。
JavaScript のエンジンは JavaScriptCore らしいです。

実際に Web ページにアクセスして、レンダリング結果の画面のキャプチャをとったり、ページのタイトルを取ってきたり、DOM の値を取ってきたり、いろいろできます。

Quick Start を見ると何ができるかが分かると思います。

例えば、

evaluate.js var url = "http://www.google.com"; var page = require("webpage").create(); page.open(url, function(status) { var title = page.evaluate(function() { return document.title; }); console.log("Page title is " + title); phantom.exit(); }); というコードを書いて実行すると、ページのタイトルを取れます。

$ phantomjs evaluate.js
Page title is Google
サンプルもたくさん用意されています。



Jasmine

Jasmine は JavaScript コードをテストするためのフレームワークです。 使い方は Introduction のコードを見るのがわかりやすいです。その他の情報は Wiki にあります。

最新版は Jasmine 1.3.1 で https://github.com/pivotal/jasmine/downloads からダウンロードできます。

jasmine-standalone-1.3.1.zip を展開すると、次のような構成になっています。

lib/
spec/
src/
SpecRunner.html
lib/ には jasmine.js や jasmine-html.js が入っています。

SpecRunner.html は jasmine を使ったテストのサンプルです。
基本的には、この SpecRunner.html を自分のプロジェクトに合わせて変えることでテストをセットアップできます。

SpecRunner.html で Player.js, Song.js が指定されている部分 にテストしたい元コードを、
SpecHelper.js, PlayerSpec.js が指定されている部分に テストコードを置きます。

下の方の Javascript のコードは window.onload でテストを実行し、結果を html に表示するための部分なので変更はいらいないです。 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Jasmine Spec Runner</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.3.1/jasmine_favicon.png"> <link rel="stylesheet" type="text/css" href="lib/jasmine-1.3.1/jasmine.css"> <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine.js"></script> <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine-html.js"></script> <!-- include source files here... --> <script type="text/javascript" src="src/Player.js"></script> <script type="text/javascript" src="src/Song.js"></script> <!-- include spec files here... --> <script type="text/javascript" src="spec/SpecHelper.js"></script> <script type="text/javascript" src="spec/PlayerSpec.js"></script> <script type="text/javascript"> (function() { var jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000; var htmlReporter = new jasmine.HtmlReporter(); jasmineEnv.addReporter(htmlReporter); jasmineEnv.specFilter = function(spec) { return htmlReporter.specFilter(spec); }; var currentWindowOnload = window.onload; window.onload = function() { if (currentWindowOnload) { currentWindowOnload(); } execJasmine(); }; function execJasmine() { jasmineEnv.execute(); } })(); </script> </head> <body> </body> </html> この SpecRunner.html をブラウザで開くと、このようにテスト結果が表示されます。

Jasmine は JavaScript で構築されているため、Jasmine を実行するには、web page など JavaScript が実行できる環境にいなければいけません。

しかし、この JavaScript を実行するのに毎回ブラウザを立ち上げていたらテストに時間がかかってしまいます。そこで上記の PhantomJS の登場です。

追記 : X Windowとか動いてないLinux機上(大抵のJenkins氏が動いてるサーバはそういう環境)の上で、ブラウザを使ってテストしたいなーというのもある by @vvakame

例えば、
test-jasmine1.js var url = "file:///home/yanzm/Downloads/jasmine-standalone-1.3.1/SpecRunner.html" var page = require("webpage").create(); page.onConsoleMessage = function (msg) { if(msg == "finish-jasmine") { phantom.exit(); } else if(msg != "\n") { console.log(msg); } }; page.open(url, function(status) { page.evaluate(function() { var jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000; var consoleReporter = new jasmine.ConsoleReporter( function(log) { console.log(log); }, function(runner) { console.log("finish-jasmine"); }, false); jasmineEnv.addReporter(consoleReporter); jasmineEnv.execute(); }); }); SpecRunner.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Jasmine Spec Runner</title> <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine.js"></script> <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine-console.js"></script> <!-- include source files here... --> <script type="text/javascript" src="src/Player.js"></script> <script type="text/javascript" src="src/Song.js"></script> <!-- include spec files here... --> <script type="text/javascript" src="spec/SpecHelper.js"></script> <script type="text/javascript" src="spec/PlayerSpec.js"></script> </head> <body> </body> </html> (jasmine-console.js の中身は ConsoleReporter.js です。)

のようにすると、コンソールからテストできるようになります。
$ phantomjs test-jasmin1.js 
Started
.
.
.
.
.
Finished in 0.005 seconds
5 specs, 0 failures



grunt

grunt は要は make みたいなものです。

makegrunt
Makefilegrunt.js
make hogegrunt hoge


gruntfile と呼ばれる grunt.js に設定を書いていきます。
Getting Started を見るとなんとなく書き方がわかると思います。

grunt は実行時にカレントディレクトリの grunt.js を見に行くのですが、ない場合は見つけるまで親のディレクトリを遡って探します。普通はプロジェクトリポジトリのルートに置きます。
grunt.js は次の3つの要素からなる JavaScript です。
  • プロジェクトの設定(依存しているライブラリのダウンロードなど)
  • grunt のプラグインやタスクフォルダの読み込み
  • タスクとヘルパー
プロジェクトの設定は grunt.initConfig() で行います。
プラグインやタスクフォルダの指定は grunt.loadTasks() や grunt.loadNpmTasks() で行います。
タスクやヘルパーの指定は grunt.registerTask() で行います。

module.exports = function(grunt) { // Project configuration. grunt.initConfig({ lint: { all: ['grunt.js', 'lib/**/*.js', 'test/**/*.js'] }, jshint: { options: { browser: true } } }); // Load tasks from "grunt-sample" grunt plugin installed via Npm. grunt.loadNpmTasks('grunt-sample'); // Default task. grunt.registerTask('default', 'lint sample'); }; 各 grunt タスクは、grunt.initConfig() に渡されるオブジェクトで定義されている情報に依存します。
このオブジェクトは JavaScript であって JSON ではないので、プログラムで設定オブジェクトを生成させるようなこともできます。
ビルトインのタスクの設定オブジェクトの詳細は Document の Built-in tasks にあります。


フォルダからタスクやヘルパーを読み込むには
grunt.loadTask(folderName);
を使います。

npm を介して grunt のプラグインを読み込むには
grunt.loadNpmTasks(pluginName)
で行います。


grunt.registerTask() で default タスクを設定するまで、単に grunt を実行してもになにも起こりません。

grunt.registerTask('default', 'hoge_task fuga_task');

のように default タスクを登録すると

$ grunt
$ grunt default

と実行したときに第2引数で指定したタスクが実行されます。
上記の場合

$ grunt hoge_task fuga_task

と実行した場合と同じになります。

grunt.registerTask('test', 'hoge_test fuga_test');

のように、好きな alias を登録できます。
この場合、

$ grunt test

とすれば

$ grunt hoge_test fuga_test

と実行したのと同じになります。

init task(ビルトインのタスク)を見てみると、grunt による project の構成がだいだいわかると思います。



まとめ

@vvakame のプロジェクトの grunt.js では以下のライブラリを使っています。

まとめると、
grunt でディレクトリの clean、typescript や less のコンパイル、jasmine の設定など

jasmine で phantomJS を使ってテスト

結果が JUnit 形式の XML で出力される(出力先は grunt.js で設定)

という流れです。



2012年12月7日金曜日

TypeScript での Type Assertion

document.getElementById("#input"); の戻り値は HTMLElement なので var input : HTMLInputElement = document.getElementById("#input"); とすると、キャストできないと怒られます。
Cannot convert 'HTMLElement' to 'HTMLInputElement': Type 'HTMLElement' is missing property 'setSelectionRange' from type 'HTMLInputElement'

そこで、次のように < > を使ってキャストすれば怒られなくなります。 var input : HTMLInputElement = <HTMLInputElement>document.getElementById("#input");

2012年12月6日木曜日

TypeScript で jQuery を使う (Sublime Text 2 で jquery の補完)

TypeScript で jQuery を使うには、jQuery の型を定義したファイルが必要です。

TypeScript のコードと一緒に公開されているので、ダウンロードして作業フォルダに入れます。
jquery.d.ts

現状は // Typing for the jQuery library, version 1.7.x とあるので、1.7.x の jQuery に対応しているようです。


次に、自分の .ts ファイルの先頭に
/// <reference path="jquery.d.ts" /> を追加します。これは外部の ts ファイルを読み込むための書き方です。

で、ここで気づきました。Sublime Text 2 で jquery の補完がでません。。。

以前作ったプラグイン(Sublime Text 2 で TypeScript の補完を出すプラグイン作った")を修正しないといけない(修正すれば jquery、というか reference で指定してるファイルの補完がでる)ということにも気づきました。

ということで修正しました。
現在の tsc_completion のバージョンは v1.0.3 になってます。
Sublime Text 2 のプラグインのコードも新しくなっているので、こちらも置き換えてください。

こんな感じで補完がでます。



例えば、こういうのが
/// <reference path="jquery.d.ts" /> var questionArea : JQuery; var inputArea : JQuery; var star1 : JQuery; var star2 : JQuery; var star3 : JQuery; ... $(document).ready(function () { inputArea = $("#text_area"); inputArea.keyup(onInput); questionArea = $("#question_area"); star1 = $("#star1"); star2 = $("#star2"); star3 = $("#star3"); inputArea.focus(); // show first text showNextText(); })
こういうのに変換されます。
var questionArea; var inputArea; var star1; var star2; var star3; ... $(document).ready(function () { inputArea = $("#text_area"); inputArea.keyup(onInput); questionArea = $("#question_area"); star1 = $("#star1"); star2 = $("#star2"); star3 = $("#star3"); inputArea.focus(); showNextText(); }); クラスとか使ってないからそのままだねw


jquery で HTMLInputElement にあたる要素で focus() 呼んでもフォーカスあたらないのはなんでなんだ。。。

jquery 1.8.3 にしたら直った


TypeScript で SourceMap を使う

tsc コマンドに --sourcemap をつけてコンパイルすることで SourceMap ファイル(hoge.js.map)と、SourceMap の情報が書かれた js ファイルが作成されます。
> tsc --sourcemap hoge.ts

> ls
hoge.ts  hoge.js  hoge.js.map

> tail -1 hoge.js
//@ sourceMappingURL=hoge.js.map


この SourceMap を使って Chrome でデバッグするには、Chrome Dev Tool を開いて(右クリックして Inspect Element をクリック or Ctrl + Shif + i (Mac は Command + option + i))、右下の設定(歯車アイコン)をクリックします。



General タブの Enable source maps にチェックを入れます。



リロードすると、Sources で .ts が選択できるようになります。
# なんで .js が2つでてるのかは謎



.ts のほうの行数のところをクリックして Breakpoint を設定できます。



.ts の方の Breakpoint で止まります。




# .ts のほうでうまく Breakpoint が動くときと、なぜか Breakpoint の対応する js 側の行で止まることがあり、まだ SourceMap はうまく動かないのかもしれない。。。


2012年12月2日日曜日

TypeScript でタグ属性値の操作

helloworld2.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>hello world 2</title> <style type="text/css"> #box { width: 150px; height: 150px; border: 1px solid #4c4c4c; } .red { background-color: #ffcccc; } .blue { background-color: #ccccff;} </style> </head> <body> <h1>Hello World 2</h1> <div id="box"> Hello World 2 </div> <img id="shape" src="circle.png"></img> <br /> <br /> <input type="button" value="get attributes" id="button1"> <script src="helloworld2.js"></script> </body> </html>

helloworld2.ts function boxOver(e : MouseEvent) { box.className = "red"; } function boxNormal(e : MouseEvent) { box.className = "blue"; } function shapeOver(e : MouseEvent) { image.src = "star.png"; } function shapeNormal(e : MouseEvent) { image.src = "circle.png"; } function getAttributes(e : MouseEvent) { var attrs : Attr[] = box.attributes; var msg = ""; for(var i = 0; i < attrs.length; i++) { var attr = attrs[i]; msg = msg + attr.nodeName + ":" + attr.nodeValue + "\n"; } alert(msg); } var box : HTMLElement = document.getElementById("box"); box.addEventListener("mouseover", boxOver, false); box.addEventListener("mouseout", boxNormal, false); var image : HTMLImageElement = <HTMLImageElement>document.getElementById("shape") image.addEventListener("mouseover", shapeOver, false); image.addEventListener("mouseout", shapeNormal, false); var btn1 : HTMLElement = document.getElementById("button1"); btn1.addEventListener("click", getAttributes, false);

HTMLElement の attributes は Attr[] という配列になる。

TypeScript で DOM 操作

helloworld1.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>hello world 1</title> </head> <body> <h1>Hello World 1</h1> <input type="button" id="button1" value="pick h1 tag text" /> <br /> <br /> <div id="authors"> <div>芥川 竜之介</div> <div>夏目 漱石</div> <div></div> <div>江戸川 乱歩</div> </div> <input type="button" id="button2" value="pick all authors" /> <script src="helloworld1.js"></script> </body> </html>

helloworld1.ts function helloworld1(e : MouseEvent) { var h1Elm : Node = document.getElementsByTagName('h1')[0]; var textNode : Node = h1Elm.childNodes[0]; var text : string = textNode.nodeValue; alert(text); } function helloworld2(e : MouseEvent) { var authorsElem : Node = document.getElementById('authors'); var authors = new Array(); for (var i = 0; i < authorsElem.childNodes.length; i++) { var node = authorsElem.childNodes.item(i); if(node.nodeType != 1) { continue; } if(!node.hasChildNodes()) { continue; } if(node.firstChild.nodeType != 3) { continue; } authors.push(node.firstChild.nodeValue); } alert(authors.join("\n")); } var btn1 : HTMLElement = document.getElementById("button1"); btn1.addEventListener("click", helloworld1, false); var btn2 : HTMLElement = document.getElementById("button2"); btn2.addEventListener("click", helloworld2, false);
ノードの種類nodeTypenodeNamenodeValue
要素ノード1タグ名null
属性ノード2属性名属性値
テキストノード3#textテキストの内容
コメントノード8#commentコメントの内容
ドキュメントノード9#documentnull

2012年11月27日火曜日

Sublime Text 2 で TypeScript をビルドする

Sublime Text 2 に TypeScript の Build System を作ります。

[Tools] → [Build System] → [New Build System...]

TypeScript.build-system という名前で以下を保存
(パッケージフォルダのしたの User/ の保存される)

{ "cmd": ["tsc","$file"], "file_regex": "(.*\\.ts?)\\s\\(([0-9]+)\\,([0-9]+)\\)\\:\\s(...*?)$", "selector": "source.ts", "osx": { "path": "/usr/local/bin:/opt/local/bin" }, "linux": { "path": "/usr/local/bin:/usr/bin" } } TypeScript でのビルドを明示したいなら、[Tools] → [Build System] → [TypeScript] を選択する。
Auto のままでも拡張子が .ts なら TypeScript でビルドされる。

[Tools] → [Build] もしくは Ctrl (Mac は Command) + B でビルド



var を ver とタイポしたときのエラー表示



file_regex は tsc のエラーの正規表現にする。



解説は以下↓


Build Systems

Sublime Text には、外部のプログラムにファイルをかませる機能があります。

独自の Build System を作るには以下のステップを行います。
  • オプション : 外部の実行可能ファイル(スクリプトやバイナリファイル)を用意する
  • .sublime-build という拡張子の設定ファイル(JSON 形式で記述する)を用意する
  • ビルドを開始する Sublime Text のコマンドを用意する
デフォルトでは build systems は Packages/Default/exec.py に実装されている exec コマンドを使います。このコマンドをオーバーライドすることができます。

.build-system ファイルの例 { "cmd": ["python", "-u", "$file"], "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", "selector": "source.python" }

オプション
  • cmd
    実行するコマンドと必要な引数が入った配列。
    フルパスを指定しなかった場合、システムの環境変数 PATH から外部のプログラムが検索される。

  • file_regex
    オプション。
    cmd のエラー出力をキャプチャするための正規表現。

  • line_regex
    オプション。
    もし file_regex が現在のラインとマッチせず、line_regex が存在して現在のラインとマッチするなら、file_regex とマッチするラインが見つかるまでバッファ使って遡り、これら2つのマッチを使って進むべきファイルとラインを決定する

  • selector
    オプション。
    [Tools] → [Build System] → [Automatic] が true にセットされているときに利用される。
    Sublime Text はアクティブな View 用の適切な build system を見つけるためにこのスコープセレクターを使う。

  • working_dir
    オプション。
    cmd を走らせる前に変更するカレントディレクトリとして変更するディレクトリ。
    元のカレントディレクトリは後でリストアされる。

  • encoding
    オプション。
    cmd の出力エンコーディング。有効な python エンコーディングでなければならない。デフォルトは UTF-8。

  • target
    オプション。
    実行する Sublime Text コマンド。デフォルトは exec (Packages/Default/exec.py)。

  • env
    オプション。
    現在のプロセスの環境変数が cmd に渡されるまえに、現在のプロセスの環境変数にマージされる環境変数の Dictonary。

  • shell
    オプション。
    true の場合、cmd は shell を介して実行される。

  • path
    オプション。
    cmd が呼ばれる前に、現在のプロセスの PATH がこの文字列に置き換わる。
    元の PATH の値は後でリストアされる。

  • variants
    オプション。
    メインの build system のオプションを上書きするオプションの Dictionary のリスト。

  • name
    variants の内部でだけ有効。
    variant build system を識別する。
    name が Run の場合、variant は Tools | Build System メユーの下に表示され、Ctrl + Shift + B がバインドされる。


プラットフォーム独自のオプション
  • windows
  • osx
  • linux
{ "cmd": ["ant"], "file_regex": "^ *\\[javac\\] (.+):([0-9]+):() (.*)$", "working_dir": "${project_path:${folder}}", "selector": "source.java", "windows": { "cmd": ["ant.bat"] } }

Variants

{ "selector": "source.python", "cmd": ["date"], "variants": [ { "cmd": ["ls -l *.py"], "name": "List Python Files", "shell": true }, { "cmd": ["wc", "$file"], "name": "Word Count (current file)" }, { "cmd": ["python", "-u", "$file"], "name": "Run" } ] }

Build System の変数
  • $file_path
    現在のファイルのディレクトリ 例) /Files/
  • $file
    現在のファイルのフルパス 例)/Files/File.txt
  • $file_name
    現在のファイルの名前 例) File.txt
  • $file_extension
    現在のファイルの拡張子 例) .txt
  • $file_base_name
    現在のファイルの名前部分 例) File.
  • $packages
    パッケージフォルダへのフルパス
  • $project
    現在のプロジェクトファイルへのフルパス
  • $project_path
    現在のプロジエクとファイルのディレクトリ
  • $project_name
    現在のプロジェクトファイルの名前
  • $project_extension
    現在のプロジェクトファイルの拡張子
  • $project_base_name
    現在のプロジェクトファイルの名前部分


Build System を実行する

[Tools] → [Build System] から実行したい build system を選択して、[Tools] → [Build] を選択するか Ctrl (Command) + B を押す。



Sublime Text 2 に TypeScript の syntax highlighting を入れる

Interoperability @ Microsoft MSDN Blogs - Sublime Text, Vi, Emacs: TypeScript enabled!
で Sublime Text のアイコンをクリックして zip ファイルをダウンロード

展開すると
  • README-sublime-typescript.txt
  • typescript.tmLanguage
が得られる

Sublime Text の syntax highlighting の作り方は
http://docs.sublimetext.info/en/latest/extensibility/syntaxdefs.html
にあり、自分で作成する場合は以下のようにするが、

JSON 形式で記述
 ↓
.tmLanguage ファイル(XML形式)に変換する

上記のエントリでは .tmLanguage の状態のものを提供しているので、Sublime Text を起動して [Preferences] - [Browse Package...] で開くフォルダ(私の場合(Ubuntu)は ~/.config/sublime-text-2/ だった)に TypeScript フォルダを作成し、そのなかに typescript.tmLanguage ファイルをコピーして Sublime Text を再起動すれば OK.


2012年11月21日水曜日

Ubuntu に Typescript をインストールした

Synaptic Package Manager で
  • npm
  • nodejs
をインストール

> npm install -g typescript
すると
npm ERR! couldn't read package.json in .
npm ERR! Error installing .
npm ERR! Error: ENOENT, No such file or directory 'package.json'
npm ERR! Report this *entire* log at 
npm ERR! or email it to 
npm ERR! Just tweeting a tiny part of the error will not be helpful.
npm not ok

と言われる。

どうもインストールした npm のバージョンが古かったようだ

github : isaacs / npm - couldn't read package.json in .

1.x をインストールしないといけないらしい
Synaptic から入れた node.js も古かった

ということで node.js と npm を一旦アンインストールし、コメントの最後のほうで isaacs さんが紹介している https://launchpad.net/~chris-lea/+archive/node.js/ からインストール

そのためにまず ppa:chris-lea/node.js を PPA(Personal Package Archive) に追加

> sudo add-apt-repository ppa:chris-lea/node.js

You are about to add the following PPA to your system:
 node.js
 Evented I/O for V8 javascript. Node's goal is to provide an easy way to build scalable network programs
 More info: https://launchpad.net/~chris-lea/+archive/node.js
Press [ENTER] to continue or ctrl-c to cancel adding it

gpg: keyring `/tmp/tmpIBxqM3/secring.gpg' created
gpg: keyring `/tmp/tmpIBxqM3/pubring.gpg' created
gpg: requesting key C7917B12 from hkp server keyserver.ubuntu.com
gpg: /tmp/tmpIBxqM3/trustdb.gpg: trustdb created
gpg: key C7917B12: public key "Launchpad chrislea" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK

> sudo apt-get update
次に node.js と npm をインストール

> sudo apt-get install nodejs
> sudo apt-get install npm

> npm -v
1.1.65
よしよし

ようやく

>  npm install -g typescript
npm http GET https://registry.npmjs.org/typescript
npm http 200 https://registry.npmjs.org/typescript
npm http GET https://registry.npmjs.org/typescript/-/typescript-0.8.1.tgz
npm http 200 https://registry.npmjs.org/typescript/-/typescript-0.8.1.tgz
npm ERR! Error: EACCES, mkdir '/usr/lib/node_modules'
...
キターとおもったらエラー orz

> sudo npm install -g typescript
npm http GET https://registry.npmjs.org/typescript
npm http 304 https://registry.npmjs.org/typescript
/usr/bin/tsc -> /usr/lib/node_modules/typescript/bin/tsc
[email protected] /usr/lib/node_modules/typescript
はいったぽい?

Tutorial のコードを書いて

> cat greeter.ts 
function greeter(person) {
    return "Hello, " + person;
}

var user = "Jane User";

document.body.innerHTML = greeter(user);

> tsc greeter.ts 
怒られなかったー

> ls
greeter.js  greeter.ts
js ファイルできてるー