Skip to content

Commit

Permalink
Update: Add autofix for sort-vars (#9496)
Browse files Browse the repository at this point in the history
* Update: Add autofix for `sort-vars`

* Chore: Add test cases and small refactor for `sort-vars`
  • Loading branch information
trevinhofmann authored and not-an-aardvark committed Nov 26, 2017
1 parent 71eedbf commit 5619910
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 21 deletions.
55 changes: 45 additions & 10 deletions lib/rules/sort-vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,64 @@ module.exports = {
},
additionalProperties: false
}
]
],

fixable: "code"
},

create(context) {

const configuration = context.options[0] || {},
ignoreCase = configuration.ignoreCase || false;
ignoreCase = configuration.ignoreCase || false,
sourceCode = context.getSourceCode();

return {
VariableDeclaration(node) {
const idDeclarations = node.declarations.filter(decl => decl.id.type === "Identifier");
const getSortableName = ignoreCase ? decl => decl.id.name.toLowerCase() : decl => decl.id.name;
const unfixable = idDeclarations.some(decl => decl.init !== null && decl.init.type !== "Literal");
let fixed = false;

idDeclarations.slice(1).reduce((memo, decl) => {
let lastVariableName = memo.id.name,
currenVariableName = decl.id.name;
const lastVariableName = getSortableName(memo),
currentVariableName = getSortableName(decl);

if (ignoreCase) {
lastVariableName = lastVariableName.toLowerCase();
currenVariableName = currenVariableName.toLowerCase();
}
if (currentVariableName < lastVariableName) {
context.report({
node: decl,
message: "Variables within the same declaration block should be sorted alphabetically.",
fix(fixer) {
if (unfixable || fixed) {
return null;
}
return fixer.replaceTextRange(
[idDeclarations[0].range[0], idDeclarations[idDeclarations.length - 1].range[1]],
idDeclarations

// Clone the idDeclarations array to avoid mutating it
.slice()

// Sort the array into the desired order
.sort((declA, declB) => {
const aName = getSortableName(declA);
const bName = getSortableName(declB);

return aName > bName ? 1 : -1;
})

// Build a string out of the sorted list of identifier declarations and the text between the originals
.reduce((sourceText, identifier, index) => {
const textAfterIdentifier = index === idDeclarations.length - 1
? ""
: sourceCode.getText().slice(idDeclarations[index].range[1], idDeclarations[index + 1].range[0]);

return sourceText + sourceCode.getText(identifier) + textAfterIdentifier;
}, "")

if (currenVariableName < lastVariableName) {
context.report({ node: decl, message: "Variables within the same declaration block should be sorted alphabetically." });
);
}
});
fixed = true;
return memo;
}
return decl;
Expand Down
135 changes: 124 additions & 11 deletions tests/lib/rules/sort-vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,34 +113,147 @@ ruleTester.run("sort-vars", rule, {
}
],
invalid: [
{ code: "var b, a", errors: [expectedError] },
{ code: "var b=10, a=20;", errors: [expectedError] },
{ code: "var all=10, a = 1", errors: [expectedError] },
{ code: "var b, c, a, d", errors: [expectedError] },
{ code: "var c, d, a, b", errors: 2 },
{ code: "var a, A;", errors: [expectedError] },
{ code: "var a, B;", errors: [expectedError] },
{ code: "var a, B, c;", errors: [expectedError] },
{ code: "var B, a;", options: ignoreCaseArgs, errors: [expectedError] },
{ code: "var B, A, c;", options: ignoreCaseArgs, errors: [expectedError] },
{
code: "var b, a",
output: "var a, b",
errors: [expectedError]
},
{
code: "var b , a",
output: "var a , b",
errors: [expectedError]
},
{
code: [
"var b,",
" a;"
].join("\n"),
output: [
"var a,",
" b;"
].join("\n"),
errors: [expectedError]
},
{
code: "var b=10, a=20;",
output: "var a=20, b=10;",
errors: [expectedError]
},
{
code: "var b=10, a=20, c=30;",
output: "var a=20, b=10, c=30;",
errors: [expectedError]
},
{
code: "var all=10, a = 1",
output: "var a = 1, all=10",
errors: [expectedError]
},
{
code: "var b, c, a, d",
output: "var a, b, c, d",
errors: [expectedError]
},
{
code: "var c, d, a, b",
output: "var a, b, c, d",
errors: 2
},
{
code: "var a, A;",
output: "var A, a;",
errors: [expectedError]
},
{
code: "var a, B;",
output: "var B, a;",
errors: [expectedError]
},
{
code: "var a, B, c;",
output: "var B, a, c;",
errors: [expectedError]
},
{
code: "var B, a;",
output: "var a, B;",
options: ignoreCaseArgs,
errors: [expectedError]
},
{
code: "var B, A, c;",
output: "var A, B, c;",
options: ignoreCaseArgs,
errors: [expectedError]
},
{
code: "var d, a, [b, c] = {};",
output: "var a, d, [b, c] = {};",
options: ignoreCaseArgs,
parserOptions: { ecmaVersion: 6 },
errors: [expectedError]
},
{
code: "var d, a, [b, {x: {c, e}}] = {};",
output: "var a, d, [b, {x: {c, e}}] = {};",
options: ignoreCaseArgs,
parserOptions: { ecmaVersion: 6 },
errors: [expectedError]
},

{
code: "var {} = 1, b, a",
output: "var {} = 1, a, b",
options: ignoreCaseArgs,
parserOptions: { ecmaVersion: 6 },
errors: [expectedError]
},
{
code: "var b=10, a=f();",
output: null,
errors: [expectedError]
},
{
code: "var b=10, a=b;",
output: null,
errors: [expectedError]
},
{
code: "var b = 0, a = `${b}`;",
output: null,
parserOptions: { ecmaVersion: 6 },
errors: [expectedError]
},
{
code: "var b = 0, a = `${f()}`",
output: null,
parserOptions: { ecmaVersion: 6 },
errors: [expectedError]
},
{
code: "var b = 0, c = b, a;",
output: null,
errors: [expectedError]
},
{
code: "var b = 0, c = 0, a = b + c;",
output: null,
errors: [expectedError]
},
{
code: "var b = f(), c, d, a;",
output: null,
errors: [expectedError]
},
{
code: "var b = `${f()}`, c, d, a;",
output: null,
parserOptions: { ecmaVersion: 6 },
errors: [expectedError]
},
{
code: "var c, a = b = 0",
output: null,
errors: [expectedError]
}
]
});

0 comments on commit 5619910

Please sign in to comment.