textlintのコアをTypeScriptで書き直した、textlintの今後について
textlint 9.0.0をリリースしました。 textlint 9.0.0では@textlint/kernelという内部的に使うコアモジュールをTypeScriptで書き直したバージョンが使われています。
元々textlintはNode.jsで動くように作られたため、fs
モジュールなどNode.jsに依存しています。
そのため、ブラウザなどで動かす場合などはビルド時に色々工夫しないと動きません。
この問題をどうにかするためには、textlint
というモジュールからロジックやLint処理部分だけをNode.jsなどに依存しない純粋なJavaScriptとして切り出す必要があります。
アドホックに対応するならブラウザ向けのbundleをbrowser fieldなどで提供すれば終わりですが、長期的なことを考えるとモジュールを分けたほうが建設的です。
textlint organizationを見ると分かるようにtextlintはMarkdownパーサやトラバーサ、フォーマッターなどがモジュールとして各リポジトリに分けられていました。部品となるモジュールとリポジトリを1対1で分けると、Aをアップデートすると、Aに依存するBやCを更新するといったアップデートの連鎖反応が起きる問題があります。 また、新しいモジュールを切り出す心理的なコストがありました。
そのため、まずはtextlint
を構成するモジュールを1つのリポジトリにまとめたmonorepo化をすることにしました。
monorepo
textlintではlernaを使ってmonorepo化しています。これにより、モジュール間の依存のアップデートが1つのPRにまとめられるなどアップデートの連鎖反応がある程度自動化できるメリットがあります。 また、新しいモジュールを追加するのも単純にディレクトリを切るだけなので心理的なコストは軽減されます。
- Setup monorepo · Issue #255 · textlint/textlint
- Import * to monorepo · Issue #270 · textlint/textlint
一方、CIにかかる時間やpublishする際のコストは増加する傾向があります。 また、まだmonorepoにおけるリリースノートの戦略がイマイチ決まっていないという問題もあります。 これはalminとかtextlint-rule-preset-googleなど、他にもmonorepoをやっているのでいい方法を見出したいです。
@textlint/kernel
monorepo化がひとまずできたので、textlint 8.1.0でtextlint
モジュールから@textlint/kernelというコアモジュールを切り出しました。(Coreという名前じゃないのは既にCoreという名前を使ったものがあったため)
@textlint/kernelはfs
などNode.js特有のものに依存してないような作りになっているので普通にwebpackやbrowserifyなどでビルドすれば動作します。
今回のtextlint 9.0.0ではさらにこの@textlint/kernelをTypeScriptに書き換えました。理由としては@textlint/kernelはロジックの塊であることと今後のリファクタリングのしやすさを考えたためです。
TL;DR: both Flow and TypeScript are pretty good, and conservatively either of them can prevent about 15% of the bugs that end up in committed code.
https://blog.acolyer.org/2017/09/19/to-type-or-not-to-type-quantifying-detectable-bugs-in-javascript/
JavaScriptに型注釈を加えることで15%程度バグを減らすことができるという話もありますが、IDEなどでリファクタリングがしやすくなるメリットは大きいです。(名前に依存した壊れたリファクタリングが発生しにくい)
JavaScriptからTypeScriptへの移行方法は次の記事で書いてるような手法を取っています。
まだ単に型を付けただけであったり、テストはTypeScriptになってなかったりします。
本体のtextlint
の方もTypeScript化したいので興味がある人は次のIssueを参照してください。
また、まだルール側をTypeScriptで書きやすくなってはいないのでその辺もどうにかしたいですね。
今後
textlintはルールを気軽に作れるようにする土台を作ることが目的です。
今回色々リファクタリングして、@textlint/kernelの分離でLint以外への発展も少し見えてきています。Lintは入力に対して解答(正否)を出さないと行けないですが、textstatのように統計データを出したり、Glosserのようなフィードバックエンジンを作ってみたいです。
また、現在textlintに関係するリポジトリは200以上、textlintルールは100以上あります。 ただ、半分以上は自分が関連しているものなので、もっと属人性を解消して安定させたいです。
textlint 200 repositories. pic.twitter.com/ZpF7DeuSLr
— azu (@azu_re) October 29, 2017
もっと安定して良くしていくために、textlint organizationのコラボレーターを募集しています。最初からコラボレーター(リリース権限とかもてる人)というのも互いに変ではあるので、まずはコントビューションしてくれる人を募集しています。
textlintではどういうところが足りてない、直せるのかなどについて簡単にまとめてみます。
textlintへのコントビューション
相談したいことがある場合はGitterに日本語のchatがあるのでそちらを使ってみてください。 (これどうやって直せばいいのとか?)
textlintを直す
Contributing Guideにコミット方法やテスト方法など一通りのやり方は書いてあります。
ドキュメントを直す
- 適当な英語が多いので修正歓迎
ドキュメントを追加する
- ルールの作り方とかもっと具体例のドキュメント増やしたい
- こういうのがわからないというIssueを立てるでもよさそう
コアを直す
- textlintはmonorepoになっているのでtextlintに色々なパッケージが入っています。
- monorepoへの移行が完璧ではないのでそれをなおすのも歓迎です
- Import * to monorepo #270
label:"good first issue
というラベルが付いてるものは、比較的やることがはっきりしています。
そのため最初のコントビューションとして手が出しやすいかもしれません。
また、textlintはあまりパフォーマンスの最適化がまだ行われていません。markdown-parserなど明らかに無駄な処理をしている部分があります。 一方、500以上のユニットテストや典型的なユースケースのExampleテスト、実際の文章を使ったIntegration testなどが書かれています。 そのため、壊れるとテストが落ちるはずなのでパフォーマンスの改善やリファクタリングなどはある程度し易いかもしれません。
TypeScriptで書きたいという人は、textlint本体もTypeScript化したり、型定義を整理したりすると良いかもしれません。
また、textlintをブラウザでもっと簡単に上手く動かしたいという人は次のIssueにどういうものがあると便利なのかやPOCを作ってみると良いかもしれません。
ルールを直す
- textlintはデフォルトでルールをもっていません
- そのためすべてのルールはプラグイン扱いです
- ルール一覧はCollection of textlint rule · textlint/textlint Wikiにあります
- 各ルールにPull RequestやIssueを立てるのがよさそうです
- textlint-jaで管理している日本語専用のルールは、日本語が分かる人じゃないと使わないので、Issueなどは日本語で問題ないです
ルールを追加する
textlintのルールを置く場所には特に制限はありません。また自由にルールを書けます。
- ルールの作り方: Creating Rules
ただ一度作ったルールがメンテナンスされなくなってしまうのはもったないので、textlint-ruleとtextlint-jaはMaintenance Guidelines for Organizationというガイドラインの元にしています。
人がボトルネックになることを避けるため、人が正しいことをできるように信用することという原則を元にしてリポジトリやnpmパッケージの権限を共有できるようにするという方針です。 そのため、textlintルールを作ったはいいけど置き場所や管理が不安というは、Organizationに参加してみるといいかもしれません。
それぞれoranizationも用意してあるので興味がある人は、@azu_reかGitterで言ってもらえれば inviteします。
- 日本語専用のルール: textlint-ja
- その他のルール: textlint-rule
[email protected]でscoped moduleのサポートを拡張したのもこういったOrganizationでのルール管理のしやすさを改善するためでもあります。
{
"rules": {
"@textlint-rule/preset-google": true
}
}
ルールを紹介する
自分が使っているルールや設定をブログなどで紹介するのも貢献です。
ツールを良くする
textlintのElectronアプリがありますがそこまで作り込まれてません。
- textlintのElectronアプリを作った | Web Scratch
- textlint/textlint-app: textlint standalone application top on Electron.
textlintのルールをコマンド一発で作り始めることができるツールがあります。 コーパスを使ってルールをチェックしやすくするなどもっと色々な工夫をして、ルールづくりを簡単にできると嬉しいです。
- textlintのルールを簡単に作り始めることができるツールを作りました | Web Scratch
- textlint/create-textlint-rule: Create textlint rule project with no configuration.
- textlint-ja/technological-book-corpus-ja: 日本語で書かれた技術書のコーパス
ウェブサイト
textlintのウェブサイト兼オンラインデモとしてtextlint - pluggable linting tool for text and markdownがあります。
こちらもlabel:"good first issue"
のラベルがついたIssueがあります。
その他
textlintの直し方に簡単にコントビューション方法についてまとめています。
お知らせ欄
JavaScript Primerの書籍版がAmazonで購入できます。
JavaScriptに関する最新情報は週一でJSer.infoを更新しています。
GitHub Sponsorsでの支援を募集しています。