@@ -11,7 +11,7 @@ import {
1111 restoreToSurfaceFromKey ,
1212 is括弧Token ,
1313} from "./token-utils" ;
14- import { TxtNode } from "@textlint/ast-node-types" ;
14+ import { TxtNode , TxtParentNode } from "@textlint/ast-node-types" ;
1515import { TextlintRuleModule } from "@textlint/types" ;
1616import { StringSource } from "textlint-util-to-string" ;
1717
@@ -84,6 +84,7 @@ export interface Options {
8484 /**
8585 * 助詞の最低間隔値
8686 * 指定した間隔値以下で同じ助詞が出現した場合エラーが出力されます
87+ * デフォルトは1なので、同じ助詞が連続した場合にエラーとなります。
8788 */
8889 min_interval ?: number ;
8990 /**
@@ -106,13 +107,36 @@ export interface Options {
106107 commaCharacters ?: string [ ] ;
107108}
108109
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+ }
109135/*
110136 1. Paragraph Node -> text
111137 2. text -> sentences
112138 3. tokenize sentence
113139 4. report error if found word that match the rule.
114-
115- TODO: need abstraction
116140 */
117141const report : TextlintRuleModule < Options > = function ( context , options = { } ) {
118142 const helper = new RuleHelper ( context ) ;
@@ -142,7 +166,9 @@ const report: TextlintRuleModule<Options> = function (context, options = {}) {
142166 } ) ;
143167 const sentences = txtParentNode . children . filter ( isSentenceNode ) ;
144168 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 ) ;
146172 const text = sentenceSource . toString ( ) ;
147173 const tokens = await tokenize ( text ) ;
148174 // 助詞 + 助詞は 一つの助詞として扱う
@@ -154,18 +180,25 @@ const report: TextlintRuleModule<Options> = function (context, options = {}) {
154180 if ( isStrict ) {
155181 return is助詞Token ( token ) ;
156182 }
183+ // デフォルトでは、"、"などを間隔値の距離としてカウントする
157184 // "("や")"などもトークンとしてカウントする
158185 // xxxx(xxx) xxx でカッコの中と外に距離を一つ増やす目的
159186 // https://github.com/textlint-ja/textlint-rule-no-doubled-joshi/issues/31
160187 if ( is括弧Token ( token ) ) {
161188 return true ;
162189 }
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+ }
163197 // "、" があると助詞同士の距離が開くようにすることで、並列的な"、"の使い方を許容する目的
164198 // https://github.com/azu/textlint-rule-no-doubled-joshi/issues/2
165199 if ( is読点Token ( token ) ) {
166200 return true ;
167201 }
168- // デフォルトでは、"、"を間隔値の距離としてカウントする
169202 return is助詞Token ( token ) ;
170203 } ) ;
171204 const joshiTokenSurfaceKeyMap = createSurfaceKeyMap ( countableTokens ) ;
0 commit comments