My External Storage

Jan 19, 2020 - 5 minute read - Comments - textlint review

[Re:VIEW] textlintのlintエラーからttインライン命令で装飾された文字列を除外する

Re:VIEWで文書を作成するときはtextlintを使って文書校正をしている。
@<tt>{git commit --amend}のような等幅設定をしている中で、git => Git (prh)というような警告を受けたくないときに行なう設定をまとめる。

TL;DR

  • ttインライン命令で囲った文字列は静的解析の対象にしたくない
    • @<tt>{git commit --amend}の"git"はコマンド名なので、“Git`ではない
  • Re:VIEWファイルにtextlintを使っているときは、textlint-plugin-reviewプラグインを使っているだろう。
  • textlint-plugin-reviewプラグインでは、ttインライン命令はTeletypeというSyntaxの分類にパースされる。
    • tt: inlineTextTagParser(Syntax.Teletype)
  • Teletypeはtextlint本体ではInlineというノードタイプに分類される。
    • Teletype: 'Inline'
  • textlint-filter-rule-node-typesプラグインを使って、Inlineを静的解析対象から除外すればよい。
  • codeインライン命令で装飾された文字列は警告から除外されているようだ

今回書いた.textlintrcファイルの設定は以下の通り。

// .textlintrc
{
  "filters": {
    // ...
    "node-types": {
      "nodeTypes": ["Inline"]
    }
  }
}

textlintが等幅フォント文字列(ttインライン命令)に対して静的解析エラーを出力してしまう

技術書典に向けてRe:VIEW形式で原稿を書くにあたり、textlintを導入している。

textlintは文書に対して静的解析を行なってくれるツールだ。プラグインでさまざまなルールを追加できて、文書校正を自動で行なってくれる。

Re:VIEWではインライン命令を使って文書の装飾をする。 コードや技術的用語を文中で書くときは等幅フォントにするため、@<code>インライン命令や@<tt>インライン命令を使う。

@<code>{golang.org/x}という@<code>{import}パスから始まる準標準パッケージがあることをご存じでしょうか。
アセンブラ別の実装が含まれており、Goのデバッガである@<tt>{Delve}(@<tt>{dlv}コマンド)@<fn>{delve}などで利用されています。

@ttインライン命令で囲った文字列はコマンドだったりするので、textlintで静的解析の対象にしてほしくない。

$ cat articles/budougumi0617.re
@<code>{git commit --amend}はエラーにしてほしくない。(デフォルトで無視される)
@<tt>{git commit --amend}はエラーにしてほしくない。

$ $(npm bin)/textlint articles/*.re

/Users/budougumi0617/go/src/github.com/FOOOO/SHOTEN8/articles/budougumi0617.re
  2:7  ✓ error  git => Git  prh

✖ 1 problem (1 error, 0 warnings)1 fixable problem.
Try to run: $ textlint --fix [file]

上記の例の場合は、gitコマンドに対して、(正式名称の)Gitにしろと静的解析エラーが発生している。
@<code>インライン命令を使えば解決するのだが、せっかくなので誤検知を解消することにした。

ttインライン命令がtextlintでどのように認識されているか

Re:VIEW形式の文書をtextlintを静的解析をするときは、textlint-plugin-reviewプラグインを使っているだろう。

textlint-plugin-reviewプラグインがどのようにRe:VIEW形式の文書から抽象構文木(AST)を作っているのか確認してみる。
textlint-plugin-reviewプラグインでは、tt命令はTeletypeというSyntax.Teletypeの分類にパースされる。

const InlineParsers = {
  // text tags
  
  // ...
  
  tt:      inlineTextTagParser(Syntax.Teletype),
  
  // ...

Syntax.Teletypeがtextlint本体ではどういうノードとして扱われるかというと、Inlineというノードタイプに分類される。

export const Syntax = {
  // human readable name in ReVIEW's context => textlint name

  // ...

  // ReVIEW specific inline tags
  // NOTE: 'Inline' means review's inline tag having no special meanings, whose children are Strs.
  //       'Reference' means reference to other tag, which have no child.
  //       'NonString' means non-string stuffs like character number, equation, etc.
  Teletype: 'Inline',
  
  // ...
};

よって、Inlineノードを静的解析のルールから除外すれば良い。

textlint-filter-rule-node-typesプラグインを使ってInlineノードを除外する

textlintにおいて、特定のノードを静的解析のルールから除外するには、textlint-filter-rule-node-typesプラグインを使えばよい。

``textlint-filter-rule-node-typesプラグインをnpm installしたあと、.textlintrcを以下のようにすると、Inline`ノードに対して静的解析が行われなくなった。

// .textlintrc
{
  "rules": {
    // ...
  },
  "plugins": [
    "review"
  ],
  "filters": {
    // ...
    "node-types": {
      "nodeTypes": ["Inline"]
    }
  }
}

終わりに

(textlintやJavaScriptにはまったく関係はないが、)最近パーサーを書いているので、textlint-plugin-reviewプラグインの中の構造もなんとなく読むことができた。
何事も勉強したことは無駄にならない。

参考

関連記事