Skip to content

Commit c9efb5f

Browse files
authored
Fix: preserve formatting when rules are removed from disable directives (#15081)
1 parent 14a4739 commit c9efb5f

File tree

3 files changed

+644
-17
lines changed

3 files changed

+644
-17
lines changed

lib/linter/apply-disable-directives.js

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,26 +46,95 @@ function groupByParentComment(directives) {
4646
* @returns {{ description, fix, position }[]} Details for later creation of output Problems.
4747
*/
4848
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+
*/
5066
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+
*/
5576

5677
return directives.map(directive => {
5778
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+
}
62131

63132
return {
64133
description: `'${ruleId}'`,
65134
fix: {
66135
range: [
67-
listStart + ruleOffset + (ruleText.startsWith(",") && ruleText.endsWith(",") ? 1 : 0),
68-
listStart + ruleEndOffset
136+
commentValueStart + removalStartOffset,
137+
commentValueStart + removalEndOffset
69138
],
70139
text: ""
71140
},

tests/lib/linter/apply-disable-directives.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,7 +1451,7 @@ describe("apply-disable-directives", () => {
14511451
line: 1,
14521452
column: 24,
14531453
fix: {
1454-
range: [24, 33],
1454+
range: [23, 32],
14551455
text: ""
14561456
},
14571457
severity: 2,
@@ -1492,7 +1492,7 @@ describe("apply-disable-directives", () => {
14921492
line: 1,
14931493
column: 18,
14941494
fix: {
1495-
range: [18, 25],
1495+
range: [18, 26],
14961496
text: ""
14971497
},
14981498
severity: 2,
@@ -1581,7 +1581,7 @@ describe("apply-disable-directives", () => {
15811581
line: 1,
15821582
column: 18,
15831583
fix: {
1584-
range: [18, 27],
1584+
range: [18, 28],
15851585
text: ""
15861586
},
15871587
severity: 2,
@@ -1593,7 +1593,7 @@ describe("apply-disable-directives", () => {
15931593
line: 1,
15941594
column: 28,
15951595
fix: {
1596-
range: [27, 37],
1596+
range: [26, 36],
15971597
text: ""
15981598
},
15991599
severity: 2,
@@ -1648,7 +1648,7 @@ describe("apply-disable-directives", () => {
16481648
line: 1,
16491649
column: 18,
16501650
fix: {
1651-
range: [18, 27],
1651+
range: [18, 28],
16521652
text: ""
16531653
},
16541654
severity: 2,
@@ -1660,7 +1660,7 @@ describe("apply-disable-directives", () => {
16601660
line: 1,
16611661
column: 28,
16621662
fix: {
1663-
range: [27, 37],
1663+
range: [26, 36],
16641664
text: ""
16651665
},
16661666
severity: 2,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy