eslint-plugin-simple-sort-keys
v1.0.1
Published
ESLint plugin to sort object keys with autofix
Maintainers
Readme
eslint-plugin-simple-sort-keys
Sort object keys alphabetically — with autofix.
The rule logic is based on ESLint's built-in sort-keys, extended with an autofix that reorders properties in one shot, and a plugin structure that mirrors eslint-plugin-simple-import-sort.
Why this plugin?
sort-keys only reports violations; it cannot fix them. This plugin adds the missing autofix so you can enforce sorted keys and let the linter clean them up automatically, the same way eslint-plugin-simple-import-sort does for imports.
Installation
npm install --save-dev eslint-plugin-simple-sort-keysPeer dependency:
eslint≥ 9 (flat config required). Node.js: ≥ 18.18.0
Usage
Flat config (eslint.config.js)
import simpleKeySort from 'eslint-plugin-simple-sort-keys'
export default [
{
plugins: {
'simple-sort-keys': simpleKeySort,
},
rules: {
'simple-sort-keys/sort': 'error',
},
},
]With options
'simple-sort-keys/sort': [
'error',
'asc',
{
allowLineSeparatedGroups: false,
caseSensitive: true,
ignoreComputedKeys: false,
minKeys: 2,
natural: false,
},
]Rule: simple-sort-keys/sort
Requires all object keys to be sorted. Reports a single error per unsorted group and provides an autofix that sorts the entire group at once.
Note: Only object expressions (
{ key: value }) are affected. Destructuring patterns (const { b, a } = obj) are intentionally ignored.
Options
Argument 1 — order
"asc" (default) | "desc"
Direction of the sort.
// ✓ "asc"
const a = { bar: 2, foo: 1 }
// ✓ "desc"
const b = { foo: 1, bar: 2 }Argument 2 — options object
| Option | Type | Default | Description |
|---|---|---|---|
| allowLineSeparatedGroups | boolean | false | When true, a blank line between properties starts a new independent sort group. Keys in different groups are not compared with each other. |
| caseSensitive | boolean | true | When true, uppercase letters sort before lowercase (A < a). When false, case is ignored during comparison. |
| ignoreComputedKeys | boolean | false | When true, a computed property with a dynamic key (e.g. { [expr]: 1 }) acts as a group separator. When false (default), dynamic computed keys are skipped during comparison and left in place. Computed properties with static literal keys (e.g. { ["foo"]: 1 }) are always sortable. |
| minKeys | integer (≥ 2) | 2 | Minimum number of keys in an object before the rule is enforced. |
| natural | boolean | false | When true, uses natural sort order so that digit sequences are compared numerically (item2 before item10). |
Examples
allowLineSeparatedGroups
/* eslint simple-sort-keys/sort: ["error", "asc", { allowLineSeparatedGroups: true }] */
// ✓ each blank-line group is sorted independently
const config = {
alpha: 1,
beta: 2,
x: 10,
y: 20,
}
// ✗ within a group, keys must still be sorted
const config = {
beta: 2, // ← "Run autofix to sort these keys!"
alpha: 1,
}caseSensitive
/* eslint simple-sort-keys/sort: ["error", "asc", { caseSensitive: true }] */
// ✓ uppercase before lowercase (Unicode order)
const a = { Bar: 1, foo: 2 }
/* eslint simple-sort-keys/sort: ["error", "asc", { caseSensitive: false }] */
// ✓ case is ignored, so "bar" and "Bar" are equivalent
const b = { Bar: 1, foo: 2 }
const c = { bar: 1, Foo: 2 }ignoreComputedKeys
/* eslint simple-sort-keys/sort: ["error", "asc", { ignoreComputedKeys: true }] */
const KEY = 'dynamic'
// ✓ the dynamic computed key resets sorting; each segment is sorted independently
const a = {
alpha: 1,
beta: 2,
[KEY]: 3, // ← group separator
x: 4,
y: 5,
}
// ✓ computed keys with a literal value are still sorted
const b = { ["bar"]: 1, ["foo"]: 2 }With the default (ignoreComputedKeys: false), dynamic computed keys are skipped during comparison and left in place:
// ✓ [getKey()] is skipped; a and b are compared with each other
const c = { [getKey()]: 1, a: 2, b: 3 }minKeys
/* eslint simple-sort-keys/sort: ["error", "asc", { minKeys: 3 }] */
// ✓ only 2 keys — below the threshold
const a = { b: 2, a: 1 }
// ✗ 3 keys — rule is active
const b = { c: 3, a: 1, b: 2 }natural
/* eslint simple-sort-keys/sort: ["error", "asc", { natural: true }] */
// ✓ natural order treats digit sequences as numbers
const a = {
item1: true,
item2: true,
item10: true, // after item2, not after item1
}
/* eslint simple-sort-keys/sort: ["error", "asc", { natural: false }] */
// ✓ lexicographic order
const b = {
item1: true,
item10: true, // "10" < "2" lexicographically
item2: true,
}Numeric keys: Numeric literal keys (e.g.
{ 1: 'a', 2: 'b', 10: 'c' }) are compared as strings by default, so"10"sorts before"2". Usenatural: trueto compare them numerically.
Spread elements
Spread elements (...obj) always act as group separators. Keys before and after a spread are sorted independently so that spreading semantics are never broken.
// ✓
const merged = {
alpha: 1,
beta: 2,
...defaults,
x: 10,
y: 20,
}Autofix
When the rule reports a violation, running eslint --fix (or the editor quick-fix action) reorders all keys in the unsorted group in a single operation.
The fixer preserves surrounding context exactly:
- Leading comments (lines above a key) travel with the key they annotate.
- Inline trailing comments (on the same line as the value) travel with their key.
- Trailing commas move with the property. If a property that had no trailing comma ends up in a non-last position, a comma is inserted automatically.
// Before fix
const options = {
// network
timeout: 5000,
method: 'GET', // ← "Run autofix to sort these keys!"
baseUrl: 'https://api.example.com', // base
}
// After fix
const options = {
baseUrl: 'https://api.example.com', // base
method: 'GET',
// network
timeout: 5000,
}Comparison with sort-keys
| Feature | sort-keys | simple-sort-keys/sort |
|---|---|---|
| Autofix | No | Yes |
| Spread separators | Yes | Yes |
| allowLineSeparatedGroups | Yes | Yes |
| caseSensitive | Yes | Yes |
| ignoreComputedKeys | Yes | Yes |
| minKeys | Yes | Yes |
| natural | Yes | Yes |
| Error per key | Yes (one per violation) | No (one per group) |
Development
npm testTests use Node.js's built-in test runner (node --test) with ESLint's RuleTester.
License
MIT © Joaquin Aguirre
