eslint-plugin-perfectionist 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/alphabet.d.ts +176 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +8 -0
  4. package/dist/rules/sort-array-includes.js +2 -0
  5. package/dist/rules/sort-classes.js +6 -2
  6. package/dist/rules/sort-decorators.js +4 -0
  7. package/dist/rules/sort-enums.js +5 -0
  8. package/dist/rules/sort-exports.js +4 -0
  9. package/dist/rules/sort-heritage-clauses.js +4 -0
  10. package/dist/rules/sort-imports.js +5 -0
  11. package/dist/rules/sort-interfaces.js +1 -0
  12. package/dist/rules/sort-intersection-types.js +4 -0
  13. package/dist/rules/sort-jsx-props.js +4 -0
  14. package/dist/rules/sort-maps.js +4 -0
  15. package/dist/rules/sort-modules.js +6 -2
  16. package/dist/rules/sort-named-exports.js +4 -0
  17. package/dist/rules/sort-named-imports.js +4 -0
  18. package/dist/rules/sort-object-types.js +10 -11
  19. package/dist/rules/sort-objects.js +32 -5
  20. package/dist/rules/sort-switch-case.js +4 -0
  21. package/dist/rules/sort-union-types.js +4 -0
  22. package/dist/rules/sort-variable-declarations.js +4 -0
  23. package/dist/utils/alphabet.js +385 -0
  24. package/dist/utils/common-json-schemas.js +16 -1
  25. package/dist/utils/compare.js +88 -38
  26. package/dist/utils/convert-boolean-to-sign.js +4 -0
  27. package/dist/{rules → utils}/get-custom-groups-compare-options.js +1 -0
  28. package/dist/utils/get-matching-context-options.js +18 -0
  29. package/dist/utils/get-settings.js +1 -0
  30. package/dist/utils/is-node-function-type.js +15 -0
  31. package/dist/utils/validate-custom-sort-configuration.js +11 -0
  32. package/dist/{rules → utils}/validate-generated-groups-configuration.js +1 -1
  33. package/package.json +7 -3
  34. package/readme.md +4 -3
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
3
3
  let typeJsonSchema = {
4
- enum: ['alphabetical', 'natural', 'line-length'],
4
+ enum: ['alphabetical', 'natural', 'line-length', 'custom'],
5
5
  description: 'Specifies the sorting method.',
6
6
  type: 'string',
7
7
  }
@@ -11,6 +11,10 @@ let orderJsonSchema = {
11
11
  enum: ['asc', 'desc'],
12
12
  type: 'string',
13
13
  }
14
+ let alphabetJsonSchema = {
15
+ description: 'Alphabet to use for the `custom` sort type.',
16
+ type: 'string',
17
+ }
14
18
  let localesJsonSchema = {
15
19
  oneOf: [
16
20
  {
@@ -96,6 +100,15 @@ let newlinesBetweenJsonSchema = {
96
100
  enum: ['ignore', 'always', 'never'],
97
101
  type: 'string',
98
102
  }
103
+ let useConfigurationIfJsonSchema = {
104
+ properties: {
105
+ allNamesMatchPattern: {
106
+ type: 'string',
107
+ },
108
+ },
109
+ additionalProperties: false,
110
+ type: 'object',
111
+ }
99
112
  let customGroupSortJsonSchema = {
100
113
  type: {
101
114
  enum: ['alphabetical', 'line-length', 'natural', 'unsorted'],
@@ -169,6 +182,7 @@ let elementNamePatternJsonSchema = {
169
182
  description: 'Element name pattern filter.',
170
183
  type: 'string',
171
184
  }
185
+ exports.alphabetJsonSchema = alphabetJsonSchema
172
186
  exports.buildCustomGroupModifiersJsonSchema =
173
187
  buildCustomGroupModifiersJsonSchema
174
188
  exports.buildCustomGroupSelectorJsonSchema = buildCustomGroupSelectorJsonSchema
@@ -184,3 +198,4 @@ exports.partitionByCommentJsonSchema = partitionByCommentJsonSchema
184
198
  exports.partitionByNewLineJsonSchema = partitionByNewLineJsonSchema
185
199
  exports.specialCharactersJsonSchema = specialCharactersJsonSchema
186
200
  exports.typeJsonSchema = typeJsonSchema
201
+ exports.useConfigurationIfJsonSchema = useConfigurationIfJsonSchema
@@ -1,53 +1,103 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
3
3
  const naturalOrderby = require('natural-orderby')
4
+ const convertBooleanToSign = require('./convert-boolean-to-sign.js')
5
+ let alphabetCache = /* @__PURE__ */ new Map()
4
6
  let compare = (a, b, options) => {
5
- let orderCoefficient = options.order === 'asc' ? 1 : -1
6
7
  let sortingFunction
7
8
  let nodeValueGetter = options.nodeValueGetter ?? (node => node.name)
8
- if (options.type === 'alphabetical') {
9
- let formatString = getFormatStringFunction(
10
- options.ignoreCase,
11
- options.specialCharacters,
9
+ switch (options.type) {
10
+ case 'alphabetical':
11
+ sortingFunction = getAlphabeticalSortingFunction(options, nodeValueGetter)
12
+ break
13
+ case 'natural':
14
+ sortingFunction = getNaturalSortingFunction(options, nodeValueGetter)
15
+ break
16
+ case 'custom':
17
+ sortingFunction = getCustomSortingFunction(options, nodeValueGetter)
18
+ break
19
+ case 'line-length':
20
+ sortingFunction = getLineLengthSortingFunction(options, nodeValueGetter)
21
+ }
22
+ return (
23
+ convertBooleanToSign.convertBooleanToSign(options.order === 'asc') *
24
+ sortingFunction(a, b)
25
+ )
26
+ }
27
+ let getAlphabeticalSortingFunction = (
28
+ { specialCharacters, ignoreCase, locales },
29
+ nodeValueGetter,
30
+ ) => {
31
+ let formatString = getFormatStringFunction(ignoreCase, specialCharacters)
32
+ return (aNode, bNode) =>
33
+ formatString(nodeValueGetter(aNode)).localeCompare(
34
+ formatString(nodeValueGetter(bNode)),
35
+ locales,
12
36
  )
13
- sortingFunction = (aNode, bNode) =>
14
- formatString(nodeValueGetter(aNode)).localeCompare(
15
- formatString(nodeValueGetter(bNode)),
16
- options.locales,
17
- )
18
- } else if (options.type === 'natural') {
19
- let naturalCompare = naturalOrderby.compare({
20
- locale: options.locales.toString(),
21
- })
22
- let formatString = getFormatStringFunction(
23
- options.ignoreCase,
24
- options.specialCharacters,
37
+ }
38
+ let getNaturalSortingFunction = (
39
+ { specialCharacters, ignoreCase, locales },
40
+ nodeValueGetter,
41
+ ) => {
42
+ let naturalCompare = naturalOrderby.compare({
43
+ locale: locales.toString(),
44
+ })
45
+ let formatString = getFormatStringFunction(ignoreCase, specialCharacters)
46
+ return (aNode, bNode) =>
47
+ naturalCompare(
48
+ formatString(nodeValueGetter(aNode)),
49
+ formatString(nodeValueGetter(bNode)),
25
50
  )
26
- sortingFunction = (aNode, bNode) =>
27
- naturalCompare(
28
- formatString(nodeValueGetter(aNode)),
29
- formatString(nodeValueGetter(bNode)),
30
- )
31
- } else {
32
- sortingFunction = (aNode, bNode) => {
33
- let aSize = aNode.size
34
- let bSize = bNode.size
35
- let { maxLineLength } = options
36
- if (maxLineLength) {
37
- let isTooLong = (size, node) =>
38
- size > maxLineLength && node.hasMultipleImportDeclarations
39
- if (isTooLong(aSize, aNode)) {
40
- aSize = nodeValueGetter(aNode).length + 10
41
- }
42
- if (isTooLong(bSize, bNode)) {
43
- bSize = nodeValueGetter(bNode).length + 10
44
- }
51
+ }
52
+ let getCustomSortingFunction = (
53
+ { specialCharacters, ignoreCase, alphabet },
54
+ nodeValueGetter,
55
+ ) => {
56
+ let formatString = getFormatStringFunction(ignoreCase, specialCharacters)
57
+ let indexByCharacters = alphabetCache.get(alphabet)
58
+ if (!indexByCharacters) {
59
+ indexByCharacters = /* @__PURE__ */ new Map()
60
+ for (let [index, character] of [...alphabet].entries()) {
61
+ indexByCharacters.set(character, index)
62
+ }
63
+ alphabetCache.set(alphabet, indexByCharacters)
64
+ }
65
+ return (aNode, bNode) => {
66
+ let aValue = formatString(nodeValueGetter(aNode))
67
+ let bValue = formatString(nodeValueGetter(bNode))
68
+ for (let i = 0; i < aValue.length; i++) {
69
+ let aCharacter = aValue[i]
70
+ let bCharacter = bValue[i]
71
+ let indexOfA = indexByCharacters.get(aCharacter)
72
+ let indexOfB = indexByCharacters.get(bCharacter)
73
+ indexOfA ?? (indexOfA = Infinity)
74
+ indexOfB ?? (indexOfB = Infinity)
75
+ if (indexOfA !== indexOfB) {
76
+ return convertBooleanToSign.convertBooleanToSign(
77
+ indexOfA - indexOfB > 0,
78
+ )
45
79
  }
46
- return aSize - bSize
47
80
  }
81
+ return 0
48
82
  }
49
- return orderCoefficient * sortingFunction(a, b)
50
83
  }
84
+ let getLineLengthSortingFunction =
85
+ ({ maxLineLength }, nodeValueGetter) =>
86
+ (aNode, bNode) => {
87
+ let aSize = aNode.size
88
+ let bSize = bNode.size
89
+ if (maxLineLength) {
90
+ let isTooLong = (size, node) =>
91
+ size > maxLineLength && node.hasMultipleImportDeclarations
92
+ if (isTooLong(aSize, aNode)) {
93
+ aSize = nodeValueGetter(aNode).length + 10
94
+ }
95
+ if (isTooLong(bSize, bNode)) {
96
+ bSize = nodeValueGetter(bNode).length + 10
97
+ }
98
+ }
99
+ return aSize - bSize
100
+ }
51
101
  let getFormatStringFunction = (ignoreCase, specialCharacters) => value => {
52
102
  let valueToCompare = value
53
103
  if (ignoreCase) {
@@ -0,0 +1,4 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
3
+ let convertBooleanToSign = value => (value ? 1 : -1)
4
+ exports.convertBooleanToSign = convertBooleanToSign
@@ -22,6 +22,7 @@ let getCustomGroupsCompareOptions = (options, groupNumber) => {
22
22
  specialCharacters: options.specialCharacters,
23
23
  type: (customGroup == null ? void 0 : customGroup.type) ?? options.type,
24
24
  ignoreCase: options.ignoreCase,
25
+ alphabet: options.alphabet,
25
26
  locales: options.locales,
26
27
  }
27
28
  }
@@ -0,0 +1,18 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
3
+ const matches = require('./matches.js')
4
+ let getMatchingContextOptions = ({ contextOptions, nodeNames }) =>
5
+ contextOptions.find(options => {
6
+ var _a
7
+ let allNamesMatchPattern =
8
+ (_a = options.useConfigurationIf) == null
9
+ ? void 0
10
+ : _a.allNamesMatchPattern
11
+ return (
12
+ !allNamesMatchPattern ||
13
+ nodeNames.every(nodeName =>
14
+ matches.matches(nodeName, allNamesMatchPattern),
15
+ )
16
+ )
17
+ })
18
+ exports.getMatchingContextOptions = getMatchingContextOptions
@@ -11,6 +11,7 @@ let getSettings = (settings = {}) => {
11
11
  'specialCharacters',
12
12
  'ignorePattern',
13
13
  'ignoreCase',
14
+ 'alphabet',
14
15
  'locales',
15
16
  'order',
16
17
  'type',
@@ -0,0 +1,15 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
3
+ let isNodeFunctionType = node => {
4
+ if (node.type === 'TSMethodSignature' || node.type === 'TSFunctionType') {
5
+ return true
6
+ }
7
+ if (node.type === 'TSUnionType' || node.type === 'TSIntersectionType') {
8
+ return node.types.every(isNodeFunctionType)
9
+ }
10
+ if (node.type === 'TSPropertySignature' && node.typeAnnotation) {
11
+ return isNodeFunctionType(node.typeAnnotation.typeAnnotation)
12
+ }
13
+ return false
14
+ }
15
+ exports.isNodeFunctionType = isNodeFunctionType
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
3
+ let validateCustomSortConfiguration = ({ alphabet, type }) => {
4
+ if (type !== 'custom') {
5
+ return
6
+ }
7
+ if (!alphabet.length) {
8
+ throw new Error('`alphabet` option must not be empty')
9
+ }
10
+ }
11
+ exports.validateCustomSortConfiguration = validateCustomSortConfiguration
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
3
- const validateGroupsConfiguration = require('../utils/validate-groups-configuration.js')
3
+ const validateGroupsConfiguration = require('./validate-groups-configuration.js')
4
4
  let validateGeneratedGroupsConfiguration = ({
5
5
  customGroups,
6
6
  selectors,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-perfectionist",
3
- "version": "4.2.0",
3
+ "version": "4.3.0",
4
4
  "description": "ESLint plugin for sorting various data such as objects, imports, types, enums, JSX props, etc.",
5
5
  "keywords": [
6
6
  "eslint",
@@ -17,14 +17,18 @@
17
17
  "types": "./dist/index.d.ts",
18
18
  "default": "./dist/index.js"
19
19
  },
20
+ "./alphabet": {
21
+ "types": "./dist/alphabet.d.ts",
22
+ "default": "./dist/utils/alphabet.js"
23
+ },
20
24
  "./package.json": "./package.json"
21
25
  },
22
26
  "files": [
23
27
  "./dist"
24
28
  ],
25
29
  "dependencies": {
26
- "@typescript-eslint/types": "^8.17.0",
27
- "@typescript-eslint/utils": "^8.17.0",
30
+ "@typescript-eslint/types": "^8.18.0",
31
+ "@typescript-eslint/utils": "^8.18.0",
28
32
  "natural-orderby": "^5.0.0"
29
33
  },
30
34
  "peerDependencies": {
package/readme.md CHANGED
@@ -165,6 +165,7 @@ module.exports = {
165
165
  | [recommended-alphabetical](https://perfectionist.dev/configs/recommended-alphabetical) | All plugin rules with alphabetical sorting in ascending order |
166
166
  | [recommended-natural](https://perfectionist.dev/configs/recommended-natural) | All plugin rules with natural sorting in ascending order |
167
167
  | [recommended-line-length](https://perfectionist.dev/configs/recommended-line-length) | All plugin rules with sorting by line length in descending order |
168
+ | [recommended-custom](https://perfectionist.dev/configs/recommended-custom) | All plugin rules with sorting by your own custom order |
168
169
 
169
170
  ## Rules
170
171
 
@@ -201,15 +202,15 @@ module.exports = {
201
202
 
202
203
  ### Can I automatically fix problems in the editor?
203
204
 
204
- Yes. To do this, you need to enable autofix in ESLint when you save the file in your editor. Instructions for your editor can be found [here](https://perfectionist.dev/guide/integrations).
205
+ Yes. To do this, you need to enable autofix in ESLint when you save the file in your editor. You may find instructions for your editor can be found [here](https://perfectionist.dev/guide/integrations).
205
206
 
206
207
  ### Is it safe?
207
208
 
208
- On the whole, yes. We are very careful to make sure that the work of the plugin does not negatively affect the work of the code. For example, the plugin takes into account spread operators in JSX and objects, comments to the code. Safety is our priority. If you encounter any problem, you can create an [issue](https://github.com/azat-io/eslint-plugin-perfectionist/issues/new/choose).
209
+ Overall, yes. We want to make sure that the work of the plugin does not negatively affect the behavior of the code. For example, the plugin takes into account spread operators in JSX and objects, comments to the code. Safety is our priority. If you encounter any problem, you can create an [issue](https://github.com/azat-io/eslint-plugin-perfectionist/issues/new/choose).
209
210
 
210
211
  ### Why not Prettier?
211
212
 
212
- I love Prettier. However, this is not his area of responsibility. Prettier is used for formatting, and ESLint is also used for styling. For example, changing the order of imports can affect how the code works (console.log calls, fetch, style loading). Prettier should not change the AST. There is a cool article about this: ["The Blurry Line Between Formatting and Style"](https://blog.joshuakgoldberg.com/the-blurry-line-between-formatting-and-style) by **@joshuakgoldberg**.
213
+ I love Prettier. However, this is not its area of responsibility. Prettier is used for formatting, and ESLint is also used for styling. For example, changing the order of imports can affect how the code works (console.log calls, fetch, style loading). Prettier should not change the AST. There is a cool article about this: ["The Blurry Line Between Formatting and Style"](https://blog.joshuakgoldberg.com/the-blurry-line-between-formatting-and-style) by **@joshuakgoldberg**.
213
214
 
214
215
  ## Versioning Policy
215
216