この記事は 弁護士ドットコム Advent Calendar 2022 の 11 日目の記事です。
はじめに
皆さんは textlint を使っていますか?
ESLint を始めとした Linter は、ソースコードを静的解析してバグになりそうな記法やコーディングルールに則っていない部分を指摘・修正してくれます。
textlint は名前の通り text、つまりプレーンテキストや Markdown などの Linter です。
また、先日 Lint Night #1 という勉強会があり、そこで作者の azu さんが発表されていました。
自分は参加できなかったのですが、発表されていたスライドがあるので、こちらもぜひご覧ください!
活用事例
弊社でも textlint を活用していて、Slack のチャットボット「凛さん」が稼働しています。
今年は 13 日担当の @shellme が、去年の Advent Calendar で書いた記事があるので、詳しくはこちらをご覧ください!
こちらの記事が公開されて本運用が開始してから 1 年経過しましたが、現在でも継続的に使われています。
実際に使っている図。
自分でも拡張してみたい
textlint を自分も含めて周囲が使っているので、それをもっと活用できないかと考えたとき、「ルールを自分で追加できたら面白いのでは?」と思い立って作ってみることにしました。
作ったもの
設定に記述した URL に該当するリンクがあったら警告してくれるルールです。
例えば ^http://
と設定しておけば HTTPS でないリンクを警告してくれますし、^https?://localhost
と設定しておけば パブリックでないリンクを警告してくれます。
設定次第では、URL ではないもの(ファイルパスなど)を記述してしまうことも避けられそうですね。
実際に作ってみた
事前準備
まずルールの名前を決めます。
近い働きをするルールとして ESLint の @typescript-eslint/ban-types があったので、これに則って ban-links
としてみました。
次に、textlint のルールを開発するためのプロジェクトを作ります。
公式がテンプレートを公開してくれているので、こちらを使用しました。
# 出力は抜粋
$ npx create-textlint-rule textlint-rule-ban-links --typescript
# プロジェクトの設定を入力する
Press ^C at any time to quit.
package name: (textlint-rule-ban-links)
version: (1.0.0)
description: This rule bans links with URLs of the specified patterns.
git repository: https://github.com/tee-talog/textlint-rule-ban-links
author: tee-talog
license: (ISC) MIT
Is this OK? (yes)
Wait... Installing npm packages for development
✔ Complete: Lets write textlint rule
$ cd textlint-rule-ban-links
$ ls
README.md lib node_modules package-lock.json package.json src test tsconfig.json
テンプレートの内容を見てみる
初期状態では、bugs
という文字列が入ってたら、Found bugs.
と出力してその位置を表示してくれるもののようでした。
テストが内蔵されていて、コマンドひとつで正しく実装できているかチェックできます。
アサーションメッセージや位置までしっかりテストできるのでとても開発しやすいです。
$ npm run test
rule
✔ It is bugs.
✔ It has many bugs.
One more bugs
✔ text
✔ It is bugs, but it should be ignored
4 passing (37ms)
ルールの本体は src/index.ts
、テストは test/index-test.ts
です。
実際にルールを変更してみる
実装の第 1 段階として、リンクを検出したらエラーを出すようにしてみました。
diff
テストを実行してみるとすべて通っているようです。
$ npm run test
ban-links
✔ [text](https://example.com)
✔ plain text
次に、固定の URL(http://example.com*
)エラーとするようにしてみました。
引数にノードに関する情報が渡ってくるので、そこから必要な情報を参照します。
今回は url
プロパティを参照しています。
diff
最後に、textlint の config で設定した値を参照して警告を出すようにしました。
options
という変数に入ってきているようですので、元々記載されていた allows
オプションを削除して patterns
というオプションを追加してみます。
設定値は正規表現として解釈して、一致するかどうかを調べます。
diff
テストを実行して問題ないか確かめてみます。
$ npm run test
ban-links
✔ [match patterns](http://example.com)
✔ multiline
[match](http://example.com/)
✔ [windows like file path](C:\\Users)
✔ plain text
✔ [no patterns](http://example.com)
✔ [no match patterns](https://example.com)
完成!
実際に使ってみた
npm link
コマンドを使用すると、npm publish する前に動作を確かめられます。
この記事を書いているプロジェクトにリンクして使ってみます。
# パッケージ側
$ cd textlint-rule-ban-links
$ npm run build
$ npm link
# 使う側
$ cd article-add-textlint-rule
$ npm link textlint-rule-ban-links
module.exports = {
rules: {
'preset-ja-technical-writing': true,
// 追加
'ban-links': {
patterns:['^https?://localhost']
}
}
}
VSCode の textlint プラグインを使うと、このように表示されます。
(プロジェクトごとに有効化すると使い勝手がいいです)
あれ、表示位置が予想と違いますね……
[local link](https://localhost:8080) です。
というテキストの後ろにエラーの表示が来ています。
本来であればリンクが書いてある付近に表示されてほしいのですが。
別のルール のコードを読んでみたところ、アサーションをもっとシンプルに書けば良さそうでした。
diff
再度試してみます。
正常に動作するようになりました 🎉
欲を言えばリンクが書かれている部分全体に赤波線が引かれると良さそうですが、今はこれで満足としましょう。
まとめ
今回は textlint のルールを作ってみました。
textlint の仕組みを実際に手を動かして学べたので楽しかったです。
ルールを作るだけなら、テンプレートも用意してある上にコードもわかりやすいので、とても簡単でした。
普段使用している VSCode 上で動いて見た目にわかりやすい、というのも嬉しいポイントでした。
次はルールだけでなく、テキストをパースして AST を作る部分も作ってみたいと思いました。
明日の担当は @michimani です!