diff --git a/docs/rules/sort-array-includes.md b/docs/rules/sort-array-includes.md index f109a12b..87d32488 100644 --- a/docs/rules/sort-array-includes.md +++ b/docs/rules/sort-array-includes.md @@ -81,6 +81,10 @@ This rule aims to promote code readability and maintainability by enforcing a co - `asc` - enforce properties to be in ascending order. - `desc` - enforce properties to be in descending order. +### `ignore-case` + +- `boolean` (default: `false`) - only affects alphabetical and natural sorting. When `true` the rule ignores the case-sensitivity of the order. + ### `spreadLast` - `boolean` (default: `false`) - enforce spread elements in array to be last diff --git a/docs/rules/sort-enums.md b/docs/rules/sort-enums.md index 8eda0fac..71de18cb 100644 --- a/docs/rules/sort-enums.md +++ b/docs/rules/sort-enums.md @@ -75,6 +75,10 @@ enum Hinamizawa { - `asc` - enforce properties to be in ascending order. - `desc` - enforce properties to be in descending order. +### `ignore-case` + +- `boolean` (default: `false`) - only affects alphabetical and natural sorting. When `true` the rule ignores the case-sensitivity of the order. + ## ⚙️ Usage ### Legacy Config diff --git a/docs/rules/sort-imports.md b/docs/rules/sort-imports.md index 40bfd353..7ff5d740 100644 --- a/docs/rules/sort-imports.md +++ b/docs/rules/sort-imports.md @@ -151,6 +151,10 @@ import './style.css' - `asc` - enforce properties to be in ascending order. - `desc` - enforce properties to be in descending order. +### `ignore-case` + +- `boolean` (default: `false`) - only affects alphabetical and natural sorting. When `true` the rule ignores the case-sensitivity of the order. + ### `groups` - `[array]` diff --git a/docs/rules/sort-interfaces.md b/docs/rules/sort-interfaces.md index c53ac3ee..c6add824 100644 --- a/docs/rules/sort-interfaces.md +++ b/docs/rules/sort-interfaces.md @@ -83,6 +83,10 @@ interface Hero { - `asc` - enforce properties to be in ascending order. - `desc` - enforce properties to be in descending order. +### `ignore-case` + +- `boolean` (default: `false`) - only affects alphabetical and natural sorting. When `true` the rule ignores the case-sensitivity of the order. + ### `ignore-pattern` - `[string]` (default: `[]`) - allows to ignore interface by pattern diff --git a/docs/rules/sort-jsx-props.md b/docs/rules/sort-jsx-props.md index 839eb2f7..c225896f 100644 --- a/docs/rules/sort-jsx-props.md +++ b/docs/rules/sort-jsx-props.md @@ -91,6 +91,10 @@ let Riko = () => ( - `asc` - enforce properties to be in ascending order. - `desc` - enforce properties to be in descending order. +### `ignore-case` + +- `boolean` (default: `false`) - only affects alphabetical and natural sorting. When `true` the rule ignores the case-sensitivity of the order. + ## ⚙️ Usage ### Legacy Config diff --git a/docs/rules/sort-map-elements.md b/docs/rules/sort-map-elements.md index ca7dd93a..a1d580fe 100644 --- a/docs/rules/sort-map-elements.md +++ b/docs/rules/sort-map-elements.md @@ -79,6 +79,10 @@ let bebop = Map([ - `asc` - enforce properties to be in ascending order. - `desc` - enforce properties to be in descending order. +### `ignore-case` + +- `boolean` (default: `false`) - only affects alphabetical and natural sorting. When `true` the rule ignores the case-sensitivity of the order. + ## ⚙️ Usage ### Legacy Config diff --git a/docs/rules/sort-named-exports.md b/docs/rules/sort-named-exports.md index 56920c41..ab061709 100644 --- a/docs/rules/sort-named-exports.md +++ b/docs/rules/sort-named-exports.md @@ -79,6 +79,10 @@ export { - `asc` - enforce properties to be in ascending order. - `desc` - enforce properties to be in descending order. +### `ignore-case` + +- `boolean` (default: `false`) - only affects alphabetical and natural sorting. When `true` the rule ignores the case-sensitivity of the order. + ## ⚙️ Usage ### Legacy Config diff --git a/docs/rules/sort-named-imports.md b/docs/rules/sort-named-imports.md index 08e697f5..dec55c46 100644 --- a/docs/rules/sort-named-imports.md +++ b/docs/rules/sort-named-imports.md @@ -83,6 +83,10 @@ export { - `asc` - enforce properties to be in ascending order. - `desc` - enforce properties to be in descending order. +### `ignore-case` + +- `boolean` (default: `false`) - only affects alphabetical and natural sorting. When `true` the rule ignores the case-sensitivity of the order. + ## ⚙️ Usage ### Legacy Config diff --git a/docs/rules/sort-object-keys.md b/docs/rules/sort-object-keys.md index 50bd6d9e..9440c0ba 100644 --- a/docs/rules/sort-object-keys.md +++ b/docs/rules/sort-object-keys.md @@ -77,6 +77,10 @@ let family = { - `asc` - enforce properties to be in ascending order. - `desc` - enforce properties to be in descending order. +### `ignore-case` + +- `boolean` (default: `false`) - only affects alphabetical and natural sorting. When `true` the rule ignores the case-sensitivity of the order. + ## ⚙️ Usage ### Legacy Config diff --git a/docs/rules/sort-union-types.md b/docs/rules/sort-union-types.md index 2b3e4bb7..b34d6d03 100644 --- a/docs/rules/sort-union-types.md +++ b/docs/rules/sort-union-types.md @@ -79,6 +79,10 @@ type DevilHunter = - `asc` - enforce properties to be in ascending order. - `desc` - enforce properties to be in descending order. +### `ignore-case` + +- `boolean` (default: `false`) - only affects alphabetical and natural sorting. When `true` the rule ignores the case-sensitivity of the order. + ## ⚙️ Usage ### Legacy Config diff --git a/index.ts b/index.ts index b6320b58..7eb69f14 100644 --- a/index.ts +++ b/index.ts @@ -18,6 +18,7 @@ type RuleDeclaration = [RuleSeverity, { [key: string]: unknown }?] let createConfigWithOptions = (options: { type: SortType order: SortOrder + 'ignore-case'?: boolean }): { plugins: ['perfectionist'] rules: { @@ -84,10 +85,12 @@ export default { 'recommended-alphabetical': createConfigWithOptions({ type: SortType.alphabetical, order: SortOrder.asc, + 'ignore-case': false, }), 'recommended-natural': createConfigWithOptions({ type: SortType.natural, order: SortOrder.asc, + 'ignore-case': false, }), 'recommended-line-length': createConfigWithOptions({ type: SortType['line-length'], diff --git a/rules/sort-array-includes.ts b/rules/sort-array-includes.ts index acf9e1dc..637958df 100644 --- a/rules/sort-array-includes.ts +++ b/rules/sort-array-includes.ts @@ -16,9 +16,10 @@ type MESSAGE_ID = 'unexpectedArrayIncludesOrder' type Options = [ Partial<{ + spreadLast: boolean + 'ignore-case': boolean order: SortOrder type: SortType - spreadLast: boolean }>, ] @@ -49,6 +50,10 @@ export default createEslintRule({ enum: [SortOrder.asc, SortOrder.desc], default: SortOrder.asc, }, + 'ignore-case': { + type: 'boolean', + default: false, + }, spreadLast: { type: 'boolean', default: false, @@ -79,6 +84,7 @@ export default createEslintRule({ let options = complete(context.options.at(0), { type: SortType.alphabetical, order: SortOrder.asc, + 'ignore-case': false, spreadLast: false, }) diff --git a/rules/sort-enums.ts b/rules/sort-enums.ts index 3797307b..cf6fe5d4 100644 --- a/rules/sort-enums.ts +++ b/rules/sort-enums.ts @@ -15,6 +15,7 @@ type MESSAGE_ID = 'unexpectedEnumsOrder' type Options = [ Partial<{ + 'ignore-case': boolean order: SortOrder type: SortType }>, @@ -43,6 +44,10 @@ export default createEslintRule({ ], default: SortType.natural, }, + 'ignore-case': { + type: 'boolean', + default: false, + }, order: { enum: [SortOrder.asc, SortOrder.desc], default: SortOrder.asc, @@ -66,6 +71,7 @@ export default createEslintRule({ let options = complete(context.options.at(0), { type: SortType.alphabetical, order: SortOrder.asc, + 'ignore-case': false, }) if (node.members.length > 1) { diff --git a/rules/sort-imports.ts b/rules/sort-imports.ts index bd562397..1e734cf2 100644 --- a/rules/sort-imports.ts +++ b/rules/sort-imports.ts @@ -50,6 +50,7 @@ type Options = [ 'internal-pattern': string[] groups: (Group[] | Group)[] 'read-tsconfig': boolean + 'ignore-case': boolean }>, ] @@ -86,6 +87,10 @@ export default createEslintRule({ enum: [SortOrder.asc, SortOrder.desc], default: SortOrder.asc, }, + 'ignore-case': { + type: 'boolean', + default: false, + }, groups: { type: 'array', default: [], @@ -132,6 +137,7 @@ export default createEslintRule({ type: SortType.alphabetical, 'read-tsconfig': false, order: SortOrder.asc, + 'ignore-case': false, groups: ['unknown'], }) diff --git a/rules/sort-interfaces.ts b/rules/sort-interfaces.ts index 488350fe..34146492 100644 --- a/rules/sort-interfaces.ts +++ b/rules/sort-interfaces.ts @@ -18,6 +18,7 @@ type Options = [ Partial<{ order: SortOrder type: SortType + 'ignore-case': boolean 'ignore-pattern': string[] }>, ] @@ -49,6 +50,10 @@ export default createEslintRule({ enum: [SortOrder.asc, SortOrder.desc], default: SortOrder.asc, }, + 'ignore-case': { + type: 'boolean', + default: false, + }, 'ignore-pattern': { type: 'array', default: [], @@ -72,6 +77,7 @@ export default createEslintRule({ TSInterfaceDeclaration: node => { let options = complete(context.options.at(0), { type: SortType.alphabetical, + 'ignore-case': false, order: SortOrder.asc, 'ignore-pattern': [], }) diff --git a/rules/sort-jsx-props.ts b/rules/sort-jsx-props.ts index c8a392db..ea83ae03 100644 --- a/rules/sort-jsx-props.ts +++ b/rules/sort-jsx-props.ts @@ -18,6 +18,7 @@ type Options = [ Partial<{ order: SortOrder type: SortType + 'ignore-case': boolean }>, ] @@ -48,6 +49,10 @@ export default createEslintRule({ enum: [SortOrder.asc, SortOrder.desc], default: SortOrder.asc, }, + 'ignore-case': { + type: 'boolean', + default: false, + }, }, additionalProperties: false, }, @@ -67,6 +72,7 @@ export default createEslintRule({ JSXElement: node => { let options = complete(context.options.at(0), { type: SortType.alphabetical, + 'ignore-case': false, order: SortOrder.asc, }) diff --git a/rules/sort-map-elements.ts b/rules/sort-map-elements.ts index b4e8c349..e8f263d3 100644 --- a/rules/sort-map-elements.ts +++ b/rules/sort-map-elements.ts @@ -16,6 +16,7 @@ type MESSAGE_ID = 'unexpectedMapElementsOrder' type Options = [ Partial<{ + 'ignore-case': boolean order: SortOrder type: SortType }>, @@ -48,6 +49,10 @@ export default createEslintRule({ enum: [SortOrder.asc, SortOrder.desc], default: SortOrder.asc, }, + 'ignore-case': { + type: 'boolean', + default: false, + }, }, additionalProperties: false, }, @@ -72,6 +77,7 @@ export default createEslintRule({ ) { let options = complete(context.options.at(0), { type: SortType.alphabetical, + 'ignore-case': false, order: SortOrder.asc, }) diff --git a/rules/sort-named-exports.ts b/rules/sort-named-exports.ts index 0fe04139..d51f2b31 100644 --- a/rules/sort-named-exports.ts +++ b/rules/sort-named-exports.ts @@ -13,6 +13,7 @@ type MESSAGE_ID = 'unexpectedNamedExportsOrder' type Options = [ Partial<{ + 'ignore-case': boolean order: SortOrder type: SortType }>, @@ -45,6 +46,10 @@ export default createEslintRule({ enum: [SortOrder.asc, SortOrder.desc], default: SortOrder.asc, }, + 'ignore-case': { + type: 'boolean', + default: false, + }, }, additionalProperties: false, }, @@ -64,6 +69,7 @@ export default createEslintRule({ ExportNamedDeclaration: node => { let options = complete(context.options.at(0), { type: SortType.alphabetical, + 'ignore-case': false, order: SortOrder.asc, }) diff --git a/rules/sort-named-imports.ts b/rules/sort-named-imports.ts index 103630e2..b7d86d49 100644 --- a/rules/sort-named-imports.ts +++ b/rules/sort-named-imports.ts @@ -13,6 +13,7 @@ type MESSAGE_ID = 'unexpectedNamedImportsOrder' type Options = [ Partial<{ + 'ignore-case': boolean order: SortOrder type: SortType }>, @@ -45,6 +46,10 @@ export default createEslintRule({ enum: [SortOrder.asc, SortOrder.desc], default: SortOrder.asc, }, + 'ignore-case': { + type: 'boolean', + default: false, + }, }, additionalProperties: false, }, @@ -64,6 +69,7 @@ export default createEslintRule({ ImportDeclaration: node => { let options = complete(context.options.at(0), { type: SortType.alphabetical, + 'ignore-case': false, order: SortOrder.asc, }) diff --git a/rules/sort-object-keys.ts b/rules/sort-object-keys.ts index ee5f8211..df093717 100644 --- a/rules/sort-object-keys.ts +++ b/rules/sort-object-keys.ts @@ -16,6 +16,7 @@ type MESSAGE_ID = 'unexpectedObjectKeysOrder' type Options = [ Partial<{ + 'ignore-case': boolean order: SortOrder type: SortType }>, @@ -48,6 +49,10 @@ export default createEslintRule({ enum: [SortOrder.asc, SortOrder.desc], default: SortOrder.asc, }, + 'ignore-case': { + type: 'boolean', + default: false, + }, }, additionalProperties: false, }, @@ -68,6 +73,7 @@ export default createEslintRule({ if (node.properties.length > 1) { let options = complete(context.options.at(0), { type: SortType.alphabetical, + 'ignore-case': false, order: SortOrder.asc, }) diff --git a/rules/sort-union-types.ts b/rules/sort-union-types.ts index f4afa5ec..78ac3141 100644 --- a/rules/sort-union-types.ts +++ b/rules/sort-union-types.ts @@ -14,6 +14,7 @@ type MESSAGE_ID = 'unexpectedUnionTypesOrder' type Options = [ Partial<{ + 'ignore-case': boolean order: SortOrder type: SortType }>, @@ -46,6 +47,10 @@ export default createEslintRule({ enum: [SortOrder.asc, SortOrder.desc], default: SortOrder.asc, }, + 'ignore-case': { + type: 'boolean', + default: false, + }, }, additionalProperties: false, }, @@ -67,6 +72,7 @@ export default createEslintRule({ let options = complete(context.options.at(0), { type: SortType.alphabetical, + 'ignore-case': false, order: SortOrder.asc, }) diff --git a/test/sort-imports.test.ts b/test/sort-imports.test.ts index 55d6c1f2..6e79833b 100644 --- a/test/sort-imports.test.ts +++ b/test/sort-imports.test.ts @@ -25,6 +25,7 @@ describe(RULE_NAME, () => { { type: SortType.alphabetical, order: SortOrder.asc, + 'ignore-case': true, }, ], }, @@ -43,6 +44,7 @@ describe(RULE_NAME, () => { { type: SortType.alphabetical, order: SortOrder.asc, + 'ignore-case': true, }, ], errors: [ @@ -639,6 +641,7 @@ describe(RULE_NAME, () => { { type: SortType.natural, order: SortOrder.asc, + 'ignore-case': true, }, ], }, @@ -657,6 +660,7 @@ describe(RULE_NAME, () => { { type: SortType.natural, order: SortOrder.asc, + 'ignore-case': true, }, ], errors: [ @@ -1253,6 +1257,7 @@ describe(RULE_NAME, () => { { type: SortType['line-length'], order: SortOrder.desc, + 'ignore-case': true, }, ], }, @@ -1271,6 +1276,7 @@ describe(RULE_NAME, () => { { type: SortType['line-length'], order: SortOrder.desc, + 'ignore-case': true, }, ], errors: [ diff --git a/test/sort-jsx-props.test.ts b/test/sort-jsx-props.test.ts index 85c294cb..8b44bf82 100644 --- a/test/sort-jsx-props.test.ts +++ b/test/sort-jsx-props.test.ts @@ -37,6 +37,7 @@ describe(RULE_NAME, () => { { type: SortType.alphabetical, order: SortOrder.asc, + 'ignore-case': true, }, ], }, @@ -69,6 +70,7 @@ describe(RULE_NAME, () => { { type: SortType.alphabetical, order: SortOrder.asc, + 'ignore-case': true, }, ], errors: [ @@ -252,6 +254,7 @@ describe(RULE_NAME, () => { { type: SortType.natural, order: SortOrder.asc, + 'ignore-case': true, }, ], }, @@ -284,6 +287,7 @@ describe(RULE_NAME, () => { { type: SortType.natural, order: SortOrder.asc, + 'ignore-case': true, }, ], errors: [ @@ -467,6 +471,7 @@ describe(RULE_NAME, () => { { type: SortType['line-length'], order: SortOrder.desc, + 'ignore-case': true, }, ], }, @@ -499,6 +504,7 @@ describe(RULE_NAME, () => { { type: SortType['line-length'], order: SortOrder.desc, + 'ignore-case': true, }, ], errors: [ diff --git a/utils/compare.ts b/utils/compare.ts index 31aa5c41..519c74c6 100644 --- a/utils/compare.ts +++ b/utils/compare.ts @@ -8,6 +8,7 @@ export let compare = ( a: SortingNode, b: SortingNode, options: { + 'ignore-case'?: boolean order: SortOrder type: SortType }, @@ -15,10 +16,15 @@ export let compare = ( let orderCoefficient = options.order === 'asc' ? 1 : -1 let sortingFunction: (a: SortingNode, b: SortingNode) => number + let formatString = (string: string) => + options['ignore-case'] ? string.toLowerCase() : string + if (options.type === SortType.alphabetical) { - sortingFunction = (aNode, bNode) => aNode.name.localeCompare(bNode.name) + sortingFunction = (aNode, bNode) => + formatString(aNode.name).localeCompare(formatString(bNode.name)) } else if (options.type === SortType.natural) { - sortingFunction = (aNode, bNode) => naturalCompare(aNode.name, bNode.name) + sortingFunction = (aNode, bNode) => + naturalCompare(formatString(aNode.name), formatString(bNode.name)) } else { sortingFunction = (aNode, bNode) => aNode.size - bNode.size } diff --git a/utils/sort-nodes.ts b/utils/sort-nodes.ts index e0a9ebf9..d8f34ba5 100644 --- a/utils/sort-nodes.ts +++ b/utils/sort-nodes.ts @@ -7,5 +7,6 @@ export let sortNodes = ( options: { order: SortOrder type: SortType + 'ignore-case'?: boolean }, ): T[] => [...nodes].sort((a, b) => Number(compare(a, b, options)) || -1)