2 * @fileoverview Rule to require object keys to be sorted
3 * @author Toru Nagashima
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils = require("./utils/ast-utils"),
13 naturalCompare = require("natural-compare");
15 //------------------------------------------------------------------------------
17 //------------------------------------------------------------------------------
20 * Gets the property name of the given `Property` node.
22 * - If the property's key is an `Identifier` node, this returns the key's name
23 * whether it's a computed property or not.
24 * - If the property has a static name, this returns the static name.
25 * - Otherwise, this returns null.
26 * @param {ASTNode} node The `Property` node to get.
27 * @returns {string|null} The property name or null.
30 function getPropertyName(node) {
31 const staticName = astUtils.getStaticPropertyName(node);
33 if (staticName !== null) {
37 return node.key.name || null;
41 * Functions which check that the given 2 names are in specific order.
43 * Postfix `I` is meant insensitive.
44 * Postfix `N` is meant natural.
47 const isValidOrders = {
52 return a.toLowerCase() <= b.toLowerCase();
55 return naturalCompare(a, b) <= 0;
58 return naturalCompare(a.toLowerCase(), b.toLowerCase()) <= 0;
61 return isValidOrders.asc(b, a);
64 return isValidOrders.ascI(b, a);
67 return isValidOrders.ascN(b, a);
70 return isValidOrders.ascIN(b, a);
74 //------------------------------------------------------------------------------
76 //------------------------------------------------------------------------------
83 description: "require object keys to be sorted",
84 category: "Stylistic Issues",
86 url: "https://eslint.org/docs/rules/sort-keys"
110 additionalProperties: false
115 sortKeys: "Expected object keys to be in {{natural}}{{insensitive}}{{order}}ending order. '{{thisName}}' should be before '{{prevName}}'."
122 const order = context.options[0] || "asc";
123 const options = context.options[1];
124 const insensitive = options && options.caseSensitive === false;
125 const natural = options && options.natural;
126 const minKeys = options && options.minKeys;
127 const isValidOrder = isValidOrders[
128 order + (insensitive ? "I" : "") + (natural ? "N" : "")
131 // The stack to save the previous property's name for each object literals.
135 ObjectExpression(node) {
139 numKeys: node.properties.length
143 "ObjectExpression:exit"() {
147 SpreadElement(node) {
148 if (node.parent.type === "ObjectExpression") {
149 stack.prevName = null;
154 if (node.parent.type === "ObjectPattern") {
158 const prevName = stack.prevName;
159 const numKeys = stack.numKeys;
160 const thisName = getPropertyName(node);
162 if (thisName !== null) {
163 stack.prevName = thisName;
166 if (prevName === null || thisName === null || numKeys < minKeys) {
170 if (!isValidOrder(prevName, thisName)) {
174 messageId: "sortKeys",
179 insensitive: insensitive ? "insensitive " : "",
180 natural: natural ? "natural " : ""