-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e8cb7f9
commit f0cf240
Showing
7 changed files
with
913 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
# requires object keys to be sorted (sort-keys) | ||
|
||
When declaring multiple properties, some developers prefer to sort property names alphabetically to be able to find necessary property easier at the later time. Others feel that it adds complexity and becomes burden to maintain. | ||
|
||
## Rule Details | ||
|
||
This rule checks all property definitions of object expressions and verifies that all variables are sorted alphabetically. | ||
|
||
Examples of **incorrect** code for this rule: | ||
|
||
```js | ||
/*eslint sort-keys: "error"*/ | ||
/*eslint-env es6*/ | ||
|
||
let obj = {a: 1, c: 3, b: 2}; | ||
let obj = {a: 1, "c": 3, b: 2}; | ||
|
||
// Case-sensitive by default. | ||
let obj = {a: 1, b: 2, C: 3}; | ||
|
||
// Non-natural order by default. | ||
let obj = {1: a, 2: c, 10: b}; | ||
|
||
// This rule checks computed properties which have a simple name as well. | ||
// Simple names are names which are expressed by an Identifier node or a Literal node. | ||
const S = Symbol("s") | ||
let obj = {a: 1, ["c"]: 3, b: 2}; | ||
let obj = {a: 1, [S]: 3, b: 2}; | ||
``` | ||
|
||
Examples of **correct** code for this rule: | ||
|
||
```js | ||
/*eslint sort-keys: "error"*/ | ||
/*eslint-env es6*/ | ||
|
||
let obj = {a: 1, b: 2, c: 3}; | ||
let obj = {a: 1, "b": 2, c: 3}; | ||
|
||
// Case-sensitive by default. | ||
let obj = {C: 3, a: 1, b: 2}; | ||
|
||
// Non-natural order by default. | ||
let obj = {1: a, 10: b, 2: c}; | ||
|
||
// This rule checks computed properties which have a simple name as well. | ||
let obj = {a: 1, ["b"]: 2, c: 3}; | ||
let obj = {a: 1, [b]: 2, c: 3}; | ||
|
||
// This rule ignores computed properties which have a non-simple name. | ||
let obj = {a: 1, [c + d]: 3, b: 2}; | ||
let obj = {a: 1, ["c" + "d"]: 3, b: 2}; | ||
let obj = {a: 1, [`${c}`]: 3, b: 2}; | ||
let obj = {a: 1, [tag`c`]: 3, b: 2}; | ||
``` | ||
|
||
## Options | ||
|
||
```json | ||
{ | ||
"sort-keys": ["error", "asc", {"caseSensitive": true, "natural": false}] | ||
} | ||
``` | ||
|
||
The 1st option is `"asc"` or `"desc"`. | ||
|
||
* `"asc"` (default) - enforce properties to be in ascending order. | ||
* `"desc"` - enforce properties to be in descending order. | ||
|
||
The 2nd option is an object which has 2 properties. | ||
|
||
* `caseSensitive` - if `true`, enforce properties to be in case-sensitive order. Default is `true`. | ||
* `natural` - if `true`, enforce properties to be in natural order. Default is `false`. | ||
|
||
### desc | ||
|
||
Examples of **incorrect** code for the `"desc"` option: | ||
|
||
```js | ||
/*eslint sort-keys: ["error", "desc"]*/ | ||
/*eslint-env es6*/ | ||
|
||
let obj = {b: 2, c: 3, a: 1}; | ||
let obj = {"b": 2, c: 3, a: 1}; | ||
|
||
// Case-sensitive by default. | ||
let obj = {C: 1, b: 3, a: 2}; | ||
|
||
// Non-natural order by default. | ||
let obj = {10: b, 2: c, 1: a}; | ||
``` | ||
|
||
Examples of **correct** code for the `"desc"` option: | ||
|
||
```js | ||
/*eslint sort-keys: ["error", "desc"]*/ | ||
/*eslint-env es6*/ | ||
|
||
let obj = {c: 3, b: 2, a: 1}; | ||
let obj = {c: 3, "b": 2, a: 1}; | ||
|
||
// Case-sensitive by default. | ||
let obj = {b: 3, a: 2, C: 1}; | ||
|
||
// Non-natural order by default. | ||
let obj = {2: c, 10: b, 1: a}; | ||
``` | ||
|
||
### insensitive | ||
|
||
Examples of **incorrect** code for the `{caseSensitive: false}` option: | ||
|
||
```js | ||
/*eslint sort-keys: ["error", "asc", {caseSensitive: false}]*/ | ||
/*eslint-env es6*/ | ||
|
||
let obj = {a: 1, c: 3, C: 4, b: 2}; | ||
let obj = {a: 1, C: 3, c: 4, b: 2}; | ||
``` | ||
|
||
Examples of **correct** code for the `{caseSensitive: false}` option: | ||
|
||
```js | ||
/*eslint sort-keys: ["error", "asc", {caseSensitive: false}]*/ | ||
/*eslint-env es6*/ | ||
|
||
let obj = {a: 1, b: 2, c: 3, C: 4}; | ||
let obj = {a: 1, b: 2, C: 3, c: 4}; | ||
``` | ||
|
||
### natural | ||
|
||
Examples of **incorrect** code for the `{natural: true}` option: | ||
|
||
```js | ||
/*eslint sort-keys: ["error", "asc", {natural: true}]*/ | ||
/*eslint-env es6*/ | ||
|
||
let obj = {1: a, 10: c, 2: b}; | ||
``` | ||
|
||
Examples of **correct** code for the `{natural: true}` option: | ||
|
||
```js | ||
/*eslint sort-keys: ["error", "asc", {natural: true}]*/ | ||
/*eslint-env es6*/ | ||
|
||
let obj = {1: a, 2: b, 10: c}; | ||
``` | ||
|
||
## When Not To Use It | ||
|
||
If you don't want to notify about properties' order, then it's safe to disable this rule. | ||
|
||
## Related Rules | ||
|
||
* [sort-imports](http://eslint.org/docs/rules/sort-imports) | ||
* [sort-vars](http://eslint.org/docs/rules/sort-vars) | ||
|
||
## Compatibility | ||
|
||
* **JSCS:** [validateOrderInObjectKeys](http://jscs.info/rule/validateOrderInObjectKeys) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/** | ||
* @fileoverview Rule to requires object keys to be sorted | ||
* @author Toru Nagashima | ||
*/ | ||
|
||
"use strict"; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Requirements | ||
//------------------------------------------------------------------------------ | ||
|
||
const astUtils = require("../ast-utils"), | ||
naturalCompare = require("natural-compare"); | ||
|
||
//------------------------------------------------------------------------------ | ||
// Helpers | ||
//------------------------------------------------------------------------------ | ||
|
||
/** | ||
* Gets the property name of the given `Property` node. | ||
* | ||
* - If the property's key is an `Identifier` node, this returns the key's name | ||
* whether it's a computed property or not. | ||
* - If the property has a static name, this returns the static name. | ||
* - Otherwise, this returns null. | ||
* | ||
* @param {ASTNode} node - The `Property` node to get. | ||
* @returns {string|null} The property name or null. | ||
* @private | ||
*/ | ||
function getPropertyName(node) { | ||
return astUtils.getStaticPropertyName(node) || node.key.name || null; | ||
} | ||
|
||
/** | ||
* Functions which check that the given 2 names are in specific order. | ||
* | ||
* Postfix `I` is meant insensitive. | ||
* Postfix `N` is meant natual. | ||
* | ||
* @private | ||
*/ | ||
const isValidOrders = { | ||
asc(a, b) { | ||
return a <= b; | ||
}, | ||
ascI(a, b) { | ||
return a.toLowerCase() <= b.toLowerCase(); | ||
}, | ||
ascN(a, b) { | ||
return naturalCompare(a, b) <= 0; | ||
}, | ||
ascIN(a, b) { | ||
return naturalCompare(a.toLowerCase(), b.toLowerCase()) <= 0; | ||
}, | ||
desc(a, b) { | ||
return isValidOrders.asc(b, a); | ||
}, | ||
descI(a, b) { | ||
return isValidOrders.ascI(b, a); | ||
}, | ||
descN(a, b) { | ||
return isValidOrders.ascN(b, a); | ||
}, | ||
descIN(a, b) { | ||
return isValidOrders.ascIN(b, a); | ||
}, | ||
}; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Rule Definition | ||
//------------------------------------------------------------------------------ | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: "requires object keys to be sorted", | ||
category: "Stylistic Issues", | ||
recommended: false | ||
}, | ||
schema: [ | ||
{ | ||
enum: ["asc", "desc"] | ||
}, | ||
{ | ||
type: "object", | ||
properties: { | ||
caseSensitive: { | ||
type: "boolean" | ||
}, | ||
natural: { | ||
type: "boolean" | ||
} | ||
}, | ||
additionalProperties: false | ||
} | ||
] | ||
}, | ||
|
||
create: function(context) { | ||
|
||
// Parse options. | ||
const order = context.options[0] || "asc"; | ||
const options = context.options[1]; | ||
const insensitive = (options && options.caseSensitive) === false; | ||
const natual = Boolean(options && options.natural); | ||
const isValidOrder = isValidOrders[ | ||
order + (insensitive ? "I" : "") + (natual ? "N" : "") | ||
]; | ||
|
||
// The stack to save the previous property's name for each object literals. | ||
let stack = null; | ||
|
||
return { | ||
ObjectExpression() { | ||
stack = { | ||
upper: stack, | ||
prevName: null | ||
}; | ||
}, | ||
|
||
"ObjectExpression:exit"() { | ||
stack = stack.upper; | ||
}, | ||
|
||
Property(node) { | ||
const prevName = stack.prevName; | ||
const thisName = getPropertyName(node); | ||
|
||
stack.prevName = thisName || prevName; | ||
|
||
if (!prevName || !thisName) { | ||
return; | ||
} | ||
|
||
if (!isValidOrder(prevName, thisName)) { | ||
context.report({ | ||
node: node, | ||
loc: node.key.loc, | ||
message: "Expected object keys to be in {{natual}}{{insensitive}}{{order}}ending order. '{{thisName}}' should be before '{{prevName}}'.", | ||
data: { | ||
thisName, | ||
prevName, | ||
order, | ||
insensitive: insensitive ? "insensitive " : "", | ||
natual: natual ? "natural " : "", | ||
} | ||
}); | ||
} | ||
} | ||
}; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.