@@ -46,26 +46,95 @@ function groupByParentComment(directives) {
46
46
* @returns {{ description, fix, position }[] } Details for later creation of output Problems.
47
47
*/
48
48
function createIndividualDirectivesRemoval ( directives , commentToken ) {
49
- const listOffset = / ^ \s * \S + \s + / u. exec ( commentToken . value ) [ 0 ] . length ;
49
+
50
+ /*
51
+ * `commentToken.value` starts right after `//` or `/*`.
52
+ * All calculated offsets will be relative to this index.
53
+ */
54
+ const commentValueStart = commentToken . range [ 0 ] + "//" . length ;
55
+
56
+ // Find where the list of rules starts. `\S+` matches with the directive name (e.g. `eslint-disable-line`)
57
+ const listStartOffset = / ^ \s * \S + \s + / u. exec ( commentToken . value ) [ 0 ] . length ;
58
+
59
+ /*
60
+ * Get the list text without any surrounding whitespace. In order to preserve the original
61
+ * formatting, we don't want to change that whitespace.
62
+ *
63
+ * // eslint-disable-line rule-one , rule-two , rule-three -- comment
64
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
65
+ */
50
66
const listText = commentToken . value
51
- . slice ( listOffset ) // remove eslint-*
52
- . split ( / \s - { 2 , } \s / u) [ 0 ] // remove -- directive comment
53
- . trimRight ( ) ;
54
- const listStart = commentToken . range [ 0 ] + 2 + listOffset ;
67
+ . slice ( listStartOffset ) // remove directive name and all whitespace before the list
68
+ . split ( / \s - { 2 , } \s / u) [ 0 ] // remove `-- comment`, if it exists
69
+ . trimRight ( ) ; // remove all whitespace after the list
70
+
71
+ /*
72
+ * We can assume that `listText` contains multiple elements.
73
+ * Otherwise, this function wouldn't be called - if there is
74
+ * only one rule in the list, then the whole comment must be removed.
75
+ */
55
76
56
77
return directives . map ( directive => {
57
78
const { ruleId } = directive ;
58
- const match = new RegExp ( String . raw `(?:^|,)\s*${ escapeRegExp ( ruleId ) } \s*(?:$|,)` , "u" ) . exec ( listText ) ;
59
- const ruleOffset = match . index ;
60
- const ruleEndOffset = ruleOffset + match [ 0 ] . length ;
61
- const ruleText = listText . slice ( ruleOffset , ruleEndOffset ) ;
79
+
80
+ const regex = new RegExp ( String . raw `(?:^|\s*,\s*)${ escapeRegExp ( ruleId ) } (?:\s*,\s*|$)` , "u" ) ;
81
+ const match = regex . exec ( listText ) ;
82
+ const matchedText = match [ 0 ] ;
83
+ const matchStartOffset = listStartOffset + match . index ;
84
+ const matchEndOffset = matchStartOffset + matchedText . length ;
85
+
86
+ const firstIndexOfComma = matchedText . indexOf ( "," ) ;
87
+ const lastIndexOfComma = matchedText . lastIndexOf ( "," ) ;
88
+
89
+ let removalStartOffset , removalEndOffset ;
90
+
91
+ if ( firstIndexOfComma !== lastIndexOfComma ) {
92
+
93
+ /*
94
+ * Since there are two commas, this must one of the elements in the middle of the list.
95
+ * Matched range starts where the previous rule name ends, and ends where the next rule name starts.
96
+ *
97
+ * // eslint-disable-line rule-one , rule-two , rule-three -- comment
98
+ * ^^^^^^^^^^^^^^
99
+ *
100
+ * We want to remove only the content between the two commas, and also one of the commas.
101
+ *
102
+ * // eslint-disable-line rule-one , rule-two , rule-three -- comment
103
+ * ^^^^^^^^^^^
104
+ */
105
+ removalStartOffset = matchStartOffset + firstIndexOfComma ;
106
+ removalEndOffset = matchStartOffset + lastIndexOfComma ;
107
+
108
+ } else {
109
+
110
+ /*
111
+ * This is either the first element or the last element.
112
+ *
113
+ * If this is the first element, matched range starts where the first rule name starts
114
+ * and ends where the second rule name starts. This is exactly the range we want
115
+ * to remove so that the second rule name will start where the first one was starting
116
+ * and thus preserve the original formatting.
117
+ *
118
+ * // eslint-disable-line rule-one , rule-two , rule-three -- comment
119
+ * ^^^^^^^^^^^
120
+ *
121
+ * Similarly, if this is the last element, we've already matched the range we want to
122
+ * remove. The previous rule name will end where the last one was ending, relative
123
+ * to the content on the right side.
124
+ *
125
+ * // eslint-disable-line rule-one , rule-two , rule-three -- comment
126
+ * ^^^^^^^^^^^^^
127
+ */
128
+ removalStartOffset = matchStartOffset ;
129
+ removalEndOffset = matchEndOffset ;
130
+ }
62
131
63
132
return {
64
133
description : `'${ ruleId } '` ,
65
134
fix : {
66
135
range : [
67
- listStart + ruleOffset + ( ruleText . startsWith ( "," ) && ruleText . endsWith ( "," ) ? 1 : 0 ) ,
68
- listStart + ruleEndOffset
136
+ commentValueStart + removalStartOffset ,
137
+ commentValueStart + removalEndOffset
69
138
] ,
70
139
text : ""
71
140
} ,
0 commit comments