diff --git a/conf/eslint.json b/conf/eslint.json index 95ef38e6000..3d7779ea065 100755 --- a/conf/eslint.json +++ b/conf/eslint.json @@ -207,6 +207,7 @@ "rest-spread-spacing": "off", "semi": "off", "semi-spacing": "off", + "sort-keys": "off", "sort-imports": "off", "sort-vars": "off", "space-before-blocks": "off", diff --git a/docs/rules/sort-imports.md b/docs/rules/sort-imports.md index 20398f3bcf8..b2539ba31ea 100644 --- a/docs/rules/sort-imports.md +++ b/docs/rules/sort-imports.md @@ -198,3 +198,8 @@ Default is `["none", "all", "multiple", "single"]`. ## When Not To Use It This rule is a formatting preference and not following it won't negatively affect the quality of your code. If alphabetizing imports isn't a part of your coding standards, then you can leave this rule disabled. + +## Related Rules + +* [sort-keys](http://eslint.org/docs/rules/sort-keys) +* [sort-vars](http://eslint.org/docs/rules/sort-vars) diff --git a/docs/rules/sort-keys.md b/docs/rules/sort-keys.md new file mode 100644 index 00000000000..5c685c167b6 --- /dev/null +++ b/docs/rules/sort-keys.md @@ -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) diff --git a/docs/rules/sort-vars.md b/docs/rules/sort-vars.md index 7e0f918377c..1bcfad4c86e 100644 --- a/docs/rules/sort-vars.md +++ b/docs/rules/sort-vars.md @@ -73,3 +73,8 @@ var a, B, c; ## When Not To Use It This rule is a formatting preference and not following it won't negatively affect the quality of your code. If you alphabetizing variables isn't a part of your coding standards, then you can leave this rule off. + +## Related Rules + +* [sort-keys](http://eslint.org/docs/rules/sort-keys) +* [sort-imports](http://eslint.org/docs/rules/sort-imports) diff --git a/lib/rules/sort-keys.js b/lib/rules/sort-keys.js new file mode 100644 index 00000000000..1c8a97b1d0b --- /dev/null +++ b/lib/rules/sort-keys.js @@ -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 " : "", + } + }); + } + } + }; + } +}; diff --git a/package.json b/package.json index 38b581efd47..882c6ea6fcc 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "levn": "^0.3.0", "lodash": "^4.0.0", "mkdirp": "^0.5.0", + "natural-compare": "^1.4.0", "optionator": "^0.8.1", "path-is-inside": "^1.0.1", "pluralize": "^1.2.1", diff --git a/tests/lib/rules/sort-keys.js b/tests/lib/rules/sort-keys.js new file mode 100644 index 00000000000..fc4f8145914 --- /dev/null +++ b/tests/lib/rules/sort-keys.js @@ -0,0 +1,586 @@ +/** + * @fileoverview Tests for sort-keys rule. + * @author Toru Nagashima + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require("../../../lib/rules/sort-keys"), + RuleTester = require("../../../lib/testers/rule-tester"); + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester(); + +ruleTester.run("sort-keys", rule, { + valid: [ + + // default (asc) + {code: "var obj = {_:2, a:1, b:3} // default", options: []}, + {code: "var obj = {a:1, b:3, c:2}", options: []}, + {code: "var obj = {a:2, b:3, b_:1}", options: []}, + {code: "var obj = {C:3, b_:1, c:2}", options: []}, + {code: "var obj = {$:1, A:3, _:2, a:4}", options: []}, + {code: "var obj = {1:1, '11':2, 2:4, A:3}", options: []}, + {code: "var obj = {'#':1, 'Z':2, À:3, è:4}", options: []}, + + // ignore non-simple computed properties. + {code: "var obj = {a:1, b:3, [a + b]: -1, c:2}", options: [], parserOptions: {ecmaVersion: 6}}, + + // ignore spred properties. + {code: "var obj = {a:1, ...z, b:1}", options: [], parserOptions: {ecmaVersion: 6, ecmaFeatures: {experimentalObjectRestSpread: true}}}, + + // nested + {code: "var obj = {a:1, b:{x:1, y:1}, c:1}", options: []}, + + // asc + {code: "var obj = {_:2, a:1, b:3} // asc", options: ["asc"]}, + {code: "var obj = {a:1, b:3, c:2}", options: ["asc"]}, + {code: "var obj = {a:2, b:3, b_:1}", options: ["asc"]}, + {code: "var obj = {C:3, b_:1, c:2}", options: ["asc"]}, + {code: "var obj = {$:1, A:3, _:2, a:4}", options: ["asc"]}, + {code: "var obj = {1:1, '11':2, 2:4, A:3}", options: ["asc"]}, + {code: "var obj = {'#':1, 'Z':2, À:3, è:4}", options: ["asc"]}, + + // asc, insensitive + {code: "var obj = {_:2, a:1, b:3} // asc, insensitive", options: ["asc", {caseSensitive: false}]}, + {code: "var obj = {a:1, b:3, c:2}", options: ["asc", {caseSensitive: false}]}, + {code: "var obj = {a:2, b:3, b_:1}", options: ["asc", {caseSensitive: false}]}, + {code: "var obj = {b_:1, C:3, c:2}", options: ["asc", {caseSensitive: false}]}, + {code: "var obj = {b_:1, c:3, C:2}", options: ["asc", {caseSensitive: false}]}, + {code: "var obj = {$:1, _:2, A:3, a:4}", options: ["asc", {caseSensitive: false}]}, + {code: "var obj = {1:1, '11':2, 2:4, A:3}", options: ["asc", {caseSensitive: false}]}, + {code: "var obj = {'#':1, 'Z':2, À:3, è:4}", options: ["asc", {caseSensitive: false}]}, + + // asc, natural + {code: "var obj = {_:2, a:1, b:3} // asc, natural", options: ["asc", {natural: true}]}, + {code: "var obj = {a:1, b:3, c:2}", options: ["asc", {natural: true}]}, + {code: "var obj = {a:2, b:3, b_:1}", options: ["asc", {natural: true}]}, + {code: "var obj = {C:3, b_:1, c:2}", options: ["asc", {natural: true}]}, + {code: "var obj = {$:1, _:2, A:3, a:4}", options: ["asc", {natural: true}]}, + {code: "var obj = {1:1, 2:4, '11':2, A:3}", options: ["asc", {natural: true}]}, + {code: "var obj = {'#':1, 'Z':2, À:3, è:4}", options: ["asc", {natural: true}]}, + + // asc, natural, insensitive + {code: "var obj = {_:2, a:1, b:3} // asc, natural, insensitive", options: ["asc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {a:1, b:3, c:2}", options: ["asc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {a:2, b:3, b_:1}", options: ["asc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {b_:1, C:3, c:2}", options: ["asc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {b_:1, c:3, C:2}", options: ["asc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {$:1, _:2, A:3, a:4}", options: ["asc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {1:1, 2:4, '11':2, A:3}", options: ["asc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {'#':1, 'Z':2, À:3, è:4}", options: ["asc", {natural: true, caseSensitive: false}]}, + + // desc + {code: "var obj = {b:3, a:1, _:2} // desc", options: ["desc"]}, + {code: "var obj = {c:2, b:3, a:1}", options: ["desc"]}, + {code: "var obj = {b_:1, b:3, a:2}", options: ["desc"]}, + {code: "var obj = {c:2, b_:1, C:3}", options: ["desc"]}, + {code: "var obj = {a:4, _:2, A:3, $:1}", options: ["desc"]}, + {code: "var obj = {A:3, 2:4, '11':2, 1:1}", options: ["desc"]}, + {code: "var obj = {è:4, À:3, 'Z':2, '#':1}", options: ["desc"]}, + + // desc, insensitive + {code: "var obj = {b:3, a:1, _:2} // desc, insensitive", options: ["desc", {caseSensitive: false}]}, + {code: "var obj = {c:2, b:3, a:1}", options: ["desc", {caseSensitive: false}]}, + {code: "var obj = {b_:1, b:3, a:2}", options: ["desc", {caseSensitive: false}]}, + {code: "var obj = {c:2, C:3, b_:1}", options: ["desc", {caseSensitive: false}]}, + {code: "var obj = {C:2, c:3, b_:1}", options: ["desc", {caseSensitive: false}]}, + {code: "var obj = {a:4, A:3, _:2, $:1}", options: ["desc", {caseSensitive: false}]}, + {code: "var obj = {A:3, 2:4, '11':2, 1:1}", options: ["desc", {caseSensitive: false}]}, + {code: "var obj = {è:4, À:3, 'Z':2, '#':1}", options: ["desc", {caseSensitive: false}]}, + + // desc, natural + {code: "var obj = {b:3, a:1, _:2} // desc, natural", options: ["desc", {natural: true}]}, + {code: "var obj = {c:2, b:3, a:1}", options: ["desc", {natural: true}]}, + {code: "var obj = {b_:1, b:3, a:2}", options: ["desc", {natural: true}]}, + {code: "var obj = {c:2, b_:1, C:3}", options: ["desc", {natural: true}]}, + {code: "var obj = {a:4, A:3, _:2, $:1}", options: ["desc", {natural: true}]}, + {code: "var obj = {A:3, '11':2, 2:4, 1:1}", options: ["desc", {natural: true}]}, + {code: "var obj = {è:4, À:3, 'Z':2, '#':1}", options: ["desc", {natural: true}]}, + + // desc, natural, insensitive + {code: "var obj = {b:3, a:1, _:2} // desc, natural, insensitive", options: ["desc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {c:2, b:3, a:1}", options: ["desc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {b_:1, b:3, a:2}", options: ["desc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {c:2, C:3, b_:1}", options: ["desc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {C:2, c:3, b_:1}", options: ["desc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {a:4, A:3, _:2, $:1}", options: ["desc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {A:3, '11':2, 2:4, 1:1}", options: ["desc", {natural: true, caseSensitive: false}]}, + {code: "var obj = {è:4, À:3, 'Z':2, '#':1}", options: ["desc", {natural: true, caseSensitive: false}]}, + ], + invalid: [ + + // default (asc) + { + code: "var obj = {a:1, _:2, b:3} // default", + errors: ["Expected object keys to be in ascending order. '_' should be before 'a'."] + }, + { + code: "var obj = {a:1, c:2, b:3}", + errors: ["Expected object keys to be in ascending order. 'b' should be before 'c'."] + }, + { + code: "var obj = {b_:1, a:2, b:3}", + errors: ["Expected object keys to be in ascending order. 'a' should be before 'b_'."] + }, + { + code: "var obj = {b_:1, c:2, C:3}", + errors: ["Expected object keys to be in ascending order. 'C' should be before 'c'."] + }, + { + code: "var obj = {$:1, _:2, A:3, a:4}", + errors: ["Expected object keys to be in ascending order. 'A' should be before '_'."] + }, + { + code: "var obj = {1:1, 2:4, A:3, '11':2}", + errors: ["Expected object keys to be in ascending order. '11' should be before 'A'."] + }, + { + code: "var obj = {'#':1, À:3, 'Z':2, è:4}", + errors: ["Expected object keys to be in ascending order. 'Z' should be before 'À'."] + }, + + // not ignore simple computed properties. + { + code: "var obj = {a:1, b:3, [a]: -1, c:2}", + parserOptions: {ecmaVersion: 6}, + errors: ["Expected object keys to be in ascending order. 'a' should be before 'b'."] + }, + + // ignore spred properties. + { + code: "var obj = {b:1, ...z, a:1}", + parserOptions: { + ecmaVersion: 6, + ecmaFeatures: {experimentalObjectRestSpread: true} + }, + errors: [ + "Expected object keys to be in ascending order. 'a' should be before 'b'.", + ] + }, + + // nested + { + code: "var obj = {a:1, c:{y:1, x:1}, b:1}", + errors: [ + "Expected object keys to be in ascending order. 'x' should be before 'y'.", + "Expected object keys to be in ascending order. 'b' should be before 'c'.", + ] + }, + + // asc + { + code: "var obj = {a:1, _:2, b:3} // asc", + options: ["asc"], + errors: [ + "Expected object keys to be in ascending order. '_' should be before 'a'.", + ] + }, + { + code: "var obj = {a:1, c:2, b:3}", + options: ["asc"], + errors: [ + "Expected object keys to be in ascending order. 'b' should be before 'c'.", + ] + }, + { + code: "var obj = {b_:1, a:2, b:3}", + options: ["asc"], + errors: [ + "Expected object keys to be in ascending order. 'a' should be before 'b_'.", + ] + }, + { + code: "var obj = {b_:1, c:2, C:3}", + options: ["asc"], + errors: [ + "Expected object keys to be in ascending order. 'C' should be before 'c'.", + ] + }, + { + code: "var obj = {$:1, _:2, A:3, a:4}", + options: ["asc"], + errors: [ + "Expected object keys to be in ascending order. 'A' should be before '_'.", + ] + }, + { + code: "var obj = {1:1, 2:4, A:3, '11':2}", + options: ["asc"], + errors: [ + "Expected object keys to be in ascending order. '11' should be before 'A'.", + ] + }, + { + code: "var obj = {'#':1, À:3, 'Z':2, è:4}", + options: ["asc"], + errors: [ + "Expected object keys to be in ascending order. 'Z' should be before 'À'.", + ] + }, + + // asc, insensitive + { + code: "var obj = {a:1, _:2, b:3} // asc, insensitive", + options: ["asc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive ascending order. '_' should be before 'a'.", + ] + }, + { + code: "var obj = {a:1, c:2, b:3}", + options: ["asc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive ascending order. 'b' should be before 'c'.", + ] + }, + { + code: "var obj = {b_:1, a:2, b:3}", + options: ["asc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive ascending order. 'a' should be before 'b_'.", + ] + }, + { + code: "var obj = {$:1, A:3, _:2, a:4}", + options: ["asc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive ascending order. '_' should be before 'A'.", + ] + }, + { + code: "var obj = {1:1, 2:4, A:3, '11':2}", + options: ["asc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive ascending order. '11' should be before 'A'.", + ] + }, + { + code: "var obj = {'#':1, À:3, 'Z':2, è:4}", + options: ["asc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive ascending order. 'Z' should be before 'À'.", + ] + }, + + // asc, natural + { + code: "var obj = {a:1, _:2, b:3} // asc, natural", + options: ["asc", {natural: true}], + errors: [ + "Expected object keys to be in natural ascending order. '_' should be before 'a'.", + ] + }, + { + code: "var obj = {a:1, c:2, b:3}", + options: ["asc", {natural: true}], + errors: [ + "Expected object keys to be in natural ascending order. 'b' should be before 'c'.", + ] + }, + { + code: "var obj = {b_:1, a:2, b:3}", + options: ["asc", {natural: true}], + errors: [ + "Expected object keys to be in natural ascending order. 'a' should be before 'b_'.", + ] + }, + { + code: "var obj = {b_:1, c:2, C:3}", + options: ["asc", {natural: true}], + errors: [ + "Expected object keys to be in natural ascending order. 'C' should be before 'c'.", + ] + }, + { + code: "var obj = {$:1, A:3, _:2, a:4}", + options: ["asc", {natural: true}], + errors: [ + "Expected object keys to be in natural ascending order. '_' should be before 'A'.", + ] + }, + { + code: "var obj = {1:1, 2:4, A:3, '11':2}", + options: ["asc", {natural: true}], + errors: [ + "Expected object keys to be in natural ascending order. '11' should be before 'A'.", + ] + }, + { + code: "var obj = {'#':1, À:3, 'Z':2, è:4}", + options: ["asc", {natural: true}], + errors: [ + "Expected object keys to be in natural ascending order. 'Z' should be before 'À'.", + ] + }, + + // asc, natural, insensitive + { + code: "var obj = {a:1, _:2, b:3} // asc, natural, insensitive", + options: ["asc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive ascending order. '_' should be before 'a'.", + ] + }, + { + code: "var obj = {a:1, c:2, b:3}", + options: ["asc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive ascending order. 'b' should be before 'c'.", + ] + }, + { + code: "var obj = {b_:1, a:2, b:3}", + options: ["asc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive ascending order. 'a' should be before 'b_'.", + ] + }, + { + code: "var obj = {$:1, A:3, _:2, a:4}", + options: ["asc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive ascending order. '_' should be before 'A'.", + ] + }, + { + code: "var obj = {1:1, '11':2, 2:4, A:3}", + options: ["asc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive ascending order. '2' should be before '11'.", + ] + }, + { + code: "var obj = {'#':1, À:3, 'Z':2, è:4}", + options: ["asc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive ascending order. 'Z' should be before 'À'.", + ] + }, + + // desc + { + code: "var obj = {a:1, _:2, b:3} // desc", + options: ["desc"], + errors: [ + "Expected object keys to be in descending order. 'b' should be before '_'.", + ] + }, + { + code: "var obj = {a:1, c:2, b:3}", + options: ["desc"], + errors: [ + "Expected object keys to be in descending order. 'c' should be before 'a'.", + ] + }, + { + code: "var obj = {b_:1, a:2, b:3}", + options: ["desc"], + errors: [ + "Expected object keys to be in descending order. 'b' should be before 'a'.", + ] + }, + { + code: "var obj = {b_:1, c:2, C:3}", + options: ["desc"], + errors: [ + "Expected object keys to be in descending order. 'c' should be before 'b_'.", + ] + }, + { + code: "var obj = {$:1, _:2, A:3, a:4}", + options: ["desc"], + errors: [ + "Expected object keys to be in descending order. '_' should be before '$'.", + "Expected object keys to be in descending order. 'a' should be before 'A'.", + ] + }, + { + code: "var obj = {1:1, 2:4, A:3, '11':2}", + options: ["desc"], + errors: [ + "Expected object keys to be in descending order. '2' should be before '1'.", + "Expected object keys to be in descending order. 'A' should be before '2'.", + ] + }, + { + code: "var obj = {'#':1, À:3, 'Z':2, è:4}", + options: ["desc"], + errors: [ + "Expected object keys to be in descending order. 'À' should be before '#'.", + "Expected object keys to be in descending order. 'è' should be before 'Z'.", + ] + }, + + // desc, insensitive + { + code: "var obj = {a:1, _:2, b:3} // desc, insensitive", + options: ["desc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive descending order. 'b' should be before '_'.", + ] + }, + { + code: "var obj = {a:1, c:2, b:3}", + options: ["desc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive descending order. 'c' should be before 'a'.", + ] + }, + { + code: "var obj = {b_:1, a:2, b:3}", + options: ["desc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive descending order. 'b' should be before 'a'.", + ] + }, + { + code: "var obj = {b_:1, c:2, C:3}", + options: ["desc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive descending order. 'c' should be before 'b_'.", + ] + }, + { + code: "var obj = {$:1, _:2, A:3, a:4}", + options: ["desc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive descending order. '_' should be before '$'.", + "Expected object keys to be in insensitive descending order. 'A' should be before '_'.", + ] + }, + { + code: "var obj = {1:1, 2:4, A:3, '11':2}", + options: ["desc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive descending order. '2' should be before '1'.", + "Expected object keys to be in insensitive descending order. 'A' should be before '2'.", + ] + }, + { + code: "var obj = {'#':1, À:3, 'Z':2, è:4}", + options: ["desc", {caseSensitive: false}], + errors: [ + "Expected object keys to be in insensitive descending order. 'À' should be before '#'.", + "Expected object keys to be in insensitive descending order. 'è' should be before 'Z'.", + ] + }, + + // desc, natural + { + code: "var obj = {a:1, _:2, b:3} // desc, natural", + options: ["desc", {natural: true}], + errors: [ + "Expected object keys to be in natural descending order. 'b' should be before '_'.", + ] + }, + { + code: "var obj = {a:1, c:2, b:3}", + options: ["desc", {natural: true}], + errors: [ + "Expected object keys to be in natural descending order. 'c' should be before 'a'.", + ] + }, + { + code: "var obj = {b_:1, a:2, b:3}", + options: ["desc", {natural: true}], + errors: [ + "Expected object keys to be in natural descending order. 'b' should be before 'a'.", + ] + }, + { + code: "var obj = {b_:1, c:2, C:3}", + options: ["desc", {natural: true}], + errors: [ + "Expected object keys to be in natural descending order. 'c' should be before 'b_'.", + ] + }, + { + code: "var obj = {$:1, _:2, A:3, a:4}", + options: ["desc", {natural: true}], + errors: [ + "Expected object keys to be in natural descending order. '_' should be before '$'.", + "Expected object keys to be in natural descending order. 'A' should be before '_'.", + "Expected object keys to be in natural descending order. 'a' should be before 'A'.", + ] + }, + { + code: "var obj = {1:1, 2:4, A:3, '11':2}", + options: ["desc", {natural: true}], + errors: [ + "Expected object keys to be in natural descending order. '2' should be before '1'.", + "Expected object keys to be in natural descending order. 'A' should be before '2'.", + ] + }, + { + code: "var obj = {'#':1, À:3, 'Z':2, è:4}", + options: ["desc", {natural: true}], + errors: [ + "Expected object keys to be in natural descending order. 'À' should be before '#'.", + "Expected object keys to be in natural descending order. 'è' should be before 'Z'.", + ] + }, + + // desc, natural, insensitive + { + code: "var obj = {a:1, _:2, b:3} // desc, natural, insensitive", + options: ["desc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive descending order. 'b' should be before '_'.", + ] + }, + { + code: "var obj = {a:1, c:2, b:3}", + options: ["desc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive descending order. 'c' should be before 'a'.", + ] + }, + { + code: "var obj = {b_:1, a:2, b:3}", + options: ["desc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive descending order. 'b' should be before 'a'.", + ] + }, + { + code: "var obj = {b_:1, c:2, C:3}", + options: ["desc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive descending order. 'c' should be before 'b_'.", + ] + }, + { + code: "var obj = {$:1, _:2, A:3, a:4}", + options: ["desc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive descending order. '_' should be before '$'.", + "Expected object keys to be in natural insensitive descending order. 'A' should be before '_'.", + ] + }, + { + code: "var obj = {1:1, 2:4, '11':2, A:3}", + options: ["desc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive descending order. '2' should be before '1'.", + "Expected object keys to be in natural insensitive descending order. '11' should be before '2'.", + "Expected object keys to be in natural insensitive descending order. 'A' should be before '11'.", + ] + }, + { + code: "var obj = {'#':1, À:3, 'Z':2, è:4}", + options: ["desc", {natural: true, caseSensitive: false}], + errors: [ + "Expected object keys to be in natural insensitive descending order. 'À' should be before '#'.", + "Expected object keys to be in natural insensitive descending order. 'è' should be before 'Z'.", + ] + }, + ] +});