@@ -12,40 +12,69 @@ import { RuleHelper } from "textlint-rule-helper";
1212export function checkPair ( context , { left, right } ) {
1313 assert ( left ) ;
1414 assert ( right ) ;
15- let { Syntax, RuleError, report, getSource } = context ;
16- let helper = new RuleHelper ( context ) ;
15+ const { Syntax, RuleError, report, getSource } = context ;
16+ const helper = new RuleHelper ( context ) ;
1717 let isInParagraph = false ;
1818 let currentStrInParagraph = [ ] ;
1919 /**
2020 * `Str` nodeの配列を受け取り、pairが見つからないnodeを返す
2121 * @param {Object } currentStrInParagraph
2222 * @returns {{node, index}[] }
2323 */
24+ const findAllSymbolLocations = ( symbol , text ) => {
25+ let index = 0 ;
26+ const symbolLocations = [ ] ;
27+ while ( index < text . length ) {
28+ index = text . indexOf ( symbol , index ) ;
29+ if ( index < 0 ) break ;
30+ symbolLocations . push ( {
31+ index,
32+ symbol
33+ } ) ;
34+ index += 1 ;
35+ }
36+ return symbolLocations ;
37+ } ;
2438 const foundMissingPairNodes = ( currentStrInParagraph ) => {
25- let foundLeft = false ;
26- let matchParentheses = [ ] ;
27- currentStrInParagraph . forEach ( ( node ) => {
28- const text = getSource ( node ) ;
29- // left を探す
30- let leftIndex = - 1 ;
31- if ( ! foundLeft ) {
32- leftIndex = text . indexOf ( left ) ;
33- if ( leftIndex !== - 1 ) {
34- matchParentheses . push ( {
35- node,
36- index : leftIndex
37- } ) ;
38- foundLeft = true ;
39- }
39+ let matchParentheses = currentStrInParagraph
40+ . map ( ( node ) => {
41+ let text = getSource ( node ) ;
42+ const leftSymbolLocations = findAllSymbolLocations ( left , text ) ;
43+ const rightSymbolLocations = left !== right ? findAllSymbolLocations ( right , text ) : [ ] ;
44+ const allSymbolLocations = [ ...leftSymbolLocations , ...rightSymbolLocations ] . sort (
45+ ( a , b ) => a . index - b . index
46+ ) ;
47+ return allSymbolLocations . map ( ( loc ) => ( { ...loc , ...{ node } } ) ) ;
48+ } )
49+ . flat ( ) ;
50+ if ( left === right ) {
51+ const isCompletedParentheses = matchParentheses . length % 2 == 0 ;
52+ if ( isCompletedParentheses ) {
53+ return [ ] ;
54+ } else {
55+ return [ matchParentheses [ matchParentheses . length - 1 ] ] ;
4056 }
41- // right を探す
42- let pairIndex = text . indexOf ( right , leftIndex + 1 ) ;
43- if ( pairIndex !== - 1 ) {
44- matchParentheses . pop ( ) ;
45- foundLeft = false ;
57+ } else {
58+ const lastUnmatchParences = [ ] ;
59+ while ( matchParentheses . length > 0 ) {
60+ const item = matchParentheses . shift ( ) ;
61+ if ( item . symbol == left ) {
62+ lastUnmatchParences . push ( item ) ;
63+ } else {
64+ // right
65+ const last = lastUnmatchParences . pop ( ) ;
66+ if ( last ) {
67+ if ( last . symbol == right ) {
68+ lastUnmatchParences . push ( last ) ;
69+ lastUnmatchParences . push ( item ) ;
70+ }
71+ } else {
72+ lastUnmatchParences . push ( item ) ;
73+ }
74+ }
4675 }
47- } ) ;
48- return matchParentheses ;
76+ return lastUnmatchParences ;
77+ }
4978 } ;
5079 return {
5180 [ Syntax . Paragraph ] ( node ) {
@@ -69,13 +98,12 @@ export function checkPair(context, { left, right }) {
6998 if ( missingPairList . length === 0 ) {
7099 return ;
71100 }
72- missingPairList . forEach ( ( { node, index } ) => {
73- report (
74- node ,
75- new RuleError ( `${ left } の対となる${ right } が見つかりません。${ left } ${ right } ` , {
76- index
77- } )
78- ) ;
101+ missingPairList . forEach ( ( { index, node, symbol } ) => {
102+ let message =
103+ symbol === left
104+ ? `${ left } の対となる${ right } が見つかりません。${ left } ${ right } `
105+ : `${ right } の対となる${ left } が見つかりません。${ left } ${ right } ` ;
106+ report ( node , new RuleError ( message , { index } ) ) ;
79107 } ) ;
80108 }
81109 } ;
0 commit comments