OxcにJSDocのサポートを入れるべく、このへんをよく調査してる今日この頃。聞いてはいたけど、噂に違わぬ魔境であった。
というわけで、せっかく調査したのでそのメモを残しておく。
一口にJSDocといっても
ぱっと思いつくのはアノテーションからドキュメントを作れるアレではあるけど、昨今はもっといろんな使われ方をしてる。
/**
* JSDoc example.
* @param {string} x X!
* @returns {string}
*/
const dummy = (x) => {
return `${x}!`;
};
そしてみんな似た目的(大まかに)のために、微妙に違うことをやってる。
- TypeScript(JSDoc TS)
- ESTreeとは違った独自のASTで扱う
- https://github.com/microsoft/TypeScript/blob/d04e3489b0d8e6bc9a8a9396a633632a5a467328/src/compiler/types.ts#L40
- EndOfFileというトークンもある
- JSDocもASTの中で定義されてる
- jsdoc.app
@babel/parser
= ESTreeを使ってる- https://github.com/jsdoc/jsdoc/blob/3c68ce426711d9bd05dfe33f9c00f15a5bf9bde6/packages/jsdoc-ast/lib/ast-builder.js#L17
- 独自のwalker/visitorを実装してがんばってる
- eslint-plugin-jsdoc
- ESLintのAST、つまり
espree(acorn)
= ESTreeを使ってる - 実装がどうなってるかは、今から読み解いてく
- ESLintのAST、つまり
- etc…
共通のSpecがあるわけでも、共通の実装があるわけでもないってのがポイント。
育ってきた環境が違うから〜って感じで、まぁそれはそれでいいとしても、どれもいろんな方向性で読むのが大変なソースコードに仕上がってる。
eslint-plugin-jsdocのルール
gajus/eslint-plugin-jsdoc https://github.com/gajus/eslint-plugin-jsdoc
最初に概観を知っておきたく、どういうルールがあるのかもざっと見ておく。
どうやらほぼすべてのルールがiterateJsdoc()
という高階関数を介してたので、特殊そうなオプション指定についてもメモしておく。
数が多いので、とりあえずrecommendedなルールのみ。
- check-access:
checkPrivate
,iterateAllJsdocs
@access
に正しい値が入ってるか、@private
などが併用されてないか重複してないか
- check-alignment:
iterateAllJsdocs
- コメントブロックの
*
の位置が揃っているか
- コメントブロックの
- check-param-names
@param
で定義した引数が、ちゃんと実装にあるか
- check-property-names:
iterateAllJsdocs
@property
で存在しないプロパティを指してないか(foo
なしでfoo.bar
って書いてるとか)
- check-tag-names:
iterateAllJsdocs
@xxx
のタグ名が既定の値になってるかどうか
- check-types:
iterateAllJsdocs
{string}
のように型を指定する部分の指定が、規定の文字列になっているか(String
としていないか)
- check-values:
iterateAllJsdocs
- 特定のタグに対して、正しいフォーマット(
version
はsemver
準拠かどうかなど)が指定されてるか
- 特定のタグに対して、正しいフォーマット(
- empty-tags:
checkInternal
,checkPrivate
,iterateAllJsdocs
- 特定のタグに対して、空値になってるかどうか
- implements-on-classes:
contextDefaults
@implements
が正しい条件下で使われているか
- multiline-blocks:
iterateAllJsdocs
- コメントブロックのスタイル(複数行 or 行など)を強制できる
- no-multi-asterisks:
iterateAllJsdocs
- コメントブロック中の各行において、
*
が複数登場しないようにできる
- コメントブロック中の各行において、
- no-undefined-types:
iterateAllJsdocs
{}
で指定された型がスコープ内に存在し、undefined
になってないか
- require-jsdoc
- JSDocの記述を強制する
- ⚠️ このルールだけは
iterateJsdoc()
ではなく、独自でVisitorを用意
- require-param:
contextDefaults
,noTracking
- 関数の引数がすべて
@param
で定義されているか
- 関数の引数がすべて
- require-param-description:
contextDefaults
@param
に説明文がついているか
- require-param-name:
contextDefaults
@param
に名前がついているか
- require-param-type:
contextDefaults
@param
に型の指定がついているか
- require-property:
iterateAllJsdocs
@typedef
と@namespace
でオブジェクトが定義されるとき、@property
がセットになっているかどうか
- require-property-description:
iterateAllJsdocs
@property
に説明文がついているか
- require-property-name:
iterateAllJsdocs
@property
に名前がついているか
- require-property-type:
iterateAllJsdocs
@property
に型の指定がついているか
- require-returns:
contextDefaults
@returns
が定義されているか
- require-returns-check
@returns
が定義されているとき、return
が書かれているか
- require-returns-description:
contextDefaults
undefined|void
を含まない@returns
に説明文がついてるか
- require-returns-type:
contextDefaults
@returns
に方の指定がついているか
- require-yields:
contextDefaults
- ジェネレータ関数に
@yields
が定義されているか
- ジェネレータ関数に
- require-yields-check
@yields
が定義されているとき、yield
が書かれているか
- tag-lines:
iterateAllJsdocs
- JSDocコメント内の空行の置き方を強制できる
- valid-types:
iterateAllJsdocs
{}
の型指定がシンタックスエラーになっていないか
細かく役割が分かれたシンプルなルールもあれば、とても重厚な実装のあるルールもある。役割が被ってない?何が違うの?っていうのもある。
recommendedではないものは一旦追わずに置いておく・・・。
- check-examples
- check-indentation
- check-line-alignment
- check-syntax
- informative-docs
- match-description
- no-bad-blocks
- no-blank-block-descriptions
- no-defaults
- no-missing-syntax
- no-restricted-syntax
- no-types
- require-asterisk-prefix
- require-description
- require-description-complete-sentence
- require-example
- require-file-overview
- require-hyphen-before-param-description
- require-throws
- sort-tags
実装のOverview
- 各ルールは、
iterateJsdoc(ruleIter, ruleConfig)
というutilsが起点ruleConfig
のiterateAllJsdocs
などの指定で、その挙動をコントロール- (指定漏れてない?ってのもある)(そもそも関数分けろという気持ち)
- utilsを名乗るコードが、あわせて4000行くらいある😇
- JSDocが結構書かれてるせいでもあるけど、それでもよ・・・
- 動的に文字列から組み上げたり、クロージャだらけだったり追うのが辛い
- 各ルールは、このutilsをたっぷり使って実装してる
- 肝心のJSDocコメントを探し出す部分は別ライブラリになってる
jsdoccomment
は、次の2つに強く依存してるeslint-plugin-jsdoc
本体も、この2つには依存してる
という前提を踏まえつつ、コードを読んでいく必要がある。
続く
入口からしてろくなテストケースもないとこから察するに、読むのに難儀しそうであるなあ。
続く。