Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: extend the autofix range in comma-dangle to ensure the last element #15669

Merged
merged 1 commit into from Mar 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 24 additions & 4 deletions lib/rules/comma-dangle.js
Expand Up @@ -243,8 +243,18 @@ module.exports = {
node: lastItem,
loc: trailingToken.loc,
messageId: "unexpected",
fix(fixer) {
return fixer.remove(trailingToken);
*fix(fixer) {
yield fixer.remove(trailingToken);

/*
* Extend the range of the fix to include surrounding tokens to ensure
* that the element after which the comma is removed stays _last_.
* This intentionally makes conflicts in fix ranges with rules that may be
* adding or removing elements in the same autofix pass.
* https://github.com/eslint/eslint/issues/15660
*/
yield fixer.insertTextBefore(sourceCode.getTokenBefore(trailingToken), "");
yield fixer.insertTextAfter(sourceCode.getTokenAfter(trailingToken), "");
}
});
}
Expand Down Expand Up @@ -282,8 +292,18 @@ module.exports = {
end: astUtils.getNextLocation(sourceCode, trailingToken.loc.end)
},
messageId: "missing",
fix(fixer) {
return fixer.insertTextAfter(trailingToken, ",");
*fix(fixer) {
yield fixer.insertTextAfter(trailingToken, ",");

/*
* Extend the range of the fix to include surrounding tokens to ensure
* that the element after which the comma is inserted stays _last_.
* This intentionally makes conflicts in fix ranges with rules that may be
* adding or removing elements in the same autofix pass.
* https://github.com/eslint/eslint/issues/15660
*/
yield fixer.insertTextBefore(trailingToken, "");
yield fixer.insertTextAfter(sourceCode.getTokenAfter(trailingToken), "");
}
});
}
Expand Down
84 changes: 84 additions & 0 deletions tests/lib/rules/comma-dangle.js
Expand Up @@ -10,6 +10,7 @@
//------------------------------------------------------------------------------

const path = require("path"),
{ unIndent } = require("../../_utils"),
rule = require("../../../lib/rules/comma-dangle"),
{ RuleTester } = require("../../../lib/rule-tester");

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

const ruleTester = new RuleTester();

ruleTester.defineRule("add-named-import", {
meta: {
fixable: "code"
},
create(context) {
return {
ImportDeclaration(node) {
const sourceCode = context.getSourceCode();
const closingBrace = sourceCode.getLastToken(node, token => token.value === "}");
const addComma = sourceCode.getTokenBefore(closingBrace).value !== ",";

context.report({
message: "Add I18nManager.",
node,
fix(fixer) {
return fixer.insertTextBefore(closingBrace, `${addComma ? "," : ""}I18nManager`);
}
});
}
};
}
});

ruleTester.run("comma-dangle", rule, {
valid: [
"var foo = { bar: 'baz' }",
Expand Down Expand Up @@ -1766,6 +1790,66 @@ let d = 0;export {d,};
output: "foo(a)",
parserOptions: { ecmaVersion: 8 },
errors: [{ messageId: "unexpected" }]
},

// https://github.com/eslint/eslint/issues/15660
{
code: unIndent`
/*eslint add-named-import:1*/
import {
StyleSheet,
View,
TextInput,
ImageBackground,
Image,
TouchableOpacity,
SafeAreaView
} from 'react-native';
`,
output: unIndent`
/*eslint add-named-import:1*/
import {
StyleSheet,
View,
TextInput,
ImageBackground,
Image,
TouchableOpacity,
SafeAreaView,
} from 'react-native';
`,
options: [{ imports: "always-multiline" }],
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: 2
},
{
code: unIndent`
/*eslint add-named-import:1*/
import {
StyleSheet,
View,
TextInput,
ImageBackground,
Image,
TouchableOpacity,
SafeAreaView,
} from 'react-native';
`,
output: unIndent`
/*eslint add-named-import:1*/
import {
StyleSheet,
View,
TextInput,
ImageBackground,
Image,
TouchableOpacity,
SafeAreaView
} from 'react-native';
`,
options: [{ imports: "never" }],
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: 2
}
]
});