e85c6534e3a1896cea52304dc056e46f3cfc97f6
[dotfiles/.git] / sort-vars.js
1 /**
2  * @fileoverview Rule to require sorting of variables within a single Variable Declaration block
3  * @author Ilya Volodin
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 module.exports = {
13     meta: {
14         type: "suggestion",
15
16         docs: {
17             description: "require variables within the same declaration block to be sorted",
18             category: "Stylistic Issues",
19             recommended: false,
20             url: "https://eslint.org/docs/rules/sort-vars"
21         },
22
23         schema: [
24             {
25                 type: "object",
26                 properties: {
27                     ignoreCase: {
28                         type: "boolean",
29                         default: false
30                     }
31                 },
32                 additionalProperties: false
33             }
34         ],
35
36         fixable: "code"
37     },
38
39     create(context) {
40
41         const configuration = context.options[0] || {},
42             ignoreCase = configuration.ignoreCase || false,
43             sourceCode = context.getSourceCode();
44
45         return {
46             VariableDeclaration(node) {
47                 const idDeclarations = node.declarations.filter(decl => decl.id.type === "Identifier");
48                 const getSortableName = ignoreCase ? decl => decl.id.name.toLowerCase() : decl => decl.id.name;
49                 const unfixable = idDeclarations.some(decl => decl.init !== null && decl.init.type !== "Literal");
50                 let fixed = false;
51
52                 idDeclarations.slice(1).reduce((memo, decl) => {
53                     const lastVariableName = getSortableName(memo),
54                         currentVariableName = getSortableName(decl);
55
56                     if (currentVariableName < lastVariableName) {
57                         context.report({
58                             node: decl,
59                             message: "Variables within the same declaration block should be sorted alphabetically.",
60                             fix(fixer) {
61                                 if (unfixable || fixed) {
62                                     return null;
63                                 }
64                                 return fixer.replaceTextRange(
65                                     [idDeclarations[0].range[0], idDeclarations[idDeclarations.length - 1].range[1]],
66                                     idDeclarations
67
68                                         // Clone the idDeclarations array to avoid mutating it
69                                         .slice()
70
71                                         // Sort the array into the desired order
72                                         .sort((declA, declB) => {
73                                             const aName = getSortableName(declA);
74                                             const bName = getSortableName(declB);
75
76                                             return aName > bName ? 1 : -1;
77                                         })
78
79                                         // Build a string out of the sorted list of identifier declarations and the text between the originals
80                                         .reduce((sourceText, identifier, index) => {
81                                             const textAfterIdentifier = index === idDeclarations.length - 1
82                                                 ? ""
83                                                 : sourceCode.getText().slice(idDeclarations[index].range[1], idDeclarations[index + 1].range[0]);
84
85                                             return sourceText + sourceCode.getText(identifier) + textAfterIdentifier;
86                                         }, "")
87
88                                 );
89                             }
90                         });
91                         fixed = true;
92                         return memo;
93                     }
94                     return decl;
95
96                 }, idDeclarations[0]);
97             }
98         };
99     }
100 };