textlint-rule-ja-grade-kanji 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +123 -0
  3. package/dist/data/grade1.d.ts +6 -0
  4. package/dist/data/grade1.d.ts.map +1 -0
  5. package/dist/data/grade1.js +11 -0
  6. package/dist/data/grade1.js.map +1 -0
  7. package/dist/data/grade2.d.ts +6 -0
  8. package/dist/data/grade2.d.ts.map +1 -0
  9. package/dist/data/grade2.js +11 -0
  10. package/dist/data/grade2.js.map +1 -0
  11. package/dist/data/grade3.d.ts +6 -0
  12. package/dist/data/grade3.d.ts.map +1 -0
  13. package/dist/data/grade3.js +11 -0
  14. package/dist/data/grade3.js.map +1 -0
  15. package/dist/data/grade4.d.ts +6 -0
  16. package/dist/data/grade4.d.ts.map +1 -0
  17. package/dist/data/grade4.js +11 -0
  18. package/dist/data/grade4.js.map +1 -0
  19. package/dist/data/grade5.d.ts +6 -0
  20. package/dist/data/grade5.d.ts.map +1 -0
  21. package/dist/data/grade5.js +11 -0
  22. package/dist/data/grade5.js.map +1 -0
  23. package/dist/data/grade6.d.ts +6 -0
  24. package/dist/data/grade6.d.ts.map +1 -0
  25. package/dist/data/grade6.js +11 -0
  26. package/dist/data/grade6.js.map +1 -0
  27. package/dist/data/index.d.ts +16 -0
  28. package/dist/data/index.d.ts.map +1 -0
  29. package/dist/data/index.js +24 -0
  30. package/dist/data/index.js.map +1 -0
  31. package/dist/index.d.ts +4 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +13 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/kanji.d.ts +10 -0
  36. package/dist/kanji.d.ts.map +1 -0
  37. package/dist/kanji.js +37 -0
  38. package/dist/kanji.js.map +1 -0
  39. package/dist/rule.d.ts +5 -0
  40. package/dist/rule.d.ts.map +1 -0
  41. package/dist/rule.js +61 -0
  42. package/dist/rule.js.map +1 -0
  43. package/dist/types.d.ts +10 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +3 -0
  46. package/dist/types.js.map +1 -0
  47. package/docs/getting-started.md +222 -0
  48. package/package.json +60 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 101ta28
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # textlint-rule-ja-grade-kanji
2
+
3
+ `textlint-rule-ja-grade-kanji` は、文部科学省「学年別漢字配当表」に基づき、指定した小学校学年までに学習する漢字だけが文章で使われているか確認する textlint ルールです。
4
+
5
+ 小学生向け教材や案内文で、対象読者にとって未習の漢字を1文字ずつ検出できます。
6
+
7
+ ## インストール
8
+
9
+ textlintを初めて使う場合は、Node.jsの準備から検査結果の読み方まで説明した[はじめての漢字チェック](docs/getting-started.md)を参照してください。
10
+
11
+ ```bash
12
+ npm install --save-dev textlint textlint-rule-ja-grade-kanji
13
+ ```
14
+
15
+ ## 基本設定
16
+
17
+ `.textlintrc.json` にルールを追加します。
18
+
19
+ ```json
20
+ {
21
+ "rules": {
22
+ "ja-grade-kanji": {
23
+ "grade": 3
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ `grade: 3` は3年生で初めて習う漢字だけでなく、1〜3年生の配当漢字を累積して許可します。
30
+
31
+ ```text
32
+ 小学1〜3年配当 OK
33
+ 小学4〜6年配当 NG
34
+ 配当表外 NG
35
+ ```
36
+
37
+ 設定を `"ja-grade-kanji": true` とした場合、`grade` の既定値は6です。小学1〜6年の全1,026字を許可し、それ以外のCJK統合漢字を報告します。
38
+
39
+ ## オプション
40
+
41
+ ### `grade`
42
+
43
+ 検査対象の最高学年を `1`〜`6` の整数で指定します。既定値は `6` です。`0`、`7`、`"3"` などは設定ミスとしてエラーになります。
44
+
45
+ ### `allow`
46
+
47
+ 対象学年外でも例外的に許可する文字列の配列です。各要素はUnicodeコードポイント単位で展開されるため、`"情報"` を指定すると「情」と「報」の両方を許可します。英数字など、漢字判定の対象外の文字を含めても影響しません。
48
+
49
+ ```json
50
+ {
51
+ "rules": {
52
+ "ja-grade-kanji": {
53
+ "grade": 3,
54
+ "allow": ["誰", "情報", "AI"]
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ ### `ignore`
61
+
62
+ 検査しないtextlint ASTコンテナのNode種別を指定します。たとえばリンクの表示テキストを除外するには次のように設定します。
63
+
64
+ ```json
65
+ {
66
+ "rules": {
67
+ "ja-grade-kanji": {
68
+ "grade": 3,
69
+ "ignore": ["Link"]
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ Markdownのインラインコード(`Code`)とコードブロック(`CodeBlock`)は本文を表す `Str` Nodeではないため、textlint標準ASTの構造上、設定なしでも検査対象になりません。リンク先URLも対象外ですが、リンクの表示テキストは通常の本文として検査します。表示テキストも除外したい場合に `"Link"` を指定してください。`ignore` は利用中のProcessorが生成するNode種別名を受け付けます。
76
+
77
+ ## 報告例
78
+
79
+ 入力が `植物を観察する`、設定が `grade: 2` の場合、問題の漢字ごとに次のようなメッセージを表示します。
80
+
81
+ ```text
82
+ 「植」は小学3年生で学習する漢字です。小学2年生までの文章では使用できません。
83
+ 「観」は小学4年生で学習する漢字です。小学2年生までの文章では使用できません。
84
+ 「察」は小学4年生で学習する漢字です。小学2年生までの文章では使用できません。
85
+ ```
86
+
87
+ 配当表にない漢字は次のように報告します。
88
+
89
+ ```text
90
+ 「誰」は学年別漢字配当表に含まれていません。
91
+ ```
92
+
93
+ 各エラーの範囲は問題の1文字だけです。補助平面のCJK統合漢字についても、JavaScriptのUTF-16インデックスを考慮した正しい範囲を返します。
94
+
95
+ ## JavaScript / TypeScript API
96
+
97
+ ルール本体はデフォルトエクスポートです。判定ロジックを単体でも利用できるよう、`getKanjiGrade`、`isKanji`、`createAllowedKanji` なども名前付きで公開しています。
98
+
99
+ ```ts
100
+ import { getKanjiGrade } from "textlint-rule-ja-grade-kanji";
101
+
102
+ getKanjiGrade("一"); // 1
103
+ getKanjiGrade("植"); // 3
104
+ getKanjiGrade("誰"); // null
105
+ ```
106
+
107
+ ## 開発
108
+
109
+ ```bash
110
+ npm install
111
+ npm run build
112
+ npm test
113
+ ```
114
+
115
+ テストでは各学年の字数(80 / 160 / 200 / 202 / 193 / 191)、合計1,026字、学年間の重複がないこと、textlint上の検出結果と位置範囲を検証します。
116
+
117
+ ## データ出典
118
+
119
+ 文字データは、文部科学省の一次資料 [小学校学習指導要領(平成29年告示)](https://www.mext.go.jp/content/20230120-mxt_kyoiku02-100002604_01.pdf) の国語・別表「学年別漢字配当表」に基づきます。字数と改訂内容は [小学校学習指導要領(平成29年告示)解説 国語編](https://www.mext.go.jp/content/20220606-mxt_kyoiku02-100002607_002.pdf) でも照合しています。
120
+
121
+ ## ライセンス
122
+
123
+ MIT
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
3
+ * 国語・別表「学年別漢字配当表」に基づく(80字)。
4
+ */
5
+ export declare const grade1Kanji: readonly string[];
6
+ //# sourceMappingURL=grade1.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade1.d.ts","sourceRoot":"","sources":["../../src/data/grade1.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW,mBAEd,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.grade1Kanji = void 0;
4
+ /**
5
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
6
+ * 国語・別表「学年別漢字配当表」に基づく(80字)。
7
+ */
8
+ exports.grade1Kanji = [
9
+ ..."一右雨円王音下火花貝学気九休玉金空月犬見五口校左三山子四糸字耳七車手十出女小上森人水正生青夕石赤千川先早草足村大男竹中虫町天田土二日入年白八百文木本名目立力林六",
10
+ ];
11
+ //# sourceMappingURL=grade1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade1.js","sourceRoot":"","sources":["../../src/data/grade1.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,WAAW,GAAG;IACzB,GAAG,kFAAkF;CAC7E,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
3
+ * 国語・別表「学年別漢字配当表」に基づく(160字)。
4
+ */
5
+ export declare const grade2Kanji: readonly string[];
6
+ //# sourceMappingURL=grade2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade2.d.ts","sourceRoot":"","sources":["../../src/data/grade2.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW,mBAEd,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.grade2Kanji = void 0;
4
+ /**
5
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
6
+ * 国語・別表「学年別漢字配当表」に基づく(160字)。
7
+ */
8
+ exports.grade2Kanji = [
9
+ ..."引羽雲園遠何科夏家歌画回会海絵外角楽活間丸岩顔汽記帰弓牛魚京強教近兄形計元言原戸古午後語工公広交光考行高黄合谷国黒今才細作算止市矢姉思紙寺自時室社弱首秋週春書少場色食心新親図数西声星晴切雪船線前組走多太体台地池知茶昼長鳥朝直通弟店点電刀冬当東答頭同道読内南肉馬売買麦半番父風分聞米歩母方北毎妹万明鳴毛門夜野友用曜来里理話",
10
+ ];
11
+ //# sourceMappingURL=grade2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade2.js","sourceRoot":"","sources":["../../src/data/grade2.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,WAAW,GAAG;IACzB,GAAG,kKAAkK;CAC7J,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
3
+ * 国語・別表「学年別漢字配当表」に基づく(200字)。
4
+ */
5
+ export declare const grade3Kanji: readonly string[];
6
+ //# sourceMappingURL=grade3.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade3.d.ts","sourceRoot":"","sources":["../../src/data/grade3.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW,mBAEd,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.grade3Kanji = void 0;
4
+ /**
5
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
6
+ * 国語・別表「学年別漢字配当表」に基づく(200字)。
7
+ */
8
+ exports.grade3Kanji = [
9
+ ..."悪安暗医委意育員院飲運泳駅央横屋温化荷界開階寒感漢館岸起期客究急級宮球去橋業曲局銀区苦具君係軽血決研県庫湖向幸港号根祭皿仕死使始指歯詩次事持式実写者主守取酒受州拾終習集住重宿所暑助昭消商章勝乗植申身神真深進世整昔全相送想息速族他打対待代第題炭短談着注柱丁帳調追定庭笛鉄転都度投豆島湯登等動童農波配倍箱畑発反坂板皮悲美鼻筆氷表秒病品負部服福物平返勉放味命面問役薬由油有遊予羊洋葉陽様落流旅両緑礼列練路和",
10
+ ];
11
+ //# sourceMappingURL=grade3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade3.js","sourceRoot":"","sources":["../../src/data/grade3.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,WAAW,GAAG;IACzB,GAAG,0MAA0M;CACrM,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
3
+ * 国語・別表「学年別漢字配当表」に基づく(202字)。
4
+ */
5
+ export declare const grade4Kanji: readonly string[];
6
+ //# sourceMappingURL=grade4.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade4.d.ts","sourceRoot":"","sources":["../../src/data/grade4.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW,mBAEd,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.grade4Kanji = void 0;
4
+ /**
5
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
6
+ * 国語・別表「学年別漢字配当表」に基づく(202字)。
7
+ */
8
+ exports.grade4Kanji = [
9
+ ..."愛案以衣位茨印英栄媛塩岡億加果貨課芽賀改械害街各覚潟完官管関観願岐希季旗器機議求泣給挙漁共協鏡競極熊訓軍郡群径景芸欠結建健験固功好香候康佐差菜最埼材崎昨札刷察参産散残氏司試児治滋辞鹿失借種周祝順初松笑唱焼照城縄臣信井成省清静席積折節説浅戦選然争倉巣束側続卒孫帯隊達単置仲沖兆低底的典伝徒努灯働特徳栃奈梨熱念敗梅博阪飯飛必票標不夫付府阜富副兵別辺変便包法望牧末満未民無約勇要養浴利陸良料量輪類令冷例連老労録",
10
+ ];
11
+ //# sourceMappingURL=grade4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade4.js","sourceRoot":"","sources":["../../src/data/grade4.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,WAAW,GAAG;IACzB,GAAG,4MAA4M;CACvM,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
3
+ * 国語・別表「学年別漢字配当表」に基づく(193字)。
4
+ */
5
+ export declare const grade5Kanji: readonly string[];
6
+ //# sourceMappingURL=grade5.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade5.d.ts","sourceRoot":"","sources":["../../src/data/grade5.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW,mBAEd,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.grade5Kanji = void 0;
4
+ /**
5
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
6
+ * 国語・別表「学年別漢字配当表」に基づく(193字)。
7
+ */
8
+ exports.grade5Kanji = [
9
+ ..."圧囲移因永営衛易益液演応往桜可仮価河過快解格確額刊幹慣眼紀基寄規喜技義逆久旧救居許境均禁句型経潔件険検限現減故個護効厚耕航鉱構興講告混査再災妻採際在財罪殺雑酸賛士支史志枝師資飼示似識質舎謝授修述術準序招証象賞条状常情織職制性政勢精製税責績接設絶祖素総造像増則測属率損貸態団断築貯張停提程適統堂銅導得毒独任燃能破犯判版比肥非費備評貧布婦武復複仏粉編弁保墓報豊防貿暴脈務夢迷綿輸余容略留領歴",
10
+ ];
11
+ //# sourceMappingURL=grade5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade5.js","sourceRoot":"","sources":["../../src/data/grade5.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,WAAW,GAAG;IACzB,GAAG,mMAAmM;CAC9L,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
3
+ * 国語・別表「学年別漢字配当表」に基づく(191字)。
4
+ */
5
+ export declare const grade6Kanji: readonly string[];
6
+ //# sourceMappingURL=grade6.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade6.d.ts","sourceRoot":"","sources":["../../src/data/grade6.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW,mBAEd,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.grade6Kanji = void 0;
4
+ /**
5
+ * 文部科学省「小学校学習指導要領(平成29年告示)」
6
+ * 国語・別表「学年別漢字配当表」に基づく(191字)。
7
+ */
8
+ exports.grade6Kanji = [
9
+ ..."胃異遺域宇映延沿恩我灰拡革閣割株干巻看簡危机揮貴疑吸供胸郷勤筋系敬警劇激穴券絹権憲源厳己呼誤后孝皇紅降鋼刻穀骨困砂座済裁策冊蚕至私姿視詞誌磁射捨尺若樹収宗就衆従縦縮熟純処署諸除承将傷障蒸針仁垂推寸盛聖誠舌宣専泉洗染銭善奏窓創装層操蔵臓存尊退宅担探誕段暖値宙忠著庁頂腸潮賃痛敵展討党糖届難乳認納脳派拝背肺俳班晩否批秘俵腹奮並陛閉片補暮宝訪亡忘棒枚幕密盟模訳郵優預幼欲翌乱卵覧裏律臨朗論",
10
+ ];
11
+ //# sourceMappingURL=grade6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade6.js","sourceRoot":"","sources":["../../src/data/grade6.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,WAAW,GAAG;IACzB,GAAG,iMAAiM;CAC5L,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { grade1Kanji } from "./grade1.js";
2
+ import { grade2Kanji } from "./grade2.js";
3
+ import { grade3Kanji } from "./grade3.js";
4
+ import { grade4Kanji } from "./grade4.js";
5
+ import { grade5Kanji } from "./grade5.js";
6
+ import { grade6Kanji } from "./grade6.js";
7
+ export { grade1Kanji, grade2Kanji, grade3Kanji, grade4Kanji, grade5Kanji, grade6Kanji };
8
+ export declare const kanjiByGrade: {
9
+ readonly 1: readonly string[];
10
+ readonly 2: readonly string[];
11
+ readonly 3: readonly string[];
12
+ readonly 4: readonly string[];
13
+ readonly 5: readonly string[];
14
+ readonly 6: readonly string[];
15
+ };
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AAExF,eAAO,MAAM,YAAY;aACvB,CAAC;aACD,CAAC;aACD,CAAC;aACD,CAAC;aACD,CAAC;aACD,CAAC;CACO,CAAC"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.kanjiByGrade = exports.grade6Kanji = exports.grade5Kanji = exports.grade4Kanji = exports.grade3Kanji = exports.grade2Kanji = exports.grade1Kanji = void 0;
4
+ const grade1_js_1 = require("./grade1.js");
5
+ Object.defineProperty(exports, "grade1Kanji", { enumerable: true, get: function () { return grade1_js_1.grade1Kanji; } });
6
+ const grade2_js_1 = require("./grade2.js");
7
+ Object.defineProperty(exports, "grade2Kanji", { enumerable: true, get: function () { return grade2_js_1.grade2Kanji; } });
8
+ const grade3_js_1 = require("./grade3.js");
9
+ Object.defineProperty(exports, "grade3Kanji", { enumerable: true, get: function () { return grade3_js_1.grade3Kanji; } });
10
+ const grade4_js_1 = require("./grade4.js");
11
+ Object.defineProperty(exports, "grade4Kanji", { enumerable: true, get: function () { return grade4_js_1.grade4Kanji; } });
12
+ const grade5_js_1 = require("./grade5.js");
13
+ Object.defineProperty(exports, "grade5Kanji", { enumerable: true, get: function () { return grade5_js_1.grade5Kanji; } });
14
+ const grade6_js_1 = require("./grade6.js");
15
+ Object.defineProperty(exports, "grade6Kanji", { enumerable: true, get: function () { return grade6_js_1.grade6Kanji; } });
16
+ exports.kanjiByGrade = {
17
+ 1: grade1_js_1.grade1Kanji,
18
+ 2: grade2_js_1.grade2Kanji,
19
+ 3: grade3_js_1.grade3Kanji,
20
+ 4: grade4_js_1.grade4Kanji,
21
+ 5: grade5_js_1.grade5Kanji,
22
+ 6: grade6_js_1.grade6Kanji,
23
+ };
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":";;;AAAA,2CAA0C;4FAAjC,uBAAW;AACpB,2CAA0C;4FAAjC,uBAAW;AACpB,2CAA0C;4FAAjC,uBAAW;AACpB,2CAA0C;4FAAjC,uBAAW;AACpB,2CAA0C;4FAAjC,uBAAW;AACpB,2CAA0C;4FAAjC,uBAAW;AAIP,QAAA,YAAY,GAAG;IAC1B,CAAC,EAAE,uBAAW;IACd,CAAC,EAAE,uBAAW;IACd,CAAC,EAAE,uBAAW;IACd,CAAC,EAAE,uBAAW;IACd,CAAC,EAAE,uBAAW;IACd,CAAC,EAAE,uBAAW;CACN,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { reporter, reporter as default } from "./rule.js";
2
+ export { createAllowedKanji, getKanjiGrade, isAllowedKanji, isKanji, kanjiGradeMap, } from "./kanji.js";
3
+ export type { ElementaryGrade, GradeKanjiOptions } from "./types.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,IAAI,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,OAAO,EACP,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.kanjiGradeMap = exports.isKanji = exports.isAllowedKanji = exports.getKanjiGrade = exports.createAllowedKanji = exports.default = exports.reporter = void 0;
4
+ var rule_js_1 = require("./rule.js");
5
+ Object.defineProperty(exports, "reporter", { enumerable: true, get: function () { return rule_js_1.reporter; } });
6
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return rule_js_1.reporter; } });
7
+ var kanji_js_1 = require("./kanji.js");
8
+ Object.defineProperty(exports, "createAllowedKanji", { enumerable: true, get: function () { return kanji_js_1.createAllowedKanji; } });
9
+ Object.defineProperty(exports, "getKanjiGrade", { enumerable: true, get: function () { return kanji_js_1.getKanjiGrade; } });
10
+ Object.defineProperty(exports, "isAllowedKanji", { enumerable: true, get: function () { return kanji_js_1.isAllowedKanji; } });
11
+ Object.defineProperty(exports, "isKanji", { enumerable: true, get: function () { return kanji_js_1.isKanji; } });
12
+ Object.defineProperty(exports, "kanjiGradeMap", { enumerable: true, get: function () { return kanji_js_1.kanjiGradeMap; } });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qCAA0D;AAAjD,mGAAA,QAAQ,OAAA;AAAE,kGAAA,QAAQ,OAAW;AACtC,uCAMoB;AALlB,8GAAA,kBAAkB,OAAA;AAClB,yGAAA,aAAa,OAAA;AACb,0GAAA,cAAc,OAAA;AACd,mGAAA,OAAO,OAAA;AACP,yGAAA,aAAa,OAAA"}
@@ -0,0 +1,10 @@
1
+ import type { ElementaryGrade } from "./types.js";
2
+ export declare const kanjiGradeMap: ReadonlyMap<string, ElementaryGrade>;
3
+ /** Returns the elementary-school grade in which a kanji is first taught. */
4
+ export declare function getKanjiGrade(character: string): ElementaryGrade | null;
5
+ /** Identifies a single CJK unified ideograph, including supplementary-plane characters. */
6
+ export declare function isKanji(character: string): boolean;
7
+ /** Builds the cumulative character set allowed at the target grade. */
8
+ export declare function createAllowedKanji(targetGrade: ElementaryGrade, allow?: readonly string[]): Set<string>;
9
+ export declare function isAllowedKanji(character: string, allowedCharacters: ReadonlySet<string>): boolean;
10
+ //# sourceMappingURL=kanji.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kanji.d.ts","sourceRoot":"","sources":["../src/kanji.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAI9D,CAAC;AAIF,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAEvE;AAED,2FAA2F;AAC3F,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,eAAe,EAC5B,KAAK,GAAE,SAAS,MAAM,EAAO,GAC5B,GAAG,CAAC,MAAM,CAAC,CAgBb;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAEjG"}
package/dist/kanji.js ADDED
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.kanjiGradeMap = void 0;
4
+ exports.getKanjiGrade = getKanjiGrade;
5
+ exports.isKanji = isKanji;
6
+ exports.createAllowedKanji = createAllowedKanji;
7
+ exports.isAllowedKanji = isAllowedKanji;
8
+ const index_js_1 = require("./data/index.js");
9
+ exports.kanjiGradeMap = new Map(Object.entries(index_js_1.kanjiByGrade).flatMap(([grade, kanji]) => kanji.map((character) => [character, Number(grade)])));
10
+ const unifiedIdeographPattern = /^\p{Unified_Ideograph}$/u;
11
+ /** Returns the elementary-school grade in which a kanji is first taught. */
12
+ function getKanjiGrade(character) {
13
+ return exports.kanjiGradeMap.get(character) ?? null;
14
+ }
15
+ /** Identifies a single CJK unified ideograph, including supplementary-plane characters. */
16
+ function isKanji(character) {
17
+ return unifiedIdeographPattern.test(character);
18
+ }
19
+ /** Builds the cumulative character set allowed at the target grade. */
20
+ function createAllowedKanji(targetGrade, allow = []) {
21
+ const allowed = new Set();
22
+ for (let grade = 1; grade <= targetGrade; grade += 1) {
23
+ for (const character of index_js_1.kanjiByGrade[grade]) {
24
+ allowed.add(character);
25
+ }
26
+ }
27
+ for (const value of allow) {
28
+ for (const character of value) {
29
+ allowed.add(character);
30
+ }
31
+ }
32
+ return allowed;
33
+ }
34
+ function isAllowedKanji(character, allowedCharacters) {
35
+ return !isKanji(character) || allowedCharacters.has(character);
36
+ }
37
+ //# sourceMappingURL=kanji.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kanji.js","sourceRoot":"","sources":["../src/kanji.ts"],"names":[],"mappings":";;;;;;;AAAA,8CAA+C;AAGlC,QAAA,aAAa,GAAyC,IAAI,GAAG,CACvE,MAAM,CAAC,OAAO,CAAC,uBAAY,CAAsD,CAAC,OAAO,CACxF,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAoB,CAAU,CAAC,CACrG,CACF,CAAC;AAEF,MAAM,uBAAuB,GAAG,0BAA0B,CAAC;AAE3D,4EAA4E;AAC5E,uBAA8B,SAAiB;IAC7C,OAAO,QAAA,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;AAC9C,CAAC;AAED,2FAA2F;AAC3F,iBAAwB,SAAiB;IACvC,OAAO,uBAAuB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACjD,CAAC;AAED,uEAAuE;AACvE,4BACE,WAA4B,EAC5B,KAAK,GAAsB,EAAE;IAE7B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,WAAW,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,KAAK,MAAM,SAAS,IAAI,uBAAY,CAAC,KAAwB,CAAC,EAAE,CAAC;YAC/D,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,wBAA+B,SAAiB,EAAE,iBAAsC;IACtF,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACjE,CAAC"}
package/dist/rule.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { TextlintRuleReporter } from "@textlint/types";
2
+ import type { GradeKanjiOptions } from "./types.js";
3
+ export declare const reporter: TextlintRuleReporter<GradeKanjiOptions>;
4
+ export default reporter;
5
+ //# sourceMappingURL=rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../src/rule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA6B,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEvF,OAAO,KAAK,EAAmB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAuBrE,eAAO,MAAM,QAAQ,EAAE,oBAAoB,CAAC,iBAAiB,CA0C5D,CAAC;eAEa,QAAQ"}
package/dist/rule.js ADDED
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reporter = void 0;
4
+ const kanji_js_1 = require("./kanji.js");
5
+ const DEFAULT_GRADE = 6;
6
+ const VALID_GRADES = new Set([1, 2, 3, 4, 5, 6]);
7
+ function parseGrade(value) {
8
+ if (value === undefined) {
9
+ return DEFAULT_GRADE;
10
+ }
11
+ if (typeof value !== "number" || !Number.isInteger(value) || !VALID_GRADES.has(value)) {
12
+ throw new TypeError('ja-grade-kanji: "grade" must be an integer between 1 and 6.');
13
+ }
14
+ return value;
15
+ }
16
+ function createMessage(character, targetGrade) {
17
+ const learnedGrade = (0, kanji_js_1.getKanjiGrade)(character);
18
+ if (learnedGrade === null) {
19
+ return `「${character}」は学年別漢字配当表に含まれていません。`;
20
+ }
21
+ return `「${character}」は小学${learnedGrade}年生で学習する漢字です。小学${targetGrade}年生までの文章では使用できません。`;
22
+ }
23
+ const reporter = (context, options = {}) => {
24
+ const { Syntax, RuleError, report, getSource, locator } = context;
25
+ const targetGrade = parseGrade(options.grade);
26
+ const allowedCharacters = (0, kanji_js_1.createAllowedKanji)(targetGrade, options.allow ?? []);
27
+ const ignoredNodeTypes = new Set(options.ignore ?? []);
28
+ let ignoredDepth = 0;
29
+ const handlers = {
30
+ [Syntax.Str](node) {
31
+ if (ignoredDepth > 0) {
32
+ return;
33
+ }
34
+ const text = getSource(node);
35
+ let utf16Index = 0;
36
+ for (const character of text) {
37
+ if (!(0, kanji_js_1.isAllowedKanji)(character, allowedCharacters)) {
38
+ report(node, new RuleError(createMessage(character, targetGrade), {
39
+ padding: locator.range([utf16Index, utf16Index + character.length]),
40
+ }));
41
+ }
42
+ utf16Index += character.length;
43
+ }
44
+ },
45
+ };
46
+ for (const nodeType of ignoredNodeTypes) {
47
+ if (nodeType === Syntax.Str || nodeType.endsWith(":exit")) {
48
+ continue;
49
+ }
50
+ handlers[nodeType] = () => {
51
+ ignoredDepth += 1;
52
+ };
53
+ handlers[`${nodeType}:exit`] = () => {
54
+ ignoredDepth = Math.max(0, ignoredDepth - 1);
55
+ };
56
+ }
57
+ return handlers;
58
+ };
59
+ exports.reporter = reporter;
60
+ exports.default = exports.reporter;
61
+ //# sourceMappingURL=rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule.js","sourceRoot":"","sources":["../src/rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export type ElementaryGrade = 1 | 2 | 3 | 4 | 5 | 6;
2
+ export interface GradeKanjiOptions {
3
+ /** The highest elementary-school grade whose kanji are allowed. */
4
+ grade?: ElementaryGrade;
5
+ /** Additional characters to allow. Each string is expanded by code point. */
6
+ allow?: string[];
7
+ /** textlint AST container node types whose descendants should be skipped. */
8
+ ignore?: string[];
9
+ }
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,mEAAmE;IACnE,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,222 @@
1
+ # はじめての漢字チェック
2
+
3
+ 小学生向けの原稿に、対象学年ではまだ習わない漢字が入っていないか確認したい人のための手順です。
4
+ プログラミングの知識は必要ありませんが、最初の準備と原稿の検査には、文字でパソコンを操作する「ターミナル」を使います。
5
+
6
+ この手順を終えると、テキストファイルまたはMarkdownファイルに対して、次のような結果を表示できます。
7
+
8
+ ```text
9
+ 原稿.txt
10
+ 3:5 error 「植」は小学3年生で学習する漢字です。小学2年生までの文章では使用できません。 ja-grade-kanji
11
+ ```
12
+
13
+ textlintは問題の場所を報告するだけで、原稿を自動では書き換えません。
14
+ 報告を読んで、漢字をひらがなにするか、そのまま使うかを執筆者が判断できます。
15
+
16
+ ## 準備するもの
17
+
18
+ 検査できる原稿は、ファイル名の末尾が `.txt` または `.md` のファイルです。
19
+ Microsoft Wordの `.docx` ファイルは直接検査できません。
20
+ Wordで執筆している場合は、原稿の複製を「書式なしテキスト(`.txt`)」として保存してから検査してください。
21
+
22
+ 検査の仕組みを動かすために、**Node.js**というソフトウェアも使います。
23
+ Node.jsは最初に一度インストールすれば、原稿を検査するたびに入れ直す必要はありません。
24
+
25
+ ## Node.jsをインストールする
26
+
27
+ [Node.jsの公式サイト](https://nodejs.org/ja)を開き、LTSと表示された版をダウンロードしてインストールします。
28
+ このルールを使うには、Node.js 20以上が必要です。
29
+ インストーラーの選択肢は、特別な理由がなければ初期設定のまま進めてください。
30
+
31
+ インストールが終わったら、Windowsでは「PowerShell」、macOSでは「ターミナル」を開きます。
32
+ 以後、この画面をまとめて「ターミナル」と呼びます。
33
+
34
+ 次の2行を1行ずつ入力し、そのたびにEnterキーを押します。
35
+
36
+ ```shell
37
+ node --version
38
+ npm --version
39
+ ```
40
+
41
+ それぞれにバージョン番号が表示されれば、Node.jsの準備は完了です。
42
+ `node`または`npm`が見つからないという内容が表示された場合は、いったんターミナルを閉じて開き直してください。
43
+
44
+ ## 原稿を検査するフォルダーを作る
45
+
46
+ 原稿と設定をまとめる専用フォルダーを作ります。
47
+ ターミナルで次の3行を順番に実行してください。
48
+
49
+ ```shell
50
+ mkdir kanji-check
51
+ cd kanji-check
52
+ npm init -y
53
+ ```
54
+
55
+ `kanji-check`がフォルダー名です。
56
+ 別の名前にしたい場合は、最初の2行にある`kanji-check`を同じ名前に置き換えます。
57
+
58
+ 最後のコマンドによって、`package.json`という管理用ファイルが作られます。
59
+ このファイルを自分で編集する必要はありません。
60
+
61
+ ## textlintと漢字チェックをインストールする
62
+
63
+ `kanji-check`フォルダーにいる状態で、次のコマンドを実行します。
64
+
65
+ ```shell
66
+ npm install --save-dev textlint textlint-rule-ja-grade-kanji
67
+ ```
68
+
69
+ 処理には少し時間がかかることがあります。
70
+ ターミナルに再び文字を入力できる状態になり、`npm error`で始まる表示がなければインストールは完了です。
71
+
72
+ この処理によって、`node_modules`フォルダーと複数の管理用ファイルが作られます。
73
+ 通常は中身を確認したり編集したりする必要はありません。
74
+
75
+ ## 検査する学年を設定する
76
+
77
+ 次のコマンドで、textlintの設定ファイルを作ります。
78
+
79
+ ```shell
80
+ npx textlint --init
81
+ ```
82
+
83
+ `kanji-check`フォルダーに`.textlintrc.json`が作られます。
84
+ 先頭が`.`のファイルは、環境によって通常の一覧に表示されないことがあります。
85
+
86
+ `.textlintrc.json`をテキストエディターで開き、中身をすべて次の内容に置き換えます。
87
+ この例では、小学2年生までに習う漢字を許可します。
88
+
89
+ ```json
90
+ {
91
+ "rules": {
92
+ "ja-grade-kanji": {
93
+ "grade": 2
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ 対象学年を変えるには、`grade`の数値を`1`から`6`までの整数に変更します。
100
+ たとえば小学4年生向けの原稿なら、`"grade": 4`と指定します。
101
+
102
+ この設定ファイルには、コメントや末尾の余分なカンマを書けません。
103
+ 設定エラーが出た場合は、まず上の内容をそのまま貼り直してください。
104
+
105
+ ## 原稿を検査する
106
+
107
+ 検査する`.txt`または`.md`ファイルを、`kanji-check`フォルダーへコピーします。
108
+ ここでは、ファイル名を`原稿.txt`とします。
109
+
110
+ ターミナルで次のコマンドを実行します。
111
+
112
+ ```shell
113
+ npx textlint "原稿.txt"
114
+ ```
115
+
116
+ ファイル名に空白が含まれていても扱えるように、ファイル名は`"`で囲んでください。
117
+
118
+ 対象学年では習わない漢字があると、ファイル名、行番号、列番号、理由が表示されます。
119
+
120
+ ```text
121
+ 原稿.txt
122
+ 3:5 error 「植」は小学3年生で学習する漢字です。小学2年生までの文章では使用できません。 ja-grade-kanji
123
+ ```
124
+
125
+ この例の`3:5`は、3行目の5文字目付近に問題があることを示します。
126
+ 原稿を直して保存したあと、同じコマンドをもう一度実行してください。
127
+ ターミナルで上矢印キーを押すと、直前のコマンドを呼び出せます。
128
+
129
+ 何も表示されずに次の入力を受け付ける状態へ戻れば、検出対象の漢字はありません。
130
+ ただし、文章の難しさや読みやすさまで保証するものではないため、最後は対象読者に合わせて原稿を読み直してください。
131
+
132
+ ## 複数の原稿をまとめて検査する
133
+
134
+ 同じフォルダーにあるすべての`.txt`ファイルと`.md`ファイルを検査するには、次のコマンドを使います。
135
+
136
+ ```shell
137
+ npx textlint "*.txt" "*.md"
138
+ ```
139
+
140
+ 原稿を子フォルダーにも分けている場合は、次のコマンドでその中まで検査できます。
141
+
142
+ ```shell
143
+ npx textlint "**/*.txt" "**/*.md"
144
+ ```
145
+
146
+ ## 固有名詞などを例外として許可する
147
+
148
+ 人名や地名など、対象学年外でも原稿に必要な漢字は、`allow`へ登録できます。
149
+ 次の設定は、小学2年生までの漢字に加えて「誰」「情」「報」を許可します。
150
+
151
+ ```json
152
+ {
153
+ "rules": {
154
+ "ja-grade-kanji": {
155
+ "grade": 2,
156
+ "allow": ["誰", "情報"]
157
+ }
158
+ }
159
+ }
160
+ ```
161
+
162
+ `"情報"`のように複数の文字をまとめて書くと、その中の漢字を1文字ずつ許可します。
163
+ 登録した語だけを例外にする設定ではないため、「情」と「報」は別の語に含まれていても許可されます。
164
+
165
+ ## よくあるエラー
166
+
167
+ ### `npm error 404 Not Found`と表示される
168
+
169
+ インストールするパッケージ名がnpmに見つからないときの表示です。
170
+ コマンドが次の内容と一致しているか確認してください。
171
+
172
+ ```shell
173
+ npm install --save-dev textlint textlint-rule-ja-grade-kanji
174
+ ```
175
+
176
+ 名前が一致していても同じエラーが続く場合は、パッケージがまだnpmに公開されていない可能性があります。
177
+ これは利用者のパソコンでは解決できないため、パッケージの公開後にもう一度実行してください。
178
+
179
+ ### `node`または`npm`が見つからない
180
+
181
+ Node.jsをインストールしたあと、開いたままのターミナルには設定が反映されないことがあります。
182
+ ターミナルを閉じて開き直し、`node --version`を再実行してください。
183
+
184
+ ### `Cannot find module`またはルールが見つからないと表示される
185
+
186
+ ターミナルが`kanji-check`以外のフォルダーを開いているか、インストールが完了していません。
187
+ 次のコマンドを順番に実行してから、原稿を再検査してください。
188
+
189
+ ```shell
190
+ cd kanji-check
191
+ npm install
192
+ ```
193
+
194
+ ### 設定ファイルを読み込めない
195
+
196
+ ファイル名が`.textlintrc.json.txt`になっていないか確認してください。
197
+ Windowsのメモ帳で保存する場合は、ファイルの種類に「すべてのファイル」を選び、`.textlintrc.json`という名前で保存します。
198
+
199
+ ファイル名が正しければ、設定内容の引用符、波括弧、カンマを確認します。
200
+ 原因がわからない場合は、「検査する学年を設定する」に掲載した設定例へいったん戻してください。
201
+
202
+ ### 原稿が見つからないと表示される
203
+
204
+ 原稿が`kanji-check`フォルダーにあるか、コマンドに書いたファイル名と実際の名前が一致しているか確認します。
205
+ `.txt`や`.md`まで含めて同じ名前にしてください。
206
+
207
+ ### 警告が多すぎる
208
+
209
+ `grade`が原稿の対象学年と一致しているか確認します。
210
+ 固有名詞など意図して使う漢字は、理由を確認したうえで`allow`へ登録してください。
211
+ 大量の漢字をまとめて許可すると、本来見つけたい未習漢字まで見逃すため、必要な文字だけを登録します。
212
+
213
+ ## 次回からの使い方
214
+
215
+ 初回の準備が終われば、次回から必要な操作は次の4つです。
216
+
217
+ 1. ターミナルを開く。
218
+ 2. `cd kanji-check`を実行する。
219
+ 3. 原稿を`kanji-check`フォルダーへ入れる。
220
+ 4. `npx textlint "原稿.txt"`を実行する。
221
+
222
+ 対象学年を変えるときだけ、`.textlintrc.json`の`grade`を変更します。
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "textlint-rule-ja-grade-kanji",
3
+ "version": "1.0.0",
4
+ "description": "学年別漢字配当表に基づいて対象学年では未習の漢字を検出するtextlintルール",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "require": "./dist/index.js",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "docs",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc -p tsconfig.json",
22
+ "test": "vitest run",
23
+ "prepack": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "textlint",
27
+ "textlint-rule",
28
+ "japanese",
29
+ "kanji",
30
+ "education"
31
+ ],
32
+ "author": "101ta28",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/101ta28/textlint-rule-ja-grade-kanji.git"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/101ta28/textlint-rule-ja-grade-kanji/issues"
40
+ },
41
+ "homepage": "https://github.com/101ta28/textlint-rule-ja-grade-kanji#readme",
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "type": "commonjs",
46
+ "engines": {
47
+ "node": ">=20"
48
+ },
49
+ "peerDependencies": {
50
+ "textlint": ">=15.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@textlint/kernel": "^15.8.0",
54
+ "@textlint/textlint-plugin-markdown": "^15.8.0",
55
+ "@textlint/types": "^15.8.0",
56
+ "textlint": "^15.8.0",
57
+ "typescript": "^7.0.2",
58
+ "vitest": "^4.1.11"
59
+ }
60
+ }