@@ -11,7 +11,7 @@ import {
11
11
restoreToSurfaceFromKey ,
12
12
is括弧Token ,
13
13
} from "./token-utils" ;
14
- import { TxtNode } from "@textlint/ast-node-types" ;
14
+ import { TxtNode , TxtParentNode } from "@textlint/ast-node-types" ;
15
15
import { TextlintRuleModule } from "@textlint/types" ;
16
16
import { StringSource } from "textlint-util-to-string" ;
17
17
@@ -84,6 +84,7 @@ export interface Options {
84
84
/**
85
85
* 助詞の最低間隔値
86
86
* 指定した間隔値以下で同じ助詞が出現した場合エラーが出力されます
87
+ * デフォルトは1なので、同じ助詞が連続した場合にエラーとなります。
87
88
*/
88
89
min_interval ?: number ;
89
90
/**
@@ -106,13 +107,36 @@ export interface Options {
106
107
commaCharacters ?: string [ ] ;
107
108
}
108
109
110
+ /**
111
+ * `obj.method` のCode Nodeのように、区切り文字として意味をもつノードがある場合に、
112
+ * このルールでは単純に無視したいので、同じ文字数で意味のない文字列に置き換える
113
+ * @param sentenceNode
114
+ * @param maskedType
115
+ */
116
+ const maskNode = ( sentenceNode : TxtParentNode , maskedType : string [ ] ) : TxtParentNode => {
117
+ // recursive mask
118
+ return {
119
+ ...sentenceNode ,
120
+ children : sentenceNode . children . map ( ( node ) => {
121
+ if ( maskedType . includes ( node . type ) ) {
122
+ return {
123
+ ...node ,
124
+ type : node . type ,
125
+ value : "_" . repeat ( node . value . length ) ,
126
+ } ;
127
+ }
128
+ if ( node . children ) {
129
+ return maskNode ( node as TxtParentNode , maskedType ) ;
130
+ }
131
+ return node ;
132
+ } )
133
+ }
134
+ }
109
135
/*
110
136
1. Paragraph Node -> text
111
137
2. text -> sentences
112
138
3. tokenize sentence
113
139
4. report error if found word that match the rule.
114
-
115
- TODO: need abstraction
116
140
*/
117
141
const report : TextlintRuleModule < Options > = function ( context , options = { } ) {
118
142
const helper = new RuleHelper ( context ) ;
@@ -142,7 +166,9 @@ const report: TextlintRuleModule<Options> = function (context, options = {}) {
142
166
} ) ;
143
167
const sentences = txtParentNode . children . filter ( isSentenceNode ) ;
144
168
const checkSentence = async ( sentence : SentenceNode ) => {
145
- const sentenceSource = new StringSource ( sentence ) ;
169
+ // コードの中身は無視するため、無意味な文字列に置き換える
170
+ const maskedSentence = maskNode ( sentence , [ Syntax . Code ] ) ;
171
+ const sentenceSource = new StringSource ( maskedSentence ) ;
146
172
const text = sentenceSource . toString ( ) ;
147
173
const tokens = await tokenize ( text ) ;
148
174
// 助詞 + 助詞は 一つの助詞として扱う
@@ -154,18 +180,25 @@ const report: TextlintRuleModule<Options> = function (context, options = {}) {
154
180
if ( isStrict ) {
155
181
return is助詞Token ( token ) ;
156
182
}
183
+ // デフォルトでは、"、"などを間隔値の距離としてカウントする
157
184
// "("や")"などもトークンとしてカウントする
158
185
// xxxx(xxx) xxx でカッコの中と外に距離を一つ増やす目的
159
186
// https://github.com/textlint-ja/textlint-rule-no-doubled-joshi/issues/31
160
187
if ( is括弧Token ( token ) ) {
161
188
return true ;
162
189
}
190
+ // sentence-splitterでセンテンスに区切った場合、 "Xは「カッコ書きの中の文」と言った。" というように、「」の中の文は区切られない
191
+ // そのため、トークナイズしたトークンで区切り文字となる文字(。や.)があった場合には、カウントを増やす
192
+ // デフォルトではmin_interval:1 なので、「今日は早朝から出発したが、定刻には間に合わなかった。定刻には間に合わなかったが、無事会場に到着した」のようなものがエラーではなくなる
193
+ // https://github.com/textlint-ja/textlint-rule-no-doubled-joshi/issues/40
194
+ if ( separatorCharacters . includes ( token . surface_form ) ) {
195
+ return true ;
196
+ }
163
197
// "、" があると助詞同士の距離が開くようにすることで、並列的な"、"の使い方を許容する目的
164
198
// https://github.com/azu/textlint-rule-no-doubled-joshi/issues/2
165
199
if ( is読点Token ( token ) ) {
166
200
return true ;
167
201
}
168
- // デフォルトでは、"、"を間隔値の距離としてカウントする
169
202
return is助詞Token ( token ) ;
170
203
} ) ;
171
204
const joshiTokenSurfaceKeyMap = createSurfaceKeyMap ( countableTokens ) ;
0 commit comments