├── .githooks └── pre-commit ├── .github ├── release.yml └── workflows │ ├── test.yml │ └── website.yml ├── .gitignore ├── .mocharc.json ├── LICENSE ├── README.md ├── dict ├── 2.1.5.yml ├── 2.1.6.yml ├── 2.2.1.yml └── 2.2.3.yml ├── example ├── .npmrc ├── .textlintrc ├── README.md ├── package.json └── pnpm-lock.yaml ├── jtf_style_guide2.2.pdf ├── package.json ├── pnpm-lock.yaml ├── src ├── 1.1.1.js ├── 1.1.2.js ├── 1.1.3.js ├── 1.1.5.js ├── 1.2.1.js ├── 1.2.2.js ├── 2.1.10.js ├── 2.1.2.js ├── 2.1.5.js ├── 2.1.6.js ├── 2.1.8.js ├── 2.1.9.js ├── 2.2.1.js ├── 2.2.2.js ├── 2.2.3.js ├── 3.1.1.js ├── 3.1.2.js ├── 3.2.js ├── 3.3.js ├── 4.1.1.js ├── 4.1.3.js ├── 4.2.1.js ├── 4.2.2.js ├── 4.2.4.js ├── 4.2.5.js ├── 4.2.6.js ├── 4.2.7.js ├── 4.2.8.js ├── 4.2.9.js ├── 4.3.1.js ├── 4.3.2.js ├── 4.3.3.js ├── 4.3.4.js ├── 4.3.5.js ├── 4.3.6.js ├── 4.3.7.js ├── 4.3.8.js ├── index.js └── util │ ├── merge-matches.js │ ├── node-util.js │ ├── pair-checker.js │ └── regexp.js ├── test ├── 1.1.1-test.js ├── 1.1.2-test.js ├── 1.1.3-test.js ├── 1.1.5-test.js ├── 1.2.1-test.js ├── 1.2.2-test.js ├── 2.1.10-test.js ├── 2.1.2-test.js ├── 2.1.5-test.js ├── 2.1.6-test.js ├── 2.1.8-test.js ├── 2.1.9-test.js ├── 2.2.1-test.js ├── 2.2.2-test.js ├── 2.2.3-test.js ├── 3.1.1-test.js ├── 3.1.2-test.js ├── 3.2-test.js ├── 3.3-test.js ├── 4.1.1-test.js ├── 4.1.3-test.js ├── 4.2.1-test.js ├── 4.2.2-test.js ├── 4.2.4-test.js ├── 4.2.5-test.js ├── 4.2.6-test.js ├── 4.2.7-test.js ├── 4.2.8-test.js ├── 4.2.9-test.js ├── 4.3.1-test.js ├── 4.3.2-test.js ├── 4.3.3-test.js ├── 4.3.4-test.js ├── 4.3.5-test.js ├── 4.3.6-test.js ├── 4.3.7-test.js ├── 4.3.8-test.js ├── fixer-test.js ├── fixtures │ ├── input.md │ └── output.md ├── index-test.js └── prh-test.js └── tool └── create-fixtures.js /.githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | npx --no-install lint-staged 3 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - 'Type: Meta' 5 | - 'Type: Question' 6 | - 'Type: Release' 7 | 8 | categories: 9 | - title: Security Fixes 10 | labels: ['Type: Security'] 11 | - title: Breaking Changes 12 | labels: ['Type: Breaking Change'] 13 | - title: Features 14 | labels: ['Type: Feature'] 15 | - title: Bug Fixes 16 | labels: ['Type: Bug'] 17 | - title: Documentation 18 | labels: ['Type: Documentation'] 19 | - title: Refactoring 20 | labels: ['Type: Refactoring'] 21 | - title: Testing 22 | labels: ['Type: Testing'] 23 | - title: Maintenance 24 | labels: ['Type: Maintenance'] 25 | - title: CI 26 | labels: ['Type: CI'] 27 | - title: Dependency Updates 28 | labels: ['Type: Dependencies', "dependencies"] 29 | - title: Other Changes 30 | labels: ['*'] 31 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | name: "Test on Node.js ${{ matrix.node-version }}" 6 | runs-on: ubuntu-latest 7 | permissions: 8 | contents: read 9 | strategy: 10 | matrix: 11 | node-version: [ 18, 20, 22 ] 12 | steps: 13 | - name: checkout 14 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 15 | with: 16 | persist-credentials: false 17 | 18 | - name: Install pnpm 19 | uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 20 | - name: setup Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - name: Install 25 | run: pnpm install 26 | - name: Test 27 | run: pnpm test 28 | -------------------------------------------------------------------------------- /.github/workflows/website.yml: -------------------------------------------------------------------------------- 1 | name: website 2 | on: 3 | push: 4 | branches: 5 | - master 6 | workflow_dispatch: 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: write 13 | steps: 14 | - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 15 | with: 16 | persist-credentials: false 17 | 18 | - name: Install pnpm 19 | uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 20 | - name: Setup Node.js 21 | uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 22 | with: 23 | node-version: 22 24 | - name: Set Env 25 | run: | 26 | echo "CURRENT_VERSION=$(node -p 'require("./package.json").version')" >> $GITHUB_ENV 27 | - name: Install and Build Root 28 | run: | 29 | pnpm install 30 | pnpm run build 31 | - name: Build Website 32 | run: | 33 | pnpm install 34 | pnpm run website -- --metadataVersion="${CURRENT_VERSION}" 35 | env: 36 | CURRENT_VERSION: ${{ env.CURRENT_VERSION }} 37 | working-directory: example/ 38 | - name: Deploy 39 | uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 40 | with: 41 | github_token: ${{ secrets.GITHUB_TOKEN }} 42 | publish_dir: ./example/dist 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | /lib 3 | ### https://raw.github.com/github/gitignore/408c616ae0ad8f4b8101d8e876b9b67ac6b14059/Node.gitignore 4 | 5 | # Logs 6 | logs 7 | *.log 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directory 30 | # Commenting this out is preferred by some people, see 31 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 32 | node_modules 33 | 34 | 35 | ### https://raw.github.com/github/gitignore/408c616ae0ad8f4b8101d8e876b9b67ac6b14059/Global/JetBrains.gitignore 36 | 37 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 38 | 39 | *.iml 40 | 41 | ## Directory-based project format: 42 | .idea/ 43 | # if you remove the above rule, at least ignore the following: 44 | 45 | # User-specific stuff: 46 | # .idea/workspace.xml 47 | # .idea/tasks.xml 48 | # .idea/dictionaries 49 | 50 | # Sensitive or high-churn files: 51 | # .idea/dataSources.ids 52 | # .idea/dataSources.xml 53 | # .idea/sqlDataSources.xml 54 | # .idea/dynamic.xml 55 | # .idea/uiDesigner.xml 56 | 57 | # Gradle: 58 | # .idea/gradle.xml 59 | # .idea/libraries 60 | 61 | # Mongo Explorer plugin: 62 | # .idea/mongoSettings.xml 63 | 64 | ## File-based project format: 65 | *.ipr 66 | *.iws 67 | 68 | ## Plugin-specific files: 69 | 70 | # IntelliJ 71 | out/ 72 | 73 | # mpeltonen/sbt-idea plugin 74 | .idea_modules/ 75 | 76 | # JIRA plugin 77 | atlassian-ide-plugin.xml 78 | 79 | /src/jtf-style.js 80 | # Crashlytics plugin (for Android Studio and IntelliJ) 81 | com_crashlytics_export_strings.xml 82 | crashlytics.properties 83 | crashlytics-build.properties 84 | 85 | 86 | ### https://raw.github.com/github/gitignore/408c616ae0ad8f4b8101d8e876b9b67ac6b14059/Node.gitignore 87 | 88 | # Logs 89 | logs 90 | *.log 91 | 92 | # Runtime data 93 | pids 94 | *.pid 95 | *.seed 96 | 97 | # Directory for instrumented libs generated by jscoverage/JSCover 98 | lib-cov 99 | 100 | # Coverage directory used by tools like istanbul 101 | coverage 102 | 103 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 104 | .grunt 105 | 106 | # node-waf configuration 107 | .lock-wscript 108 | 109 | # Compiled binary addons (http://nodejs.org/api/addons.html) 110 | build/Release 111 | 112 | # Dependency directory 113 | # Commenting this out is preferred by some people, see 114 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 115 | node_modules 116 | 117 | 118 | ### https://raw.github.com/github/gitignore/408c616ae0ad8f4b8101d8e876b9b67ac6b14059/Global/JetBrains.gitignore 119 | 120 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 121 | 122 | *.iml 123 | 124 | ## Directory-based project format: 125 | .idea/ 126 | # if you remove the above rule, at least ignore the following: 127 | 128 | # User-specific stuff: 129 | # .idea/workspace.xml 130 | # .idea/tasks.xml 131 | # .idea/dictionaries 132 | 133 | # Sensitive or high-churn files: 134 | # .idea/dataSources.ids 135 | # .idea/dataSources.xml 136 | # .idea/sqlDataSources.xml 137 | # .idea/dynamic.xml 138 | # .idea/uiDesigner.xml 139 | 140 | # Gradle: 141 | # .idea/gradle.xml 142 | # .idea/libraries 143 | 144 | # Mongo Explorer plugin: 145 | # .idea/mongoSettings.xml 146 | 147 | ## File-based project format: 148 | *.ipr 149 | *.iws 150 | 151 | ## Plugin-specific files: 152 | 153 | # IntelliJ 154 | out/ 155 | 156 | # mpeltonen/sbt-idea plugin 157 | .idea_modules/ 158 | 159 | # JIRA plugin 160 | atlassian-ide-plugin.xml 161 | 162 | # Crashlytics plugin (for Android Studio and IntelliJ) 163 | com_crashlytics_export_strings.xml 164 | crashlytics.properties 165 | crashlytics-build.properties 166 | 167 | 168 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": [ 3 | "textlint-scripts/register" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # textlint-rule-preset-JTF-style [![textlint rule](https://img.shields.io/badge/textlint-fixable-green.svg?style=social)](https://textlint.github.io/) [![Actions Status: test](https://github.com/textlint-ja/textlint-rule-preset-JTF-style/workflows/test/badge.svg)](https://github.com/textlint-ja/textlint-rule-preset-JTF-style/actions?query=workflow%3A"test") 2 | 3 | [JTF日本語標準スタイルガイド(翻訳用)](https://www.jtf.jp/tips/styleguide "JTF日本語標準スタイルガイド(翻訳用)") for [textlint](https://github.com/textlint/textlint "textlint"). 4 | 5 | [2016年2月22日改訂第2.2版](https://github.com/textlint-ja/textlint-rule-preset-JTF-style/blob/master/jtf_style_guide2.2.pdf)を元にしています。 6 | 7 | ## Installation 8 | 9 | npm install textlint-rule-preset-jtf-style 10 | 11 | ## Usage 12 | 13 | 基本的に[textlint](https://github.com/textlint/textlint "textlint")の使い方と同じです。 14 | 15 | - [textlintで日本語の文章をチェックする | Web Scratch](https://efcl.info/2015/09/10/introduce-textlint/ "textlintで日本語の文章をチェックする | Web Scratch") 16 | 17 | ### 最も手軽な方法(グローバル) 18 | 19 | npmでグローバルにインストールし、`--preset`で利用するのが一番お手軽です。 20 | 21 | npm install -g textlint textlint-rule-preset-jtf-style 22 | textlint --preset textlint-rule-preset-jtf-style README.md 23 | # README.mdをLintした結果が出力されます 24 | 25 | グローバルにインストールするよりは、次のようにプロジェクト毎のディレクトリにインストールする方法を推奨します。 26 | 27 | ### `.textlintrc`を使う方法(推奨) 28 | 29 | 現在のディレクトリにtextlintとtextlint-rule-preset-jtf-styleをインストールする方法です。 30 | (グローバルにインストールしなくていいので環境がキレイに作れます) 31 | 32 | ``` 33 | npm init # package.jsonがないなら 34 | npm install -D textlint textlint-rule-preset-jtf-style 35 | ``` 36 | 37 | textlintの設定ファイルとなっている`.textlintrc`に次のように`jtf-style`と指定します(`textlint-rule-`を取り除いたプリセット名)。 38 | 39 | ```json5 40 | { 41 | "rules": { 42 | "preset-jtf-style": true 43 | } 44 | } 45 | ``` 46 | 47 | 実行するには、`$ textlint <対象ファイル>` を行うだけで、自動的に同じディレクトリにある`.textlintrc`の設定を読み込んでくれます。 48 | 49 | ``` 50 | node_modules/.bin/textlint /path/to/target.md 51 | ``` 52 | 53 | npm run-script経由で実行すれば、`node_modules/.bin/`は省略出来ます。 54 | 55 | - [npm で依存もタスクも一元化する - Qiita](https://qiita.com/Jxck/items/efaff21b977ddc782971#%E3%82%BF%E3%82%B9%E3%82%AF%E3%81%AE%E5%AE%9F%E8%A1%8C "npm で依存もタスクも一元化する - Qiita") 56 | 57 | ## 自動修正 58 | 59 | ルールの設定して`textlint`コマンドでチェックするとたくさんのエラーが表示されると思います。 60 | 61 | ``` 62 | textlint /path/to/target.md 63 | ``` 64 | 65 | `textlint-rule-preset-JTF-style`の一部ルールは`textlint`の`--fix`にも対応しています。 66 | `--fix`を使うことで機械的に判断して修正できる部分は自動修正します。 67 | 68 | ```sh 69 | textlint --fix /path/to/target.md 70 | ``` 71 | 72 | 実際にファイルを書き換えるので、必ずファイルをコピーしておくなどしてファイルを戻せるようにしてから実行してください。 73 | 74 | ### サンプル 75 | 76 | [example/](example/) に実行できるサンプルプロジェクトがあります。 77 | 78 | ## ルール一覧 79 | 80 | それぞれのルールの詳細は以下を読んでください。 81 | 82 | - [JTF日本語標準スタイルガイド(翻訳用)(PDFファイル)](https://www.jtf.jp/pdf/jtf_style_guide.pdf) 83 | 84 | `textlint-rule-preset-jtf-style`で対応するルールと実装状況は以下のとおりです。 85 | 86 | 辞書ベースと書かれているものは、独自の辞書をベースとしているため精度が曖昧となっています。 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 |
対応ルールページ(v2.1)小項目JTF標準ルール中項目大項目
1.1.1.js10本文目的に応じて敬体、常体のどちらかに統一する。文体基本文型
1.1.2.js10見出し常体または体言止め。
1.1.3.js10箇条書き「本文」の文体に合わせる。
不可11図表内テキスト「本文」の文体に合わせる。
1.1.5.js11図表のキャプション「本文」の文体に合わせる。
1.2.1.js11句点(。)と読点(、)全角の「、」と「。」を使う。句読点の使用
1.2.2.js11ピリオド(.)とカンマ(,)和文の句読点として使用しない。
未実装11ひらがな全角。昭和61年7月1日内閣告示第1号の「現代仮名遣い」に準じる。用字、用語文字の表記
2.1.2.js (辞書ベース)11漢字常用漢字表にゆるやかに準じる。
未実装12漢字の送りがな昭和48年6月18日内閣告示第2号「送り仮名の付け方」に準じる。
未実装13複合語の送りがな昭和48年6月18日内閣告示第2号「送り仮名の付け方」に準じる。
2.1.5.js (辞書ベース/デフォルト無効)14カタカナ全角。半角カタカナは特殊用途を除いて使わない。
2.1.6.js (辞書ベース/デフォルト無効)14カタカナの長音原則として省略しない。
不可15カタカナ複合語中黒または半角スペースで区切る。
2.1.8.js16算用数字半角。
2.1.9.js16アルファベット半角。
2.1.10.js16算用数字(位取りの表記)桁区切りには「カンマ」、小数点には「ピリオド」を使う。ただし桁区切りの「カンマ」は省略する場合がある。
2.2.1.js (辞書ベース/デフォルト無効)17ひらがなと漢字の使い分け参考文献に従う。文字の表記と使い分け
2.2.2.js19算用数字と漢数字の使い分け数えられるものは算用数字。慣用句は漢数字。
2.2.3.js20一部の助数詞の表記「〜か月」、「〜か所」
3.1.1.js20全角と半角の間スペースなし単一文字間のスペースの有無文字間のスペース
3.1.2.js20全角どうしスペースなし
不可20半角どうし和文中に欧文を引用するなど、和文に欧文が含まれる場合は欧文中の半角スペースを維持する。
3.2.js20カタカナ語間のスペースの有無中黒または半角スペースを入れる。カタカナ語間のスペースの有無
3.3.js20かっこ類と隣接する文字の間のスペーススペースなしかっこ類と隣接する文字の間のスペースの有無
4.1.1.js21句点(。)全角句読点記号の表記と用途
不可(1.2.2参照)21読点(、)全角
4.1.3.js (1.2.2参照)21ピリオド(.)、カンマ(,)半角
4.2.1.js21感嘆符(!)全角。和文では多用しない。記号
4.2.2.js22疑問符(?)全角。和文では多用しない。
チェック項目なし22スラッシュ(/)全角または半角
4.2.4.js22中黒(・)全角
4.2.5.js22波線(〜または~)全角
4.2.6.js22ハイフン(-)原則として和文では使用しない。
4.2.7.js23コロン(:)全角。和文では多用しない。
4.2.8.js23セミコロン(;)原則として和文では使用しない。
4.2.9.js23ダッシュ(-)原則として和文では使用しない。
4.3.1.js23丸かっこ()全角かっこ
4.3.2.js23大かっこ[]全角
4.3.3.js23かぎかっこ「」全角
4.3.4.js23二重かぎかっこ『』全角
4.3.5.js (対の有無)23二重引用符\" \"半角。和文では多用しない。
4.3.6.js (対の有無)24中かっこ{}原則として和文では使用しない。
4.3.7.js (対の有無)24山かっこ<>原則として和文では使用しない。
4.3.8.js (対の有無)24一重引用符' '原則として和文では使用しない。
不可24JIS規格Z8202「量及び単位」、Z8203「国際単位系(SI)及びその使い方」に従う。単位系単位の表記
24主に、英字による表記とカタカナによる表記がある。単位記号の表記
24時間、時刻時間、時、分、秒、ミリ秒個別の単位
24長さmm、km、ミリメートル、センチメートル
24質量g、kg、t、グラム、キログラム、トン
24面積、体積㎡、平方メートル、立法メートル
24電気A、W、V、アンペア、ワット、ボルト
25温度
25周波数Hz、ヘルツ
25速度m/s、キロメートル毎時、分速~km
25伝送速度bps、Kbps、バイト/秒
25割合%、パーセント
25角度90°、90度
25記憶容量ビット、バイト、Kb、KB、Mb、MB
25通貨円、米ドル、ユーロ、$、USD
25その他
586 | 587 | ## FAQ 588 | 589 | Q. このルールはスタイルガイドと合ってないのでは? 590 | 591 | A. [Issue](https://github.com/textlint-ja/textlint-rule-preset-jtf-style/issues/new)に詳細を書いてみるといいと思います。 592 | 593 | Issueには以下の項目が書かれていると問題を解決しやすくなります。 594 | 595 | - 試した文章(もしくはファイル) 596 | - 期待する結果 597 | - 例: このルール(1.2.3)でエラーとなるはず 598 | - 実際の結果 599 | - 例: 実際にはエラーとならなかった 600 | 601 | また、[JTF日本語標準スタイルガイド(翻訳用)](https://www.jtf.jp/pdf/jtf_style_guide.pdf)に記載されてる全てのルールが実装済みではないため、 602 | Pull Requestも歓迎しています。 603 | 604 | ----- 605 | 606 | Q. 特定のルールを使いたくない 607 | 608 | A. `.textlintrc` にルール毎の設定を追加することが出来ます。 609 | 610 | - [textlintで日本語の文章をチェックする | Web Scratch](https://efcl.info/2015/09/10/introduce-textlint/ "textlintで日本語の文章をチェックする | Web Scratch") 611 | 612 | `1.2.2.ピリオド(.)とカンマ(,)`のルールを無効化したい場合は、`.textlintrc`に次のように`false`値を設定することで無効化出来ます。 613 | デフォルトでは`textlint-rule-preset-jtf-style`に含まれるルールが全て有効化されています。 614 | 615 | ```json5 616 | { 617 | "rules": { 618 | "preset-jtf-style": { 619 | "1.2.2.ピリオド(.)とカンマ(,)": false 620 | } 621 | } 622 | } 623 | ``` 624 | 625 | それぞれの指定できる`rules`のキー名は[index.js](src/index.js)を参照してください。 626 | 627 | `jtf-style/` となります。 628 | 629 | Q. 辞書ベースのルールの質がよくない 630 | 631 | A. 正規表現の辞書ベースのルールが幾つかあります。 632 | 633 | その他のtextlintルールと衝突が発生しやすい辞書ベースのルールとなっています。 634 | そのため、辞書を改善していくかルール自体を無効化するアプローチを取る必要あります。 635 | 636 | デフォルトでは次の辞書ベースのルールは無効化されています。 637 | 638 | - [2.1.2.漢字](./src/2.1.2.js) 639 | - [2.1.5.カタカナ](./src/2.1.5.js) 640 | - [2.1.6.カタカナの長音](./src/2.1.6.js) 641 | - [2.2.1.ひらがなと漢字の使い分け](./src/2.2.1.js) 642 | 643 | これらのルールを有効化したい場合は、`.textlintrc`で明示的に有効化する必要があります。 644 | 645 | ```json5 646 | { 647 | "rules": { 648 | "preset-jtf-style": { 649 | "2.1.2.漢字": true, 650 | "2.1.5.カタカナ": true, 651 | "2.1.6.カタカナの長音": true, 652 | "2.2.1.ひらがなと漢字の使い分け": true 653 | } 654 | } 655 | } 656 | ``` 657 | 658 | Q. 半角かっこの外側のスペースを禁止したい・必須にしたい 659 | 660 | A. オプションで半角かっこの外側のスペースの扱いを変更することが出来ます。 661 | 662 | [3.3.かっこ類と隣接する文字の間のスペースの有無](./src/3.3.js)のオプションを設定することで、半角かっこの外側のスペースの扱いを変更することができます。 663 | 664 | `allowOutsideHalfParentheses` は半角かっこの外側の半角スペースを許容するオプションです。 665 | デフォルトは `true` です。 666 | `false` に設定することで、半角かっこの外側のスペースを禁止できます。 667 | 668 | ```json5 669 | { 670 | "rules": { 671 | "preset-jtf-style": { 672 | "3.3.かっこ類と隣接する文字の間のスペースの有無": { 673 | "allowOutsideHalfParentheses": false 674 | } 675 | } 676 | } 677 | } 678 | ``` 679 | 680 | `requireOutsideHalfParentheses` は半角かっこの外側の半角スペースを必須にするオプションです。 681 | デフォルトは `false` です。 682 | 683 | ```json5 684 | { 685 | "rules": { 686 | "preset-jtf-style": { 687 | "3.3.かっこ類と隣接する文字の間のスペースの有無": { 688 | "requireOutsideHalfParentheses": true 689 | } 690 | } 691 | } 692 | } 693 | ``` 694 | 695 | ## Migration: `textlint-plugin-jtf-style` to `textlint-rule-preset-jtf-style` 696 | 697 | `textlint-plugin-jtf-style` から `textlint-rule-preset-jtf-style` へ移行したい場合の移行手順です。 698 | 699 | 次のようにモジュールを切り替えます。 700 | 701 | ```sh 702 | npm uninstall -D textlint-plugin-jtf-style 703 | npm install -D textlint-rule-preset-jtf-style 704 | ``` 705 | 706 | その後、`.textlintrc`にかかれている設定を 707 | 708 | ```json5 709 | { 710 | "plugins": [ 711 | "jtf-style" 712 | ], 713 | "rules": { 714 | "jtf-style/2.1.2.漢字": true, 715 | "jtf-style/2.1.5.カタカナ": true, 716 | "jtf-style/2.1.6.カタカナの長音": true, 717 | "jtf-style/2.2.1.ひらがなと漢字の使い分け": true 718 | } 719 | } 720 | ``` 721 | 722 | 以下のように書き換えれば完了です。 723 | 724 | ```json5 725 | { 726 | "rules": { 727 | "preset-jtf-style": { 728 | "2.1.2.漢字": true, 729 | "2.1.5.カタカナ": true, 730 | "2.1.6.カタカナの長音": true, 731 | "2.2.1.ひらがなと漢字の使い分け": true 732 | } 733 | } 734 | } 735 | ``` 736 | 737 | 738 | ## Contributing 739 | 740 | まだ未実装なルールがありますのでPull Request歓迎。 741 | 実装済みのルールでもその項目を全て満たせてないケースがあるかもしれません。 742 | 743 | 1. Fork it! 744 | 2. Create your feature branch: `git checkout -b my-new-feature` 745 | 3. Commit your changes: `git commit -am 'Add some feature'` 746 | 4. Push to the branch: `git push origin my-new-feature` 747 | 5. Submit a pull request :D 748 | 749 | ## License 750 | 751 | by Japan Translation Federation (CC BY-SA) www.jtf.jp 752 | 本著作物は「JTF日本語標準スタイルガイド2.0」(JTF, CC BY-SA)を改変して作成したものです。 753 | 754 | - [JTFスタイルガイドとCCライセンスの素敵な関係 | JTFジャーナルWeb](https://webjournal.jtf.jp/back-number/#b271/6/ "JTFスタイルガイドとCCライセンスの素敵な関係 | JTFジャーナルWeb") 755 | 756 | その他のコードはMITライセンスです。 757 | -------------------------------------------------------------------------------- /dict/2.1.5.yml: -------------------------------------------------------------------------------- 1 | # This dictionary is based on http://www.jtf.jp/jp/style_guide/jtfstylechecker.html 2 | # テクニカルコミュニケーター協会> 外来語(カタカナ)表記ガイドライン http://www.jtca.org/standardization/ 3 | # TODO: [WIP] not complete 4 | version: 1 5 | rules: 6 | - expected: アジア 7 | patterns: アジヤ 8 | 9 | - expected: アトランティック 10 | patterns: アトランチック 11 | 12 | - expected: アベレージ 13 | patterns: アヴェレージ 14 | 15 | - expected: アベレージ 16 | patterns: アベレイジ 17 | 18 | - expected: アンチ 19 | patterns: アンティ 20 | 21 | - expected: アンティーク 22 | patterns: アンチーク 23 | 24 | - expected: アンモニア 25 | patterns: アンモニヤ 26 | 27 | - expected: イタリア 28 | patterns: イタリヤ 29 | 30 | - expected: イニシアチブ 31 | patterns: イニシアティブ 32 | 33 | - expected: イベント 34 | patterns: イヴェント 35 | 36 | - expected: イミテーション 37 | patterns: イミテイション 38 | 39 | - expected: イヤホン 40 | patterns: イアホン 41 | 42 | - expected: イヤホン 43 | patterns: イヤフォン 44 | 45 | - expected: インジケーター 46 | patterns: インディケータ 47 | 48 | - expected: インターフェイス 49 | patterns: インタフェイス 50 | 51 | - expected: インターフェイス 52 | patterns: インターフェース 53 | 54 | - expected: インターフェイス 55 | patterns: インタフェース 56 | 57 | - expected: インターホン 58 | patterns: インターフォン 59 | 60 | - expected: インフォメーション 61 | patterns: インホメーション 62 | 63 | - expected: ウェア 64 | patterns: ウエア 65 | 66 | - expected: エジソン 67 | patterns: エディソン 68 | 69 | - expected: エスカレーター 70 | patterns: エスカレイタ 71 | 72 | - expected: エラー 73 | patterns: エラア 74 | 75 | - expected: エレベーター 76 | patterns: エレベイタ 77 | 78 | - expected: オーディオ 79 | patterns: オウディオ 80 | 81 | - expected: オートマチック 82 | patterns: オートマチック 83 | 84 | - expected: オーナー 85 | patterns: オウナー 86 | 87 | - expected: オーバー 88 | patterns: オウバー 89 | 90 | - expected: オーバーコート 91 | patterns: オウバーコート 92 | 93 | - expected: カバー 94 | patterns: カバア 95 | 96 | - expected: カフェテリア 97 | patterns: カフェテリヤ 98 | 99 | - expected: カラー 100 | patterns: カラア 101 | 102 | - expected: ギア 103 | patterns: ギヤ 104 | 105 | - expected: キー 106 | patterns: キイ 107 | 108 | - expected: キャラバン 109 | patterns: キャラヴァン 110 | 111 | - expected: グラビア 112 | patterns: グラビヤ 113 | 114 | - expected: クリエーティブ 115 | patterns: クリエイティブ 116 | 117 | - expected: ケア 118 | patterns: ケアー 119 | 120 | - expected: ケース 121 | patterns: ケイス 122 | 123 | - expected: ゲーム 124 | patterns: ゲイム 125 | 126 | - expected: コピー 127 | patterns: コピイ 128 | 129 | - expected: コンディション 130 | patterns: コンデション 131 | 132 | - expected: サービス 133 | patterns: サーヴィス 134 | 135 | - expected: サーベイ 136 | patterns: サーヴェイ 137 | 138 | - expected: サラダボウル 139 | patterns: サラダボール 140 | 141 | - expected: シェード 142 | patterns: シェイド 143 | 144 | - expected: ジフテリア 145 | patterns: ジフテリヤ 146 | 147 | - expected: シミュレーション 148 | patterns: シミュレイション 149 | 150 | - expected: シミュレーション 151 | patterns: シュミレーション 152 | 153 | - expected: シミュレーター 154 | patterns: シュミレータ 155 | 156 | - expected: ショー 157 | patterns: ショウ 158 | 159 | - expected: スーパー 160 | patterns: スーパア 161 | 162 | - expected: スケール 163 | patterns: スケイル 164 | 165 | - expected: スタジアム 166 | patterns: スタディアム 167 | 168 | - expected: ストア 169 | patterns: ストアー 170 | 171 | - expected: スペース 172 | patterns: スペイス 173 | 174 | - expected: スリッパ 175 | patterns: スリッパー 176 | 177 | - expected: セーフティー 178 | patterns: セイフティー 179 | 180 | - expected: セピア 181 | patterns: セピヤ 182 | 183 | - expected: セロハン 184 | patterns: セロファン 185 | 186 | - expected: ソフトウェア 187 | patterns: ソフトウエア 188 | 189 | - expected: タイヤ 190 | patterns: タイア 191 | 192 | - expected: ダイヤグラム 193 | patterns: ダイアグラム 194 | 195 | - expected: ダイヤモンド 196 | patterns: ダイアモンド 197 | 198 | - expected: ダイヤラー 199 | patterns: ダイアラ 200 | 201 | - expected: ダイヤル 202 | patterns: ダイアル 203 | 204 | - expected: ダミー 205 | patterns: ダミイ 206 | 207 | - expected: チアミン 208 | patterns: ティアミン 209 | 210 | - expected: チェーン 211 | patterns: チェイン 212 | 213 | - expected: チケット 214 | patterns: ティケット 215 | 216 | - expected: チップ 217 | patterns: ティップ 218 | 219 | - expected: ディスカッション 220 | patterns: デスカッション 221 | 222 | - expected: ディスカバリー 223 | patterns: デスカバリ 224 | 225 | - expected: ディズニー 226 | patterns: デズニー 227 | 228 | - expected: ディスプレー 229 | patterns: ディスプレイ 230 | 231 | - expected: ディスプレー 232 | patterns: デスプレー 233 | 234 | - expected: ディスプレー 235 | patterns: デスプレイ 236 | 237 | - expected: デジタル 238 | patterns: ディジタル 239 | 240 | - expected: テレフォンサービス 241 | patterns: テレホンサービス 242 | 243 | - expected: ドア 244 | patterns: ドアー 245 | 246 | - expected: トナー 247 | patterns: トナア 248 | 249 | - expected: ドメイン 250 | patterns: ドメーン 251 | 252 | - expected: トライアル 253 | patterns: トライヤル 254 | 255 | - expected: ドリア 256 | patterns: ドリヤ 257 | 258 | - expected: トレーナー 259 | patterns: トレイナー 260 | 261 | - expected: ニュートン 262 | patterns: ニュウトン 263 | 264 | - expected: ネーチャー 265 | patterns: ネイチャー 266 | 267 | - expected: ネーム 268 | patterns: ネイム 269 | 270 | - expected: ネガティブ 271 | patterns: ネガティヴ 272 | 273 | - expected: バージョン 274 | patterns: ヴァージョン 275 | 276 | - expected: ハードウェア 277 | patterns: ハードウエア 278 | 279 | - expected: バイアス 280 | patterns: バイヤス 281 | 282 | - expected: バイオリン 283 | patterns: ヴァイオリン 284 | 285 | - expected: バクテリア 286 | patterns: バクテリヤ 287 | 288 | - expected: バニラ 289 | patterns: ヴァニラ 290 | 291 | - expected: バリエーション 292 | patterns: ヴァリエーション 293 | 294 | - expected: バルブ 295 | patterns: ヴァルブ 296 | 297 | - expected: バレエ 298 | patterns: バレー 299 | 300 | - expected: ハンチング 301 | patterns: ハンティング 302 | 303 | - expected: ピアノ 304 | patterns: ピヤノ 305 | 306 | - expected: ビジー 307 | patterns: ビジイ 308 | 309 | - expected: ビデオ 310 | patterns: ヴィデオ 311 | 312 | - expected: ビリヤード 313 | patterns: ビリアード 314 | 315 | - expected: ファンタスティック 316 | patterns: ファンタスチック 317 | 318 | - expected: フォークダンス 319 | patterns: ホークダンス 320 | 321 | - expected: フォルダー 322 | patterns: ホルダー 323 | 324 | - expected: フォワード 325 | patterns: ホワード 326 | 327 | - expected: プラスチック 328 | patterns: プラスティック 329 | 330 | - expected: プラットホーム 331 | patterns: プラットフォーム 332 | 333 | - expected: プレーヤー 334 | patterns: プレイヤー 335 | 336 | - expected: ページ 337 | patterns: ペイジ 338 | 339 | - expected: ペーパー 340 | patterns: ペイパー 341 | 342 | - expected: ベール 343 | patterns: ヴェール 344 | 345 | - expected: ベテラン 346 | patterns: ヴェテラン 347 | 348 | - expected: ベニヤ 349 | patterns: ベニア 350 | 351 | - expected: ボーカル 352 | patterns: ヴォーカル 353 | 354 | - expected: ボランティア 355 | patterns: ヴォランティア 356 | 357 | - expected: ボランティア 358 | patterns: ボランティヤ 359 | 360 | - expected: ボリューム 361 | patterns: ヴォリューム 362 | 363 | - expected: ホルマリン 364 | patterns: フォルマリン 365 | 366 | - expected: マルチ 367 | patterns: マルティ 368 | 369 | - expected: ミラー 370 | patterns: ミラア 371 | 372 | - expected: メイン 373 | patterns: メーン 374 | 375 | - expected: メーカー 376 | patterns: メイカー 377 | 378 | - expected: メール 379 | patterns: メイル 380 | 381 | - expected: メガホン 382 | patterns: メガフォン 383 | 384 | - expected: メッセージ 385 | patterns: メッセイジ 386 | 387 | - expected: メディア 388 | patterns: メディヤ 389 | 390 | - expected: メンテナンス 391 | patterns: メインテナンス 392 | 393 | - expected: モルヒネ 394 | patterns: モルフィネ 395 | 396 | - expected: ユニバーサル 397 | patterns: ユニヴァーサル 398 | 399 | - expected: ユニフォーム 400 | patterns: ユニホーム 401 | 402 | - expected: ラジアル 403 | patterns: ラジヤル 404 | 405 | - expected: ラジオ 406 | patterns: ラディオ 407 | 408 | - expected: リバイバル 409 | patterns: リヴァイヴァル 410 | 411 | - expected: レイアウト 412 | patterns: レーアウト 413 | 414 | - expected: レイヤー 415 | patterns: レイアー 416 | 417 | - expected: レインコート 418 | patterns: レーンコート 419 | 420 | - expected: レーザー 421 | patterns: レイザー 422 | 423 | - expected: レーダー 424 | patterns: レイダー 425 | 426 | - expected: レター 427 | patterns: レタア 428 | 429 | - expected: レビュー 430 | patterns: レヴュー 431 | 432 | - expected: レベル 433 | patterns: レヴェル 434 | -------------------------------------------------------------------------------- /dict/2.1.6.yml: -------------------------------------------------------------------------------- 1 | # This dictionary is based on http://www.jtf.jp/jp/style_guide/jtfstylechecker.html 2 | # テクニカルコミュニケーター協会> 外来語(カタカナ)表記ガイドライン http://www.jtca.org/standardization/ 3 | # TODO: [WIP] not complete 4 | version: 1 5 | rules: 6 | - expected: アドベンチャー$1 7 | patterns: /アドベンチャ((?:[^ーァ-ン]){1,2}|(?=$))/ 8 | 9 | - expected: アイデンティティー$1 10 | patterns: /アイデンティティ((?:[^ーァ-ン]){1,2}|(?=$))/ 11 | 12 | - expected: アクセサリー$1 13 | patterns: /アクセサリ((?:[^ーァ-ン]){1,2}|(?=$))/ 14 | 15 | - expected: アセンブラー$1 16 | patterns: /アセンブラ((?:[^ーァ-ン]){1,2}|(?=$))/ 17 | 18 | - expected: アダプター$1 19 | patterns: /アダプタ((?:[^ーァ-ン]){1,2}|(?=$))/ 20 | 21 | - expected: アドバイザー$1 22 | patterns: /アドバイザ((?:[^ーァ-ン]){1,2}|(?=$))/ 23 | 24 | - expected: アブソーバー$1 25 | patterns: /アブソーバ((?:[^ーァ-ン]){1,2}|(?=$))/ 26 | 27 | - expected: イレーサー$1 28 | patterns: /イレーサ((?:[^ーァ-ン]){1,2}|(?=$))/ 29 | 30 | - expected: インジケーター$1 31 | patterns: /インジケータ((?:[^ーァ-ン]){1,2}|(?=$))/ 32 | 33 | - expected: インストラクター$1 34 | patterns: /インストラクタ((?:[^ーァ-ン]){1,2}|(?=$))/ 35 | 36 | - expected: インタビュー$1 37 | patterns: /インタビュ((?:[^ーァ-ン]){1,2}|(?=$))/ 38 | 39 | - expected: エクスプローラー$1 40 | patterns: /エクスプローラ((?:[^ーァ-ン]){1,2}|(?=$))/ 41 | 42 | - expected: エスカレーター$1 43 | patterns: /エスカレータ((?:[^ーァ-ン]){1,2}|(?=$))/ 44 | 45 | - expected: エディター$1 46 | patterns: /エディタ((?:[^ーァ-ン]){1,2}|(?=$))/ 47 | 48 | - expected: エネルギー$1 49 | patterns: /エネルギ((?:[^ーァ-ン]){1,2}|(?=$))/ 50 | 51 | - expected: エレベーター$1 52 | patterns: /エレベータ((?:[^ーァ-ン]){1,2}|(?=$))/ 53 | 54 | - expected: エントリー$1 55 | patterns: /エントリ((?:[^ーァ-ン]){1,2}|(?=$))/ 56 | 57 | - expected: オペレーター$1 58 | patterns: /オペレータ((?:[^ーァ-ン]){1,2}|(?=$))/ 59 | 60 | - expected: カウンター$1 61 | patterns: /カウンタ((?:[^ーァ-ン]){1,2}|(?=$))/ 62 | 63 | - expected: カスタマー$1 64 | patterns: /カスタマ((?:[^ーァ-ン]){1,2}|(?=$))/ 65 | 66 | - expected: カテゴリー$1 67 | patterns: /カテゴリ((?:[^ーァ-ン]){1,2}|(?=$))/ 68 | 69 | - expected: カプラー$1 70 | patterns: /カプラ((?:[^ーァ-ン]){1,2}|(?=$))/ 71 | 72 | - expected: カレンダー$1 73 | patterns: /カレンダ((?:[^ーァ-ン]){1,2}|(?=$))/ 74 | 75 | - expected: キャラクター$1 76 | patterns: /キャラクタ((?:[^ーァ-ン]){1,2}|(?=$))/ 77 | 78 | - expected: クーラー$1 79 | patterns: /クーラ((?:[^ーァ-ン]){1,2}|(?=$))/ 80 | 81 | - expected: クリーナー$1 82 | patterns: /クリーナ((?:[^ーァ-ン]){1,2}|(?=$))/ 83 | 84 | - expected: コーディネーター$1 85 | patterns: /コーディネータ((?:[^ーァ-ン]){1,2}|(?=$))/ 86 | 87 | - expected: コーナー$1 88 | patterns: /コーナ((?:[^ーァ-ン]){1,2}|(?=$))/ 89 | 90 | - expected: コネクター$1 91 | patterns: /コネクタ((?:[^ーァ-ン]){1,2}|(?=$))/ 92 | 93 | - expected: コミュニティー$1 94 | patterns: /コミュニティ((?:[^ーァ-ン]){1,2}|(?=$))/ 95 | 96 | - expected: コンダクター$1 97 | patterns: /コンダクタ((?:[^ーァ-ン]){1,2}|(?=$))/ 98 | 99 | - expected: コンデンサー$1 100 | patterns: /コンデンサ((?:[^ーァ-ン]){1,2}|(?=$))/ 101 | 102 | - expected: コントローラー$1 103 | patterns: /コントローラ((?:[^ーァ-ン]){1,2}|(?=$))/ 104 | 105 | - expected: コンバーター$1 106 | patterns: /コンバータ((?:[^ーァ-ン]){1,2}|(?=$))/ 107 | 108 | - expected: コンパイラー$1 109 | patterns: /コンパイラ((?:[^ーァ-ン]){1,2}|(?=$))/ 110 | 111 | - expected: コンピューター$1 112 | patterns: /コンピュータ((?:[^ーァ-ン]){1,2}|(?=$))/ 113 | 114 | - expected: サーバー$1 115 | patterns: /サーバ((?:[^ーァ-ン]){1,2}|(?=$))/ 116 | 117 | - expected: サマリー$1 118 | patterns: /サマリ((?:[^ーァ-ン]){1,2}|(?=$))/ 119 | 120 | - expected: ジェネレーター$1 121 | patterns: /ジェネレータ((?:[^ーァ-ン]){1,2}|(?=$))/ 122 | 123 | - expected: シミュレーター$1 124 | patterns: /シミュレータ((?:[^ーァ-ン]){1,2}|(?=$))/ 125 | 126 | - expected: シャッター$1 127 | patterns: /シャッタ((?:[^ーァ-ン]){1,2}|(?=$))/ 128 | 129 | - expected: シリンダー$1 130 | patterns: /シリンダ((?:[^ーァ-ン]){1,2}|(?=$))/ 131 | 132 | - expected: シンナー$1 133 | patterns: /シンナ((?:[^ーァ-ン]){1,2}|(?=$))/ 134 | 135 | - expected: スーパーバイザー$1 136 | patterns: /スーパーバイザ((?:[^ーァ-ン]){1,2}|(?=$))/ 137 | 138 | - expected: スキャナー$1 139 | patterns: /スキャナ((?:[^ーァ-ン]){1,2}|(?=$))/ 140 | 141 | - expected: スタッカー$1 142 | patterns: /スタッカ((?:[^ーァ-ン]){1,2}|(?=$))/ 143 | 144 | - expected: セーバー$1 145 | patterns: /セーバ((?:[^ーァ-ン]){1,2}|(?=$))/ 146 | 147 | - expected: セーフティー$1 148 | patterns: /セーフティ((?:[^ーァ-ン]){1,2}|(?=$))/ 149 | 150 | - expected: セキュリティー$1 151 | patterns: /セキュリティ((?:[^ーァ-ン]){1,2}|(?=$))/ 152 | 153 | - expected: セパレーター$1 154 | patterns: /セパレータ((?:[^ーァ-ン]){1,2}|(?=$))/ 155 | 156 | - expected: セレクター$1 157 | patterns: /セレクタ((?:[^ーァ-ン]){1,2}|(?=$))/ 158 | 159 | - expected: センサー$1 160 | patterns: /センサ((?:[^ーァ-ン]){1,2}|(?=$))/ 161 | 162 | - expected: ソーター$1 163 | patterns: /ソータ((?:[^ーァ-ン]){1,2}|(?=$))/ 164 | 165 | - expected: ダイアリー$1 166 | patterns: /ダイアリ((?:[^ーァ-ン]){1,2}|(?=$))/ 167 | 168 | - expected: タイプライター$1 169 | patterns: /タイプライタ((?:[^ーァ-ン]){1,2}|(?=$))/ 170 | 171 | - expected: タイマー$1 172 | patterns: /タイマ((?:[^ーァ-ン]){1,2}|(?=$))/ 173 | 174 | - expected: チャージャー$1 175 | patterns: /チャージャ((?:[^ーァ-ン]){1,2}|(?=$))/ 176 | 177 | - expected: ディレクター$1 178 | patterns: /ディレクタ((?:[^ーァ-ン]){1,2}|(?=$))/ 179 | 180 | - expected: ディレクトリー$1 181 | patterns: /ディレクトリ((?:[^ーァ-ン]){1,2}|(?=$))/ 182 | 183 | - expected: デコーダー$1 184 | patterns: /デコーダ((?:[^ーァ-ン]){1,2}|(?=$))/ 185 | 186 | - expected: デリバリー$1 187 | patterns: /デリバリ((?:[^ーァ-ン]){1,2}|(?=$))/ 188 | 189 | - expected: ドライバー$1 190 | patterns: /ドライバ((?:[^ーァ-ン]){1,2}|(?=$))/ 191 | 192 | - expected: トランシーバー$1 193 | patterns: /トランシーバ((?:[^ーァ-ン]){1,2}|(?=$))/ 194 | 195 | - expected: トランスミッター$1 196 | patterns: /トランスミッタ((?:[^ーァ-ン]){1,2}|(?=$))/ 197 | 198 | - expected: トレーナー$1 199 | patterns: /トレーナ((?:[^ーァ-ン]){1,2}|(?=$))/ 200 | 201 | - expected: パーティー$1 202 | patterns: /パーティ((?:[^ーァ-ン]){1,2}|(?=$))/ 203 | 204 | - expected: バイナリー$1 205 | patterns: /バイナリ((?:[^ーァ-ン]){1,2}|(?=$))/ 206 | 207 | - expected: ハイパー$1 208 | patterns: /ハイパ((?:[^ーァ-ン]){1,2}|(?=$))/ 209 | 210 | - expected: バインダー$1 211 | patterns: /バインダ((?:[^ーァ-ン]){1,2}|(?=$))/ 212 | 213 | - expected: バインダリー$1 214 | patterns: /バインダリ((?:[^ーァ-ン]){1,2}|(?=$))/ 215 | 216 | - expected: バッテリー$1 217 | patterns: /バッテリ((?:[^ーァ-ン]){1,2}|(?=$))/ 218 | 219 | - expected: バッファー$1 220 | patterns: /バッファ((?:[^ーァ-ン]){1,2}|(?=$))/ 221 | 222 | - expected: バナー$1 223 | patterns: /バナ((?:[^ーァ-ン]){1,2}|(?=$))/ 224 | 225 | - expected: バラエティー$1 226 | patterns: /バラエティ((?:[^ーァ-ン]){1,2}|(?=$))/ 227 | 228 | - expected: パラメーター$1 229 | patterns: /パラメータ((?:[^ーァ-ン]){1,2}|(?=$))/ 230 | 231 | - expected: ハンディー$1 232 | patterns: /ハンディ((?:[^ーァ-ン]){1,2}|(?=$))/ 233 | 234 | - expected: ハンドラー$1 235 | patterns: /ハンドラ((?:[^ーァ-ン]){1,2}|(?=$))/ 236 | 237 | - expected: ビューアー$1 238 | patterns: /ビューア((?:[^ーァ-ン]){1,2}|(?=$))/ 239 | 240 | - expected: ファインダー$1 241 | patterns: /ファインダ((?:[^ーァ-ン]){1,2}|(?=$))/ 242 | 243 | - expected: ファミリー$1 244 | patterns: /ファミリ((?:[^ーァ-ン]){1,2}|(?=$))/ 245 | 246 | - expected: フィーダー$1 247 | patterns: /フィーダ((?:[^ーァ-ン]){1,2}|(?=$))/ 248 | 249 | - expected: フィニッシャー$1 250 | patterns: /フィニッシャ((?:[^ーァ-ン]){1,2}|(?=$))/ 251 | 252 | - expected: フィルター$1 253 | patterns: /フィルタ((?:[^ーァ-ン]){1,2}|(?=$))/ 254 | 255 | - expected: フォルダー$1 256 | patterns: /フォルダ((?:[^ーァ-ン]){1,2}|(?=$))/ 257 | 258 | - expected: フッター$1 259 | patterns: /フッタ((?:[^ーァ-ン]){1,2}|(?=$))/ 260 | 261 | - expected: フューザー$1 262 | patterns: /フューザ((?:[^ーァ-ン]){1,2}|(?=$))/ 263 | 264 | - expected: プライマリー$1 265 | patterns: /プライマリ((?:[^ーァ-ン]){1,2}|(?=$))/ 266 | 267 | - expected: ブラウザー$1 268 | patterns: /ブラウザ((?:[^ーァ-ン]){1,2}|(?=$))/ 269 | 270 | - expected: プリンター$1 271 | patterns: /プリンタ((?:[^ーァ-ン]){1,2}|(?=$))/ 272 | 273 | - expected: プレーヤー$1 274 | patterns: /プレーヤ((?:[^ーァ-ン]){1,2}|(?=$))/ 275 | 276 | - expected: プロジェクター$1 277 | patterns: /プロジェクタ((?:[^ーァ-ン]){1,2}|(?=$))/ 278 | 279 | - expected: プロセッサー$1 280 | patterns: /プロセッサ((?:[^ーァ-ン]){1,2}|(?=$))/ 281 | 282 | - expected: プロッター$1 283 | patterns: /プロッタ((?:[^ーァ-ン]){1,2}|(?=$))/ 284 | 285 | - expected: フロッピー$1 286 | patterns: /フロッピ((?:[^ーァ-ン]){1,2}|(?=$))/ 287 | 288 | - expected: プロバイダー$1 289 | patterns: /プロバイダ((?:[^ーァ-ン]){1,2}|(?=$))/ 290 | 291 | - expected: ヘッダー$1 292 | patterns: /ヘッダ((?:[^ーァ-ン]){1,2}|(?=$))/ 293 | 294 | - expected: ポインター$1 295 | patterns: /ポインタ((?:[^ーァ-ン]){1,2}|(?=$))/ 296 | 297 | - expected: ボディー$1 298 | patterns: /ボディ((?:[^ーァ-ン]){1,2}|(?=$))/ 299 | 300 | - expected: ポリシー$1 301 | patterns: /ポリシ((?:[^ーァ-ン]){1,2}|(?=$))/ 302 | 303 | - expected: マーカー$1 304 | patterns: /マーカ((?:[^ーァ-ン]){1,2}|(?=$))/ 305 | 306 | - expected: マスター$1 307 | patterns: /マスタ((?:[^ーァ-ン]){1,2}|(?=$))/ 308 | 309 | - expected: マネージャー$1 310 | patterns: /マネージャ((?:[^ーァ-ン]){1,2}|(?=$))/ 311 | 312 | - expected: メーカー$1 313 | patterns: /メーカ((?:[^ーァ-ン]){1,2}|(?=$))/ 314 | 315 | - expected: メーター$1 316 | patterns: /メータ((?:[^ーァ-ン]){1,2}|(?=$))/ 317 | 318 | - expected: メモリー$1 319 | patterns: /メモリ((?:[^ーァ-ン]){1,2}|(?=$))/ 320 | 321 | - expected: メロディー$1 322 | patterns: /メロディ((?:[^ーァ-ン]){1,2}|(?=$))/ 323 | 324 | - expected: メンバー$1 325 | patterns: /メンバ((?:[^ーァ-ン]){1,2}|(?=$))/ 326 | 327 | - expected: モーター$1 328 | patterns: /モータ((?:[^ーァ-ン]){1,2}|(?=$))/ 329 | 330 | - expected: モジュラー$1 331 | patterns: /モジュラ((?:[^ーァ-ン]){1,2}|(?=$))/ 332 | 333 | - expected: モニター$1 334 | patterns: /モニタ((?:[^ーァ-ン]){1,2}|(?=$))/ 335 | 336 | - expected: ユーザー$1 337 | patterns: /ユーザ((?:[^ーァ-ン]){1,2}|(?=$))/ 338 | 339 | - expected: ユーティリティー$1 340 | patterns: /ユーティリティ((?:[^ーァ-ン]){1,2}|(?=$))/ 341 | 342 | - expected: ライター$1 343 | patterns: /ライタ((?:[^ーァ-ン]){1,2}|(?=$))/ 344 | 345 | - expected: ライブラリー$1 346 | patterns: /ライブラリ((?:[^ーァ-ン]){1,2}|(?=$))/ 347 | 348 | - expected: ラスター$1 349 | patterns: /ラスタ((?:[^ーァ-ン]){1,2}|(?=$))/ 350 | 351 | - expected: リーダー$1 352 | patterns: /リーダ((?:[^ーァ-ン]){1,2}|(?=$))/ 353 | 354 | - expected: リポジトリー$1 355 | patterns: /リポジトリ((?:[^ーァ-ン]){1,2}|(?=$))/ 356 | 357 | - expected: ルーラー$1 358 | patterns: /ルーラ((?:[^ーァ-ン]){1,2}|(?=$))/ 359 | 360 | - expected: レイヤー$1 361 | patterns: /レイヤ((?:[^ーァ-ン]){1,2}|(?=$))/ 362 | 363 | - expected: レーダー$1 364 | patterns: /レーダ((?:[^ーァ-ン]){1,2}|(?=$))/ 365 | 366 | - expected: レコーダー$1 367 | patterns: /レコーダ((?:[^ーァ-ン]){1,2}|(?=$))/ 368 | 369 | - expected: レシーバー$1 370 | patterns: /レシーバ((?:[^ーァ-ン]){1,2}|(?=$))/ 371 | 372 | - expected: レジスター$1 373 | patterns: /レジスタ((?:[^ーァ-ン]){1,2}|(?=$))/ 374 | 375 | - expected: レジストリー$1 376 | patterns: /レジストリ((?:[^ーァ-ン]){1,2}|(?=$))/ 377 | 378 | - expected: ローラー$1 379 | patterns: /ローラ((?:[^ーァ-ン]){1,2}|(?=$))/ 380 | -------------------------------------------------------------------------------- /dict/2.2.1.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | rules: 3 | - expected: あらかじめ 4 | patterns: 予め 5 | - expected: いずれ 6 | patterns: 何れ 7 | - expected: いつ 8 | patterns: 何時 9 | - expected: およそ 10 | patterns: 凡そ 11 | - expected: おもむろに 12 | patterns: 徐に 13 | - expected: かえって 14 | patterns: 却って 15 | - expected: かつ 16 | patterns: 且つ 17 | - expected: かもしれない 18 | patterns: かも知れない 19 | - expected: ください 20 | patterns: 下さい 21 | specs: 22 | - from: 提出して下さい。 23 | to : 提出してください。 24 | - expected: これほど 25 | patterns: これ程 26 | - expected: ご$1 27 | patterns: /御(覧|意見)/ 28 | specs: 29 | - from: 御覧ください 30 | to: ご覧ください 31 | - from: 御意見 32 | to: ご意見 33 | - expected: 子ども 34 | patterns: 35 | - 子供 36 | - こども 37 | # 接続詞 または 文頭であることを考慮する 38 | - expected: $1さらに 39 | patterns: 40 | - /([\s。、\nぁ-んァ-ヶ])更に/ 41 | specs: 42 | - from: Aは加速した、更に加速した。 43 | to: Aは加速した、さらに加速した。 44 | - from: 加速すると更に加速した 45 | to: 加速するとさらに加速した 46 | - from: 変更に加えて 47 | to: 変更に加えて 48 | - expected: さらに 49 | patterns: /^更に/ 50 | specs: 51 | - from: 更に加速した。 52 | to: さらに加速した。 53 | - expected: しかし 54 | patterns: 然し 55 | - expected: しばらく 56 | patterns: 暫く 57 | - expected: すなわち 58 | patterns: 即ち 59 | - expected: すべき 60 | patterns: 可き 61 | - expected: せっかく 62 | patterns: 折角 63 | - expected: たびたび 64 | patterns: 度々 65 | - expected: ただし 66 | patterns: 但し 67 | # 誤爆を避けるのが難しい 68 | # - expected: たち 69 | # patterns: 達 70 | 71 | - expected: できる 72 | patterns: 出来る 73 | - expected: どこ 74 | patterns: 何処 75 | - expected: ないし 76 | patterns: 乃至 77 | # なお => 尚 78 | - expected: なおさら 79 | patterns: 尚さら 80 | - expected: なかなか 81 | patterns: 中々 82 | specs: 83 | - from: 中々できないことだ。 84 | to: なかなかできないことだ。 85 | # 程 -> ほど 86 | - expected: これほど 87 | patterns: これ程 88 | - expected: または 89 | patterns: 又は 90 | - expected: むしろ 91 | patterns: 寧ろ 92 | - expected: めったに 93 | patterns: 滅多に 94 | 95 | - expected: もはや 96 | patterns: 最早 97 | - expected: もしくは 98 | patterns: 若しくは 99 | - expected: もって 100 | patterns: 101 | - 以て 102 | - 以って 103 | - expected: のように 104 | patterns: /の様に/ 105 | specs: 106 | - from: 一様に 107 | to: 一様に 108 | - from: 〜の様に 109 | to: 〜のように 110 | - expected: よほど 111 | patterns: 余程 112 | # 漢字で書く 113 | - expected: 一切 114 | patterns: いっさい 115 | - expected: 必ず 116 | patterns: かならず 117 | - expected: 大いに 118 | patterns: おおいに 119 | - expected: 強いて 120 | patterns: しいて 121 | - expected: $1中 122 | patterns: /(世界|日)じゅう/ 123 | spec: 124 | - from: 一日じゅう 125 | to: 一日中 126 | - from: 世界じゅう 127 | to : 世界中 128 | - expected: 時々 129 | patterns: ときどき 130 | - expected: 何しろ 131 | patterns: なにしろ 132 | specs: 133 | - from: なにしろ困っている 134 | to: 何しろ困っている 135 | 136 | - expected: 何も 137 | patterns: なにも 138 | specs: 139 | - from: なにも知らない 140 | to: 何も知らない 141 | - expected: 何らかの 142 | patterns: なんらかの 143 | specs: 144 | - from: なんらかの策。 145 | to: 何らかの策。 146 | - expected: 何とも 147 | patterns: なんとも 148 | spec: 149 | - from: なんとも言えない。 150 | to: 何とも言えない。 151 | # 漢字を使い分ける 152 | #「個」が表外音 153 | - expected: 箇所 154 | patterns: 個所 155 | #「個」が表外音 156 | - expected: 箇条書き 157 | patterns: 個条書き 158 | # 動詞では「付属する」が一般的 159 | - expected: 付属する 160 | patterns: 附属する 161 | #「摩」は「こする」、「磨」は「磨く(みがく)」の意味 162 | - expected: 摩耗 163 | patterns: 磨耗 164 | - expected: 摩滅 165 | patterns: 磨滅 166 | # 品詞・意味で使い分ける 167 | - expected: および 168 | patterns: 及び 169 | - expected: が及ぶ 170 | patterns: がおよぶ 171 | specs: 172 | - from: (例)影響がおよぶ。 173 | to: (例)影響が及ぶ。 174 | # メンテナンスが難しいの無効 175 | # - expected: $1いたします 176 | # patterns: ([^引招送誘拉一合極雅筆風])致します 177 | # specs: 178 | # - from: (例)お願い致します。 179 | # to: (例)お願いいたします。 180 | - expected: 致す 181 | patterns: いたす 182 | specs: 183 | - from: (例)思いをいたす。 184 | to: (例)思いを致す。 185 | # (接続詞の場合)ひらがなを使う 186 | - expected: したがって 187 | patterns: /(に)?従って/ 188 | regexpMustEmpty: $1 189 | #(動詞の場合)漢字を使う 190 | - expected: に従って 191 | pattern: にしたがって 192 | - expected: 従う 193 | patterns: したがう 194 | - expected: $1だす 195 | patterns: /(うり|売り|送り|さし|差し|造り|創り|とり|取り|はき|よび|呼び|よみ|読み|動き|笑い)出す/ 196 | specs: 197 | - from: (例)動き出す。 198 | to: (例)動きだす。 199 | - from: (例)笑い出す。 200 | to: (例)笑いだす。 201 | - from: 探しだす 202 | to: 探しだす 203 | - expected: $1出す 204 | patterns: /(探し|見つけ|見い)だす/ 205 | specs: 206 | - from: 探しだす 207 | to: 探し出す 208 | - from: 見つけだす 209 | to: 見つけ出す 210 | #(動詞の場合)漢字を使う 211 | - expected: $1付く 212 | patterns: /(気が|利子が)つく/ 213 | specs: 214 | - from: 気がつく。 215 | to: 気が付く。 216 | - from: 利子がつく。 217 | to: 利子が付く。 218 | #(接尾語の場合)ひらがなを使う 219 | - expected: 活気づく 220 | patterns: 活気付く 221 | specs: 222 | - from: 活気付く 223 | to: 活気づく 224 | - expected: 凍りつく 225 | patterns: 凍り付く 226 | specs: 227 | - from: 凍り付く 228 | to: 凍りつく 229 | - expected: $1つき 230 | patterns: /(手|目|腰)付き/ 231 | specs: 232 | - from: 目付き。 233 | to: 目つき。 234 | - from: 手付き。 235 | to: 手つき。 236 | - expected: $1とおり 237 | patterns: /(思った|以下の)通り/ 238 | specs: 239 | - from: (例)思った通り。 240 | to: (例)思ったとおり。 241 | - from: 以下の通りです。 242 | to: 以下のとおりです。 243 | #(数詞に付く場合) 244 | - expected: $1通り 245 | patterns: /(\d)とおり/ 246 | specs: 247 | - from: (例)2とおりの方法 248 | to: (例)2通りの方法 249 | # (補助動詞の場合)ひらがなを使う 250 | - expected: てほしい 251 | patterns: て欲しい 252 | specs: 253 | - from: 考えて欲しい 254 | to: 考えてほしい 255 | - expected: が欲しい 256 | patterns: がほしい 257 | specs: 258 | - from: この本がほしい 259 | to: この本が欲しい -------------------------------------------------------------------------------- /dict/2.2.3.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | rules: 3 | - expected: $1か$2 4 | patterns: 5 | - /(\d+)ヶ([所月国年])/ 6 | specs: 7 | - from: 3ヶ月未満。 8 | to: 3か月未満。 9 | - from: 10ヶ所 10 | to: 10か所 11 | - from: 5ヶ年計画。 12 | to: 5か年計画。 -------------------------------------------------------------------------------- /example/.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | -------------------------------------------------------------------------------- /example/.textlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "preset-jtf-style": true 4 | } 5 | } -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # サンプル 2 | 3 | ## 使い方 4 | 5 | `npm run-script textlint`が定義されているので次のようにすれば、この`README.md`ファイルをtextlint出来ます。 6 | 7 | これは問題です。 8 | 9 | 10 | 11 | ``` 12 | npm install 13 | npm run textlint -- README.md 14 | ``` 15 | 16 | (npm 2.x以上をインストールしている必要があります) 17 | 18 | - [run-script | npm Documentation](https://docs.npmjs.com/cli/run-script/ "run-script | npm Documentation") 19 | 20 | ### もっと手動に 21 | 22 | ``` 23 | npm install 24 | ./node_modules/.bin/textlint /path/to/target.md 25 | ``` 26 | 27 | ## 設定ファイル 28 | 29 | [.textlintrc](./.textlintrc)に設定ファイルが配置されています。 30 | 31 | ## サンプル文章。 32 | 33 | この文章はサンプルである。 -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "textlint-rule-preset-jtf-style", 3 | "version": "1.0.0", 4 | "description": "JTF Style Guide for Translators Working into Japanese for textlint.", 5 | "main": "index.js", 6 | "homepage": "https://github.com/textlint-ja/textlint-rule-preset-jtf-style", 7 | "scripts": { 8 | "textlint": "textlint", 9 | "textlint:fix": "textlint --fix ../README.md", 10 | "test": "npm run textlint -- -f pretty-error ../README.md", 11 | "website": "textlint-website-generator --output-dir dist" 12 | }, 13 | "author": "azu", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "@textlint/website-generator": "^0.18.0", 17 | "textlint": "^15.2.2" 18 | }, 19 | "dependencies": { 20 | "textlint-rule-preset-jtf-style": "file:.." 21 | }, 22 | "packageManager": "pnpm@10.18.2+sha512.9fb969fa749b3ade6035e0f109f0b8a60b5d08a1a87fdf72e337da90dcc93336e2280ca4e44f2358a649b83c17959e9993e777c2080879f3801e6f0d999ad3dd" 23 | } 24 | -------------------------------------------------------------------------------- /jtf_style_guide2.2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textlint-ja/textlint-rule-preset-JTF-style/ef2f028e5e858ea97862c92798447aa4b8090a43/jtf_style_guide2.2.pdf -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "textlint-rule-preset-jtf-style", 3 | "repository": { 4 | "type": "git", 5 | "url": "git+https://github.com/textlint-ja/textlint-rule-preset-jtf-style.git" 6 | }, 7 | "author": "azu", 8 | "email": "azuciao@gmail.com", 9 | "homepage": "https://github.com/textlint-ja/textlint-rule-preset-jtf-style", 10 | "license": "MIT", 11 | "type": "commonjs", 12 | "bugs": { 13 | "url": "https://github.com/textlint-ja/textlint-rule-preset-jtf-style/issues" 14 | }, 15 | "version": "3.0.3", 16 | "description": "JTF Style Guide for Translators Working into Japanese for textlint.", 17 | "main": "lib/index.js", 18 | "files": [ 19 | "lib", 20 | "src", 21 | "dict" 22 | ], 23 | "directories": { 24 | "test": "test" 25 | }, 26 | "scripts": { 27 | "build": "textlint-scripts build", 28 | "watch": "textlint-scripts build --watch", 29 | "prepublishOnly": "npm run --if-present build", 30 | "pretest": "npm run build && node tool/create-fixtures.js", 31 | "test": "textlint-scripts test && npm run test:textlint", 32 | "test:textlint": "(cd example && pnpm install && npm test)", 33 | "format": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"", 34 | "prepare": "git config --local core.hooksPath .githooks" 35 | }, 36 | "keywords": [ 37 | "textlint", 38 | "english", 39 | "japanese", 40 | "translation" 41 | ], 42 | "devDependencies": { 43 | "@textlint/legacy-textlint-core": "^15.2.2", 44 | "glob": "^11.0.3", 45 | "lint-staged": "^16.2.3", 46 | "prettier": "^3.4.1", 47 | "textlint-scripts": "^15.2.2", 48 | "textlint-tester": "^15.2.2" 49 | }, 50 | "dependencies": { 51 | "analyze-desumasu-dearu": "^2.1.2", 52 | "japanese-numerals-to-number": "^1.0.2", 53 | "match-index": "^1.0.3", 54 | "moji": "^0.5.1", 55 | "regexp.prototype.flags": "^1.5.3", 56 | "regx": "^1.0.4", 57 | "textlint-rule-helper": "^2.3.1", 58 | "textlint-rule-prh": "^6.0.0" 59 | }, 60 | "prettier": { 61 | "singleQuote": false, 62 | "printWidth": 120, 63 | "tabWidth": 4, 64 | "trailingComma": "none" 65 | }, 66 | "lint-staged": { 67 | "*.{js,jsx,ts,tsx,css}": [ 68 | "prettier --write" 69 | ] 70 | }, 71 | "packageManager": "pnpm@10.18.2+sha512.9fb969fa749b3ade6035e0f109f0b8a60b5d08a1a87fdf72e337da90dcc93336e2280ca4e44f2358a649b83c17959e9993e777c2080879f3801e6f0d999ad3dd" 72 | } 73 | -------------------------------------------------------------------------------- /src/1.1.1.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 1.1.1.本文 5 | 6 | 本文の文体は、敬体(ですます調)あるいは常体(である調)のどちらかで統一します。 7 | 敬体と常体を混在させないようにします。 8 | 敬体と常体のどちらを使うかは、文書の目的や読み手に応じて決めます。 9 | 10 |  敬体(ですます調) 11 | 一般読者向けの紹介文、パンフレット、マニュアル、ウェブサイトの本文では、基本的に「敬体」を使います。 12 | 親しみやすい、柔らかい雰囲気で内容を伝えることができます。 13 | 14 |  常体(である調) 15 | 常体は、簡潔に、力強い雰囲気で内容を伝えることができる文体です 16 | 丁寧ではない印象を読み手に与える場合があるため、通常、一般向けのマニュアルの本文では使われません。 17 | */ 18 | import { analyzeDesumasu, analyzeDearu } from "analyze-desumasu-dearu"; 19 | import { RuleHelper } from "textlint-rule-helper"; 20 | module.exports = function (context) { 21 | let { Syntax, RuleError, report, getSource } = context; 22 | let helper = new RuleHelper(context); 23 | let desumasuList = []; 24 | let dearuList = []; 25 | 26 | function reportResult(list, { desumasu, dearu }) { 27 | list.forEach(({ node, matches }) => { 28 | matches.forEach((match) => { 29 | let message; 30 | if (desumasu) { 31 | message = `本文を常体(である調)に統一して下さい。\n本文の文体は、敬体(ですます調)あるいは常体(である調)のどちらかで統一します。\n"${match.value}"が敬体(ですます調)です。`; 32 | } else if (dearu) { 33 | message = `本文を敬体(ですます調)に統一して下さい。\n本文の文体は、敬体(ですます調)あるいは常体(である調)のどちらかで統一します。\n"${match.value}"が常体(である調)です。`; 34 | } 35 | report( 36 | node, 37 | new RuleError(message, { 38 | line: match.lineNumber - 1, 39 | column: match.columnIndex 40 | }) 41 | ); 42 | }); 43 | }); 44 | } 45 | 46 | return { 47 | [Syntax.Document]() { 48 | desumasuList = []; 49 | dearuList = []; 50 | }, 51 | [Syntax.Str](node) { 52 | // 本文以外は無視する 53 | // => isUserWrittenNode 54 | if (helper.isChildNode(node, [Syntax.Link, Syntax.Image, Syntax.BlockQuote, Syntax.Emphasis])) { 55 | return; 56 | } 57 | // Listについては1.1.3. 箇条書きで扱う 58 | if (helper.isChildNode(node, [Syntax.ListItem])) { 59 | return; 60 | } 61 | let text = getSource(node); 62 | let retDesumasu = analyzeDesumasu(text); 63 | if (retDesumasu.length > 0) { 64 | desumasuList.push({ 65 | node: node, 66 | matches: retDesumasu 67 | }); 68 | } 69 | let retDearu = analyzeDearu(text); 70 | if (retDearu.length > 0) { 71 | dearuList.push({ 72 | node: node, 73 | matches: retDearu 74 | }); 75 | } 76 | }, 77 | [`${Syntax.Document}:exit`]() { 78 | let desumasuCount = desumasuList.reduce((count, { matches }) => count + matches.length, 0); 79 | let dearuCount = dearuList.reduce((count, { matches }) => count + matches.length, 0); 80 | if (desumasuCount === 0 || dearuCount === 0) { 81 | return; 82 | } 83 | if (desumasuCount > dearuCount) { 84 | reportResult(dearuList, { dearu: true }); 85 | } else if (desumasuCount < dearuCount) { 86 | reportResult(desumasuList, { desumasu: true }); 87 | } else { 88 | reportResult(dearuList, { dearu: true }); 89 | } 90 | } 91 | }; 92 | }; 93 | -------------------------------------------------------------------------------- /src/1.1.2.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 1.1.2.見出し 5 | 6 | 本文が敬体であっても、見出しには常体や体言止めを使います。 7 | 一般向けのマニュアルでは、「~には」や「~とは」などの助詞で止める文形も使います。 8 | 見出しの文末には、句点(。)を付けません。 9 | 10 | # Header 11 | 12 | のみをサポート 13 | 14 | Header 15 | ======= 16 | 17 | は無視する 18 | */ 19 | import { isUserWrittenNode } from "./util/node-util"; 20 | function mixer(context) { 21 | let { Syntax, RuleError, report, getSource, fixer } = context; 22 | return { 23 | [Syntax.Header](node) { 24 | if (!isUserWrittenNode(node, context)) { 25 | return; 26 | } 27 | let text = getSource(node); 28 | // Headerの末尾には。をつけない 29 | let matchReg = /。(\s*?)$/; 30 | let index = text.search(matchReg); 31 | if (index !== -1) { 32 | report( 33 | node, 34 | new RuleError("見出しの文末には、句点(。)を付けません。", { 35 | index: index, 36 | fix: fixer.removeRange([index, index + 1]) 37 | }) 38 | ); 39 | } 40 | // TODO: いずれの場合も、すべての見出しを通して複数の文体をできるだけ混在させないことが重要です。 41 | } 42 | }; 43 | } 44 | module.exports = { 45 | linter: mixer, 46 | fixer: mixer 47 | }; 48 | -------------------------------------------------------------------------------- /src/1.1.3.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 1.1.3.箇条書き 5 | 6 | 基本的に本文の文体に合わせます。 7 | ただし、本文が「敬体」である場合、箇条書きに「常体」または「体言止め」も使う場合があります。 8 | 一般読者向け の文書で、本文が敬体である場合、多くの場合、箇条書きでも敬体を使います。 9 | 本文が「常体」である場合、箇条書きには「常体」または「体言止め」を使います。「敬体」は使いません。 10 | いずれの場合も、ひとまとまりの箇条書きでは、敬体と常体を混在させません。文末に句点(。)を付けるかどうかも統一します。 11 | */ 12 | import { analyzeDesumasu, analyzeDearu } from "analyze-desumasu-dearu"; 13 | module.exports = function (context) { 14 | let { Syntax, RuleError, report, getSource } = context; 15 | let desumasuList = []; 16 | let dearuList = []; 17 | // 。付きのListItem 18 | let withPointList = []; 19 | // 。なしのListItem 20 | let withoutPointList = []; 21 | 22 | function resetList() { 23 | dearuList = []; 24 | desumasuList = []; 25 | withPointList = []; 26 | withoutPointList = []; 27 | } 28 | 29 | function reportPointResult(nodeList, { shouldUsePoint }) { 30 | nodeList.forEach((node) => { 31 | let message; 32 | if (shouldUsePoint) { 33 | message = `箇条書きの文末に句点(。)を付けて下さい。\n箇条書きの文末に句点(。)を付けるかを統一します。`; 34 | } else { 35 | message = `箇条書きの文末から句点(。)を外して下さい。\n箇条書きの文末に句点(。)を付けるかを統一します。`; 36 | } 37 | report(node, new RuleError(message)); 38 | }); 39 | } 40 | 41 | function reportDesumaruDearuResult(list, { desumasu, dearu }) { 42 | list.forEach(({ node, matches }) => { 43 | matches.forEach((match) => { 44 | let message; 45 | if (desumasu) { 46 | message = `箇条書きを敬体(ですます調)に統一して下さい。\nひとまとまりの箇条書きでは、敬体と常体を混在させません。\n"${match.value}"が常体(である調)です。`; 47 | } else if (dearu) { 48 | message = `箇条書きを常体(である調)に統一して下さい。\nひとまとまりの箇条書きでは、敬体と常体を混在させません。\n"${match.value}"が敬体(ですます調)です。`; 49 | } 50 | report( 51 | node, 52 | new RuleError(message, { 53 | line: match.lineNumber - 1, 54 | column: match.columnIndex 55 | }) 56 | ); 57 | }); 58 | }); 59 | } 60 | 61 | // 末尾に。があるかが統一されているのチェック 62 | function countingPoint(withPointList, withoutPointList) { 63 | if (withPointList.length === 0 || withoutPointList.length === 0) { 64 | return; 65 | } 66 | if (withPointList.length > withoutPointList.length) { 67 | // 。ありに統一 68 | reportPointResult(withoutPointList, { 69 | shouldUsePoint: true 70 | }); 71 | } else if (withPointList.length < withoutPointList.length) { 72 | // 。なしに統一 73 | reportPointResult(withPointList, { 74 | shouldUsePoint: false 75 | }); 76 | } else { 77 | // 。ありに統一 78 | reportPointResult(withoutPointList, { 79 | shouldUsePoint: true 80 | }); 81 | } 82 | } 83 | 84 | // 敬体(ですます調)あるいは常体(である調)なのかのチェック 85 | function countingDesumasuDearu(desumasuList, dearuList) { 86 | let desumasuCount = desumasuList.reduce((count, { matches }) => count + matches.length, 0); 87 | let dearuCount = dearuList.reduce((count, { matches }) => count + matches.length, 0); 88 | if (desumasuCount === 0 || dearuCount === 0) { 89 | return; 90 | } 91 | // ですます優先 92 | if (desumasuCount > dearuCount) { 93 | reportDesumaruDearuResult(dearuList, { 94 | desumasu: true 95 | }); 96 | } else if (desumasuCount < dearuCount) { 97 | // である優先 98 | reportDesumaruDearuResult(desumasuList, { 99 | dearu: true 100 | }); 101 | } else { 102 | // 同等の場合はですます優先 103 | reportDesumaruDearuResult(dearuList, { 104 | desumasu: true 105 | }); 106 | } 107 | } 108 | 109 | return { 110 | [Syntax.List](node) { 111 | resetList(); 112 | }, 113 | [Syntax.ListItem](node) { 114 | let text = getSource(node); 115 | // 末尾に。があるかが統一されているのチェック 116 | let matchPointReg = /。(\s*?)$/; 117 | if (matchPointReg.test(text)) { 118 | // 。あり 119 | withPointList.push(node); 120 | } else { 121 | // 。なし 122 | withoutPointList.push(node); 123 | } 124 | // 敬体(ですます調)あるいは常体(である調)なのかのチェック 125 | let retDesumasu = analyzeDesumasu(text); 126 | if (retDesumasu.length > 0) { 127 | desumasuList.push({ 128 | node: node, 129 | matches: retDesumasu 130 | }); 131 | } 132 | let retDearu = analyzeDearu(text); 133 | if (retDearu.length > 0) { 134 | dearuList.push({ 135 | node: node, 136 | matches: retDearu 137 | }); 138 | } 139 | }, 140 | [`${Syntax.List}:exit`](node) { 141 | countingPoint(withPointList, withoutPointList); 142 | 143 | countingDesumasuDearu(desumasuList, dearuList); 144 | } 145 | }; 146 | }; 147 | -------------------------------------------------------------------------------- /src/1.1.5.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 1.1.5.図表のキャプション 5 | 文章の内容に応じて、敬体、常体、体言止めを使います。 6 | いずれの場合も、複数の文体をできるだけ混在させないことが重要です。 7 | 通常、文末に句点(。)を付けませんが、複数の文章になる場合は句点を使用します。 8 | 9 | キャプション間で文体が混ざっていないことを確認する。 10 | */ 11 | import { analyzeDesumasu, analyzeDearu } from "analyze-desumasu-dearu"; 12 | module.exports = function (context) { 13 | let { Syntax, RuleError, report, getSource } = context; 14 | let desumasuList = []; 15 | let dearuList = []; 16 | 17 | function resetState() { 18 | desumasuList = []; 19 | dearuList = []; 20 | } 21 | 22 | const imagePaddingLet = 2; // ![ の分paddingを付ける 23 | function reportResult(list, { desumasu, dearu }) { 24 | list.forEach(({ node, matches }) => { 25 | matches.forEach((match) => { 26 | let message; 27 | if (desumasu) { 28 | message = `図表のキャプションを敬体(ですます調)に統一して下さい。\n図表のキャプション内で敬体、常体を混在させないことが重要です。\n"${match.value}"が常体(である調)です。`; 29 | } else if (dearu) { 30 | message = `図表のキャプションを常体(である調)に統一して下さい。\n図表のキャプション内で敬体、常体を混在させないことが重要です。\n"${match.value}"が敬体(ですます調)です。`; 31 | } 32 | report( 33 | node, 34 | new RuleError(message, { 35 | line: match.lineNumber - 1, 36 | column: match.columnIndex + imagePaddingLet 37 | }) 38 | ); 39 | }); 40 | }); 41 | } 42 | 43 | return { 44 | [Syntax.Document]: resetState, 45 | [Syntax.Image](node) { 46 | let text = node.alt; 47 | // alt がない場合は無視する 48 | if (text === undefined || text === null) { 49 | return; 50 | } 51 | let retDesumasu = analyzeDesumasu(text); 52 | if (retDesumasu.length > 0) { 53 | desumasuList.push({ 54 | node: node, 55 | matches: retDesumasu 56 | }); 57 | } 58 | let retDearu = analyzeDearu(text); 59 | if (retDearu.length > 0) { 60 | dearuList.push({ 61 | node: node, 62 | matches: retDearu 63 | }); 64 | } 65 | }, 66 | [`${Syntax.Document}:exit`]() { 67 | let desumasuCount = desumasuList.reduce((count, { matches }) => count + matches.length, 0); 68 | let dearuCount = dearuList.reduce((count, { matches }) => count + matches.length, 0); 69 | if (desumasuCount === 0 || dearuCount === 0) { 70 | return; 71 | } 72 | if (desumasuCount > dearuCount) { 73 | reportResult(dearuList, { 74 | desumasu: true 75 | }); 76 | } else if (desumasuCount < dearuCount) { 77 | reportResult(desumasuList, { 78 | dearu: true 79 | }); 80 | } else { 81 | reportResult(dearuList, { 82 | desumasu: true 83 | }); 84 | } 85 | } 86 | }; 87 | }; 88 | -------------------------------------------------------------------------------- /src/1.2.1.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import regx from "regx"; 4 | import { japaneseRegExp } from "./util/regexp"; 5 | import { matchCaptureGroupAll } from "match-index"; 6 | import mergeMatches from "./util/merge-matches"; 7 | const rx = regx("g"); 8 | /* 9 | 1.2.1. 句点(。)と読点(、) 10 | 句読点には全角の「、」と「。」を使います。和文の句読点としてピリオド(.)とカンマ(,)を使用しません。 11 | 「4.1.1 句点(。)」と「4.1.2 読点(、)」を参照してください。 12 | */ 13 | import { isUserWrittenNode } from "./util/node-util"; 14 | 15 | // [,.]{日本語} 16 | const leftTarget = rx` 17 | ([,\.]) 18 | ${japaneseRegExp} 19 | `; 20 | // {日本語}[,.] 21 | const rightTarget = rx` 22 | ${japaneseRegExp} 23 | ([,\.]) 24 | `; 25 | // . => 。 の置換マップ 26 | const replaceSymbol = { 27 | ".": "。", 28 | ",": "、" 29 | }; 30 | 31 | const reporter = (context) => { 32 | let { Syntax, RuleError, report, fixer, getSource } = context; 33 | return { 34 | [Syntax.Str](node) { 35 | if (!isUserWrittenNode(node, context)) { 36 | return; 37 | } 38 | const text = getSource(node); 39 | const leftMatches = matchCaptureGroupAll(text, leftTarget); 40 | const rightMatches = matchCaptureGroupAll(text, rightTarget); 41 | const matches = mergeMatches(leftMatches, rightMatches); 42 | matches.forEach((match) => { 43 | const symbol = replaceSymbol[match.text]; 44 | const indexOfSymbol = match.index; 45 | report( 46 | node, 47 | new RuleError( 48 | "句読点には全角の「、」と「。」を使います。和文の句読点としてピリオド(.)とカンマ(,)を使用しません。", 49 | { 50 | index: indexOfSymbol, 51 | fix: fixer.replaceTextRange([indexOfSymbol, indexOfSymbol + 1], symbol) 52 | } 53 | ) 54 | ); 55 | }); 56 | } 57 | }; 58 | }; 59 | module.exports = { 60 | linter: reporter, 61 | fixer: reporter 62 | }; 63 | -------------------------------------------------------------------------------- /src/1.2.2.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import { isUserWrittenNode } from "./util/node-util"; 4 | /* 5 | 1.2.2. ピリオド(.)とカンマ(,) 6 | 欧文で表記する組織名などの固有名詞や数字にピリオド(.)やカンマ(,)が含まれる場合は、和文中でもピリオド(.)とカンマ(,)を使用します。 7 | いずれの場合も半角で表記します。「4.1.3 ピリオド(.)、カンマ(,)」を参照してく ださい。 8 | */ 9 | 10 | // . => 。 の置換マップ 11 | const replaceSymbol = { 12 | ".": ".", 13 | ",": "," 14 | }; 15 | function report(context) { 16 | let { Syntax, RuleError, fixer, report, getSource } = context; 17 | return { 18 | [Syntax.Str](node) { 19 | if (!isUserWrittenNode(node, context)) { 20 | return; 21 | } 22 | let text = getSource(node); 23 | // 1.2.2. ピリオド(.)とカンマ(,) 24 | if (/[.,]/.test(text)) { 25 | const index = text.search(/[.,]/); 26 | const symbol = replaceSymbol[text[index]]; 27 | report( 28 | node, 29 | new RuleError("全角のピリオドとカンマは使用しません。", { 30 | index: index, 31 | fix: fixer.replaceTextRange([index, index + 1], symbol) 32 | }) 33 | ); 34 | } 35 | } 36 | }; 37 | } 38 | module.exports = { 39 | linter: report, 40 | fixer: report 41 | }; 42 | -------------------------------------------------------------------------------- /src/2.1.10.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 2.1.10.算用数字の位取りの表記 5 | 桁区切りには「カンマ」、小数点には「ピリオド」を使います。 6 | ただし桁区切りの「カンマ」は省略する場合があります。 7 | */ 8 | import { isUserWrittenNode } from "./util/node-util"; 9 | import { matchCaptureGroupAll } from "match-index"; 10 | function reporter(context) { 11 | let { Syntax, RuleError, report, fixer, getSource } = context; 12 | return { 13 | [Syntax.Str](node) { 14 | if (!isUserWrittenNode(node, context)) { 15 | return; 16 | } 17 | let text = getSource(node); 18 | // 数字,で絞って 19 | let numberWithComma = /([\d,]+)/g; 20 | // 0,xxx な文字列を検出する 21 | let strictMatchReg = /^0+(,)\d+$/; 22 | let match; 23 | while ((match = numberWithComma.exec(text))) { 24 | // この段階では 10,000 も含まれている 25 | // ^0,xxx をだけを取り出す 26 | let matchedString = match[0]; 27 | matchCaptureGroupAll(matchedString, strictMatchReg).forEach((subMatch) => { 28 | const { index } = subMatch; 29 | report( 30 | node, 31 | new RuleError("小数点には「ピリオド」を使います。", { 32 | index: match.index + index, 33 | fix: fixer.replaceTextRange([match.index + index, match.index + index + 1], ".") 34 | }) 35 | ); 36 | }); 37 | } 38 | } 39 | }; 40 | } 41 | module.exports = { 42 | linter: reporter, 43 | fixer: reporter 44 | }; 45 | -------------------------------------------------------------------------------- /src/2.1.5.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 2.1.5.カタカナ 5 | カタカナは「全角」で表記します。 6 | 半角カタカナは特殊な用途を除いて、原則として使いません。 7 | 8 | Halfwidth Katakana variants(半角片仮名) 9 | \uFF65-\uFF9F とする 10 | http://www.asahi-net.or.jp/~ax2s-kmtn/ref/unicode/uff00.html 11 | */ 12 | import { isUserWrittenNode } from "./util/node-util"; 13 | import prh from "textlint-rule-prh"; 14 | import path from "path"; 15 | import fs from "fs"; 16 | import { matchCaptureGroupAll } from "match-index"; 17 | import moji from "moji"; 18 | /** 19 | * 半角カタカナを全角カタカナに変換 20 | * 21 | * @param {String} str 変換したい文字列 22 | */ 23 | function toZenkaku(string) { 24 | return moji(string).convert("HK", "ZK").toString(); 25 | } 26 | 27 | function reporter(context) { 28 | let { Syntax, RuleError, fixer, report, getSource } = context; 29 | // 辞書ベースのカタカタ表記のチェックを行う 30 | let dictRule = prh.fixer(context, { 31 | ruleContents: [fs.readFileSync(path.join(__dirname, "..", "dict", "2.1.5.yml"), "utf-8")] 32 | }); 33 | let originalStrRule = dictRule[Syntax.Str]; 34 | // 半角カタカナの使用をチェックする 35 | dictRule[Syntax.Str] = function (node) { 36 | originalStrRule(node); 37 | if (!isUserWrittenNode(node, context)) { 38 | return; 39 | } 40 | const text = getSource(node); 41 | const matches = matchCaptureGroupAll(text, /([\uFF65-\uFF9F]+)/g); 42 | matches.forEach((match) => { 43 | const { index, text } = match; 44 | report( 45 | node, 46 | new RuleError("カタカナは「全角」で表記します。", { 47 | index: index, 48 | fix: fixer.replaceTextRange([index, index + text.length], toZenkaku(text)) 49 | }) 50 | ); 51 | }); 52 | }; 53 | return dictRule; 54 | } 55 | module.exports = { 56 | linter: reporter, 57 | fixer: reporter 58 | }; 59 | -------------------------------------------------------------------------------- /src/2.1.6.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 2.1.6.カタカナの長音 5 | カタカナ語の末尾の長音は原則として省略しません。 6 | カタカナの長音表記のルールについては、『外来語(カタカナ)表記ガイドライン第 2 版』(テクニカルコミュニケーター協会、2008 年)に従います。 7 | 『日本語スタイルガイド』(テクニカルコミュニケーター協会編著)の 207 ページ「付録 2 外来語(カタカナ)表記ガイドライン」も参考にします。 8 | */ 9 | import fs from "fs"; 10 | import path from "path"; 11 | import prh from "textlint-rule-prh"; 12 | 13 | const report = function (context) { 14 | // 辞書ベースのカタカナ末尾の長音のチェックを行う 15 | return prh.fixer(context, { 16 | ruleContents: [fs.readFileSync(path.join(__dirname, "..", "dict", "2.1.6.yml"), "utf-8")] 17 | }); 18 | }; 19 | module.exports = { 20 | linter: report, 21 | fixer: report 22 | }; 23 | -------------------------------------------------------------------------------- /src/2.1.8.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 2.1.8.算用数字 5 | 算用数字は「半角」で表記します。 6 | 用途によっては全角を許容します。 7 | ただし、表記をできるだけ統一するため、特別な理由がない限り半角での表記を原則とします。 8 | */ 9 | import { isUserWrittenNode } from "./util/node-util"; 10 | import moji from "moji"; 11 | import { matchCaptureGroupAll } from "match-index"; 12 | function toHankaku(string) { 13 | return moji(string).convert("ZE", "HE").toString(); 14 | } 15 | function reporter(context) { 16 | let { Syntax, RuleError, report, fixer, getSource } = context; 17 | return { 18 | [Syntax.Str](node) { 19 | if (!isUserWrittenNode(node, context)) { 20 | return; 21 | } 22 | const text = getSource(node); 23 | const matchRegExp = /([0-9]+)/; 24 | matchCaptureGroupAll(text, matchRegExp).forEach((match) => { 25 | const { index, text } = match; 26 | report( 27 | node, 28 | new RuleError("算用数字は「半角」で表記します。", { 29 | index: index, 30 | fix: fixer.replaceTextRange([index, index + text.length], toHankaku(text)) 31 | }) 32 | ); 33 | }); 34 | } 35 | }; 36 | } 37 | module.exports = { 38 | linter: reporter, 39 | fixer: reporter 40 | }; 41 | -------------------------------------------------------------------------------- /src/2.1.9.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 2.1.9.アルファベット 5 | アルファベットは「半角」で表記します。 6 | 用途によっては全角を許容します。 7 | ただし、表記をできるだけ統一するため、特別な理由がない限り半角での表記を原則とします。 8 | */ 9 | import { isUserWrittenNode } from "./util/node-util"; 10 | import { matchCaptureGroupAll } from "match-index"; 11 | import moji from "moji"; 12 | function toHankaku(string) { 13 | return moji(string).convert("ZE", "HE").toString(); 14 | } 15 | function reporter(context) { 16 | let { Syntax, RuleError, report, fixer, getSource } = context; 17 | return { 18 | [Syntax.Str](node) { 19 | if (!isUserWrittenNode(node, context)) { 20 | return; 21 | } 22 | const text = getSource(node); 23 | const matchRegExp = /([A-Z]+)/; 24 | matchCaptureGroupAll(text, matchRegExp).forEach((match) => { 25 | const { index, text } = match; 26 | report( 27 | node, 28 | new RuleError("アルファベットは「半角」で表記します。", { 29 | index: index, 30 | fix: fixer.replaceTextRange([index, index + text.length], toHankaku(text)) 31 | }) 32 | ); 33 | }); 34 | } 35 | }; 36 | } 37 | module.exports = { 38 | linter: reporter, 39 | fixer: reporter 40 | }; 41 | -------------------------------------------------------------------------------- /src/2.2.1.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 2.2.1.ひらがなと漢字の使い分け 5 | JTFスタイルガイドは、ひらがなと漢字の使い分けについて、 6 | 『用字用語 新表記辞典第四版』(第一法規)および『日本語スタイルガイド』(テクニカルコミュニケーター協会編著)の 185 ページ「付録 1 漢字とひらがなの使い分け」を主たる参考文献とします。 7 | 特にマニュアルやウェブサイトなど、製品やサービスにともなって提供される文書を和訳する際には、 8 | 『日本語 スタイルガイド』(テクニカルコミュニケーター協会編著)の 185 ページ「付録 1 漢字とひらがなの使い分け」を参考にします。 9 | 実務翻訳では、業種や分野により異なる慣例に従って、ひらがなと漢字が使い分けられています。 10 | 同じ語句を 漢字とひらがなのどちらを使っても表記できる場合、特許、金融、法律の分野では漢字で書き、情報処理、ローカライズなどの分野ではひらがなで書く傾向があります。 11 | 実務翻訳において使用頻度が高い語句について、ひらがなと漢字の使用例を以下に示します。 12 | この表を参考にして、できるだけ表記を統一するようにしてください。 13 | 14 | 用例集や用語集を作って表記の統一を図るのも有効な方法です。 15 | 漢字を使用する傾向の強い特許、金融、法律の分野では、以下のひらがなを使用する語句について、漢字を使用する場合があります。 16 | */ 17 | import fs from "fs"; 18 | import path from "path"; 19 | import prh from "textlint-rule-prh"; 20 | 21 | const report = function (context) { 22 | return prh.fixer(context, { 23 | ruleContents: [fs.readFileSync(path.join(__dirname, "..", "dict", "2.2.1.yml"), "utf-8")] 24 | }); 25 | }; 26 | module.exports = { 27 | linter: report, 28 | fixer: report 29 | }; 30 | -------------------------------------------------------------------------------- /src/2.2.2.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import { isUserWrittenNode } from "./util/node-util"; 4 | import ja2num from "japanese-numerals-to-number"; 5 | 6 | function matchToReplace(text, pattern, matchFn) { 7 | var match = pattern.exec(text); 8 | if (match) { 9 | return matchFn(text, pattern, match); 10 | } 11 | return null; 12 | } 13 | 14 | // http://www.drk7.jp/MT/archives/001587.html 15 | function _num2ja(num, opt) { 16 | var sign = { 17 | "+": "", 18 | "-": "−" 19 | }; 20 | var zero = "零"; 21 | var point = "点"; 22 | var zero2nine = ["〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"]; 23 | var ten2thou = ["", "十", "百", "千"]; 24 | var suffices = [ 25 | "", 26 | "万", 27 | "億", 28 | "兆", 29 | "京", 30 | "垓", 31 | "禾予", 32 | "穣", 33 | "溝", 34 | "澗", 35 | "正", 36 | "載,", 37 | "極", 38 | "恒河沙", 39 | "阿僧祇", 40 | "那由他", 41 | "不可思議", 42 | "無量大数" 43 | ]; 44 | 45 | num = num.replace(/,/g, ""); 46 | num.match(/([+-])?(\d+)(?:\.(\d+))?/i); 47 | var sig = RegExp.$1; 48 | var int = RegExp.$2; 49 | var fract = RegExp.$3; 50 | var seisuu = ""; 51 | var shins = []; 52 | 53 | for (let i = int.length; i > 0; i -= 4) { 54 | shins.push(int.substring(i, i - 4)); 55 | } 56 | if (shins.length >= 18) { 57 | return suffices[17]; 58 | } 59 | 60 | var suffix = 0; 61 | for (let i = 0; i < shins.length; i++) { 62 | var shin = shins[i]; 63 | if (shin == "0000") { 64 | suffix++; 65 | continue; 66 | } 67 | var sens = ""; 68 | var keta = 0; 69 | var digits = shin.split("").reverse(); 70 | for (var j = 0; j < digits.length; j++) { 71 | var digit = digits[j]; 72 | 73 | if (opt["fixed4"] || opt["with_arabic"]) { 74 | if (opt["with_arabic"]) { 75 | var flg = 0; 76 | // 余分な 0 を削除する 77 | if (digit == "0") { 78 | for (var k = j + 1; k < digits.length; k++) { 79 | flg += digits[k] == "0" ? 0 : 1; 80 | } 81 | if (flg == 0) { 82 | digit = ""; 83 | } 84 | } 85 | sens = digit + sens; 86 | } else { 87 | sens = zero2nine[digit] + sens; 88 | } 89 | } else { 90 | var suuji = digit == 1 && !opt["p_one"] && keta > 0 ? "" : zero2nine[digit]; 91 | if (digit != 0) { 92 | sens = suuji + ten2thou[keta] + sens; 93 | } 94 | } 95 | keta++; 96 | } 97 | seisuu = sens + suffices[suffix++] + seisuu; 98 | } 99 | var result = (sign[sig] || "") + seisuu; 100 | result = result || zero; 101 | if (fract) { 102 | result = result + point + fract; 103 | } 104 | return result; 105 | } 106 | 107 | function reporter(context) { 108 | let { Syntax, RuleError, report, fixer, getSource } = context; 109 | return { 110 | [Syntax.Str](node) { 111 | if (!isUserWrittenNode(node, context)) { 112 | return; 113 | } 114 | const text = getSource(node); 115 | // 漢数字 -> 算用数字 116 | const toNumber = (text, pattern, match) => { 117 | const matchedString = match[0]; 118 | const index = match.index; 119 | const expected = matchedString.replace(pattern, function (all, match) { 120 | return all.replace(match, ja2num(match)); 121 | }); 122 | const ruleError = new RuleError( 123 | `${matchedString} => ${expected} 124 | 数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。`, 125 | { 126 | index: index, 127 | fix: fixer.replaceTextRange([index, index + matchedString.length], expected) 128 | } 129 | ); 130 | report(node, ruleError); 131 | }; 132 | 133 | /** 134 | * 算用数字 -> 漢数字 135 | * @param {string} text 136 | * @param {RegExp} pattern 137 | * @param {*[]} match 138 | */ 139 | const toKanNumber = (text, pattern, match) => { 140 | const matchedString = match[0]; 141 | const expected = matchedString.replace(pattern, function (all, match) { 142 | return all.replace(match, _num2ja(match, { with_arabic: false })); 143 | }); 144 | const index = match.index; 145 | report( 146 | node, 147 | new RuleError( 148 | `${matchedString} => ${expected} 149 | 慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。`, 150 | { 151 | index: index, 152 | fix: fixer.replaceTextRange([index, index + matchedString.length], expected) 153 | } 154 | ) 155 | ); 156 | }; 157 | 158 | // ignorePatternにマッチしたらmatchFnを呼ばないようにする(エラーを無視する) 159 | const ignoreWhenMatched = (ignorePatterns, matchFn) => { 160 | return (text, pattern, match) => { 161 | if (ignorePatterns.some((p) => p.test(text))) { 162 | return null; 163 | } else { 164 | return matchFn(text, pattern, match); 165 | } 166 | }; 167 | }; 168 | 169 | // *数えられる数字は算用数字を使う 170 | // 数十万、数百億にマッチしないように"数"という文字から始まるものは除外 171 | // https://github.com/textlint-ja/textlint-rule-preset-jtf-style/pull/23 172 | matchToReplace( 173 | text, 174 | /([一二三四五六七八九十壱弐参拾百〇]+)[兆億万]/g, 175 | ignoreWhenMatched([/(数|何)([一二三四五六七八九十壱弐参拾百〇]+)[兆億万]/g], toNumber) 176 | ); 177 | matchToReplace( 178 | text, 179 | /([一二三四五六七八九十壱弐参拾百〇]+)つ/g, 180 | ignoreWhenMatched( 181 | [ 182 | /[一二三四五六七八九]つ(返事|子|ひとつ|星|編|葉|橋|と[無な]い|に一つ)/g, 183 | /(ただ|唯|[女男]手|穴|瓜|馬鹿の)[一二]つ/g 184 | ], 185 | toNumber 186 | ) 187 | ); 188 | matchToReplace(text, /([一二三四五六七八九十壱弐参拾百〇]+)回/g, toNumber); 189 | matchToReplace(text, /([一二三四五六七八九十壱弐参拾百〇]+)か月/g, toNumber); 190 | matchToReplace(text, /([一二三四五六七八九十壱弐参拾百〇]+)番目/g, toNumber); 191 | matchToReplace(text, /([一二三四五六七八九十壱弐参拾百〇]+)進法/g, toNumber); 192 | matchToReplace(text, /([一二三四五六七八九十壱弐参拾百〇]+)次元/g, toNumber); 193 | matchToReplace(text, /第([一二三四五六七八九十壱弐参拾百〇]+)章/g, toNumber); 194 | matchToReplace(text, /第([一二三四五六七八九十壱弐参拾百〇]+)節/g, toNumber); 195 | // *漢数字を使う 196 | // 慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。 197 | matchToReplace(text, /世界(1)/g, toKanNumber); 198 | matchToReplace(text, /(1)時的/g, toKanNumber); 199 | matchToReplace(text, /(1)部分/g, toKanNumber); 200 | matchToReplace(text, /第(3)者/g, toKanNumber); 201 | // 1種 -> 一種: 11種類などにはマッチしない 202 | matchToReplace(text, /[^\d](1)種(?!類)/g, toKanNumber); 203 | matchToReplace(text, /(1)部の/g, toKanNumber); 204 | matchToReplace(text, /(1)番に/g, toKanNumber); 205 | matchToReplace(text, /数(10+)倍/g, toKanNumber); 206 | matchToReplace(text, /数(10+)[兆億万]/g, toKanNumber); 207 | matchToReplace(text, /数(10+)年/g, toKanNumber); 208 | matchToReplace(text, /([0-9]+)次関数/g, toKanNumber); 209 | matchToReplace(text, /(5)大陸/g, toKanNumber); 210 | } 211 | }; 212 | } 213 | 214 | // 2.2.2. 算用数字と漢数字の使い分け 215 | module.exports = { 216 | linter: reporter, 217 | fixer: reporter 218 | }; 219 | -------------------------------------------------------------------------------- /src/2.2.3.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 2.2.3. 一部の助数詞の表記 5 | 助数詞にともなう「ヵ」、「か」、「カ」、「ヶ」、「ケ」、「箇」、「個」の表記は、原則として、ひらがなの「か」を使います。 6 | */ 7 | import prh from "textlint-rule-prh"; 8 | import path from "path"; 9 | import fs from "fs"; 10 | 11 | const report = function (context) { 12 | return prh.fixer(context, { 13 | ruleContents: [fs.readFileSync(path.join(__dirname, "..", "dict", "2.2.3.yml"), "utf-8")] 14 | }); 15 | }; 16 | module.exports = { 17 | linter: report, 18 | fixer: report 19 | }; 20 | -------------------------------------------------------------------------------- /src/3.1.1.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 3.1.1. 全角文字と半角文字の間 5 | 原則として、全角文字と半角文字の間にスペースを入れません。 6 | 7 | 。ただしカタカナ複合語の場合を除きます。「2.1.7 カタカナ複合語」を参照してください。 8 | */ 9 | import { isUserWrittenNode } from "./util/node-util"; 10 | import { matchCaptureGroupAll } from "match-index"; 11 | function reporter(context) { 12 | let { Syntax, RuleError, report, fixer, getSource } = context; 13 | return { 14 | [Syntax.Str](node) { 15 | if (!isUserWrittenNode(node, context)) { 16 | return; 17 | } 18 | let text = getSource(node); 19 | // アルファベットと全角の間は半角スペースではない 20 | let betweenHanAndZen = matchCaptureGroupAll( 21 | text, 22 | /[A-Za-z0-9]( )(?:[\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF]|[\uD840-\uD87F][\uDC00-\uDFFF]|[ぁ-んァ-ヶ])/ 23 | ); 24 | let betweenZenAndHan = matchCaptureGroupAll( 25 | text, 26 | /(?:[\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF]|[\uD840-\uD87F][\uDC00-\uDFFF]|[ぁ-んァ-ヶ])( )[A-Za-z0-9]/ 27 | ); 28 | const reportMatch = (match) => { 29 | const { index } = match; 30 | report( 31 | node, 32 | new RuleError("原則として、全角文字と半角文字の間にスペースを入れません。", { 33 | index: match.index, 34 | fix: fixer.replaceTextRange([index, index + 1], "") 35 | }) 36 | ); 37 | }; 38 | betweenHanAndZen.forEach(reportMatch); 39 | betweenZenAndHan.forEach(reportMatch); 40 | } 41 | }; 42 | } 43 | module.exports = { 44 | linter: reporter, 45 | fixer: reporter 46 | }; 47 | -------------------------------------------------------------------------------- /src/3.1.2.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import { isUserWrittenNode } from "./util/node-util"; 4 | import { matchAll } from "match-index"; 5 | import regx from "regx"; 6 | import { japaneseRegExp } from "./util/regexp"; 7 | const rx = regx("g"); 8 | /* 9 | 3.1.2. 全角文字どうし 10 | 11 | 原則として、全角文字どうしの間にスペースを入れません。ただしカタカナ複合語の場合を除きます。 12 | 「2.1.7 カタカナ複合語」を参照してください。 13 | */ 14 | function reporter(context) { 15 | let { Syntax, RuleError, report, fixer, getSource } = context; 16 | return { 17 | [Syntax.Str](node) { 18 | if (!isUserWrittenNode(node, context)) { 19 | return; 20 | } 21 | const text = getSource(node); 22 | // 全角同士の間は半角スペースを入れない 23 | const matchReg = rx`${japaneseRegExp}( )${japaneseRegExp}`; 24 | const katakakana = /[ァ-ヶ]( )[ァ-ヶ]/; 25 | matchAll(text, matchReg).forEach((match) => { 26 | const { input, captureGroups } = match; 27 | // ただしカタカナ複合語の場合を除きます。 28 | if (katakakana.test(input)) { 29 | return; 30 | } 31 | captureGroups.forEach((captureGroup) => { 32 | const index = captureGroup.index; 33 | report( 34 | node, 35 | new RuleError("原則として、全角文字どうしの間にスペースを入れません。", { 36 | index: index, 37 | fix: fixer.replaceTextRange([index, index + 1], "") 38 | }) 39 | ); 40 | }); 41 | }); 42 | } 43 | }; 44 | } 45 | module.exports = { 46 | linter: reporter, 47 | fixer: reporter 48 | }; 49 | -------------------------------------------------------------------------------- /src/3.2.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 3.2.カタカナ語間のスペースの有無 5 | 中黒または半角スペースを用いてカタカナ語を区切ります。 6 | 「2.1.7 カタカナ複合語」を参照してください。 7 | */ 8 | import { isUserWrittenNode } from "./util/node-util"; 9 | import { matchCaptureGroupAll } from "match-index"; 10 | 11 | module.exports = function (context) { 12 | let { Syntax, RuleError, report, getSource } = context; 13 | return { 14 | [Syntax.Str](node) { 15 | if (!isUserWrittenNode(node, context)) { 16 | return; 17 | } 18 | const text = getSource(node); 19 | // カタカナ(カタカナ以外)カタカナ のパターンを取り出す 20 | matchCaptureGroupAll(text, /[ァ-ヶー]([^[ァ-ヶー])[ァ-ヶー]/).forEach((match) => { 21 | // カタカナの間を全角スペースでは区切らない 22 | const { text } = match; 23 | if (text === " ") { 24 | report( 25 | node, 26 | new RuleError("カタカナ語間は中黒(・)または半角スペースを用いてカタカナ語を区切ります", { 27 | index: match.index 28 | }) 29 | ); 30 | } 31 | }); 32 | } 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /src/3.3.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 3.3. かっこ類と隣接する文字の間のスペースの有無 5 | かっこの外側、内側ともにスペースを入れません。 6 | */ 7 | import { isUserWrittenNode } from "./util/node-util"; 8 | import { matchCaptureGroupAll } from "match-index"; 9 | import { japaneseRegExp } from "./util/regexp"; 10 | 11 | const brackets = ["\\(", "\\)", "\\[", "\\]", "(", ")", "[", "]", "「", "」", "『", "』"]; 12 | const leftBrackets = brackets.map((bracket) => { 13 | return new RegExp("([  ])" + bracket, "g"); 14 | }); 15 | const rightBrackets = brackets.map((bracket) => { 16 | return new RegExp(bracket + "([  ])", "g"); 17 | }); 18 | const leftHalfParentheses = new RegExp(`${japaneseRegExp.source}(\\()`, "g"); 19 | const rightHalfParentheses = new RegExp(`(\\))${japaneseRegExp.source}`, "g"); 20 | const defaultOptions = { 21 | allowOutsideHalfParentheses: true, 22 | requireOutsideHalfParentheses: false 23 | }; 24 | function reporter(context, options) { 25 | let { Syntax, RuleError, report, fixer, getSource } = context; 26 | const allowOutsideHalfParentheses = 27 | options.allowOutsideHalfParentheses ?? defaultOptions.allowOutsideHalfParentheses; 28 | const requireOutsideHalfParentheses = 29 | options.requireOutsideHalfParentheses ?? defaultOptions.requireOutsideHalfParentheses; 30 | return { 31 | [Syntax.Str](node) { 32 | if (!isUserWrittenNode(node, context)) { 33 | return; 34 | } 35 | const text = getSource(node); 36 | // 左にスペース 37 | leftBrackets.forEach((pattern) => { 38 | matchCaptureGroupAll(text, pattern).forEach((match) => { 39 | const { index } = match; 40 | if (allowOutsideHalfParentheses && text.substring(index, index + 2) === " (") { 41 | return; 42 | } 43 | report( 44 | node, 45 | new RuleError("かっこの外側、内側ともにスペースを入れません。", { 46 | index: index, 47 | fix: fixer.replaceTextRange([index, index + 1], "") 48 | }) 49 | ); 50 | }); 51 | }); 52 | // 右にスペース 53 | rightBrackets.forEach((pattern) => { 54 | matchCaptureGroupAll(text, pattern).forEach((match) => { 55 | const { index } = match; 56 | if (allowOutsideHalfParentheses && text.substring(index - 1, index + 1) === ") ") { 57 | return; 58 | } 59 | report( 60 | node, 61 | new RuleError("かっこの外側、内側ともにスペースを入れません。", { 62 | index: index, 63 | fix: fixer.replaceTextRange([index, index + 1], "") 64 | }) 65 | ); 66 | }); 67 | }); 68 | if (requireOutsideHalfParentheses) { 69 | // 左にスペース必須 70 | matchCaptureGroupAll(text, leftHalfParentheses).forEach((match) => { 71 | const { index } = match; 72 | report( 73 | node, 74 | new RuleError("半角かっこの外側に半角スペースが必要です。", { 75 | index, 76 | fix: fixer.replaceTextRange([index, index + 1], " " + match.text) 77 | }) 78 | ); 79 | }); 80 | // 右にスペース必須 81 | matchCaptureGroupAll(text, rightHalfParentheses).forEach((match) => { 82 | const { index } = match; 83 | report( 84 | node, 85 | new RuleError("半角かっこの外側に半角スペースが必要です。", { 86 | index, 87 | fix: fixer.replaceTextRange([index, index + 1], match.text + " ") 88 | }) 89 | ); 90 | }); 91 | } 92 | } 93 | }; 94 | } 95 | module.exports = { 96 | linter: reporter, 97 | fixer: reporter 98 | }; 99 | -------------------------------------------------------------------------------- /src/4.1.1.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.1.1. 句点(。) 5 | 句点(。)は「全角」で表記します。 6 | 句点は文の終わりに付けます。 7 | 文中にかぎかっこが入る場合は、閉じかっこの前に句点を打ちません。 8 | 文中に丸かっこが入る場合も閉じかっこの前に句点を打ちません。。 9 | */ 10 | import { isUserWrittenNode } from "./util/node-util"; 11 | import { matchCaptureGroupAll } from "match-index"; 12 | const brackets = ["」", ")", "\\)"]; 13 | const leftBrackets = brackets.map((bracket) => { 14 | return new RegExp("(。)" + bracket, "g"); 15 | }); 16 | var reporter = function reporter(context) { 17 | let { Syntax, RuleError, report, fixer, getSource } = context; 18 | return { 19 | [Syntax.Str](node) { 20 | if (!isUserWrittenNode(node, context)) { 21 | return; 22 | } 23 | let text = getSource(node); 24 | leftBrackets.forEach((pattern) => { 25 | matchCaptureGroupAll(text, pattern).forEach((match) => { 26 | const { index } = match; 27 | report( 28 | node, 29 | new RuleError("文中にかぎかっこが入る場合は、閉じかっこの前に句点を打ちません。", { 30 | index: index, 31 | fix: fixer.replaceTextRange([index, index + 1], "") 32 | }) 33 | ); 34 | }); 35 | }); 36 | } 37 | }; 38 | }; 39 | module.exports = { 40 | linter: reporter, 41 | fixer: reporter 42 | }; 43 | -------------------------------------------------------------------------------- /src/4.1.3.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 5 | 4.1.3. ピリオド(.)、カンマ(,) 6 | ピリオド(.)とカンマ(,)は「半角」で表記します。 7 | 桁区切りのカンマ(,)、小数点のピリオド(.)、箇条書きの数字に 付加するピリオド(.)としても使用します。 8 | 和文の句読点としては使用しません。「1.2.2 ピリオド(.)とカンマ(,)」を 参照してください 9 | */ 10 | import { isUserWrittenNode } from "./util/node-util"; 11 | import { matchCaptureGroupAll } from "match-index"; 12 | 13 | function reporter(context) { 14 | let { Syntax, RuleError, report, fixer, getSource } = context; 15 | return { 16 | [Syntax.Str](node) { 17 | if (!isUserWrittenNode(node, context)) { 18 | return; 19 | } 20 | let text = getSource(node); 21 | // 和文. はエラー 22 | const matchReg = /(?:[\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF]|[\uD840-\uD87F][\uDC00-\uDFFF]|[ぁ-んァ-ヶ])(\.)/g; 23 | matchCaptureGroupAll(text, matchReg).forEach((match) => { 24 | const index = match.index; 25 | report( 26 | node, 27 | new RuleError("和文の句読点としてはピリオドを使用しません。", { 28 | index: index, 29 | fix: fixer.replaceTextRange([index, index + 1], "。") 30 | }) 31 | ); 32 | }); 33 | } 34 | }; 35 | } 36 | module.exports = { 37 | linter: reporter, 38 | fixer: reporter 39 | }; 40 | -------------------------------------------------------------------------------- /src/4.2.1.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.2.1. 感嘆符(!) 5 | 和文の実務文章の場合、本文では感嘆符を多用しません。 6 | 原文で感嘆符が使われている場合も、和文ではできるだけ句点を使用します。 7 | 8 | ただし、見出しや広告関連の文章、強い調子で読者の注意を促す文章など、 9 | 感嘆符の使用が適切と判断される場合には、感嘆符を使用します。 10 | 使用する場合は「全角」で表記します。 11 | 文末に感嘆符を使用し、後に 別の文が続く場合は、直後に全角スペースを挿入します。 12 | 文中に感嘆符を使用する場合はスペースを挿入しません。下記を参考にしてください。 13 | */ 14 | import { isUserWrittenNode } from "./util/node-util"; 15 | import { matchCaptureGroupAll } from "match-index"; 16 | 17 | function reporter(context) { 18 | let { Syntax, RuleError, report, fixer, getSource } = context; 19 | return { 20 | [Syntax.Str](node) { 21 | if (!isUserWrittenNode(node, context)) { 22 | return; 23 | } 24 | let text = getSource(node); 25 | // 半角の!は利用しない 26 | const matchRegExp = /(?:[\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF]|[\uD840-\uD87F][\uDC00-\uDFFF]|[ぁ-んァ-ヶ])(!)/; 27 | matchCaptureGroupAll(text, matchRegExp).forEach((match) => { 28 | const { index } = match; 29 | return report( 30 | node, 31 | new RuleError("感嘆符(!)を使用する場合は「全角」で表記します。", { 32 | index: index, 33 | fix: fixer.replaceTextRange([index, index + 1], "!") 34 | }) 35 | ); 36 | }); 37 | // !の後ろは全角スペースが推奨 38 | // 半角スペースである場合 39 | const matchAfter = /!( )[^\n]/; 40 | matchCaptureGroupAll(text, matchAfter).forEach((match) => { 41 | const { index } = match; 42 | return report( 43 | node, 44 | new RuleError("文末に感嘆符を使用し、後に別の文が続く場合は、直後に全角スペースを挿入します。", { 45 | index: index, 46 | fix: fixer.replaceTextRange([index, index + 1], " ") 47 | }) 48 | ); 49 | }); 50 | } 51 | }; 52 | } 53 | module.exports = { 54 | linter: reporter, 55 | fixer: reporter 56 | }; 57 | -------------------------------------------------------------------------------- /src/4.2.2.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.2.2.疑問符(?) 5 | 和文の実務文章の場合、本文では疑問符を多用しません。 6 | 原文で疑問符が使われている場合も、和文ではできるだけ句点を使用します。 7 | ただし、見出しや広告関連の文章、読み手の回答を求める質問文など、 8 | 疑問符の使用が適切と判断される場合には、疑問符を使用します。 9 | 使用する場合は「全角」で表記します。 10 | 文末に疑問符を使用し、後に別の 文が続く場合は、直後に全角スペースを挿入します。 11 | 文中に疑問符を使用する場合はスペースを挿入しません。 12 | */ 13 | import { isUserWrittenNode } from "./util/node-util"; 14 | import { matchCaptureGroupAll } from "match-index"; 15 | import regx from "regx"; 16 | import { japaneseRegExp } from "./util/regexp"; 17 | const rx = regx("g"); 18 | function reporter(context) { 19 | let { Syntax, RuleError, report, fixer, getSource } = context; 20 | return { 21 | [Syntax.Str](node) { 22 | if (!isUserWrittenNode(node, context)) { 23 | return; 24 | } 25 | let text = getSource(node); 26 | // 和文で半角の?は利用しない 27 | const matchRegExp = rx`${japaneseRegExp}(\?)`; 28 | matchCaptureGroupAll(text, matchRegExp).forEach((match) => { 29 | const { index } = match; 30 | return report( 31 | node, 32 | new RuleError("疑問符(?)を使用する場合は「全角」で表記します。", { 33 | index: index, 34 | fix: fixer.replaceTextRange([index, index + 1], "?") 35 | }) 36 | ); 37 | }); 38 | // ?の後ろは全角スペースが推奨 39 | // 半角スペースである場合はエラーとする 40 | const matchAfter = /?( )[^\n]/; 41 | matchCaptureGroupAll(text, matchAfter).forEach((match) => { 42 | const { index } = match; 43 | return report( 44 | node, 45 | new RuleError("文末に疑問符を使用し、後に別の文が続く場合は、直後に全角スペースを挿入します。", { 46 | index: index, 47 | fix: fixer.replaceTextRange([index, index + 1], " ") 48 | }) 49 | ); 50 | }); 51 | } 52 | }; 53 | } 54 | module.exports = { 55 | linter: reporter, 56 | fixer: reporter 57 | }; 58 | -------------------------------------------------------------------------------- /src/4.2.4.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.2.4.中黒(・) 5 | カタカナ複合語を区切る場合、同格の語句を並列する場合に使用します。 6 | 同一の文書で、カタカナ複合語の区切りに中黒を使い、同格の語句の並列にも中黒を使用するのは、お勧めしません。 7 | 読み手の理解を妨げる場合があるからです。「2.1.7 カタカナ複合語」を参照してください 8 | 9 | 「・」と「・」 10 | */ 11 | import { isUserWrittenNode } from "./util/node-util"; 12 | import { matchCaptureGroupAll } from "match-index"; 13 | import regx from "regx"; 14 | import { japaneseRegExp } from "./util/regexp"; 15 | const rx = regx("g"); 16 | function reporter(context) { 17 | let { Syntax, RuleError, report, fixer, getSource } = context; 18 | return { 19 | [Syntax.Str](node) { 20 | if (!isUserWrittenNode(node, context)) { 21 | return; 22 | } 23 | const text = getSource(node); 24 | // 和文で半角の・は利用しない 25 | const matchHanNakaguro = rx`(?:${japaneseRegExp}|[a-zA-Z])(・)(?:${japaneseRegExp}|[a-zA-Z])`; 26 | matchCaptureGroupAll(text, matchHanNakaguro).forEach((match) => { 27 | const { index } = match; 28 | report( 29 | node, 30 | new RuleError( 31 | "カタカナ複合語を区切る場合または同格の語句を並列する場合には全角の中黒(・)を使用します。", 32 | { 33 | index: index, 34 | fix: fixer.replaceTextRange([index, index + 1], "・") 35 | } 36 | ) 37 | ); 38 | }); 39 | } 40 | }; 41 | } 42 | module.exports = { 43 | linter: reporter, 44 | fixer: reporter 45 | }; 46 | -------------------------------------------------------------------------------- /src/4.2.5.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.2.5.波線(〜) 5 | 数値の範囲を示す場合に使用します。 6 | */ 7 | import { isUserWrittenNode } from "./util/node-util"; 8 | import { matchCaptureGroupAll } from "match-index"; 9 | 10 | function reporter(context) { 11 | let { Syntax, RuleError, report, fixer, getSource } = context; 12 | return { 13 | [Syntax.Str](node) { 14 | if (!isUserWrittenNode(node, context)) { 15 | return; 16 | } 17 | const text = getSource(node); 18 | // 数値の区切りに半角の~は利用しない 19 | const matchHanQuestion = /\d(~)\d/g; 20 | matchCaptureGroupAll(text, matchHanQuestion).forEach((match) => { 21 | const { index } = match; 22 | report( 23 | node, 24 | new RuleError("数値の範囲を示す場合には全角の〜を使用します。", { 25 | index: index, 26 | fix: fixer.replaceTextRange([index, index + 1], "〜") 27 | }) 28 | ); 29 | }); 30 | } 31 | }; 32 | } 33 | module.exports = { 34 | linter: reporter, 35 | fixer: reporter 36 | }; 37 | -------------------------------------------------------------------------------- /src/4.2.6.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.2.6.ハイフン(-) 5 | 原則として和文ではハイフン(-)を使用しません。 6 | 使用する場合は半角で表記します。原文でハイフンが使われている場合も、和文では使用しません。 7 | 例外は、住所や電話番号の区切りに使う場合です。 8 | */ 9 | import { isUserWrittenNode } from "./util/node-util"; 10 | import { matchCaptureGroupAll } from "match-index"; 11 | import regx from "regx"; 12 | import { japaneseRegExp } from "./util/regexp"; 13 | import mergeMatches from "./util/merge-matches"; 14 | const rx = regx("g"); 15 | module.exports = function (context) { 16 | let { Syntax, RuleError, report, getSource } = context; 17 | return { 18 | [Syntax.Str](node) { 19 | if (!isUserWrittenNode(node, context)) { 20 | return; 21 | } 22 | let text = getSource(node); 23 | // 和文ではハイフン(-)を使用しません 24 | // right 25 | const rightMatches = matchCaptureGroupAll(text, rx`${japaneseRegExp}(\-)`); 26 | // left 27 | const leftMatches = matchCaptureGroupAll(text, rx`(\-)${japaneseRegExp}`); 28 | const matches = mergeMatches(leftMatches, rightMatches); 29 | matches.forEach((match) => { 30 | const { index } = match; 31 | // 数値の符号としてのハイフンは許可する 32 | const nextChar = text[index + 1]; 33 | if (nextChar && /[0-9]/.test(nextChar)) { 34 | return; 35 | } 36 | report( 37 | node, 38 | new RuleError( 39 | `原則として和文ではハイフン(-)を使用しません。 40 | 例外は、住所や電話番号の区切りに使う場合です。`, 41 | { 42 | index: index 43 | } 44 | ) 45 | ); 46 | }); 47 | } 48 | }; 49 | }; 50 | -------------------------------------------------------------------------------- /src/4.2.7.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.2.7.コロン(:) 5 | 原則として和文ではコロン(:)を使用しません。 6 | 原文でコロンが使われている場合も、和文では使用しません。 7 | ただし和文でも、見出し語とその説明の間にコロンを使う場合があります。使用する場合は全角で表記します。 8 | */ 9 | import { isUserWrittenNode } from "./util/node-util"; 10 | import { matchCaptureGroupAll } from "match-index"; 11 | import regx from "regx"; 12 | import { japaneseRegExp } from "./util/regexp"; 13 | const rx = regx("g"); 14 | function reporter(context) { 15 | let { Syntax, RuleError, report, fixer, getSource } = context; 16 | return { 17 | [Syntax.Str](node) { 18 | if (!isUserWrittenNode(node, context)) { 19 | return; 20 | } 21 | const text = getSource(node); 22 | // "和文:" というような半角:は使用しない 23 | 24 | const matchHanQuestion = rx`(?:${japaneseRegExp})(:)`; 25 | matchCaptureGroupAll(text, matchHanQuestion).forEach((match) => { 26 | const { index } = match; 27 | report( 28 | node, 29 | new RuleError("コロン(:)を使用する場合は「全角」で表記します。", { 30 | index: index, 31 | fix: fixer.replaceTextRange([index, index + 1], ":") 32 | }) 33 | ); 34 | }); 35 | } 36 | }; 37 | } 38 | module.exports = { 39 | linter: reporter, 40 | fixer: reporter 41 | }; 42 | -------------------------------------------------------------------------------- /src/4.2.8.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.2.8.セミコロン(;) 5 | 原則として和文ではセミコロン(;)を使用しません。 6 | 原文でセミコロンが使われている場合も、和文では使用しません。 7 | */ 8 | import { isUserWrittenNode } from "./util/node-util"; 9 | import { matchCaptureGroupAll } from "match-index"; 10 | import regx from "regx"; 11 | import { japaneseRegExp } from "./util/regexp"; 12 | const rx = regx("g"); 13 | module.exports = function (context) { 14 | let { Syntax, RuleError, report, getSource } = context; 15 | return { 16 | [Syntax.Str](node) { 17 | if (!isUserWrittenNode(node, context)) { 18 | return; 19 | } 20 | const text = getSource(node); 21 | // "和文;" というような半角;は使用しない 22 | const matchRegExp = rx`(?:${japaneseRegExp})(;)`; 23 | matchCaptureGroupAll(text, matchRegExp).forEach((match) => { 24 | const { index } = match; 25 | report( 26 | node, 27 | new RuleError("原則として和文ではセミコロン(;)を使用しません。", { 28 | index: index 29 | }) 30 | ); 31 | }); 32 | } 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /src/4.2.9.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.2.9.ダッシュ(-) 5 | 原則として和文ではダッシュ(-)を使用しません。 6 | 和文でダッシュを使用すると、電子文書として処理する際に不都合が生じる場合があります。 7 | 8 | Note: ここでのダッシュはU+2012-U+2015とする 9 | 全角 —— のように使われてる事が多い 10 | https://ja.wikipedia.org/wiki/%E3%83%80%E3%83%83%E3%82%B7%E3%83%A5_%28%E8%A8%98%E5%8F%B7%29 11 | */ 12 | import { isUserWrittenNode } from "./util/node-util"; 13 | import { matchCaptureGroupAll } from "match-index"; 14 | import regx from "regx"; 15 | import { japaneseRegExp } from "./util/regexp"; 16 | const rx = regx("g"); 17 | module.exports = function (context) { 18 | let { Syntax, RuleError, report, getSource } = context; 19 | return { 20 | [Syntax.Str](node) { 21 | if (!isUserWrittenNode(node, context)) { 22 | return; 23 | } 24 | const text = getSource(node); 25 | // 和文でダッシュは使用しない 26 | const matchRegExp = rx`(?:${japaneseRegExp})([\u2012-\u2015])`; 27 | matchCaptureGroupAll(text, matchRegExp).forEach((match) => { 28 | const { index } = match; 29 | report( 30 | node, 31 | new RuleError("原則として和文ではダッシュ(―)を使用しません。", { 32 | index 33 | }) 34 | ); 35 | }); 36 | } 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /src/4.3.1.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.3.1.丸かっこ() 5 | 直前の内容を補足して説明する場合や言い換える場合に使用します。 6 | 全角のかっこを使用します 7 | */ 8 | import { isUserWrittenNode } from "./util/node-util"; 9 | import { matchCaptureGroupAll } from "match-index"; 10 | import regx from "regx"; 11 | import { japaneseRegExp } from "./util/regexp"; 12 | const rx = regx("g"); 13 | 14 | const replaceSymbol = (symbol) => { 15 | var newSymbol = { 16 | "(": "(", 17 | ")": ")" 18 | }[symbol]; 19 | if (!newSymbol) { 20 | throw new Error("fail to replace symbol"); 21 | } 22 | return newSymbol; 23 | }; 24 | function reporter(context) { 25 | let { Syntax, RuleError, report, fixer, getSource } = context; 26 | return { 27 | [Syntax.Str](node) { 28 | if (!isUserWrittenNode(node, context)) { 29 | return; 30 | } 31 | // 半角のかっこ()は使用しないで全角のかっこを使用する 32 | const text = getSource(node); 33 | const matchRegExps = [ 34 | rx`([\(\)])(?:.*${japaneseRegExp}.*)([\(\)])`, 35 | rx`(?:${japaneseRegExp})([\(\)])(?:${japaneseRegExp})`, 36 | rx`^(\()(?:${japaneseRegExp})`, 37 | rx`(?:${japaneseRegExp})(\))$` 38 | ]; 39 | matchRegExps.forEach((matchRegExp) => { 40 | matchCaptureGroupAll(text, matchRegExp).forEach((match) => { 41 | const { index } = match; 42 | report( 43 | node, 44 | new RuleError("半角のかっこ()が使用されています。全角のかっこ()を使用してください。", { 45 | index: index, 46 | fix: fixer.replaceTextRange([index, index + 1], replaceSymbol(match.text)) 47 | }) 48 | ); 49 | }); 50 | }); 51 | } 52 | }; 53 | } 54 | module.exports = { 55 | linter: reporter, 56 | fixer: reporter 57 | }; 58 | -------------------------------------------------------------------------------- /src/4.3.2.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.3.2.大かっこ[] 5 | コンピューターの画面用語などの特殊な表記で使用します。 6 | 全角の大かっこを使用します 7 | */ 8 | import { isUserWrittenNode } from "./util/node-util"; 9 | import { matchCaptureGroupAll } from "match-index"; 10 | import regx from "regx"; 11 | import { japaneseRegExp } from "./util/regexp"; 12 | const rx = regx("g"); 13 | 14 | const replaceSymbol = (symbol) => { 15 | var newSymbol = { 16 | "[": "[", 17 | "]": "]" 18 | }[symbol]; 19 | if (!newSymbol) { 20 | throw new Error("fail to replace symbol"); 21 | } 22 | return newSymbol; 23 | }; 24 | function reporter(context) { 25 | let { Syntax, RuleError, report, fixer, getSource } = context; 26 | return { 27 | [Syntax.Str](node) { 28 | if (!isUserWrittenNode(node, context)) { 29 | return; 30 | } 31 | // 半角のかっこ[]は使用しないで全角のかっこを使用する 32 | const text = getSource(node); 33 | const matchRegExp = rx`(?:${japaneseRegExp})([\[\]])`; 34 | matchCaptureGroupAll(text, matchRegExp).forEach((match) => { 35 | const { index } = match; 36 | report( 37 | node, 38 | new RuleError("半角の大かっこ[]が使用されています。全角のかっこ[]を使用してください。", { 39 | index: index, 40 | fix: fixer.replaceTextRange([index, index + 1], replaceSymbol(match.text)) 41 | }) 42 | ); 43 | }); 44 | } 45 | }; 46 | } 47 | module.exports = { 48 | linter: reporter, 49 | fixer: reporter 50 | }; 51 | -------------------------------------------------------------------------------- /src/4.3.3.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.3.3.かぎかっこ「」 5 | 引用、参照先、入力する文字を示す場合、語句を強調する場合に使用します。 6 | 7 | パラグラフをまたぐかぎかっこが存在しないことを検証する 8 | */ 9 | import { checkPair } from "./util/pair-checker"; 10 | module.exports = function (context) { 11 | return checkPair(context, { 12 | left: "「", 13 | right: "」" 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /src/4.3.4.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.3.4.二重かぎかっこ『』 5 | 文献の題を示す場合や、かぎかっこの中にさらにかぎかっこを入れる場合に使用します。 6 | */ 7 | import { checkPair } from "./util/pair-checker"; 8 | module.exports = function (context) { 9 | return checkPair(context, { 10 | left: "『", 11 | right: "』" 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /src/4.3.5.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.3.5.二重引用符"" 5 | 引用や語句を強調する場合に使用します。和文では多用しません。 6 | */ 7 | import { checkPair } from "./util/pair-checker"; 8 | module.exports = function (context) { 9 | return checkPair(context, { 10 | left: '"', 11 | right: '"' 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /src/4.3.6.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.3.6.中かっこ{} 5 | 原則として和文では使用しません。 6 | 原文で中かっこが使用されており、原文どおりに使用する必要がある場合のみ使用します。 7 | */ 8 | import { checkPair } from "./util/pair-checker"; 9 | module.exports = function (context) { 10 | return checkPair(context, { 11 | left: "{", 12 | right: "}" 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /src/4.3.7.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.3.7.山かっこ<> 5 | 原則として和文では使用しません。 6 | 原文で山かっこが使用されており、原文どおりに使用する必要がある場合のみ使用します。 7 | */ 8 | import { checkPair } from "./util/pair-checker"; 9 | module.exports = function (context) { 10 | return checkPair(context, { 11 | left: "<", 12 | right: ">" 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /src/4.3.8.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /* 4 | 4.3.8.一重引用符'' 5 | 原則として和文では使用しません。 6 | 原文で一重引用符が使用されており、原文どおりに使用する必要がある場合のみ使用します。 7 | */ 8 | import { checkPair } from "./util/pair-checker"; 9 | module.exports = function (context) { 10 | // do no anything 11 | return {}; 12 | }; 13 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | module.exports = { 4 | rules: { 5 | "1.1.1.本文": require("./1.1.1"), 6 | "1.1.2.見出し": require("./1.1.2"), 7 | "1.1.3.箇条書き": require("./1.1.3"), 8 | // 1.1.4. 図表内のテキスト はスキップ 9 | "1.1.5.図表のキャプション": require("./1.1.5"), 10 | "1.2.1.句点(。)と読点(、)": require("./1.2.1"), 11 | "1.2.2.ピリオド(.)とカンマ(,)": require("./1.2.2"), 12 | // TODO: 2.1.1.ひらがな 13 | "2.1.2.漢字": require("./2.1.2"), 14 | // TODO: 2.1.3.漢字の送りがな 15 | // TODO: 2.1.4.複合語の送りがな 16 | "2.1.5.カタカナ": require("./2.1.5"), 17 | "2.1.6.カタカナの長音": require("./2.1.6"), 18 | // TODO: 2.1.7.カタカナ複合語 19 | "2.1.8.算用数字": require("./2.1.8"), 20 | "2.1.9.アルファベット": require("./2.1.9"), 21 | "2.1.10.算用数字の位取りの表記": require("./2.1.10"), 22 | "2.2.1.ひらがなと漢字の使い分け": require("./2.2.1"), 23 | "2.2.2.算用数字と漢数字の使い分け": require("./2.2.2"), 24 | "2.2.3.一部の助数詞の表記": require("./2.2.3"), 25 | "3.1.1.全角文字と半角文字の間": require("./3.1.1"), 26 | "3.1.2.全角文字どうし": require("./3.1.2"), 27 | "3.2.カタカナ語間のスペースの有無": require("./3.2"), 28 | "3.3.かっこ類と隣接する文字の間のスペースの有無": require("./3.3"), 29 | "4.1.1.句点(。)": require("./4.1.1"), 30 | // 4.1.2. 読点(、) はスキップ 31 | "4.1.3.ピリオド(.)、カンマ(,)": require("./4.1.3"), 32 | "4.2.1.感嘆符(!)": require("./4.2.1"), 33 | "4.2.2.疑問符(?)": require("./4.2.2"), 34 | "4.2.4.中黒(・)": require("./4.2.4"), 35 | "4.2.5.波線(〜)": require("./4.2.5"), 36 | "4.2.6.ハイフン(-)": require("./4.2.6"), 37 | "4.2.7.コロン(:)": require("./4.2.7"), 38 | "4.2.8.セミコロン(;)": require("./4.2.8"), 39 | "4.2.9.ダッシュ(-)": require("./4.2.9"), 40 | "4.3.1.丸かっこ()": require("./4.3.1"), 41 | "4.3.2.大かっこ[]": require("./4.3.2"), 42 | "4.3.3.かぎかっこ「」": require("./4.3.3"), 43 | "4.3.4.二重かぎかっこ『』": require("./4.3.4"), 44 | "4.3.5.二重引用符": require("./4.3.5"), 45 | "4.3.6.中かっこ{ }": require("./4.3.6"), 46 | "4.3.7.山かっこ<>": require("./4.3.7"), 47 | "4.3.8.一重引用符": require("./4.3.8") 48 | }, 49 | rulesConfig: { 50 | "1.1.1.本文": true, 51 | "1.1.2.見出し": true, 52 | "1.1.3.箇条書き": true, 53 | "1.1.5.図表のキャプション": true, 54 | "1.2.1.句点(。)と読点(、)": true, 55 | "1.2.2.ピリオド(.)とカンマ(,)": true, 56 | "2.1.2.漢字": false, 57 | // 辞書ベース 58 | "2.1.5.カタカナ": false, 59 | // 辞書ベース 60 | "2.1.6.カタカナの長音": false, 61 | "2.1.8.算用数字": true, 62 | "2.1.9.アルファベット": true, 63 | "2.1.10.算用数字の位取りの表記": true, 64 | // 辞書ベース 65 | "2.2.1.ひらがなと漢字の使い分け": false, 66 | "2.2.2.算用数字と漢数字の使い分け": true, 67 | "2.2.3.一部の助数詞の表記": true, 68 | "3.1.1.全角文字と半角文字の間": true, 69 | "3.1.2.全角文字どうし": true, 70 | "3.2.カタカナ語間のスペースの有無": true, 71 | "3.3.かっこ類と隣接する文字の間のスペースの有無": true, 72 | "4.1.1.句点(。)": true, 73 | "4.1.3.ピリオド(.)、カンマ(,)": true, 74 | "4.2.1.感嘆符(!)": true, 75 | "4.2.2.疑問符(?)": true, 76 | "4.2.4.中黒(・)": true, 77 | "4.2.5.波線(〜)": true, 78 | "4.2.6.ハイフン(-)": true, 79 | "4.2.7.コロン(:)": true, 80 | "4.2.8.セミコロン(;)": true, 81 | "4.2.9.ダッシュ(-)": true, 82 | "4.3.1.丸かっこ()": true, 83 | "4.3.2.大かっこ[]": true, 84 | "4.3.3.かぎかっこ「」": true, 85 | "4.3.4.二重かぎかっこ『』": true, 86 | "4.3.5.二重引用符": true, 87 | "4.3.6.中かっこ{ }": true, 88 | "4.3.7.山かっこ<>": true, 89 | "4.3.8.一重引用符": true 90 | } 91 | }; 92 | -------------------------------------------------------------------------------- /src/util/merge-matches.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | module.exports = function mergeMatches(...aMatches) { 4 | const results = []; 5 | aMatches.forEach((matches) => { 6 | matches.forEach((targetMatch) => { 7 | const alreadyHave = results.some((match) => { 8 | const { text, index } = match; 9 | return targetMatch.index === index && targetMatch.text === text; 10 | }); 11 | if (!alreadyHave) { 12 | results.push(targetMatch); 13 | } 14 | }); 15 | }); 16 | return results; 17 | }; 18 | -------------------------------------------------------------------------------- /src/util/node-util.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import { RuleHelper } from "textlint-rule-helper"; 4 | 5 | /** 6 | * ユーザーが書いたと推測されるNodeかどうかを判定する 7 | * ユーザーが管理できないテキストは対象外としたいため。 8 | * @param node 9 | * @param context 10 | * @returns {boolean} 11 | */ 12 | export function isUserWrittenNode(node, context) { 13 | let helper = new RuleHelper(context); 14 | let Syntax = context.Syntax; 15 | // Strがユーザーに書かれたと断定できるNodeかを判定する 16 | // LinkやStrongなどはユーザーが書いていない可能性があるStrなので除外する 17 | if (node.type === Syntax.Str) { 18 | return helper.isPlainStrNode(node); 19 | } 20 | // ブロック要素の互換性のため古い除外ルールも残す 21 | return !helper.isChildNode(node, [Syntax.Link, Syntax.Image, Syntax.BlockQuote, Syntax.Emphasis]); 22 | } 23 | -------------------------------------------------------------------------------- /src/util/pair-checker.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | /** 4 | * 「と」といったペアがちゃんと閉じられているかをチェックします 5 | * @param {object} context 6 | * @param {string} left 7 | * @param {string} right 8 | * @returns {object} 9 | */ 10 | import assert from "assert"; 11 | import { RuleHelper } from "textlint-rule-helper"; 12 | const flat = (array) => { 13 | return [].concat.apply([], array); 14 | }; 15 | export function checkPair(context, { left, right }) { 16 | assert(left); 17 | assert(right); 18 | const { Syntax, RuleError, report, getSource } = context; 19 | const helper = new RuleHelper(context); 20 | let isInParagraph = false; 21 | let currentStrInParagraph = []; 22 | /** 23 | * `Str` nodeの配列を受け取り、pairが見つからないnodeを返す 24 | * @param {Object} currentStrInParagraph 25 | * @returns {{node, index}[]} 26 | */ 27 | const findAllSymbolLocations = (symbol, text) => { 28 | let index = 0; 29 | const symbolLocations = []; 30 | while (index < text.length) { 31 | index = text.indexOf(symbol, index); 32 | if (index < 0) break; 33 | symbolLocations.push({ 34 | index, 35 | symbol 36 | }); 37 | index += 1; 38 | } 39 | return symbolLocations; 40 | }; 41 | const foundMissingPairNodes = (currentStrInParagraph) => { 42 | const matchParentheses = flat( 43 | currentStrInParagraph.map((node) => { 44 | let text = getSource(node); 45 | const leftSymbolLocations = findAllSymbolLocations(left, text); 46 | const rightSymbolLocations = left !== right ? findAllSymbolLocations(right, text) : []; 47 | const allSymbolLocations = [...leftSymbolLocations, ...rightSymbolLocations].sort( 48 | (a, b) => a.index - b.index 49 | ); 50 | return allSymbolLocations.map((loc) => ({ ...loc, node })); 51 | }) 52 | ); 53 | if (left === right) { 54 | const isCompletedParentheses = matchParentheses.length % 2 == 0; 55 | if (isCompletedParentheses) { 56 | return []; 57 | } else { 58 | return [matchParentheses[matchParentheses.length - 1]]; 59 | } 60 | } else { 61 | const lastUnmatchParences = []; 62 | while (matchParentheses.length > 0) { 63 | const item = matchParentheses.shift(); 64 | if (item.symbol == left) { 65 | lastUnmatchParences.push(item); 66 | } else { 67 | // right 68 | const last = lastUnmatchParences.pop(); 69 | if (last) { 70 | if (last.symbol == right) { 71 | lastUnmatchParences.push(last); 72 | lastUnmatchParences.push(item); 73 | } 74 | } else { 75 | lastUnmatchParences.push(item); 76 | } 77 | } 78 | } 79 | return lastUnmatchParences; 80 | } 81 | }; 82 | return { 83 | [Syntax.Paragraph](node) { 84 | if (helper.isChildNode(node, [Syntax.BlockQuote])) { 85 | return; 86 | } 87 | currentStrInParagraph = []; 88 | isInParagraph = true; 89 | }, 90 | [Syntax.Str](node) { 91 | if (!isInParagraph) { 92 | return; 93 | } 94 | currentStrInParagraph.push(node); 95 | }, 96 | [`${Syntax.Paragraph}:exit`]() { 97 | const missingPairList = foundMissingPairNodes(currentStrInParagraph); 98 | // 探索おわり 99 | isInParagraph = false; 100 | // 全ての対が見つかったなら配列は空になる 101 | if (missingPairList.length === 0) { 102 | return; 103 | } 104 | missingPairList.forEach(({ index, node, symbol }) => { 105 | let message = 106 | symbol === left 107 | ? `${left}の対となる${right}が見つかりません。${left}${right}` 108 | : `${right}の対となる${left}が見つかりません。${left}${right}`; 109 | report(node, new RuleError(message, { index })); 110 | }); 111 | } 112 | }; 113 | } 114 | -------------------------------------------------------------------------------- /src/util/regexp.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | export const japaneseRegExp = /(?:[々〇〻\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF]|[\uD840-\uD87F][\uDC00-\uDFFF]|[ぁ-んァ-ヶ])/; 4 | // http://tama-san.com/kanji-regex/ ベース 5 | // "々" は 記号であるため除外 6 | // https://github.com/textlint-ja/textlint-rule-preset-jtf-style/issues/48 7 | export const kanjiRegExp = /(?:[〇〻\u3400-\u9FFF\uF900-\uFAFF]|[\uD840-\uD87F][\uDC00-\uDFFF])/; 8 | export const hiraganaRegExp = /[ぁ-ん]/; 9 | export const karakanaRegExp = /[ァ-ヶ]/; 10 | // 半角カタカナ 11 | export const hanKarakanaRegExp = /[\uFF65-\uFF9F]/; 12 | -------------------------------------------------------------------------------- /test/1.1.1-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/1.1.1"; 5 | var tester = new TextLintTester(); 6 | tester.run("1.1.1.本文", rule, { 7 | valid: [ 8 | "これはペンです。\nこれもペンです。", 9 | "これはペンである。\nこれもペンである。", 10 | "昨日はいい天気であったのだが、今日は悪天候である。", 11 | "今日はいい天気ですね。\n\nそうですね。", 12 | // 箇条書きは無視 13 | ` 14 | - 今日はいい天気ですね。 15 | - 今日はいい天気である。 16 | ` 17 | ], 18 | invalid: [ 19 | // 常体が多い 20 | { 21 | text: `それはペンなのだが、これもペンである。 22 | 23 | じゃあこっちは? 24 | 25 | それはペンです。`, 26 | errors: [ 27 | { 28 | message: 29 | '本文を常体(である調)に統一して下さい。\n本文の文体は、敬体(ですます調)あるいは常体(である調)のどちらかで統一します。\n"です。"が敬体(ですます調)です。', 30 | line: 5, 31 | column: 6 32 | } 33 | ] 34 | }, 35 | // 接続の混在 36 | { 37 | text: `昨日は雨だったのだが、持ち直した。 38 | 昨日は雨だったのですが、持ち直しました。 39 | `, 40 | errors: [ 41 | { 42 | message: 43 | '本文を敬体(ですます調)に統一して下さい。\n本文の文体は、敬体(ですます調)あるいは常体(である調)のどちらかで統一します。\n"のだが"が常体(である調)です。', 44 | line: 1, 45 | column: 8 46 | } 47 | ] 48 | }, 49 | // 改行なしで混ざってる時 50 | { 51 | text: `今日はいい天気ですね。今日はいい天気である。`, 52 | errors: [ 53 | { 54 | message: 55 | '本文を敬体(ですます調)に統一して下さい。\n本文の文体は、敬体(ですます調)あるいは常体(である調)のどちらかで統一します。\n"である。"が常体(である調)です。', 56 | line: 1, 57 | column: 19 58 | } 59 | ] 60 | }, 61 | // 文末が混在してるとreportされる 62 | { 63 | text: `今日はいい天気ですね。 64 | 今日はいい天気である。 65 | `, 66 | errors: [ 67 | // 同数である場合は、"ですます"に統一するのを優先する 68 | { 69 | message: `本文を敬体(ですます調)に統一して下さい。\n本文の文体は、敬体(ですます調)あるいは常体(である調)のどちらかで統一します。\n"である。"が常体(である調)です。`, 70 | line: 2, 71 | column: 8 72 | } 73 | ] 74 | } 75 | ] 76 | }); 77 | -------------------------------------------------------------------------------- /test/1.1.2-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/1.1.2"; 5 | var tester = new TextLintTester(); 6 | tester.run("1.1.2.見出し", rule, { 7 | valid: [ 8 | "# 見出しである\n\n本文はですます調です。", 9 | "## 見出しです", 10 | "### モーニング娘。について" // 。が最後ではない 11 | ], 12 | invalid: [ 13 | { 14 | text: "# 見出し。", 15 | output: "# 見出し", 16 | errors: [ 17 | { 18 | message: "見出しの文末には、句点(。)を付けません。", 19 | line: 1, 20 | column: 6 21 | } 22 | ] 23 | }, 24 | { 25 | text: "### 見出し。", 26 | output: "### 見出し", 27 | errors: [ 28 | { 29 | message: "見出しの文末には、句点(。)を付けません。", 30 | line: 1, 31 | column: 8 32 | } 33 | ] 34 | }, 35 | { 36 | text: "### 見出し。\n test", 37 | output: "### 見出し\n test", 38 | errors: [ 39 | { 40 | message: "見出しの文末には、句点(。)を付けません。", 41 | line: 1, 42 | column: 8 43 | } 44 | ] 45 | } 46 | ] 47 | }); 48 | -------------------------------------------------------------------------------- /test/1.1.3-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/1.1.3"; 5 | var tester = new TextLintTester(); 6 | tester.run("1.1.3.箇条書き", rule, { 7 | valid: [ 8 | ` 9 | - これは敬体(ですます調)です。 10 | - これも敬体(ですます調)です。 11 | `, 12 | ` 13 | - これは常体(である調)である。 14 | - これも常体(である調)である。 15 | `, 16 | ` 17 | - 文末に句点ありなしを統一 18 | - 文末に句点ありなしを統一 19 | ` 20 | ], 21 | invalid: [ 22 | { 23 | text: ` 24 | - これは敬体(ですます調)です。 25 | - これは敬体(ですます調)です。 26 | - これは常体(である調)である。 27 | `.trim(), 28 | errors: [ 29 | { 30 | message: 31 | '箇条書きを敬体(ですます調)に統一して下さい。\nひとまとまりの箇条書きでは、敬体と常体を混在させません。\n"である。"が常体(である調)です。', 32 | line: 3, 33 | column: 14 34 | } 35 | ] 36 | }, 37 | { 38 | text: ` 39 | - これは敬体(ですます調)です。 40 | - これは常体(である調)である。 41 | - これは常体(である調)である。 42 | `.trim(), 43 | errors: [ 44 | { 45 | message: 46 | '箇条書きを常体(である調)に統一して下さい。\nひとまとまりの箇条書きでは、敬体と常体を混在させません。\n"です。"が敬体(ですます調)です。', 47 | line: 1, 48 | column: 15 49 | } 50 | ] 51 | }, 52 | // 同数ならであるを注意 53 | { 54 | text: ` 55 | - これは敬体(ですます調)です。 56 | - これは常体(である調)である。 57 | `.trim(), 58 | errors: [ 59 | { 60 | message: 61 | '箇条書きを敬体(ですます調)に統一して下さい。\nひとまとまりの箇条書きでは、敬体と常体を混在させません。\n"である。"が常体(である調)です。', 62 | line: 2, 63 | column: 14 64 | } 65 | ] 66 | }, 67 | { 68 | text: ` 69 | * 文末に句点ありなしを統一。 70 | * 文末に句点ありなしを統一 71 | `.trim(), 72 | errors: [ 73 | { 74 | message: 75 | "箇条書きの文末に句点(。)を付けて下さい。\n箇条書きの文末に句点(。)を付けるかを統一します。", 76 | line: 2, 77 | column: 1 // 無指定なので - PR Welcome 78 | } 79 | ] 80 | }, 81 | { 82 | text: ` 83 | * 文末に句点ありなしを統一。 84 | * 文末に句点ありなしを統一 85 | * 文末に句点ありなしを統一 86 | `.trim(), 87 | errors: [ 88 | { 89 | message: 90 | "箇条書きの文末から句点(。)を外して下さい。\n箇条書きの文末に句点(。)を付けるかを統一します。", 91 | line: 1, 92 | column: 1 // 無指定なので - PR Welcome 93 | } 94 | ] 95 | } 96 | ] 97 | }); 98 | -------------------------------------------------------------------------------- /test/1.1.5-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/1.1.5"; 5 | var tester = new TextLintTester(); 6 | tester.run("1.1.5.図表のキャプション", rule, { 7 | valid: [ 8 | "![これは図です。](http://example.com/img) と ![これは図です。](http://example.com/img)", 9 | "![これは図である。](http://example.com/img) と ![これは図である。](http://example.com/img)", 10 | "![](http://example.com/img)" 11 | ], 12 | invalid: [ 13 | { 14 | text: 15 | "![これは図です。](http://example.com/img) と ![これは図です。](http://example.com/img) と ![これは図である。](http://example.com/img).", 16 | errors: [ 17 | { 18 | message: 19 | '図表のキャプションを敬体(ですます調)に統一して下さい。\n図表のキャプション内で敬体、常体を混在させないことが重要です。\n"である。"が常体(である調)です。', 20 | line: 1, 21 | column: 82 22 | } 23 | ] 24 | }, 25 | { 26 | text: 27 | "![これは図です。](http://example.com/img) と ![これは図である。](http://example.com/img) と ![これは図である。](http://example.com/img).", 28 | errors: [ 29 | { 30 | message: 31 | '図表のキャプションを常体(である調)に統一して下さい。\n図表のキャプション内で敬体、常体を混在させないことが重要です。\n"です。"が敬体(ですます調)です。', 32 | line: 1, 33 | column: 7 // imgのposition 34 | } 35 | ] 36 | }, 37 | // 同数ならであるを注意 38 | { 39 | text: "![これは図です。](http://example.com/img) と ![これは図である。](http://example.com/img).", 40 | errors: [ 41 | { 42 | message: 43 | '図表のキャプションを敬体(ですます調)に統一して下さい。\n図表のキャプション内で敬体、常体を混在させないことが重要です。\n"である。"が常体(である調)です。', 44 | line: 1, 45 | column: 44 46 | } 47 | ] 48 | } 49 | ] 50 | }); 51 | -------------------------------------------------------------------------------- /test/1.2.1-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/1.2.1"; 5 | var tester = new TextLintTester(); 6 | tester.run("1.2.1.句点(。)と読点(、)", rule, { 7 | valid: [ 8 | "これは、見本となる例です。", 9 | "[これは,見本となる例です.](http://example.com)" // ignore link 10 | ], 11 | invalid: [ 12 | // text, expected errors 13 | { 14 | text: "これは,見本となる例です.", 15 | output: "これは、見本となる例です。", 16 | errors: [ 17 | { 18 | message: 19 | "句読点には全角の「、」と「。」を使います。和文の句読点としてピリオド(.)とカンマ(,)を使用しません。", 20 | column: 4 21 | }, 22 | { 23 | message: 24 | "句読点には全角の「、」と「。」を使います。和文の句読点としてピリオド(.)とカンマ(,)を使用しません。", 25 | column: 13 26 | } 27 | ] 28 | } 29 | ] 30 | }); 31 | -------------------------------------------------------------------------------- /test/1.2.2-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/1.2.2"; 5 | var tester = new TextLintTester(); 6 | tester.run("1.2.2.ピリオド(.)とカンマ(,)", rule, { 7 | valid: ["The Ministry of Economy, Trade and Industry"], 8 | invalid: [ 9 | // text, expected errors 10 | { 11 | text: "785,105", 12 | output: "785,105", 13 | errors: [ 14 | { 15 | message: "全角のピリオドとカンマは使用しません。", 16 | column: 4 17 | } 18 | ] 19 | }, 20 | { 21 | text: "785.105", 22 | output: "785.105", 23 | errors: [ 24 | { 25 | message: "全角のピリオドとカンマは使用しません。", 26 | column: 4 27 | } 28 | ] 29 | } 30 | ] 31 | }); 32 | -------------------------------------------------------------------------------- /test/2.1.10-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/2.1.10"; 5 | var tester = new TextLintTester(); 6 | tester.run("2.1.10.算用数字の位取りの表記", rule, { 7 | valid: ["1,000円", "1.01", "0.01", "10,000", "12,345"], 8 | invalid: [ 9 | { 10 | text: "0,01", 11 | output: "0.01", 12 | errors: [ 13 | { 14 | message: "小数点には「ピリオド」を使います。", 15 | line: 1, 16 | column: 2 17 | } 18 | ] 19 | }, 20 | { 21 | text: "0,1", 22 | output: "0.1", 23 | errors: [ 24 | { 25 | message: "小数点には「ピリオド」を使います。", 26 | line: 1, 27 | column: 2 28 | } 29 | ] 30 | }, 31 | { 32 | text: "これは10個あるうちの0,1分", 33 | output: "これは10個あるうちの0.1分", 34 | errors: [ 35 | { 36 | message: "小数点には「ピリオド」を使います。", 37 | line: 1, 38 | column: 13 39 | } 40 | ] 41 | } 42 | ] 43 | }); 44 | -------------------------------------------------------------------------------- /test/2.1.2-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/2.1.2"; 5 | var tester = new TextLintTester(); 6 | tester.run("2.1.2.漢字", rule, { 7 | valid: ["今日は日本語の勉強をします。", "度々問題が起きる。"], 8 | invalid: [ 9 | { 10 | text: "文章を推敲する", 11 | errors: [ 12 | { 13 | message: "「敲」は「常用漢字表」外の漢字です。", 14 | line: 1, 15 | column: 5 16 | } 17 | ] 18 | }, 19 | { 20 | text: "私は聡明でありたい", 21 | errors: [ 22 | { 23 | message: "「聡」は「常用漢字表」外の漢字です。", 24 | line: 1, 25 | column: 3 26 | } 27 | ] 28 | } 29 | ] 30 | }); 31 | -------------------------------------------------------------------------------- /test/2.1.5-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/2.1.5"; 5 | var tester = new TextLintTester(); 6 | tester.run("2.1.5.カタカナ", rule, { 7 | valid: [ 8 | "カタカナ", 9 | "2.1.5.カタカナ", 10 | "㌕は大丈夫。", 11 | "_ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚_" // Strではない 12 | ], 13 | invalid: [ 14 | { 15 | text: "アジヤ", 16 | errors: [ 17 | { 18 | message: "アジヤ => アジア" 19 | } 20 | ] 21 | }, 22 | { 23 | text: ` 24 | 25 | アジア 26 | 27 | `, 28 | output: ` 29 | 30 | アジア 31 | 32 | `, 33 | errors: [ 34 | { 35 | message: "カタカナは「全角」で表記します。" 36 | } 37 | ] 38 | }, 39 | { 40 | text: "ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚", 41 | output: 42 | "ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜", 43 | errors: [ 44 | { 45 | message: "カタカナは「全角」で表記します。", 46 | line: 1, 47 | column: 1 48 | } 49 | ] 50 | }, 51 | { 52 | text: "オヤツは300円まで", 53 | output: "オヤツは300円まで", 54 | errors: [ 55 | { 56 | message: "カタカナは「全角」で表記します。", 57 | line: 1, 58 | column: 1 59 | } 60 | ] 61 | } 62 | ] 63 | }); 64 | -------------------------------------------------------------------------------- /test/2.1.6-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/2.1.6"; 5 | var tester = new TextLintTester(); 6 | tester.run("2.1.6.カタカナの長音", rule, { 7 | valid: [ 8 | "フィルターをかける", // フィルター 9 | "フィルタリングする" // フィルター 10 | ], 11 | invalid: [ 12 | { 13 | text: "フィルタをかける", 14 | output: "フィルターをかける", 15 | errors: [{ message: "フィルタをか => フィルターをか" }] 16 | }, 17 | { 18 | text: "フィルタ", 19 | output: "フィルター", 20 | errors: [{ message: "フィルタ => フィルター" }] 21 | }, 22 | { 23 | text: "フィルタ。", 24 | output: "フィルター。", 25 | errors: [{ message: "フィルタ。 => フィルター。" }] 26 | }, 27 | { 28 | text: "フィルタ、", 29 | output: "フィルター、", 30 | errors: [{ message: "フィルタ、 => フィルター、" }] 31 | } 32 | ] 33 | }); 34 | -------------------------------------------------------------------------------- /test/2.1.8-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/2.1.8"; 5 | var tester = new TextLintTester(); 6 | tester.run("2.1.8.算用数字", rule, { 7 | valid: [ 8 | "1,000円", 9 | "100 + 100 = 200", 10 | "*200*円" // Strではない 11 | ], 12 | invalid: [ 13 | { 14 | text: "200円はダメ", 15 | output: "200円はダメ", 16 | errors: [ 17 | { 18 | message: "算用数字は「半角」で表記します。", 19 | line: 1, 20 | column: 1 21 | } 22 | ] 23 | }, 24 | { 25 | text: "おやつは300円まで", 26 | output: "おやつは300円まで", 27 | errors: [ 28 | { 29 | message: "算用数字は「半角」で表記します。", 30 | line: 1, 31 | column: 5 32 | } 33 | ] 34 | } 35 | ] 36 | }); 37 | -------------------------------------------------------------------------------- /test/2.1.9-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/2.1.9"; 5 | var tester = new TextLintTester(); 6 | tester.run("2.1.9.アルファベット", rule, { 7 | valid: [ 8 | "ABC", 9 | "これはABCの歌", 10 | "_ABC_" // Strではない 11 | ], 12 | invalid: [ 13 | { 14 | text: "ABC", 15 | ouput: "ABC", 16 | errors: [ 17 | { 18 | message: "アルファベットは「半角」で表記します。", 19 | line: 1, 20 | column: 1 21 | } 22 | ] 23 | }, 24 | { 25 | text: "これはABC全角", 26 | output: "これはABC全角", 27 | errors: [ 28 | { 29 | message: "アルファベットは「半角」で表記します。", 30 | line: 1, 31 | column: 4 32 | } 33 | ] 34 | } 35 | ] 36 | }); 37 | -------------------------------------------------------------------------------- /test/2.2.1-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/2.2.1"; 5 | 6 | const tester = new TextLintTester(); 7 | tester.run("2.2.1.ひらがなと漢字の使い分け", rule, { 8 | valid: ["問題は以下のとおりです"], 9 | invalid: [ 10 | { 11 | text: "問題は以下の通り", 12 | output: "問題は以下のとおり", 13 | errors: [ 14 | { 15 | message: `以下の通り => 以下のとおり`, 16 | index: 3 17 | } 18 | ] 19 | } 20 | ] 21 | }); 22 | -------------------------------------------------------------------------------- /test/2.2.2-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/2.2.2"; 5 | var tester = new TextLintTester(); 6 | tester.run("2.2.2.算用数字と漢数字の使い分け", rule, { 7 | valid: ["1億2805 万人", "3つのボタン", "第3回大会", "第3章", "20回", "第3節", "4種類", "11種類"], 8 | invalid: [ 9 | { 10 | text: "第三章", 11 | output: "第3章", 12 | errors: [ 13 | { 14 | message: `第三章 => 第3章 15 | 数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。`, 16 | line: 1, 17 | column: 1 18 | } 19 | ] 20 | }, 21 | { 22 | text: "二十回", 23 | output: "20回", 24 | errors: [ 25 | { 26 | message: `二十回 => 20回 27 | 数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。`, 28 | line: 1, 29 | column: 1 30 | } 31 | ] 32 | }, 33 | { 34 | text: "一億百十万人", 35 | output: "1億百十万人", 36 | errors: [ 37 | { 38 | message: `一億 => 1億 39 | 数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。`, 40 | line: 1, 41 | column: 1 42 | } 43 | ] 44 | }, 45 | { 46 | text: "百八つのボタン", 47 | output: "108つのボタン", 48 | errors: [ 49 | { 50 | message: `百八つ => 108つ 51 | 数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。` 52 | } 53 | ] 54 | }, 55 | { 56 | text: "第三回大会", 57 | output: "第3回大会", 58 | errors: [ 59 | { 60 | message: `三回 => 3回 61 | 数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。` 62 | } 63 | ] 64 | }, 65 | { 66 | text: "サンフランシスコマラソン第三回大会", 67 | output: "サンフランシスコマラソン第3回大会", 68 | errors: [ 69 | { 70 | message: `三回 => 3回 71 | 数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。`, 72 | line: 1, 73 | column: 14 74 | } 75 | ] 76 | } 77 | ] 78 | }); 79 | 80 | tester.run("2.2.2.算用数字と漢数字の使い分け", rule, { 81 | valid: [ 82 | "世界一", 83 | "世界1", // 大文字 84 | "世界2位", // 数えられる数字 85 | "一時的", 86 | "一部分", 87 | "第三者", 88 | "一種の", 89 | "11種の鉱物", // <= 一種には変換されない 90 | "一部の", 91 | "一番に", 92 | "数百倍", 93 | "2倍", 94 | "二次関数", 95 | "四捨五入", 96 | "四角い", 97 | "五大陸", 98 | "数十億", 99 | "何十万", 100 | "しばしば数十万行以上に", 101 | "二つ返事でOKした", 102 | "三つ子の魂百まで", 103 | "一つひとつ確かめる", 104 | "ミシュラン二つ星", 105 | "三つ編にする", 106 | "四つ葉のクローバー", 107 | "四つ橋線", 108 | "二つと無い宝石", 109 | "二つとない宝石", 110 | "二つに一つしかない", 111 | "ただ一つの弱点", 112 | "唯一つの欠点", 113 | "女手一つで育てた", 114 | "男手一つで育てた", 115 | "人を呪わば穴二つ", 116 | "瓜二つの姉妹", 117 | "馬鹿の一つ覚えだ" 118 | ], 119 | invalid: [ 120 | { 121 | text: "これは世界1", 122 | output: "これは世界一", 123 | errors: [ 124 | { 125 | message: `世界1 => 世界一 126 | 慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。` 127 | } 128 | ] 129 | }, 130 | { 131 | text: "1部の文章", 132 | output: "一部の文章", 133 | errors: [ 134 | { 135 | message: `1部の => 一部の 136 | 慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。` 137 | } 138 | ] 139 | }, 140 | { 141 | text: "これは花の1種です", 142 | output: "これは花の一種です", 143 | errors: [ 144 | { 145 | message: `の1種 => の一種 146 | 慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。` 147 | } 148 | ] 149 | }, 150 | { 151 | text: "朝1番に", 152 | output: "朝一番に", 153 | errors: [ 154 | { 155 | message: `1番に => 一番に 156 | 慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。` 157 | } 158 | ] 159 | }, 160 | { 161 | text: "数100倍", 162 | output: "数百倍", 163 | errors: [ 164 | { 165 | message: `数100倍 => 数百倍 166 | 慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。` 167 | } 168 | ] 169 | }, 170 | { 171 | text: "数10億", 172 | output: "数十億", 173 | errors: [ 174 | { 175 | message: `数10億 => 数十億 176 | 慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。`, 177 | line: 1, 178 | column: 1 179 | } 180 | ] 181 | }, 182 | { 183 | text: "しばしば数10万行以上に", 184 | output: "しばしば数十万行以上に", 185 | errors: [ 186 | { 187 | message: `数10万 => 数十万 188 | 慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。`, 189 | line: 1, 190 | column: 5 191 | } 192 | ] 193 | }, 194 | { 195 | text: "数10年に一度の奇跡", 196 | output: "数十年に一度の奇跡", 197 | errors: [ 198 | { 199 | message: `数10年 => 数十年 200 | 慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。`, 201 | line: 1, 202 | column: 1 203 | } 204 | ] 205 | } 206 | ] 207 | }); 208 | -------------------------------------------------------------------------------- /test/2.2.3-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/2.2.3"; 5 | 6 | const tester = new TextLintTester(); 7 | tester.run("2.2.3. 一部の助数詞の表記", rule, { 8 | valid: ["3か月未満"], 9 | invalid: [ 10 | { 11 | text: "3ヶ月未満", 12 | output: "3か月未満", 13 | errors: [ 14 | { 15 | message: `3ヶ月 => 3か月`, 16 | index: 0 17 | } 18 | ] 19 | } 20 | ] 21 | }); 22 | -------------------------------------------------------------------------------- /test/3.1.1-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/3.1.1"; 5 | var tester = new TextLintTester(); 6 | tester.run("3.1.1. 全角文字と半角文字の間", rule, { 7 | valid: [ 8 | "JTF標準", 9 | "This is a pen.", 10 | "1. `./*.*`にマッチするファイルを取得 = Readable Stream", 11 | `[CONTRIBUTING.md](./CONTRIBUTING.md)に、書籍で扱うべきプラグインアーキテクチャのProposalの書き方や 12 | Pull Request、コミットのやりかたなどが書かれています。` 13 | ], 14 | invalid: [ 15 | { 16 | text: "JTF 標準", 17 | output: "JTF標準", 18 | errors: [ 19 | { 20 | message: "原則として、全角文字と半角文字の間にスペースを入れません。", 21 | column: 4 22 | } 23 | ] 24 | }, 25 | { 26 | text: "これは Unicode", 27 | output: "これはUnicode", 28 | errors: [{ message: "原則として、全角文字と半角文字の間にスペースを入れません。" }] 29 | }, 30 | { 31 | text: "これは Unicode", 32 | output: "これはUnicode", 33 | errors: [{ message: "原則として、全角文字と半角文字の間にスペースを入れません。" }] 34 | } 35 | ] 36 | }); 37 | -------------------------------------------------------------------------------- /test/3.1.2-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/3.1.2"; 5 | var tester = new TextLintTester(); 6 | tester.run("3.1.2. 全角文字どうし", rule, { 7 | valid: [ 8 | "これは正解", 9 | "This is 大丈夫", 10 | "This is a pen.", 11 | "ユーザー インターフェース" //カタカナは例外 12 | ], 13 | invalid: [ 14 | { 15 | text: "これは ダメ", 16 | output: "これはダメ", 17 | errors: [ 18 | { 19 | message: "原則として、全角文字どうしの間にスペースを入れません。", 20 | column: 4 21 | } 22 | ] 23 | }, 24 | { 25 | text: "これは どういうこと?", 26 | output: "これはどういうこと?", 27 | errors: [ 28 | { 29 | message: "原則として、全角文字どうしの間にスペースを入れません。", 30 | column: 4 31 | } 32 | ] 33 | } 34 | ] 35 | }); 36 | -------------------------------------------------------------------------------- /test/3.2-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/3.2"; 5 | var tester = new TextLintTester(); 6 | tester.run("3.2.カタカナ語間のスペースの有無", rule, { 7 | valid: [ 8 | "カタカナ・カタカナ", 9 | "カタカナ カタカナ", 10 | "カタカナ、カタカナ", // 例外としてしょうがない気がする 11 | "あいう えお", 12 | "インターフェース ブラウザ" 13 | ], 14 | invalid: [ 15 | { 16 | text: "カタカナ カタカナ", 17 | errors: [ 18 | { 19 | message: "カタカナ語間は中黒(・)または半角スペースを用いてカタカナ語を区切ります", 20 | column: 5 21 | } 22 | ] 23 | } 24 | ] 25 | }); 26 | -------------------------------------------------------------------------------- /test/3.3-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/3.3"; 5 | var tester = new TextLintTester(); 6 | tester.run("3.3.かっこ類と隣接する文字の間のスペースの有無", rule, { 7 | valid: [ 8 | "「良い」", 9 | "テスト[文章]です", 10 | "これは (test) です", 11 | ` 12 | 実装をみてもらうと分かりますが、JavaScriptの\`prototype\`の仕組みをそのまま利用しています。 13 | そのため、特別な実装は必要なく 14 | 「拡張する時は\`calculator.prototype\`の代わりに\`calculator.fn\`を拡張してください」 15 | というルールがあるだけとも言えます。 16 | `, 17 | { 18 | text: "Page(s)", 19 | options: { 20 | requireOutsideHalfParentheses: true 21 | } 22 | } 23 | ], 24 | invalid: [ 25 | { 26 | text: "「 ダメ」", 27 | output: "「ダメ」", 28 | errors: [{ message: "かっこの外側、内側ともにスペースを入れません。" }] 29 | }, 30 | { 31 | text: "これは 「ダメ」です", 32 | output: "これは「ダメ」です", 33 | errors: [ 34 | { 35 | message: "かっこの外側、内側ともにスペースを入れません。", 36 | line: 1, 37 | column: 4 38 | } 39 | ] 40 | }, 41 | { 42 | text: "これは (ダメ) です", 43 | output: "これは(ダメ)です", 44 | errors: [ 45 | { 46 | message: "かっこの外側、内側ともにスペースを入れません。", 47 | line: 1, 48 | column: 4 49 | }, 50 | { 51 | message: "かっこの外側、内側ともにスペースを入れません。", 52 | line: 1, 53 | column: 9 54 | } 55 | ] 56 | }, 57 | { 58 | text: "これはダメ (test) です", 59 | output: "これはダメ(test)です", 60 | options: { 61 | allowOutsideHalfParentheses: false 62 | }, 63 | errors: [ 64 | { 65 | message: "かっこの外側、内側ともにスペースを入れません。", 66 | line: 1, 67 | column: 6 68 | }, 69 | { 70 | message: "かっこの外側、内側ともにスペースを入れません。", 71 | line: 1, 72 | column: 13 73 | } 74 | ] 75 | }, 76 | { 77 | text: "これはダメ(test)です", 78 | output: "これはダメ (test) です", 79 | options: { 80 | requireOutsideHalfParentheses: true 81 | }, 82 | errors: [ 83 | { 84 | message: "半角かっこの外側に半角スペースが必要です。", 85 | line: 1, 86 | column: 6 87 | }, 88 | { 89 | message: "半角かっこの外側に半角スペースが必要です。", 90 | line: 1, 91 | column: 11 92 | } 93 | ] 94 | }, 95 | { 96 | text: `TEST 97 | 98 | - TODO 99 | 100 | これは 「ダメ」です 101 | `, 102 | output: `TEST 103 | 104 | - TODO 105 | 106 | これは「ダメ」です 107 | `, 108 | errors: [ 109 | { 110 | message: "かっこの外側、内側ともにスペースを入れません。", 111 | line: 5, 112 | column: 4 113 | } 114 | ] 115 | } 116 | ] 117 | }); 118 | -------------------------------------------------------------------------------- /test/4.1.1-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.1.1"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.1.1.句点(。)", rule, { 7 | valid: ["A 氏は「5 月に新製品を発売します」と述べました。", "従業員は約 30,000 人です(関連企業を含みます)。"], 8 | invalid: [ 9 | { 10 | text: "A氏は「5月に新製品を発売します。」と述べました。", 11 | output: "A氏は「5月に新製品を発売します」と述べました。", 12 | errors: [ 13 | { 14 | message: "文中にかぎかっこが入る場合は、閉じかっこの前に句点を打ちません。", 15 | column: 17 16 | } 17 | ] 18 | }, 19 | { 20 | text: "従業員は約30,000人です(関連企業を含みます。)", 21 | output: "従業員は約30,000人です(関連企業を含みます)", 22 | errors: [ 23 | { 24 | message: "文中にかぎかっこが入る場合は、閉じかっこの前に句点を打ちません。", 25 | line: 1, 26 | column: 25 27 | } 28 | ] 29 | } 30 | ] 31 | }); 32 | -------------------------------------------------------------------------------- /test/4.1.3-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.1.3"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.1.3. ピリオド(.)、カンマ(,)", rule, { 7 | valid: [ 8 | "This is a pen.", 9 | "1. テスト", // 箇条書き 10 | "1,101" // 小数点 11 | ], 12 | invalid: [ 13 | { 14 | text: "和文の終わりがピリオド.", 15 | errors: [ 16 | { 17 | message: "和文の句読点としてはピリオドを使用しません。", 18 | column: 12 19 | } 20 | ] 21 | } 22 | ] 23 | }); 24 | -------------------------------------------------------------------------------- /test/4.2.1-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.2.1"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.2.1.感嘆符(!)", rule, { 7 | valid: [ 8 | "【原文】Just plug it in, and coffee is ready in three minutes!", 9 | "【訳文】プラグを差し込めば、3 分でコーヒーができます。", 10 | "警告!", 11 | "驚きの速さ! これが新製品のキャッチコピーでした。" // 文末感嘆符+全角スペース 12 | ], 13 | invalid: [ 14 | { 15 | text: "半角感嘆符!", 16 | output: "半角感嘆符!", 17 | errors: [ 18 | { 19 | message: "感嘆符(!)を使用する場合は「全角」で表記します。", 20 | column: 6 21 | } 22 | ] 23 | }, 24 | { 25 | text: "驚きの速さ! これが新製品のキャッチコピーでした。半角 ", 26 | output: "驚きの速さ! これが新製品のキャッチコピーでした。半角 ", 27 | errors: [ 28 | { 29 | message: "文末に感嘆符を使用し、後に別の文が続く場合は、直後に全角スペースを挿入します。", 30 | column: 7 31 | } 32 | ] 33 | } 34 | ] 35 | }); 36 | -------------------------------------------------------------------------------- /test/4.2.2-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.2.2"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.2.2.疑問符(?)", rule, { 7 | valid: [ 8 | "【原文】Does the reader understand the document?", 9 | "【訳文】読者は文書の内容を理解しているでしょうか。", 10 | "オプションを変更しますか?", 11 | "A 社の成功の秘密とは? この本ではそれをご紹介します。", 12 | "どう操作したらよいのか?というユーザーの疑問に答えます。" 13 | ], 14 | invalid: [ 15 | { 16 | text: "半角疑問符?", 17 | output: "半角疑問符?", 18 | errors: [ 19 | { 20 | message: "疑問符(?)を使用する場合は「全角」で表記します。", 21 | column: 6 22 | } 23 | ] 24 | }, 25 | { 26 | text: "驚きの速さ!? これが新製品のキャッチコピーでした? これは問題なし", 27 | output: "驚きの速さ!? これが新製品のキャッチコピーでした? これは問題なし", 28 | errors: [ 29 | { 30 | message: "文末に疑問符を使用し、後に別の文が続く場合は、直後に全角スペースを挿入します。", 31 | column: 8 32 | } 33 | ] 34 | } 35 | ] 36 | }); 37 | -------------------------------------------------------------------------------- /test/4.2.4-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.2.4"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.2.4.中黒(・)", rule, { 7 | valid: ["小・中学校", "パーソナル・コンピューター"], 8 | invalid: [ 9 | { 10 | text: "小・中学校", 11 | errors: [ 12 | { 13 | message: 14 | "カタカナ複合語を区切る場合または同格の語句を並列する場合には全角の中黒(・)を使用します。", 15 | column: 2 16 | } 17 | ] 18 | } 19 | ] 20 | }); 21 | -------------------------------------------------------------------------------- /test/4.2.5-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.2.5"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.2.5.波線(~)", rule, { 7 | valid: ["18〜22 歳まで", "これ〜から"], 8 | invalid: [ 9 | { 10 | text: "18~22歳まで", 11 | output: "18〜22歳まで", 12 | errors: [ 13 | { 14 | message: "数値の範囲を示す場合には全角の〜を使用します。", 15 | column: 3 16 | } 17 | ] 18 | } 19 | ] 20 | }); 21 | -------------------------------------------------------------------------------- /test/4.2.6-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.2.6"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.2.6.ハイフン(-)", rule, { 7 | valid: [ 8 | "千代田区一番町 1-1-1", 9 | "03-5555-xxxxx", 10 | "電話番号は090-1234-5678です", 11 | "Allen Wirfs-Brock(アレン・ワーフスブラック)", 12 | "サイン関数は-1から1の範囲の値をとる" 13 | ], 14 | invalid: [ 15 | { 16 | text: "渋谷-東京", 17 | errors: [ 18 | { 19 | message: 20 | "原則として和文ではハイフン(-)を使用しません。\n例外は、住所や電話番号の区切りに使う場合です。", 21 | column: 3 22 | } 23 | ] 24 | }, 25 | { 26 | text: "A市-B市", 27 | errors: [ 28 | { 29 | message: 30 | "原則として和文ではハイフン(-)を使用しません。\n例外は、住所や電話番号の区切りに使う場合です。", 31 | column: 3 32 | } 33 | ] 34 | } 35 | ] 36 | }); 37 | -------------------------------------------------------------------------------- /test/4.2.7-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.2.7"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.2.7.コロン(:)", rule, { 7 | valid: [ 8 | "日時:3月16日午後 1 時", 9 | "例:〜", 10 | "1: これはペンです", // [^和文]: のパターン, 11 | "`this::method`" 12 | ], 13 | invalid: [ 14 | { 15 | text: "例:〜", 16 | output: "例:〜", 17 | errors: [ 18 | { 19 | message: "コロン(:)を使用する場合は「全角」で表記します。", 20 | column: 2 21 | } 22 | ] 23 | } 24 | ] 25 | }); 26 | -------------------------------------------------------------------------------- /test/4.2.8-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.2.8"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.2.8.セミコロン(;)", rule, { 7 | valid: [ 8 | "this; that is this.", 9 | "This; 和文", 10 | "1: これはペンです" // [^和文]: のパターン 11 | ], 12 | invalid: [ 13 | { 14 | text: "和文;", 15 | errors: [ 16 | { 17 | message: "原則として和文ではセミコロン(;)を使用しません。", 18 | column: 3 19 | } 20 | ] 21 | }, 22 | { 23 | text: "和文;This is", 24 | errors: [ 25 | { 26 | message: "原則として和文ではセミコロン(;)を使用しません。", 27 | column: 3 28 | } 29 | ] 30 | } 31 | ] 32 | }); 33 | -------------------------------------------------------------------------------- /test/4.2.9-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.2.9"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.2.9.ダッシュ(-)", rule, { 7 | valid: ["this ― is not problem"], 8 | invalid: [ 9 | { 10 | text: "和文\u2012", // u2012 11 | errors: [ 12 | { 13 | message: "原則として和文ではダッシュ(―)を使用しません。", 14 | column: 3 15 | } 16 | ] 17 | }, 18 | { 19 | text: "和文\u2013", 20 | errors: [ 21 | { 22 | message: "原則として和文ではダッシュ(―)を使用しません。", 23 | column: 3 24 | } 25 | ] 26 | }, 27 | { 28 | text: "和文\u2014", 29 | errors: [ 30 | { 31 | message: "原則として和文ではダッシュ(―)を使用しません。", 32 | column: 3 33 | } 34 | ] 35 | }, 36 | { 37 | text: "和文\u2015", 38 | errors: [ 39 | { 40 | message: "原則として和文ではダッシュ(―)を使用しません。", 41 | column: 3 42 | } 43 | ] 44 | } 45 | ] 46 | }); 47 | -------------------------------------------------------------------------------- /test/4.3.1-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.3.1.js"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.3.1.丸かっこ()", rule, { 7 | valid: [ 8 | "クォーク(物質の素粒子)", 9 | "(物質の素粒子)クォーク", 10 | "(物質の素粒子)", 11 | "(npm 2.x以上をインストールしている必要があります)", 12 | "(必要バージョン: 2.x)", 13 | // 英語のみの半角括弧は許可 14 | // https://github.com/textlint-ja/textlint-rule-preset-JTF-style/issues/79 15 | "これは (English text in half-width parens) です。", 16 | "これは(English text in half-width parens)です。" 17 | ], 18 | invalid: [ 19 | { 20 | // 半角かっこ 21 | text: "クォーク(物質の素粒子)", 22 | output: "クォーク(物質の素粒子)", 23 | errors: [ 24 | { 25 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 26 | column: 5 27 | }, 28 | { 29 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 30 | column: 12 31 | } 32 | ] 33 | }, 34 | { 35 | // 半角かっこ 36 | text: "(物質の素粒子)クォーク", 37 | output: "(物質の素粒子)クォーク", 38 | errors: [ 39 | { 40 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 41 | column: 1 42 | }, 43 | { 44 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 45 | column: 8 46 | } 47 | ] 48 | }, 49 | { 50 | // 半角かっこ 51 | text: "(物質の素粒子)", 52 | output: "(物質の素粒子)", 53 | errors: [ 54 | { 55 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 56 | column: 1 57 | }, 58 | { 59 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 60 | column: 8 61 | } 62 | ] 63 | }, 64 | { 65 | // 半角かっこ 66 | text: "(npm 2.x以上をインストールしている必要があります)", 67 | output: "(npm 2.x以上をインストールしている必要があります)", 68 | errors: [ 69 | { 70 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 71 | column: 1 72 | }, 73 | { 74 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 75 | column: 29 76 | } 77 | ] 78 | }, 79 | { 80 | // 半角かっこ 81 | text: "(必要バージョン: 2.x)", 82 | output: "(必要バージョン: 2.x)", 83 | errors: [ 84 | { 85 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 86 | column: 1 87 | }, 88 | { 89 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 90 | column: 14 91 | } 92 | ] 93 | }, 94 | { 95 | // 半角かっこ 96 | text: "例)テスト", 97 | output: "例)テスト", 98 | errors: [ 99 | { 100 | message: "半角のかっこ()が使用されています。全角のかっこ()を使用してください。", 101 | column: 2 102 | } 103 | ] 104 | } 105 | ] 106 | }); 107 | -------------------------------------------------------------------------------- /test/4.3.2-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.3.2"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.3.2.大かっこ[]", rule, { 7 | valid: ["[ファイル]メニュー", "- [ ] TODO", "[link](http://example.com)"], 8 | invalid: [ 9 | { 10 | // 半角かっこ Markdown的に意味を持つので片方ずつ 11 | text: "半角[かっこ", 12 | output: "半角[かっこ", 13 | errors: [ 14 | { 15 | message: "半角の大かっこ[]が使用されています。全角のかっこ[]を使用してください。", 16 | column: 3 17 | } 18 | ] 19 | }, 20 | { 21 | // 半角かっこ Markdown的に意味を持つので片方ずつ 22 | text: "半角]かっこ", 23 | output: "半角]かっこ", 24 | errors: [ 25 | { 26 | message: "半角の大かっこ[]が使用されています。全角のかっこ[]を使用してください。", 27 | column: 3 28 | } 29 | ] 30 | } 31 | ] 32 | }); 33 | -------------------------------------------------------------------------------- /test/4.3.3-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.3.3"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.3.3.かぎかっこ「」", rule, { 7 | valid: [ 8 | "「×××」を参照してください。", 9 | "「これは`code`を含んだ文章」を参照してください。", 10 | `これは複数行の例 11 | 12 | 「textlint」向けのルール 13 | `, 14 | "- [ ] 「かっこのあるリスト」" 15 | ], 16 | invalid: [ 17 | { 18 | text: "「対となるかっこがない文章です。", 19 | errors: [ 20 | { 21 | message: "「の対となる」が見つかりません。「」", 22 | column: 1 23 | } 24 | ] 25 | }, 26 | { 27 | text: `「パラグラフをまたぐような 28 | 29 | 文章」は認められない。 30 | `, 31 | errors: [ 32 | { 33 | message: "「の対となる」が見つかりません。「」", 34 | column: 1 35 | }, 36 | { 37 | message: "」の対となる「が見つかりません。「」", 38 | column: 3 39 | } 40 | ] 41 | }, 42 | { 43 | // ListItem -> Paragraphなので 44 | text: "- 「これはプラグイン", 45 | errors: [ 46 | { 47 | message: "「の対となる」が見つかりません。「」", 48 | column: 3 49 | } 50 | ] 51 | } 52 | ] 53 | }); 54 | -------------------------------------------------------------------------------- /test/4.3.4-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.3.4"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.3.4.二重かぎかっこ『』", rule, { 7 | valid: [ 8 | "彼は『『×××』を参照してください』と言った。", 9 | "彼は『『`×××`』を**参照**してください』と言った。", 10 | `これは複数行の例 11 | 12 | 彼は『『×××』を参照してください』と言った。 13 | `, 14 | "- 彼は「『×××』を参照してください」と言った。", 15 | "『基礎日本語辞典』" 16 | ], 17 | invalid: [ 18 | { 19 | text: "『対となるかっこがない文章です。", 20 | errors: [ 21 | { 22 | message: "『の対となる』が見つかりません。『』", 23 | column: 1 24 | } 25 | ] 26 | }, 27 | { 28 | text: `『パラグラフをまたぐような 29 | 30 | 文章』は認められない。 31 | `, 32 | errors: [ 33 | { 34 | message: "『の対となる』が見つかりません。『』", 35 | column: 1 36 | }, 37 | { 38 | message: "』の対となる『が見つかりません。『』", 39 | column: 3 40 | } 41 | ] 42 | }, 43 | { 44 | // ListItem -> Paragraphなので 45 | text: "- 『これはプラグイン", 46 | errors: [ 47 | { 48 | message: "『の対となる』が見つかりません。『』", 49 | column: 3 50 | } 51 | ] 52 | }, 53 | { 54 | text: "開くかっこがない文章です』", 55 | errors: [ 56 | { 57 | message: "』の対となる『が見つかりません。『』", 58 | column: 13 59 | } 60 | ] 61 | }, 62 | { 63 | text: "『多重で『閉じる』かっこが足りない文章です", 64 | errors: [ 65 | { 66 | message: "『の対となる』が見つかりません。『』", 67 | column: 1 68 | } 69 | ] 70 | }, 71 | { 72 | text: "多重で『開く』かっこが足りない文章です』", 73 | errors: [ 74 | { 75 | message: "』の対となる『が見つかりません。『』", 76 | column: 20 77 | } 78 | ] 79 | }, 80 | { 81 | text: "』開くかっこが『複数』足りない文章です』", 82 | errors: [ 83 | { 84 | message: "』の対となる『が見つかりません。『』", 85 | column: 1 86 | }, 87 | { 88 | message: "』の対となる『が見つかりません。『』", 89 | column: 20 90 | } 91 | ] 92 | } 93 | ] 94 | }); 95 | -------------------------------------------------------------------------------- /test/4.3.5-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.3.5"; 5 | var tester = new TextLintTester(); 6 | tester.run('4.3.5.二重引用符""', rule, { 7 | valid: [ 8 | '彼は"×××"を参照してくださいと言った。', 9 | '彼は"`×××`"を参照してくださいと言った。', 10 | '彼は"**×××**"を参照してくださいと言った。', 11 | `これは複数行の例 12 | 13 | 彼は"×××"を参照してくださいと言った。 14 | `, 15 | '- 彼は"×××"を参照してくださいと言った。', 16 | 'いわゆる"スマート"な都市', 17 | '彼は"xxx" "`a=1;`"を参照してくださいと言った。', 18 | '彼は"xxx" "`a="x;`"を参照してくださいと言った。コード内の不一定は"無視"されます。' 19 | ], 20 | invalid: [ 21 | { 22 | text: '"対となる二重引用符がない文章です。', 23 | errors: [ 24 | { 25 | message: '"の対となる"が見つかりません。""', 26 | column: 1 27 | } 28 | ] 29 | }, 30 | { 31 | text: `"パラグラフをまたぐような 32 | 33 | 文章"は認められない。`, 34 | errors: [ 35 | { 36 | message: '"の対となる"が見つかりません。""', 37 | column: 1 38 | }, 39 | { 40 | message: '"の対となる"が見つかりません。""', 41 | column: 3 42 | } 43 | ] 44 | }, 45 | { 46 | // ListItem -> Paragraphなので 47 | text: '- "これはプラグイン', 48 | errors: [ 49 | { 50 | message: '"の対となる"が見つかりません。""', 51 | column: 3 52 | } 53 | ] 54 | }, 55 | { 56 | text: '彼は"xxx" "`a="x";`" "yyy を参照してくださいと言った。', 57 | errors: [ 58 | { 59 | message: '"の対となる"が見つかりません。""', 60 | column: 20 61 | } 62 | ] 63 | } 64 | ] 65 | }); 66 | -------------------------------------------------------------------------------- /test/4.3.6-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.3.6"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.3.6.中かっこ{ }", rule, { 7 | valid: ["彼は{×××}を参照してくださいと言った。", "- 彼は{×××}を参照してくださいと言った。"], 8 | invalid: [ 9 | { 10 | text: "{対となるがない中かっこがない文章です。", 11 | errors: [ 12 | { 13 | message: "{の対となる}が見つかりません。{}", 14 | column: 1 15 | } 16 | ] 17 | }, 18 | { 19 | text: `{パラグラフをまたぐような 20 | 21 | 文章}は認められない。`, 22 | errors: [ 23 | { 24 | message: "{の対となる}が見つかりません。{}", 25 | column: 1 26 | }, 27 | { 28 | message: "}の対となる{が見つかりません。{}", 29 | column: 3 30 | } 31 | ] 32 | }, 33 | { 34 | // ListItem -> Paragraphなので 35 | text: "- {これはプラグイン", 36 | errors: [ 37 | { 38 | message: "{の対となる}が見つかりません。{}", 39 | column: 3 40 | } 41 | ] 42 | } 43 | ] 44 | }); 45 | -------------------------------------------------------------------------------- /test/4.3.7-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.3.7"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.3.7.山かっこ<>", rule, { 7 | valid: [ 8 | "彼は<×××>を参照してくださいと言った。", 9 | "彼は<`×××`>を参照してくださいと言った。", 10 | "- 彼は<×××>を参照してくださいと言った。" 11 | ], 12 | invalid: [ 13 | { 14 | text: "<対となるがない中かっこがない文章です。", 15 | errors: [ 16 | { 17 | message: "<の対となる>が見つかりません。<>", 18 | column: 1 19 | } 20 | ] 21 | }, 22 | { 23 | text: `<パラグラフをまたぐような 24 | 25 | 文章>は認められない。`, 26 | errors: [ 27 | { 28 | message: "<の対となる>が見つかりません。<>", 29 | column: 1 30 | }, 31 | { 32 | message: ">の対となる<が見つかりません。<>", 33 | column: 3 34 | } 35 | ] 36 | }, 37 | { 38 | // ListItem -> Paragraphなので 39 | text: "- <これはプラグイン", 40 | errors: [ 41 | { 42 | message: "<の対となる>が見つかりません。<>", 43 | column: 3 44 | } 45 | ] 46 | } 47 | ] 48 | }); 49 | -------------------------------------------------------------------------------- /test/4.3.8-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import TextLintTester from "textlint-tester"; 4 | import rule from "../src/4.3.8"; 5 | var tester = new TextLintTester(); 6 | tester.run("4.3.8.一重引用符''", rule, { 7 | valid: [ 8 | "彼は'×××'を参照してくださいと言った。", 9 | "- 彼は'×××'を参照してくださいと言った。", 10 | "Animal's bug.", 11 | `[ES5, ES6, ES2016, ES.Next: What's going on with JavaScript versioning?](http://benmccormick.org/2015/09/14/es5-es6-es2016-es-next-whats-going-on-with-javascript-versioning/ "ES5, ES6, ES2016, ES.Next: What's going on with JavaScript versioning?")` 12 | ], 13 | invalid: [] 14 | }); 15 | -------------------------------------------------------------------------------- /test/fixer-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import assert from "node:assert"; 4 | import preset from "../src/index"; 5 | import { TextLintCore } from "@textlint/legacy-textlint-core"; 6 | import path from "node:path"; 7 | import fs from "node:fs"; 8 | 9 | describe("fixer-test", function () { 10 | it("should convert expected", function () { 11 | const expected = fs.readFileSync(path.join(__dirname, "/fixtures/output.md"), "utf-8"); 12 | const textlint = new TextLintCore(); 13 | // all true 14 | textlint.setupRules(preset.rules); 15 | return textlint.fixFile(path.join(__dirname, "/fixtures/input.md")).then((result) => { 16 | assert.strictEqual(result.remainingMessages.length, 0); 17 | const inputs = result.output.split("\n"); 18 | const outputs = expected.split("\n"); 19 | for (var i = 0; i < inputs.length; i++) { 20 | const input = inputs[i]; 21 | const output = outputs[i]; 22 | assert.strictEqual( 23 | input, 24 | output, 25 | `mismatch at line ${i} 26 | 27 | at ${path.join(__dirname, "/fixtures/input.md")}:${i} 28 | at ${path.join(__dirname, "/fixtures/output.md")}:${i} 29 | ` 30 | ); 31 | } 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/fixtures/input.md: -------------------------------------------------------------------------------- 1 | # 見出し。 2 | 3 | ### 見出し。 4 | 5 | ### 見出し。 6 | test 7 | 8 | これは,見本となる例です. 9 | 10 | 785,105 11 | 12 | 785.105 13 | 14 | 0,01 15 | 16 | 0,1 17 | 18 | これは10個あるうちの0,1分 19 | 20 | オヤツは300円まで 21 | 22 | フィルタをかける 23 | 24 | フィルタ 25 | 26 | フィルタ。 27 | 28 | フィルタ、 29 | 30 | 200円はダメ 31 | 32 | おやつは300円まで 33 | 34 | これはABC全角 35 | 36 | 問題は以下の通り 37 | 38 | 第三章 39 | 40 | 二十回 41 | 42 | 一億百十万人 43 | 44 | 百八つのボタン 45 | 46 | 第三回大会 47 | 48 | サンフランシスコマラソン第三回大会 49 | 50 | これは世界1 51 | 52 | 1部の文章 53 | 54 | これは花の1種です 55 | 56 | 朝1番に 57 | 58 | 数100倍 59 | 60 | 数10億 61 | 62 | しばしば数10万行以上に 63 | 64 | 数10年に一度の奇跡 65 | 66 | 3ヶ月未満 67 | 68 | JTF 標準 69 | 70 | これは Unicode 71 | 72 | これは Unicode 73 | 74 | これは ダメ 75 | 76 | これは どういうこと? 77 | 78 | 「 ダメ」 79 | 80 | これは 「ダメ」です 81 | 82 | これは (ダメ) です 83 | 84 | A氏は「5月に新製品を発売します。」と述べました。 85 | 86 | 従業員は約30,000人です(関連企業を含みます。) 87 | 88 | 半角感嘆符! 89 | 90 | 驚きの速さ! これが新製品のキャッチコピーでした。半角  91 | 92 | 半角疑問符? 93 | 94 | 驚きの速さ!? これが新製品のキャッチコピーでした? これは問題なし 95 | 96 | 18~22歳まで 97 | 98 | 例:〜 99 | 100 | クォーク(物質の素粒子) 101 | 102 | (物質の素粒子)クォーク 103 | 104 | (物質の素粒子) 105 | 106 | (npm 2.x以上をインストールしている必要があります) 107 | 108 | (必要バージョン: 2.x) 109 | 110 | 例)テスト 111 | 112 | 半角[かっこ 113 | 114 | 半角]かっこ -------------------------------------------------------------------------------- /test/fixtures/output.md: -------------------------------------------------------------------------------- 1 | # 見出し 2 | 3 | ### 見出し 4 | 5 | ### 見出し 6 | test 7 | 8 | これは、見本となる例です。 9 | 10 | 785,105 11 | 12 | 785.105 13 | 14 | 0.01 15 | 16 | 0.1 17 | 18 | これは10個あるうちの0.1分 19 | 20 | オヤツは300円まで 21 | 22 | フィルターをかける 23 | 24 | フィルター 25 | 26 | フィルター。 27 | 28 | フィルター、 29 | 30 | 200円はダメ 31 | 32 | おやつは300円まで 33 | 34 | これはABC全角 35 | 36 | 問題は以下のとおり 37 | 38 | 第3章 39 | 40 | 20回 41 | 42 | 1億百十万人 43 | 44 | 108つのボタン 45 | 46 | 第3回大会 47 | 48 | サンフランシスコマラソン第3回大会 49 | 50 | これは世界一 51 | 52 | 一部の文章 53 | 54 | これは花の一種です 55 | 56 | 朝一番に 57 | 58 | 数百倍 59 | 60 | 数十億 61 | 62 | しばしば数十万行以上に 63 | 64 | 数十年に一度の奇跡 65 | 66 | 3か月未満 67 | 68 | JTF標準 69 | 70 | これはUnicode 71 | 72 | これはUnicode 73 | 74 | これはダメ 75 | 76 | これはどういうこと? 77 | 78 | 「ダメ」 79 | 80 | これは「ダメ」です 81 | 82 | これは(ダメ)です 83 | 84 | A氏は「5月に新製品を発売します」と述べました。 85 | 86 | 従業員は約30,000人です(関連企業を含みます) 87 | 88 | 半角感嘆符! 89 | 90 | 驚きの速さ! これが新製品のキャッチコピーでした。半角  91 | 92 | 半角疑問符? 93 | 94 | 驚きの速さ!? これが新製品のキャッチコピーでした? これは問題なし 95 | 96 | 18〜22歳まで 97 | 98 | 例:〜 99 | 100 | クォーク(物質の素粒子) 101 | 102 | (物質の素粒子)クォーク 103 | 104 | (物質の素粒子) 105 | 106 | (npm 2.x以上をインストールしている必要があります) 107 | 108 | (必要バージョン: 2.x) 109 | 110 | 例)テスト 111 | 112 | 半角[かっこ 113 | 114 | 半角]かっこ -------------------------------------------------------------------------------- /test/index-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | import assert from "node:assert"; 4 | import index from "../src/index"; 5 | describe("index-test", function () { 6 | context("rules", function () { 7 | it("should have default rulesConfig", function () { 8 | Object.keys(index.rules).forEach((ruleName) => { 9 | assert(index.rulesConfig[ruleName] !== undefined, `${ruleName} ref is undefined.`); 10 | }); 11 | }); 12 | it("should not ref same function", function () { 13 | Object.keys(index.rules).forEach((ruleName) => { 14 | let rule = index.rules[ruleName]; 15 | Object.keys(index.rules).forEach((otherRuleName) => { 16 | if (otherRuleName !== ruleName) { 17 | assert(rule !== index.rules[otherRuleName], `${ruleName} !== ${otherRuleName}`); 18 | } 19 | }); 20 | }); 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/prh-test.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | // test prh rule 4 | import TextLintTester from "textlint-tester"; 5 | var tester = new TextLintTester(); 6 | // 実際のテストはymlファイル自体に書かれている 7 | // それを実行するために使うだけのテストファイル 8 | tester.run("2.1.5.カタカナ", require("../src/2.1.5"), { 9 | valid: ["これは正常なテキストです"] 10 | }); 11 | 12 | tester.run("2.1.6.カタカナの長音", require("../src/2.1.6"), { 13 | valid: ["これは正常なテキストです"] 14 | }); 15 | tester.run("2.2.3.一部の助数詞の表記", require("../src/2.2.3"), { 16 | valid: ["これは正常なテキストです"] 17 | }); 18 | tester.run("2.2.1.ひらがなと漢字の使い分け", require("../src/2.2.1"), { 19 | valid: [ 20 | "これは正常なテキストです", 21 | "名前付きスロットはコンテンツ フラグメントに対応する `slot` 属性を持つ任意の要素に一致します。", 22 | "Array の値の変更に対しては", 23 | "したがって、このような結果になりました。", 24 | "この結果に従って、私は行動したのです。" 25 | ], 26 | invalid: [ 27 | { 28 | text: "従って、このような結果になりました。", 29 | errors: [ 30 | { 31 | message: "従って => したがって", 32 | column: 1 33 | } 34 | ] 35 | }, 36 | { 37 | text: "この結果にしたがって、私は行動したのです。", 38 | errors: [ 39 | { 40 | message: "にしたがって => に従って", 41 | column: 5 42 | } 43 | ] 44 | } 45 | ] 46 | }); 47 | -------------------------------------------------------------------------------- /tool/create-fixtures.js: -------------------------------------------------------------------------------- 1 | // LICENSE : MIT 2 | "use strict"; 3 | const path = require("path"); 4 | const fs = require("fs"); 5 | const glob = require("glob"); 6 | // result 7 | const RESULT = { 8 | input: [], 9 | output: [] 10 | }; 11 | function processFile(filePath) { 12 | const contents = fs.readFileSync(filePath, "utf-8"); 13 | const lines = contents.split(/\n/); 14 | const inputRegExp = /^\s+text:\s*?"(.*?)"/; 15 | const outputRegExp = /^\s+output:\s*?"(.*?)"/; 16 | const optionsRegExp = /^\s+options:\s*?\{/; 17 | lines.forEach(function (line, index) { 18 | const nextLine = lines[index + 1]; 19 | const nextNextLine = lines[index + 2]; 20 | if (inputRegExp.test(line) && outputRegExp.test(nextLine) && !optionsRegExp.test(nextNextLine)) { 21 | const inputMatch = line.match(inputRegExp)[1]; 22 | // \\n => \n 23 | RESULT.input.push(inputMatch.replace(/\\n/g, "\n")); 24 | } else if (outputRegExp.test(line) && !optionsRegExp.test(nextLine)) { 25 | const outputMatch = line.match(outputRegExp)[1]; 26 | RESULT.output.push(outputMatch.replace(/\\n/g, "\n")); 27 | } 28 | }); 29 | } 30 | 31 | const testDir = path.join(__dirname, "..", "test"); 32 | const filePathList = glob.sync(testDir + "/*-test.js"); 33 | filePathList.forEach(processFile); 34 | 35 | fs.writeFileSync(path.join(testDir, "fixtures/input.md"), RESULT.input.join("\n\n"), "utf-8"); 36 | fs.writeFileSync(path.join(testDir, "fixtures/output.md"), RESULT.output.join("\n\n"), "utf-8"); 37 | --------------------------------------------------------------------------------