TL;DR
- ESLint標準の
dot-notationルールは日本語などのUnicode識別子を認識しない -
obj["日本語"]→obj.日本語への自動修正が効かない - この問題を解決する eslint-plugin-dot-notation-unicode を作って公開した
npm install --save-dev eslint-plugin-dot-notation-unicode
問題:ESLintは日本語プロパティをドット記法に変換してくれない
ESLintの dot-notation ルールは、ブラケット記法をドット記法に統一してくれる便利なルールです。
// Before: ブラケット記法
obj["property"]
// After: ドット記法に自動修正
obj.property
しかし、日本語などのUnicode文字を含むプロパティ名には対応していません。
// これは修正されない...
obj["日本語"] // 本当は obj.日本語 に変換してほしい
なぜなら、ESLint本体の識別子判定はこうなっているからです:
// ESLint本体のコード
const validIdentifier = /^[a-zA-Z_$][\w$]*$/u;
ASCII文字しか考慮されていません。日本語 は有効なJavaScript識別子なのに、認識されないのです。
JavaScriptでは日本語の変数名・プロパティ名は合法
意外と知られていませんが、JavaScriptでは日本語の識別子は完全に合法です。
const 変数 = "値";
const obj = { 日本語キー: "value" };
console.log(obj.日本語キー); // OK!
ECMAScript仕様では、識別子に使える文字は Unicode Standard Annex #31 (UAX #31) で定義された ID_Start / ID_Continue カテゴリに基づいています。日本語、中国語、韓国語、フランス語、アラビア語など、多くの言語の文字が含まれます。
ESLint本体に修正を入れられない理由
「じゃあESLint本体を直せばいいのでは?」と思うかもしれませんが、残念ながら dot-notation ルールは Frozen(凍結) 状態です。
Frozen rules are ones that we are no longer considering enhancements for.
バグ修正は受け付けていますが、新機能リクエストは受け付けていません。Unicodeサポートは「バグ」か「新機能」か微妙なラインですが、対応を期待するのは難しそうです。
解決策:eslint-plugin-dot-notation-unicode
絶対誰か作ってると思ったんだけど、自分で探してもAIに探させても全然見つからないので、自分(とAI)で作りました!
npm install --save-dev eslint-plugin-dot-notation-unicode
設定方法(Flat Config)
// eslint.config.js
import dotNotationUnicode from "eslint-plugin-dot-notation-unicode";
export default [
{
plugins: {
"dot-notation-unicode": dotNotationUnicode,
},
rules: {
// 本家を無効化して、このプラグインを有効化
"dot-notation": "off",
"dot-notation-unicode/dot-notation": "error",
},
},
];
設定方法(Legacy Config)
{
"plugins": ["dot-notation-unicode"],
"rules": {
"dot-notation": "off",
"dot-notation-unicode/dot-notation": "error"
}
}
動作例
// エラー → 自動修正される
obj["日本語"] // → obj.日本語
obj["한국어"] // → obj.한국어
obj["中文"] // → obj.中文
obj["café"] // → obj.café
obj["العربية"] // → obj.العربية
// これらはOK(エラーにならない)
obj["content-type"] // ハイフンは識別子に使えない
obj["123start"] // 数字で始まる識別子は不可
obj[variable] // 変数によるアクセス
技術的なポイント:正しい識別子判定
このプラグインの核心は、識別子判定の正規表現です。
// ESLint本家(ASCII限定)
const validIdentifier = /^[a-zA-Z_$][\w$]*$/u;
// このプラグイン(Unicode対応)
const validIdentifier = /^[\p{ID_Start}_$][\p{ID_Continue}$\u200C\u200D]*$/u;
\p{ID_Start} と \p{ID_Continue} は Unicodeプロパティエスケープ と呼ばれる機能で、ES2018で導入されました。ECMAScript仕様で定義された識別子の文字クラスに正確にマッチします。
-
\p{ID_Start}: 識別子の先頭に使える文字(アルファベット、漢字、ひらがな、カタカナなど) -
\p{ID_Continue}: 識別子の2文字目以降に使える文字(上記 + 数字など) -
\u200C/\u200D: Zero Width Non-Joiner / Zero Width Joiner(一部言語で必要)
ESLint本家との互換性
このプラグインはESLint本家の dot-notation ルールをフォークし、識別子判定のみを修正しています。(GitHubのFork機能は使ってないが、意味的にはフォーク)
-
allowKeywordsオプション対応 -
allowPatternオプション対応 -
legacyParserSupportオプション追加(v0.2.0〜) - 自動修正(autofix)対応
- 本家のテストケースもコピーしてそのまんま実行
基本的に本家のドロップイン置き換えとして使えます。
注意:中黒「・」とパーサーの互換性問題
実は、Unicode識別子には落とし穴があります。中黒「・」「・」 を含むプロパティ名です。
obj.送信・受信 // これ、古い環境だとパースエラーになることがある
なぜ中黒が問題なのか
Unicode 4.1〜15.0 の間、・(U+30FB KATAKANA MIDDLE DOT)と ・(U+FF65 HALFWIDTH KATAKANA MIDDLE DOT)が 誤って ID_Continue から除外されていました。
これはUnicodeの仕様バグで、Unicode 15.1 で修正されました。しかし、古いパーサーはまだこの問題を抱えています:
- TypeScript < 5.5
- Node.js < 18.20 / 19.x / < 20.12
これらの環境では、obj.送信・受信 が構文エラーになります。
legacyParserSupport オプション
v0.2.0 で legacyParserSupport オプションを追加しました。
// eslint.config.js
{
rules: {
"dot-notation-unicode/dot-notation": ["error", {
legacyParserSupport: true
}]
}
}
このオプションを有効にすると、以下の文字を含む識別子はドット記法に変換されません:
-
・(U+30FB) KATAKANA MIDDLE DOT -
・(U+FF65) HALFWIDTH KATAKANA MIDDLE DOT - Zero Width Non-Joiner (U+200C)
- Zero Width Joiner (U+200D)
// legacyParserSupport: true の場合
obj["送信・受信"] // OK(変換されない)
obj["日本語"] // → obj.日本語 に変換される(「・」を含まないので)
最新の Node.js / TypeScript を使っている場合は、このオプションは不要です。
まとめ
- ESLintの
dot-notationは日本語プロパティに対応していない - 本体はFrozenで修正が期待できない
- eslint-plugin-dot-notation-unicode で解決できる
- Unicodeプロパティエスケープ
\p{ID_Start}\p{ID_Continue}でECMAScript仕様準拠の判定を実現
日本語の識別子を書く機会がある方(i18nのキー、ドメイン駆動設計での日本語命名、kintoneのフィールドコードetc)は、ぜひ試してみてください。
リンク
- npm: https://www.npmjs.com/package/eslint-plugin-dot-notation-unicode
- GitHub: https://github.com/the-red/eslint-plugin-dot-notation-unicode
- ESLint dot-notation ドキュメント: https://eslint.org/docs/latest/rules/dot-notation
- Unicode UAX #31: https://www.unicode.org/reports/tr31/
- UTC 176 勧告(中黒問題の修正 Section 2.2): https://www.unicode.org/L2/L2023/23160-utc176-properties-recs.pdf
- 中黒がJavaScriptの識別子に使えるようになった話: https://nanto.asablo.jp/blog/2024/06/07/9690975