@223n/lint-config-ja
v3.0.0
Published
日本語の技術文書を検査するための共有設定(textlint / markdownlint)と、禁じた語彙の混入を見る道具。
Maintainers
Readme
node_japanese_lint_template
日本語の技術文書を検査するための共有設定と、その利用見本である。
textlintとmarkdownlintの規則を1つのパッケージにまとめてあり、
利用する側は依存を1つ足して設定を2行書くだけで済む。
禁じた語彙がソースに混入していないかを見る道具(lint-vocabulary)も同梱している。
VS Code拡張「テキスト校正くん」(ics.japanese-proofreading)が使う校正辞書も同梱しており、
表記ゆれと誤用を既定で拾う。
何ができるか
| 検査 | 道具 | 見るもの |
| ---- | ---- | ---- |
| lint:md | markdownlint-cli2 | Markdownの書式 |
| lint:ja | textlint | 日本語の書き方。文体、一文の長さ、助詞の連続、表記ゆれなど |
| lint:vocab | lint-vocabulary | 禁じた語彙がソースに混入していないか |
lint:jaだけが警告という段階を持ち、警告があっても通る。
lint:mdとlint:vocabは引っかかると失敗する。
markdownlintに警告の段階は無く、指摘はすべて失敗として扱われる。
導入手順
必要なもの
Node 22以上が要る。
markdownlint-cli2 0.23がNode 22以上を求めるためである。
markdownlintを使わずtextlintと語彙検査だけを使うなら、実際にはNode 20.18でも動く。
ただしその組み合わせは検査していないため、enginesは22以上と書いてある。
既存のプロジェクトに足す
依存を入れる。
npm install --save-dev @223n/lint-config-ja textlint markdownlint-cli2textlintとmarkdownlint-cli2を並べて書くのは、この2つが実行する道具そのものだからである。
共有設定の側はpeerDependenciesとして宣言してあり、利用側が版を選べる。
npmを使わず、GitHubを直接指して入れることもできる。
npm install --save-dev \
github:223n/node_japanese_lint_template#v3.0.0 \
textlint markdownlint-cli2#v3.0.0の部分は、実在するタグを指す必要がある。
タグの一覧はリリースにある。
どちらの経路で入れても、パッケージ名は@223n/lint-config-jaである。
設定ファイルを2つ置く。
// .textlintrc.js
module.exports = require('@223n/lint-config-ja')これは@223n/lint-config-ja/config/textlint.jsと同じである。
どちらの書き方でもよい。
// .markdownlint-cli2.jsonc
{
"config": {
"extends": "@223n/lint-config-ja/config/markdownlint.jsonc"
},
"globs": ["**/*.md"],
"ignores": ["node_modules/**"]
}検査の対象から外すものを書く。
# .textlintignore
node_modules/**除外の書き方は.gitignoreと違う。
node_modules/のように末尾をスラッシュで終えても効かない。
ディレクトリごと外すときはnode_modules/**と書く。
package.jsonに呼び出しを足す。
{
"scripts": {
"lint": "npm run lint:md && npm run lint:ja",
"lint:md": "markdownlint-cli2",
"lint:md:fix": "markdownlint-cli2 --fix",
"lint:ja": "textlint .",
"lint:ja:fix": "textlint --fix ."
}
}これでnpm run lintが動く。
新しいプロジェクトを作る
GitHubの「Use this template」から作ると、設定と見本が入った状態で始まる。
example/とtest/はテンプレートを保守するためのもので、
新しいプロジェクトには要らない。消す場合はpackage.jsonのscriptsから
testとexampleとcheckも一緒に消す。消し忘れるとnpm testが動かなくなる。
語彙検査も使う
lint-vocabulary.config.jsonを置き、package.jsonに呼び出しを足す。
{
"scripts": {
"lint": "npm run lint:md && npm run lint:ja && npm run lint:vocab",
"lint:vocab": "lint-vocabulary"
}
}lintの側にも繋ぐこと。
lint:vocabを足すだけではnpm run lintから呼ばれない。
設定の書き方は語彙検査にある。
設定を変える
文体をですます調にする
// .textlintrc.js
module.exports = require('@223n/lint-config-ja/config/textlint-desumasu.js')普通体の文末も拾う
上の設定で文体を見るno-mix-dearu-desumasuは、「である」「だ」のような明示的な常体しか拾わない。
「〜を確かめる」「〜はない」「〜した」のような普通体の文末は素通りする。
表のセルは、そもそも文体の検査の対象に入らない。
そのため、ですます調の文書に普通体の文末が混ざっても検査を通る。
そこで、ですます調の設定には、規則@223n/lint-config-ja/rules/desumasu-endingが既定で入る(3.0.0から)。
文末を形態素解析で見て、述語に「です」「ます」が含まれない文末を報告する。
「ました」「ません」「でした」「でしょう」「ください」は丁寧な文末として通る。
| 見るもの | 見ないもの |
| ---- | ---- |
| 本文の段落、箇条書きの項目、表のセル | 見出し、表の見出しの行、コードブロック、コードスパン、HTML、引用、リンクのURL、URLを書いた文字列(<…>と裸のURL)、ページ内リンク(#…)の文字列、画像の代替テキスト |
ページ内リンクの文字列は、目次のように見出しを写したものが多いので見ない。 リンクだけを並べた箇条書きの項目や表のセルも、句点で終わらなければ見ない。
次のものは報告しない。
- 名詞、記号、数字、英字で終わるもの(「推奨」「約70GB」)
- 閉じかぎ(
」と』)や閉じの引用符(”、"、〟、》)で終わるもの。引用の可能性があるためである - 「あり」「なし」のように、名詞として置いた語
- 箇条書きと表で、「〜か」で終わる断片(「WebPを書き出せるか」)。名詞のように置いた問いである
- 箇条書きと表で、「と」「ので」「から」のような接続助詞で終わる断片(「保存すると」)。言い切っていない形である
文末の注記は外してから見る。
かっこの注記(「(4.10)」「[1]」「〔注〕」)、参照の印(「※1」)、<sup>の注の番号、コロン、絵文字である。
「〜します(4.10)」は「〜します」として見るので、丁寧な文末として通る。
自動の修正(--fix)は付けていない。
既定は、styleが'ですます'なら有効、'である'なら無効である。
文末を広く見るため、2.xから上げると、既存の文書で指摘が一斉に出ることがある。
すぐに直せないときは、desumasuEndingをfalseにして外す。
// .textlintrc.js
const { createTextlintConfig } = require('@223n/lint-config-ja/config/textlint-base.js')
module.exports = createTextlintConfig({ style: 'ですます', desumasuEnding: false })styleが'である'のときにtrueを渡すと、設定を作る時点で止まる。
規則の細かい動きは、作った設定の上で変える。
// .textlintrc.js
const { createTextlintConfig } = require('@223n/lint-config-ja/config/textlint-base.js')
const config = createTextlintConfig({ style: 'ですます' })
config.rules['@223n/lint-config-ja/rules/desumasu-ending'] = {
checkList: false, // 箇条書きを見ない
allow: ['^(行う|行わない)$'], // 報告しない文の正規表現。表の値として並べた語を通す
}
module.exports = config| オプション | 既定 | 意味 |
| ---- | ---- | ---- |
| checkTable | true | 表のセルを見る |
| checkList | true | 箇条書きの項目を見る |
| checkFragments | true | 表のセルと箇条書きの項目で、「。」などで終わらない断片(「使わない」)の末尾も見る。<br>や行末の空白2つで改行した行は、行ごとに見る。本文の段落では「。」などで終わる文だけを見る |
| allow | [] | 報告しない文の正規表現。文の全体(Markdownの記号を除き、句点は含まない)に当てる。'/〜/i'の形で書くとフラグを付けられる |
表の値として「行う」「行わない」を並べるような文書では、checkFragmentsをfalseにすると指摘が減る。
表に置いた人名(「わたる」)やラベル名(「対応しない」)も、動詞の形なので拾う。
書き換えられない語は、allowに足すか、下のコメントで止める。
オプションの型が違うとき("false"のような文字列)や、知らない名前を書いたときは、検査を始める時点で止まる。
文書の一部だけを止めるときは、規則の名前を書いたコメントで囲む。
<!-- textlint-disable @223n/lint-config-ja/rules/desumasu-ending -->
| 設定 | 値 |
| ---- | ---- |
| 自動更新 | しない |
<!-- textlint-enable @223n/lint-config-ja/rules/desumasu-ending -->一部だけ変える
設定を作る関数を直に呼ぶ。
// .textlintrc.js
const { createTextlintConfig } = require('@223n/lint-config-ja/config/textlint-base.js')
module.exports = createTextlintConfig({
style: 'ですます', // 'である'(既定)か 'ですます'
sentenceLength: 100, // 一文の最大文字数。既定は 120
maxKanjiContinuousLen: 5, // 漢字を連ねてよい上限。既定は 6。false で規則ごと切る
strictSentenceEnd: true, // 文末の句点を厳しく見る。既定は false
jtfStyle: false, // 日本翻訳連盟のスタイルガイドを当てる。既定は true
halfWidthSpacing: 'always', // 全角と半角の間のスペース。既定は 'never'
proofreading: false, // 校正辞書を当てる。既定は true
proofreadingSeverity: 'error', // 校正辞書の指摘の強さ。既定は 'warning'
proofreadingDictionaries: ['誤字'], // 当てる辞書。既定は7種すべて
desumasuEnding: false, // 普通体の文末を拾う。既定はですます調なら true、である調なら false
})よく使うのは次の2つである。
jtfStyleをfalseにすると、日本翻訳連盟のスタイルガイドを丸ごと外す。
このpresetは37の規則を持ち、うち33が既定で有効になる。
指摘が多すぎて手が付けられないときの逃げ道である。
halfWidthSpacingは全角と半角の間のスペースを決める。
既定の'never'は「入れない」を求める。
'always'にすると「入れる」を求め、falseにすると見ない。
コードスパン、リンク、スラッシュの前後は、この設定とは別に「入れない」を求める。
'always'にしても変わらない。
スペースを入れる書き方に合わせる場合は、下の手順でja-space-around-code、
ja-space-around-link、ja-no-space-around-slashを切る。
desumasuEndingは、上の「普通体の文末も拾う」に書いた。
規則のオプションの変え方と、文書の一部だけを止める書き方もそこにある。
校正辞書を絞る
VS Code拡張「テキスト校正くん」が使う校正辞書を同梱しており、既定で有効である。 語の対応表で表記ゆれと誤用を拾う。
| 辞書 | 拾うもの | | ---- | ---- | | 誤字 | アボガド → アボカド | | 重言 | 馬から落馬 → 落馬 | | ひらく漢字 | 出来る → できる | | 冗長な表現 | することができます → できます | | 外来語カタカナ表記 | プリンタ → プリンター | | 固有名詞 | 東京ビックサイト → 東京ビッグサイト | | 技術用語 | Github → GitHub |
指摘は警告として出るため、検査そのものは止まらない。 「ひらく漢字」と「外来語カタカナ表記」は書き手の好みに属する指摘を含み、 これで検査を止めると既存の文書が一斉に落ちるためである。
辞書を選ぶときは名前を並べる。
module.exports = createTextlintConfig({ proofreadingDictionaries: ['誤字', '技術用語'] })丸ごと切るときはproofreading: falseと書く。
proofreadingDictionaries: []は書き損じと見なして止める。
語を足したいときは、同梱した辞書を書き換えず、自分の辞書を足す。 書き換えると取得元との差分が分からなくなるためである。
const path = require('node:path')
const { createTextlintConfig } = require('@223n/lint-config-ja/config/textlint-base.js')
const config = createTextlintConfig()
config.rules.prh.rulePaths.push(path.resolve(__dirname, 'dict/my-prh.yml'))
module.exports = config規則を個別に上書きする
作った設定に手を入れる。
// .textlintrc.js
const { createTextlintConfig } = require('@223n/lint-config-ja/config/textlint-base.js')
const config = createTextlintConfig()
config.rules['preset-ja-technical-writing']['no-exclamation-question-mark'] = false
module.exports = configconfig/textlint.jsを直に読んで書き換えないこと。
requireは同じオブジェクトを返すため、読んだ先すべてに影響する。
createTextlintConfigは呼ぶたびに新しいオブジェクトを返す。
markdownlintは、同じ設定の中に書いた規則がextendsで読んだものより優先される。
行の順序ではなく、どちらに書いたかで決まる。
{
"config": {
"extends": "@223n/lint-config-ja/config/markdownlint.jsonc",
"MD033": { "allowed_elements": ["br"] }
}
}なおMD013(行の長さ)を戻しても、日本語の地の文にはほとんど効かない。
この規則は空白の無い行を報告しないため、日本語の長い一文は素通りする。
版を固定する
タグで指す。
{
"devDependencies": {
"@223n/lint-config-ja": "github:223n/node_japanese_lint_template#v3.0.0"
}
}package-lock.jsonにはタグではなくコミットの識別子が記録されるため、
npm ciは常に同じものを入れる。
規則を上げるときはタグを書き換える。
パッケージとして公開する
git参照のままでも使えるが、npmに登録すると導入が短くなり、版の範囲指定が使える。
{
"devDependencies": {
"@223n/lint-config-ja": "^3.0.0"
}
}git参照はタグで一点を指すだけなので、修正版が出ても自動では入らない。
^3.0.0と書ければ、後方互換のある修正はnpm updateで入る。
一度だけの設定
公開は.github/workflows/release.ymlが行い、認証にTrusted Publishing(OIDC)を使う。
そのためトークンを秘密として置く必要はない。
ただしTrusted Publisherの設定は、パッケージがnpmに存在して初めて現れる。 そのため順序は次のようになる。
1. 手元から一度だけ公開する
223nのアカウントを作ったうえで、次を実行する。
npm login
npm publish --access publicスコープ付きのパッケージは--access publicを付けないと非公開の扱いになり、有料のプランを求められる。
npm loginを済ませずに実行すると認証で失敗する。
また、package.jsonのnameのスコープ(@223n)と、npmのアカウント名またはorganization名が一致している必要がある。
2. Trusted Publisherを設定する
公開するとパッケージの設定画面が現れる。 npmjs.comで「Packages」から対象のパッケージを開き、「Settings」の「Trusted publishing」で次を入れる。
| 項目 | 入れる値 |
| ---- | ---- |
| 提供元 | GitHub Actions |
| 所有者 | 223n |
| リポジトリ | node_japanese_lint_template |
| ワークフローのファイル名 | release.yml |
| 環境 | 空でよい |
ファイル名は経路を含めず、release.ymlとだけ書く。
3. 以降は自動になる
2回目からはタグを切るだけでよい。
手元でのnpm loginも、トークンの保存も要らない。
公開済みの版は飛ばす
同じ版の上書きは、npmでもGitHub Packagesでもできない。 そのため公開の前に、その版が既にあるかを確かめ、あれば飛ばす。
これで次の2つの場面が扱える。
- 手元から先に公開した版へ、あとからタグを切る場合
- 片方の公開だけが落ちて、入れ直す場合
版を上げ忘れたままタグを切る誤りは、その手前の「タグと版が一致するか」で止まる。
GitHub Packagesにも公開する
release.ymlはnpmと同時にGitHub Packagesへも公開する。
こちらはGITHUB_TOKENで認証するため、設定は要らない。
ただしGitHub Packagesは公開されたパッケージでも取得に認証を求める。 GitHubの文書は「private、internal、publicのいずれのパッケージも、公開・取得・削除にアクセストークンが必要」と述べている。
そのため利用側には.npmrcと個人アクセストークンが要る。
# .npmrc
@223n:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}トークンにはread:packagesの権限が要る。
GitHub Actionsから使う場合は、その実行のGITHUB_TOKENをそのまま渡せる。
どれを使うか
3つの経路があり、利用側の手間が違う。
| 経路 | 利用側に要るもの | 版の指定 |
| ---- | ---- | ---- |
| npm | 依存を1行書くだけ | ^3.0.0の範囲指定が使える |
| git参照 | 依存を1行書くだけ | タグで一点を指す |
| GitHub Packages | .npmrcとアクセストークン | ^3.0.0の範囲指定が使える |
特に理由が無ければnpmを使うのがよい。 認証が要らず、範囲指定も使えるためである。
GitHub Packagesは、npmを使わない方針の組織や、GitHubの中で完結させたい場合に選ぶ。
公開の手順
版を上げ、タグを切って押す。
npm version patch # または minor / major
git push --follow-tagsrelease.ymlが動き、次の順に確かめてから公開する。
- タグと
package.jsonの版が一致するか - 検査が通るか
- 配布物に余計なものが入っていないか
版を上げ忘れたままタグを切ると、公開の前に止まる。
公開は実質取り消せない(npm unpublishは72時間以内に限られる)ため、手前で止める。
非公開のリポジトリとして使う場合
このリポジトリを公開しないまま使うこともできるが、認証の設定が要る。
手元では、GitHubへのSSH鍵か認証情報の補助が入っていれば動く。 短縮形ではなく完全な形で書くほうが確実である。
{
"devDependencies": {
"@223n/lint-config-ja": "git+ssh://[email protected]/223n/node_japanese_lint_template.git#v3.0.0"
}
}GitHub Actionsでは、actions/checkoutが使う既定の権限が自分のリポジトリしか読めない。
別のリポジトリを引くには、次のどちらかを足す。
# 細かい権限を絞ったトークンを秘密として置く場合
- run: git config --global url."https://x-access-token:${{ secrets.LINT_TOKEN }}@github.com/".insteadOf "https://github.com/"
- run: npm ciデプロイ鍵を使う場合は、鍵を置いてから引く。
- run: |
mkdir -p ~/.ssh
printf '%s\n' "${{ secrets.LINT_DEPLOY_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan github.com >> ~/.ssh/known_hosts
- run: npm ci第三者のアクションを使えば短く書けるが、公開の鍵を扱うため、ここでは自前で書いている。
知っておくとよいこと
依存の巻き上げを前提にしている
textlintは規則を名前で探す。
この共有設定がdependenciesに持つ規則は、npmが利用側のnode_modulesへ巻き上げることで見つかる。
pnpmやyarnのPnPのように巻き上げないやり方では、規則が見つからずに失敗することがある。
その場合は、規則のpackageを利用側のdevDependenciesにも直接足す。
版を上げると規則が増えることがある
config/markdownlint.jsoncはdefault: trueで、名前を挙げていない規則は既定のまま有効になる。
markdownlintの版が上がって規則が増えると、それも自動で有効になる。
これは意図した動きである。
ただし版を上げた直後に、新しい指摘が出ることはある。
版はpackage-lock.jsonで固定されるため、npm ciを使うかぎり勝手には変わらない。
依存の警告について
供給経路を見る道具(Socketなど)にかけると、依存の木に対する警告が並ぶ。 「難読化コード」のような強い文言も出るため、先に断っておく。
実地に確かめた結果、対応を要する危険は見つからなかった。
まず、そこに並ぶのはこのパッケージ自身のコードではない。
直接依存はpackage.jsonのdependenciesに並べたものだけだが、そこからtextlintの生態系295パッケージが広がり、警告はその全体に対して出る。
普通体の文末の規則のために直接依存へ足したkuromojinとtextlint-util-to-stringは、もとから依存の木に入っていたものである。
足しても、木に新しく加わったパッケージはない。
295パッケージすべてを走査した結果である。
| 見たもの | 結果 |
| ---- | ---- |
| インストール時に走るスクリプト | 0 |
| 外部通信を読み込むファイル | 0 |
| レジストリ以外を出所とする依存 | 0 |
| 既知の脆弱性(npm audit) | 0 |
| コピーレフトのライセンス | 0(MIT 285、BSD 5、ISC 3、Apache-2.0 2) |
開発時の依存としての実害は「入れた瞬間に走るもの」と「検査を走らせたときに動くもの」に限られるが、 どちらも成立しない。
いちばん重い「難読化コード」は、縮小して配る成果物に対する誤検出である。 該当ファイルには元のソースを含むソースマップが同梱されており、意図を隠す目的とは正反対である。 しかもそのファイルはNodeでは読み込まれない。
警告ごとの内訳、唯一の注意点、手元で同じことを確かめる手順は 依存の警告にある。
何が入っているか
| 位置 | 中身 |
| ---- | ---- |
| config/textlint.js | である調の設定。既定 |
| config/textlint-desumasu.js | ですます調の設定 |
| config/textlint-base.js | 設定を作る関数。細かく変えるときに使う |
| rules/desumasu-ending.js | 普通体の文末を拾う規則。ですます調の設定に既定で入る(desumasuEnding) |
| config/markdownlint.jsonc | Markdownの検査規則 |
| dict/ | 校正辞書。出典と許諾はdict/README.mdにある |
| bin/lint-vocabulary.mjs | 語彙検査の実行ファイル |
| example/ | 利用見本。実際に検査が通ることを確かめられる |
| test/ | 語彙検査(test/run.sh)、普通体の文末の規則(test/desumasu-ending.mjs)、導入手順(test/install.sh)の検証 |
| docs/ | 規則の理由と、語彙検査の設定方法 |
見本を動かす
npm install
npm run exampleexample/はfile:..でこのリポジトリを参照している。
規則を変えたときに、利用側から見てどうなるかをその場で確かめられる。
開発
npm install
npm run lint # このリポジトリ自身の文書を、このリポジトリが配る規則で検査する
npm test # 語彙検査と、普通体の文末の規則の検証
npm run example # 利用見本の検証
npm run check # 上の3つをまとめて文書
- 規則の理由 — どの規則をなぜ切ったか
- 語彙検査 —
lint-vocabularyの設定と使い方 - 依存の警告 — 供給経路の道具が出す警告を確かめた結果
- 校正辞書 — 同梱した辞書の出典と更新のしかた
- セキュリティに関する方針 — 弱点を見つけたときの知らせ方と、扱う範囲
ライセンス
Apache License 2.0。LICENSEを見よ。
同梱した校正辞書(dict/prh_*.yml)だけはMIT Licenseである。
取得元はICSが公開している辞書である。
全文はdict/LICENSEに、出典はdict/README.mdにある。
