eslint-plugin-sort
Advanced tools
Comparing version 1.2.1 to 1.3.0
@@ -7,6 +7,7 @@ "use strict"; | ||
var _sortObjectProperties = _interopRequireDefault(require("./rules/sort-object-properties")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
// import sortImports from "./rules/sort-imports" | ||
// import sortObjectProperties from "./rules/sort-object-properties" | ||
module.exports = { | ||
@@ -18,5 +19,5 @@ configs: { | ||
"sort/destructured-properties": "warn", | ||
"sort/imported-variables": "warn" // "sort/imports": "warn", | ||
// "sort/object-properties": "warn", | ||
"sort/imported-variables": "warn", | ||
// "sort/imports": "warn", | ||
"sort/object-properties": "warn" | ||
} | ||
@@ -27,6 +28,6 @@ } | ||
"destructured-properties": _sortObjectPatterns.default, | ||
"imported-variables": _sortImportSpecifiers.default // "imports": sortImports, | ||
// "object-properties": sortObjectProperties, | ||
"imported-variables": _sortImportSpecifiers.default, | ||
// "imports": sortImports, | ||
"object-properties": _sortObjectProperties.default | ||
} | ||
}; |
@@ -10,10 +10,8 @@ "use strict"; | ||
function getNodeText(node) { | ||
return node.imported.name; | ||
} | ||
const isImportSpecifier = node => node.type === "ImportSpecifier"; | ||
const getNodeSortValue = node => isImportSpecifier(node) ? getNodeText(node).toLowerCase() : -Infinity; | ||
const getNodeText = node => node.imported.name; | ||
const sortFn = node => isImportSpecifier(node) ? getNodeText(node).toLowerCase() : -Infinity; | ||
function autofix(context, node) { | ||
@@ -26,3 +24,3 @@ const source = context.getSourceCode(); | ||
fix(fixer) { | ||
const text = node.specifiers.slice().sort((0, _utils.getSorter)(getNodeSortValue)).reduce((acc, currentNode, index) => { | ||
const text = node.specifiers.slice().sort((0, _utils.getSorter)(sortFn)).reduce((acc, currentNode, index) => { | ||
return acc + (0, _utils.getTextWithComments)(source, currentNode) + (0, _utils.getTextBetweenNodes)(source, node.specifiers[index], node.specifiers[index + 1]); | ||
@@ -37,3 +35,4 @@ }, ""); | ||
function sort(node, context) { | ||
const specifiers = node.specifiers.filter(isImportSpecifier); // If there are less than two specifiers, there is nothing to sort. | ||
const specifiers = node.specifiers.filter(isImportSpecifier); | ||
let unsorted = false; // If there are less than two specifiers, there is nothing to sort. | ||
@@ -44,5 +43,4 @@ if (specifiers.length < 2) { | ||
let lastUnsortedNode = null; | ||
specifiers.reduce((previousNode, currentNode) => { | ||
if (getNodeSortValue(currentNode) < getNodeSortValue(previousNode)) { | ||
if (sortFn(currentNode) < sortFn(previousNode)) { | ||
context.report({ | ||
@@ -56,3 +54,3 @@ node: currentNode, | ||
}); | ||
lastUnsortedNode = currentNode; | ||
unsorted = true; | ||
} | ||
@@ -65,3 +63,3 @@ | ||
if (lastUnsortedNode) { | ||
if (unsorted) { | ||
autofix(context, node); | ||
@@ -68,0 +66,0 @@ } |
@@ -10,14 +10,4 @@ "use strict"; | ||
function getNodeText(node) { | ||
return node.key.name; | ||
} | ||
const sortFn = node => node.type === "RestElement" ? Infinity : (0, _utils.getSortValue)(node.key).toLowerCase(); | ||
function getNodeSortValue(node) { | ||
if (node.type === "RestElement") { | ||
return Infinity; | ||
} | ||
return getNodeText(node).toLowerCase(); | ||
} | ||
function autofix(context, node) { | ||
@@ -30,3 +20,3 @@ const source = context.getSourceCode(); | ||
fix(fixer) { | ||
const text = node.properties.slice().sort((0, _utils.getSorter)(getNodeSortValue)).reduce((acc, currentNode, index) => { | ||
const text = node.properties.slice().sort((0, _utils.getSorter)(sortFn)).reduce((acc, currentNode, index) => { | ||
return acc + (0, _utils.getTextWithComments)(source, currentNode) + (0, _utils.getTextBetweenNodes)(source, node.properties[index], node.properties[index + 1]); | ||
@@ -43,3 +33,4 @@ }, ""); | ||
function sort(node, context) { | ||
const properties = node.properties.filter(isProperty); // If there is one or less property, there is nothing to sort. | ||
const properties = node.properties.filter(isProperty); | ||
let unsorted = false; // If there is one or less property, there is nothing to sort. | ||
@@ -50,5 +41,4 @@ if (properties.length < 2) { | ||
let lastUnsortedNode = null; | ||
properties.reduce((previousNode, currentNode) => { | ||
if (getNodeSortValue(currentNode) < getNodeSortValue(previousNode)) { | ||
if ((0, _utils.isUnsorted)(previousNode.key, currentNode.key)) { | ||
context.report({ | ||
@@ -58,7 +48,7 @@ node: currentNode, | ||
data: { | ||
a: getNodeText(currentNode), | ||
b: getNodeText(previousNode) | ||
a: (0, _utils.getSortValue)(currentNode.key), | ||
b: (0, _utils.getSortValue)(previousNode.key) | ||
} | ||
}); | ||
lastUnsortedNode = currentNode; | ||
unsorted = true; | ||
} | ||
@@ -72,3 +62,3 @@ | ||
if (lastUnsortedNode) { | ||
if (unsorted) { | ||
autofix(context, node); | ||
@@ -75,0 +65,0 @@ } |
@@ -7,3 +7,91 @@ "use strict"; | ||
exports.default = void 0; | ||
var _default = {}; | ||
var _utils = require("./utils"); | ||
/** | ||
* When sorting object properties, we have to sort the groups of nodes between | ||
* spread elements since changing the location of the spread elements will | ||
* affect runtime. This method will split object properties into groups of nodes | ||
* between spread elements which can then be safely sorted. | ||
*/ | ||
function getNodeGroupsBetweenSpreads(node) { | ||
return node.properties.reduce((acc, property) => { | ||
if (property.type === "SpreadElement") { | ||
acc.push([]); | ||
} else { | ||
acc[acc.length - 1].push(property); | ||
} | ||
return acc; | ||
}, [[]]) // We only need to sort when there is more than one property | ||
.filter(group => group.length > 1); | ||
} | ||
function autofix(context, node) { | ||
const source = context.getSourceCode(); | ||
context.report({ | ||
node, | ||
messageId: "unsortedProperties", | ||
fix(fixer) { | ||
return getNodeGroupsBetweenSpreads(node).map((nodes, index) => { | ||
const text = nodes.slice().sort((0, _utils.getSorter)(node => (0, _utils.getSortValue)(node.key).toLowerCase())).reduce((acc, currentNode, idx, group) => { | ||
// The last node in the group should not get the text between itself | ||
// and the next property as the next property is a spread element | ||
// and is not part of the replaced text range. | ||
const endIndex = index + (idx < group.length - 1 ? 1 : 0); | ||
return acc + (0, _utils.getTextWithComments)(source, currentNode) + (0, _utils.getTextBetweenNodes)(source, node.properties[index], node.properties[endIndex]); | ||
}, ""); | ||
return fixer.replaceTextRange((0, _utils.getNodeGroupRange)(source, nodes), text); | ||
}); | ||
} | ||
}); | ||
} | ||
function sort(node, context) { | ||
let unsorted = false; | ||
getNodeGroupsBetweenSpreads(node).forEach(group => { | ||
group.reduce((previousNode, currentNode) => { | ||
if ((0, _utils.isUnsorted)(previousNode.key, currentNode.key)) { | ||
context.report({ | ||
node: currentNode, | ||
messageId: "unsorted", | ||
data: { | ||
a: (0, _utils.getSortValue)(currentNode.key), | ||
b: (0, _utils.getSortValue)(previousNode.key) | ||
} | ||
}); | ||
unsorted = true; | ||
} | ||
return currentNode; | ||
}); | ||
}); // If we fixed each set of unsorted nodes, it would require multiple runs to | ||
// fix if there are multiple unsorted nodes. Instead, we add a add special | ||
// error with an autofix rule which will sort all specifiers at once. | ||
if (unsorted) { | ||
autofix(context, node); | ||
} | ||
} | ||
var _default = { | ||
create(context) { | ||
return { | ||
ObjectExpression(node) { | ||
sort(node, context); | ||
} | ||
}; | ||
}, | ||
meta: { | ||
fixable: "code", | ||
messages: { | ||
unsorted: "Expected '{{a}}' to be before '{{b}}'.", | ||
unsortedProperties: "Expected object properties to be sorted." | ||
} | ||
} | ||
}; | ||
exports.default = _default; |
@@ -9,3 +9,4 @@ "use strict"; | ||
exports.getNodeGroupRange = getNodeGroupRange; | ||
exports.getTextBetweenNodes = void 0; | ||
exports.getSortValue = getSortValue; | ||
exports.isUnsorted = exports.getTextBetweenNodes = void 0; | ||
@@ -41,2 +42,25 @@ function getSorter(sortFn) { | ||
return getTextRange(source.getCommentsBefore(nodes[0])[0] || nodes[0], nodes[nodes.length - 1]); | ||
} | ||
} | ||
function getSortValue(node) { | ||
if (!node) { | ||
return ""; | ||
} | ||
switch (node.type) { | ||
case "Identifier": | ||
return node.name; | ||
case "Literal": | ||
return node.value.toString(); | ||
case "TemplateLiteral": | ||
return node.quasis.reduce((acc, quasi, index) => acc + quasi.value.raw + getSortValue(node.expressions[index]), ""); | ||
} | ||
return ""; | ||
} | ||
const isUnsorted = (a, b) => getSortValue(a).toLowerCase() > getSortValue(b).toLowerCase(); | ||
exports.isUnsorted = isUnsorted; |
{ | ||
"name": "eslint-plugin-sort", | ||
"description": "Autofixable sort rules for ESLint.", | ||
"version": "1.2.1", | ||
"version": "1.3.0", | ||
"author": "Mark Skelton", | ||
@@ -6,0 +6,0 @@ "repository": { |
@@ -35,5 +35,25 @@ # eslint-plugin-sort | ||
### `sort/object-properties` 🔧 | ||
Sorts object properties alphabetically and case insensitive in ascending order. | ||
Examples of **incorrect** code for this rule. | ||
```js | ||
var a = { b: 1, c: 2, a: 3 } | ||
var a = { C: 1, b: 2 } | ||
var a = { C: 1, b: { y: 1, x: 2 } } | ||
``` | ||
Examples of **correct** code for this rule. | ||
```js | ||
var a = { a: 1, b: 2, c: 3 } | ||
var a = { b: 1, C: 2 } | ||
var a = { b: { x: 1, y: 2 }, C: 1 } | ||
``` | ||
### `sort/destructured-properties` 🔧 | ||
Sorts properties in object destructuring patterns. | ||
Sorts properties in object destructuring patterns alphabetically and case insensitive in ascending order. | ||
@@ -58,3 +78,3 @@ Examples of **incorrect** code for this rule. | ||
Sorts imported variable names alphabetically and case insensitive. | ||
Sorts imported variable names alphabetically and case insensitive in ascending order. | ||
@@ -61,0 +81,0 @@ Examples of **incorrect** code for this rule. |
15985
289
114