Skip to content

Commit d625187

Browse files
committed
feat(options): add 読点 and 句点 as options
1 parent 2bc5335 commit d625187

File tree

4 files changed

+572
-46
lines changed

4 files changed

+572
-46
lines changed

package.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@
3030
"build": "textlint-scripts build",
3131
"watch": "textlint-scripts build --watch",
3232
"prepublish": "npm run --if-present build",
33-
"test": "textlint-scripts test"
33+
"test": "textlint-scripts test",
34+
"prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"",
35+
"prepare": "git config --local core.hooksPath .githook"
3436
},
3537
"devDependencies": {
38+
"lint-staged": "^10.5.4",
39+
"prettier": "^2.2.1",
3640
"textlint-scripts": "^3.0.0"
3741
},
3842
"dependencies": {
@@ -41,5 +45,16 @@
4145
"structured-source": "^3.0.2",
4246
"textlint-rule-helper": "^2.0.0",
4347
"textlint-util-to-string": "^3.1.1"
48+
},
49+
"prettier": {
50+
"singleQuote": false,
51+
"printWidth": 120,
52+
"tabWidth": 4,
53+
"trailingComma": "none"
54+
},
55+
"lint-staged": {
56+
"*.{js,jsx,ts,tsx,css}": [
57+
"prettier --write"
58+
]
4459
}
4560
}

src/max-ten.js

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
// LICENSE : MIT
22
"use strict";
3-
import { RuleHelper } from "textlint-rule-helper"
3+
import { RuleHelper } from "textlint-rule-helper";
44
import { getTokenizer } from "kuromojin";
55
import { splitAST, Syntax as SentenceSyntax } from "sentence-splitter";
66
import { StringSource } from "textlint-util-to-string";
7+
import { SeparatorParser } from "sentence-splitter/lib/parser/SeparatorParser";
78

89
const defaultOptions = {
9-
max: 3, // 1文に利用できる最大の、の数
10-
strict: false // 例外ルールを適応するかどうか
10+
// 1文に利用できる最大の、の数
11+
max: 3,
12+
// 例外ルールを適応するかどうか,
13+
strict: false,
14+
// 読点として扱う文字
15+
// https://ja.wikipedia.org/wiki/%E8%AA%AD%E7%82%B9
16+
touten: "、",
17+
// 句点として扱う文字
18+
// https://ja.wikipedia.org/wiki/%E5%8F%A5%E7%82%B9
19+
kuten: "。"
1120
};
1221

13-
function isSandwichedMeishi({
14-
before,
15-
token,
16-
after
17-
}) {
22+
function isSandwichedMeishi({ before, token, after }) {
1823
if (before === undefined || after === undefined || token === undefined) {
1924
return false;
2025
}
@@ -23,20 +28,31 @@ function isSandwichedMeishi({
2328

2429
/**
2530
* @param {RuleContext} context
26-
* @param {object} [options]
31+
* @param {typeof defaultOptions} [options]
2732
*/
2833
module.exports = function (context, options = {}) {
29-
const maxLen = options.max || defaultOptions.max;
30-
const isStrict = options.strict || defaultOptions.strict;
34+
const maxLen = options.max ?? defaultOptions.max;
35+
const isStrict = options.strict ?? defaultOptions.strict;
36+
const touten = options.touten ?? defaultOptions.touten;
37+
const kuten = options.kuten ?? defaultOptions.kuten;
3138
const helper = new RuleHelper(context);
3239
const { Syntax, RuleError, report, getSource } = context;
3340
return {
3441
[Syntax.Paragraph](node) {
3542
if (helper.isChildNode(node, [Syntax.BlockQuote])) {
3643
return;
3744
}
38-
const resultNode = splitAST(node);
39-
const sentences = resultNode.children.filter(childNode => childNode.type === SentenceSyntax.Sentence);
45+
const resultNode = splitAST(node, {
46+
SeparatorParser: {
47+
separatorCharacters: [
48+
"?", // question mark
49+
"!", // exclamation mark
50+
"?", // (ja) zenkaku question mark
51+
"!" // (ja) zenkaku exclamation mark
52+
].concat(kuten)
53+
}
54+
});
55+
const sentences = resultNode.children.filter((childNode) => childNode.type === SentenceSyntax.Sentence);
4056
/*
4157
<p>
4258
<str><code><img><str>
@@ -49,18 +65,18 @@ module.exports = function (context, options = {}) {
4965
2. sentence to tokens
5066
3. check tokens
5167
*/
52-
return getTokenizer().then(tokenizer => {
53-
sentences.forEach(sentence => {
68+
return getTokenizer().then((tokenizer) => {
69+
sentences.forEach((sentence) => {
5470
const source = new StringSource(sentence);
5571
const text = source.toString();
5672
const tokens = tokenizer.tokenizeForSentence(text);
5773
let currentTenCount = 0;
5874
let lastToken = null;
5975
tokens.forEach((token, index) => {
60-
let surface = token.surface_form;
61-
if (surface === "、") {
76+
const surface = token.surface_form;
77+
if (surface === touten) {
6278
// 名詞に囲まわれている場合は例外とする
63-
let isSandwiched = isSandwichedMeishi({
79+
const isSandwiched = isSandwichedMeishi({
6480
before: tokens[index - 1],
6581
token: token,
6682
after: tokens[index + 1]
@@ -80,15 +96,18 @@ module.exports = function (context, options = {}) {
8096
if (currentTenCount >= maxLen) {
8197
const positionInSentence = source.originalIndexFromIndex(lastToken.word_position - 1);
8298
const index = sentence.range[0] + positionInSentence;
83-
const ruleError = new context.RuleError(`一つの文で"、"を${maxLen}つ以上使用しています`, {
84-
index
85-
});
99+
const ruleError = new context.RuleError(
100+
`一つの文で"${touten}"を${maxLen}つ以上使用しています`,
101+
{
102+
index
103+
}
104+
);
86105
report(node, ruleError);
87106
currentTenCount = 0;
88107
}
89108
});
90109
});
91110
});
92111
}
93-
}
94-
}
112+
};
113+
};

test/max-ten-test.js

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
const rule = require("../src/max-ten");
1+
import TextLintTester from "textlint-tester";
2+
import rule from "../src/max-ten";
3+
24
function textIncludeTen(count) {
3-
return (new Array(count + 1)).join("テスト文章において、") + "です";
5+
return new Array(count + 1).join("テスト文章において、") + "です";
46
}
5-
var TextLintTester = require("textlint-tester");
6-
var tester = new TextLintTester();
7+
8+
const tester = new TextLintTester();
79
// ruleName, rule, expected[]
810
tester.run("max-ten", rule, {
911
// default max:3
@@ -17,19 +19,31 @@ tester.run("max-ten", rule, {
1719
{
1820
text: textIncludeTen(5 - 1),
1921
options: {
20-
"max": 5
22+
max: 5
2123
}
2224
},
2325
{
2426
text: "これは、テストです。"
27+
},
28+
{
29+
text: "これは、これは、これは、これは、オプションでカウントされないのでOK",
30+
options: {
31+
touten: ",",
32+
kuten: "."
33+
}
34+
},
35+
{
36+
text: `これは,これは.これは,これは.`,
37+
options: {
38+
touten: ",",
39+
kuten: "."
40+
}
2541
}
26-
2742
],
2843
invalid: [
2944
{
3045
text: `これは、これは、これは
31-
、d`
32-
,
46+
、d`,
3347
errors: [
3448
{
3549
message: `一つの文で"、"を3つ以上使用しています`,
@@ -38,10 +52,23 @@ tester.run("max-ten", rule, {
3852
}
3953
]
4054
},
55+
{
56+
text: `これは,これは,これは,これは。`,
57+
errors: [
58+
{
59+
message: `一つの文で","を3つ以上使用しています`,
60+
index: 11
61+
}
62+
],
63+
options: {
64+
touten: ",",
65+
kuten: "."
66+
}
67+
},
4168
{
4269
text: textIncludeTen(5),
4370
options: {
44-
"max": 5
71+
max: 5
4572
},
4673
errors: [
4774
{
@@ -52,7 +79,7 @@ tester.run("max-ten", rule, {
5279
{
5380
text: `これは、長文の例ですが、columnがちゃんと計算、されてるはずです。`,
5481
options: {
55-
"max": 3
82+
max: 3
5683
},
5784
errors: [
5885
{
@@ -65,7 +92,7 @@ tester.run("max-ten", rule, {
6592
{
6693
text: "間に、Str以外の`code`Nodeが、あっても、OK",
6794
options: {
68-
"max": 3
95+
max: 3
6996
},
7097
errors: [
7198
{
@@ -78,7 +105,7 @@ tester.run("max-ten", rule, {
78105
{
79106
text: `複数のセンテンスがある場合。これでも、columnが、ちゃんと計算、されているはずです。`,
80107
options: {
81-
"max": 3
108+
max: 3
82109
},
83110
errors: [
84111
{
@@ -91,7 +118,7 @@ tester.run("max-ten", rule, {
91118
{
92119
text: `複数のセンテンスがあって、改行されている場合でも\n大丈夫です。これでも、lineとcolumnが、ちゃんと計算、されているはずです。`,
93120
options: {
94-
"max": 3
121+
max: 3
95122
},
96123
errors: [
97124
{
@@ -102,4 +129,4 @@ tester.run("max-ten", rule, {
102129
]
103130
}
104131
]
105-
});
132+
});

0 commit comments

Comments
 (0)