Skip to content

Commit c178ce7

Browse files
authored
fix: extend the autofix range in comma-dangle to ensure the last element (#15669)
Fixes #15660
1 parent edb12e5 commit c178ce7

2 files changed

Lines changed: 108 additions & 4 deletions

File tree

lib/rules/comma-dangle.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,18 @@ module.exports = {
243243
node: lastItem,
244244
loc: trailingToken.loc,
245245
messageId: "unexpected",
246-
fix(fixer) {
247-
return fixer.remove(trailingToken);
246+
*fix(fixer) {
247+
yield fixer.remove(trailingToken);
248+
249+
/*
250+
* Extend the range of the fix to include surrounding tokens to ensure
251+
* that the element after which the comma is removed stays _last_.
252+
* This intentionally makes conflicts in fix ranges with rules that may be
253+
* adding or removing elements in the same autofix pass.
254+
* https://github.com/eslint/eslint/issues/15660
255+
*/
256+
yield fixer.insertTextBefore(sourceCode.getTokenBefore(trailingToken), "");
257+
yield fixer.insertTextAfter(sourceCode.getTokenAfter(trailingToken), "");
248258
}
249259
});
250260
}
@@ -282,8 +292,18 @@ module.exports = {
282292
end: astUtils.getNextLocation(sourceCode, trailingToken.loc.end)
283293
},
284294
messageId: "missing",
285-
fix(fixer) {
286-
return fixer.insertTextAfter(trailingToken, ",");
295+
*fix(fixer) {
296+
yield fixer.insertTextAfter(trailingToken, ",");
297+
298+
/*
299+
* Extend the range of the fix to include surrounding tokens to ensure
300+
* that the element after which the comma is inserted stays _last_.
301+
* This intentionally makes conflicts in fix ranges with rules that may be
302+
* adding or removing elements in the same autofix pass.
303+
* https://github.com/eslint/eslint/issues/15660
304+
*/
305+
yield fixer.insertTextBefore(trailingToken, "");
306+
yield fixer.insertTextAfter(sourceCode.getTokenAfter(trailingToken), "");
287307
}
288308
});
289309
}

tests/lib/rules/comma-dangle.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//------------------------------------------------------------------------------
1111

1212
const path = require("path"),
13+
{ unIndent } = require("../../_utils"),
1314
rule = require("../../../lib/rules/comma-dangle"),
1415
{ RuleTester } = require("../../../lib/rule-tester");
1516

@@ -35,6 +36,29 @@ function parser(name) {
3536

3637
const ruleTester = new RuleTester();
3738

39+
ruleTester.defineRule("add-named-import", {
40+
meta: {
41+
fixable: "code"
42+
},
43+
create(context) {
44+
return {
45+
ImportDeclaration(node) {
46+
const sourceCode = context.getSourceCode();
47+
const closingBrace = sourceCode.getLastToken(node, token => token.value === "}");
48+
const addComma = sourceCode.getTokenBefore(closingBrace).value !== ",";
49+
50+
context.report({
51+
message: "Add I18nManager.",
52+
node,
53+
fix(fixer) {
54+
return fixer.insertTextBefore(closingBrace, `${addComma ? "," : ""}I18nManager`);
55+
}
56+
});
57+
}
58+
};
59+
}
60+
});
61+
3862
ruleTester.run("comma-dangle", rule, {
3963
valid: [
4064
"var foo = { bar: 'baz' }",
@@ -1766,6 +1790,66 @@ let d = 0;export {d,};
17661790
output: "foo(a)",
17671791
parserOptions: { ecmaVersion: 8 },
17681792
errors: [{ messageId: "unexpected" }]
1793+
},
1794+
1795+
// https://github.com/eslint/eslint/issues/15660
1796+
{
1797+
code: unIndent`
1798+
/*eslint add-named-import:1*/
1799+
import {
1800+
StyleSheet,
1801+
View,
1802+
TextInput,
1803+
ImageBackground,
1804+
Image,
1805+
TouchableOpacity,
1806+
SafeAreaView
1807+
} from 'react-native';
1808+
`,
1809+
output: unIndent`
1810+
/*eslint add-named-import:1*/
1811+
import {
1812+
StyleSheet,
1813+
View,
1814+
TextInput,
1815+
ImageBackground,
1816+
Image,
1817+
TouchableOpacity,
1818+
SafeAreaView,
1819+
} from 'react-native';
1820+
`,
1821+
options: [{ imports: "always-multiline" }],
1822+
parserOptions: { ecmaVersion: 6, sourceType: "module" },
1823+
errors: 2
1824+
},
1825+
{
1826+
code: unIndent`
1827+
/*eslint add-named-import:1*/
1828+
import {
1829+
StyleSheet,
1830+
View,
1831+
TextInput,
1832+
ImageBackground,
1833+
Image,
1834+
TouchableOpacity,
1835+
SafeAreaView,
1836+
} from 'react-native';
1837+
`,
1838+
output: unIndent`
1839+
/*eslint add-named-import:1*/
1840+
import {
1841+
StyleSheet,
1842+
View,
1843+
TextInput,
1844+
ImageBackground,
1845+
Image,
1846+
TouchableOpacity,
1847+
SafeAreaView
1848+
} from 'react-native';
1849+
`,
1850+
options: [{ imports: "never" }],
1851+
parserOptions: { ecmaVersion: 6, sourceType: "module" },
1852+
errors: 2
17691853
}
17701854
]
17711855
});

0 commit comments

Comments
 (0)