eslint-plugin-perfectionist 2.7.0 → 2.9.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 (84) hide show
  1. package/dist/configs/recommended-alphabetical.js +9 -1
  2. package/dist/configs/recommended-alphabetical.mjs +5 -10
  3. package/dist/configs/recommended-line-length.js +9 -1
  4. package/dist/configs/recommended-line-length.mjs +5 -10
  5. package/dist/configs/recommended-natural.js +9 -1
  6. package/dist/configs/recommended-natural.mjs +5 -10
  7. package/dist/index.js +135 -3
  8. package/dist/index.mjs +76 -2197
  9. package/dist/package.json.js +4 -0
  10. package/dist/package.json.mjs +4 -0
  11. package/dist/rules/sort-array-includes.js +129 -0
  12. package/dist/rules/sort-array-includes.mjs +129 -0
  13. package/dist/rules/sort-astro-attributes.js +161 -0
  14. package/dist/rules/sort-astro-attributes.mjs +161 -0
  15. package/dist/rules/sort-classes.js +213 -0
  16. package/dist/rules/sort-classes.mjs +213 -0
  17. package/dist/rules/sort-enums.js +117 -0
  18. package/dist/rules/sort-enums.mjs +117 -0
  19. package/dist/rules/sort-exports.js +104 -0
  20. package/dist/rules/sort-exports.mjs +104 -0
  21. package/dist/rules/sort-imports.js +439 -0
  22. package/dist/rules/sort-imports.mjs +439 -0
  23. package/dist/rules/sort-interfaces.js +253 -0
  24. package/dist/rules/sort-interfaces.mjs +253 -0
  25. package/dist/rules/sort-intersection-types.js +92 -0
  26. package/dist/rules/sort-intersection-types.mjs +92 -0
  27. package/dist/rules/sort-jsx-props.js +156 -0
  28. package/dist/rules/sort-jsx-props.mjs +156 -0
  29. package/dist/rules/sort-maps.js +125 -0
  30. package/dist/rules/sort-maps.mjs +125 -0
  31. package/dist/rules/sort-named-exports.js +105 -0
  32. package/dist/rules/sort-named-exports.mjs +105 -0
  33. package/dist/rules/sort-named-imports.js +123 -0
  34. package/dist/rules/sort-named-imports.mjs +123 -0
  35. package/dist/rules/sort-object-types.js +189 -0
  36. package/dist/rules/sort-object-types.mjs +189 -0
  37. package/dist/rules/sort-objects.js +265 -0
  38. package/dist/rules/sort-objects.mjs +265 -0
  39. package/dist/rules/sort-svelte-attributes.js +168 -0
  40. package/dist/rules/sort-svelte-attributes.mjs +168 -0
  41. package/dist/rules/sort-union-types.js +120 -0
  42. package/dist/rules/sort-union-types.mjs +120 -0
  43. package/dist/rules/sort-vue-attributes.js +165 -0
  44. package/dist/rules/sort-vue-attributes.mjs +165 -0
  45. package/dist/typings/index.js +29 -0
  46. package/dist/typings/index.mjs +29 -0
  47. package/dist/utils/compare.js +38 -0
  48. package/dist/utils/compare.mjs +38 -0
  49. package/dist/utils/complete.js +4 -0
  50. package/dist/utils/complete.mjs +4 -0
  51. package/dist/utils/create-eslint-rule.js +7 -0
  52. package/dist/utils/create-eslint-rule.mjs +7 -0
  53. package/dist/utils/get-comment-after.js +13 -0
  54. package/dist/utils/get-comment-after.mjs +13 -0
  55. package/dist/utils/get-comment-before.js +14 -0
  56. package/dist/utils/get-comment-before.mjs +14 -0
  57. package/dist/utils/get-group-number.js +12 -0
  58. package/dist/utils/get-group-number.mjs +12 -0
  59. package/dist/utils/get-lines-between.js +10 -0
  60. package/dist/utils/get-lines-between.mjs +10 -0
  61. package/dist/utils/get-node-parent.js +14 -0
  62. package/dist/utils/get-node-parent.mjs +14 -0
  63. package/dist/utils/get-node-range.js +41 -0
  64. package/dist/utils/get-node-range.mjs +41 -0
  65. package/dist/utils/is-member-optional.js +12 -0
  66. package/dist/utils/is-member-optional.mjs +12 -0
  67. package/dist/utils/is-partition-comment.js +11 -0
  68. package/dist/utils/is-partition-comment.mjs +11 -0
  69. package/dist/utils/is-positive.js +4 -0
  70. package/dist/utils/is-positive.mjs +4 -0
  71. package/dist/utils/make-fixes.js +38 -0
  72. package/dist/utils/make-fixes.mjs +38 -0
  73. package/dist/utils/pairwise.js +14 -0
  74. package/dist/utils/pairwise.mjs +14 -0
  75. package/dist/utils/range-to-diff.js +7 -0
  76. package/dist/utils/range-to-diff.mjs +7 -0
  77. package/dist/utils/sort-nodes.js +5 -0
  78. package/dist/utils/sort-nodes.mjs +5 -0
  79. package/dist/utils/to-single-line.js +4 -0
  80. package/dist/utils/to-single-line.mjs +4 -0
  81. package/dist/utils/use-groups.js +35 -0
  82. package/dist/utils/use-groups.mjs +35 -0
  83. package/package.json +1 -1
  84. package/readme.md +20 -19
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const createEslintRule = require("../utils/create-eslint-rule.js");
4
+ const getGroupNumber = require("../utils/get-group-number.js");
5
+ const getNodeRange = require("../utils/get-node-range.js");
6
+ const toSingleLine = require("../utils/to-single-line.js");
7
+ const rangeToDiff = require("../utils/range-to-diff.js");
8
+ const isPositive = require("../utils/is-positive.js");
9
+ const index = require("../typings/index.js");
10
+ const useGroups = require("../utils/use-groups.js");
11
+ const sortNodes = require("../utils/sort-nodes.js");
12
+ const complete = require("../utils/complete.js");
13
+ const pairwise = require("../utils/pairwise.js");
14
+ const compare = require("../utils/compare.js");
15
+ const RULE_NAME = "sort-classes";
16
+ const sortClasses = createEslintRule.createEslintRule({
17
+ name: RULE_NAME,
18
+ meta: {
19
+ type: "suggestion",
20
+ docs: {
21
+ description: "enforce sorted classes"
22
+ },
23
+ fixable: "code",
24
+ schema: [
25
+ {
26
+ type: "object",
27
+ properties: {
28
+ type: {
29
+ enum: [
30
+ index.SortType.alphabetical,
31
+ index.SortType.natural,
32
+ index.SortType["line-length"]
33
+ ],
34
+ default: index.SortType.alphabetical,
35
+ type: "string"
36
+ },
37
+ "ignore-case": {
38
+ type: "boolean",
39
+ default: false
40
+ },
41
+ order: {
42
+ enum: [index.SortOrder.asc, index.SortOrder.desc],
43
+ default: index.SortOrder.asc,
44
+ type: "string"
45
+ },
46
+ groups: {
47
+ type: "array",
48
+ default: []
49
+ }
50
+ },
51
+ additionalProperties: false
52
+ }
53
+ ],
54
+ messages: {
55
+ unexpectedClassesOrder: 'Expected "{{right}}" to come before "{{left}}"'
56
+ }
57
+ },
58
+ defaultOptions: [
59
+ {
60
+ type: index.SortType.alphabetical,
61
+ order: index.SortOrder.asc
62
+ }
63
+ ],
64
+ create: (context) => ({
65
+ ClassBody: (node) => {
66
+ if (node.body.length > 1) {
67
+ let options = complete.complete(context.options.at(0), {
68
+ type: index.SortType.alphabetical,
69
+ order: index.SortOrder.asc,
70
+ "ignore-case": false,
71
+ groups: ["property", "constructor", "method", "unknown"]
72
+ });
73
+ let nodes = node.body.map((member) => {
74
+ var _a;
75
+ let name;
76
+ let { getGroup, defineGroup } = useGroups.useGroups(options.groups);
77
+ if (member.type === "StaticBlock") {
78
+ name = "static";
79
+ } else if (member.type === "TSIndexSignature") {
80
+ name = context.sourceCode.text.slice(
81
+ member.range.at(0),
82
+ ((_a = member.typeAnnotation) == null ? void 0 : _a.range.at(0)) ?? member.range.at(1)
83
+ );
84
+ } else {
85
+ if (member.key.type === "Identifier") {
86
+ ({ name } = member.key);
87
+ } else {
88
+ name = context.sourceCode.text.slice(...member.key.range);
89
+ }
90
+ }
91
+ let isPrivate = name.startsWith("_") || name.startsWith("#");
92
+ let decorated = "decorators" in member && member.decorators.length > 0;
93
+ if (member.type === "MethodDefinition") {
94
+ if (member.kind === "constructor") {
95
+ defineGroup("constructor");
96
+ }
97
+ let isPrivateMethod = member.accessibility === "private" || isPrivate;
98
+ let isStaticMethod = member.static;
99
+ if (decorated) {
100
+ if (member.kind === "get") {
101
+ defineGroup("decorated-get-method");
102
+ }
103
+ if (member.kind === "set") {
104
+ defineGroup("decorated-set-method");
105
+ }
106
+ defineGroup("decorated-method");
107
+ }
108
+ if (isPrivateMethod && isStaticMethod) {
109
+ defineGroup("static-private-method");
110
+ }
111
+ if (isPrivateMethod) {
112
+ defineGroup("private-method");
113
+ }
114
+ if (isStaticMethod) {
115
+ defineGroup("static-method");
116
+ }
117
+ if (member.kind === "get") {
118
+ defineGroup("get-method");
119
+ }
120
+ if (member.kind === "set") {
121
+ defineGroup("set-method");
122
+ }
123
+ defineGroup("method");
124
+ } else if (member.type === "TSIndexSignature") {
125
+ defineGroup("index-signature");
126
+ } else if (member.type === "AccessorProperty") {
127
+ if (decorated) {
128
+ if (member.accessibility === "private" || isPrivate) {
129
+ defineGroup("private-decorated-accessor-property");
130
+ }
131
+ defineGroup("decorated-accessor-property");
132
+ }
133
+ } else if (member.type === "PropertyDefinition") {
134
+ if (decorated) {
135
+ if (member.accessibility === "private" || isPrivate) {
136
+ defineGroup("private-decorated-property");
137
+ }
138
+ defineGroup("decorated-property");
139
+ }
140
+ if (member.accessibility === "private" || isPrivate) {
141
+ defineGroup("private-property");
142
+ }
143
+ if (member.static) {
144
+ defineGroup("static-property");
145
+ }
146
+ defineGroup("property");
147
+ }
148
+ return {
149
+ size: rangeToDiff.rangeToDiff(member.range),
150
+ group: getGroup(),
151
+ node: member,
152
+ name
153
+ };
154
+ });
155
+ pairwise.pairwise(nodes, (left, right) => {
156
+ let leftNum = getGroupNumber.getGroupNumber(options.groups, left);
157
+ let rightNum = getGroupNumber.getGroupNumber(options.groups, right);
158
+ if (left.name !== right.name && (leftNum > rightNum || leftNum === rightNum && isPositive.isPositive(compare.compare(left, right, options)))) {
159
+ context.report({
160
+ messageId: "unexpectedClassesOrder",
161
+ data: {
162
+ left: toSingleLine.toSingleLine(left.name),
163
+ right: toSingleLine.toSingleLine(right.name)
164
+ },
165
+ node: right.node,
166
+ fix: (fixer) => {
167
+ let fixes = [];
168
+ let grouped = nodes.reduce(
169
+ (accumulator, sortingNode) => {
170
+ let groupNum = getGroupNumber.getGroupNumber(options.groups, sortingNode);
171
+ if (!(groupNum in accumulator)) {
172
+ accumulator[groupNum] = [sortingNode];
173
+ } else {
174
+ accumulator[groupNum] = sortNodes.sortNodes(
175
+ [...accumulator[groupNum], sortingNode],
176
+ options
177
+ );
178
+ }
179
+ return accumulator;
180
+ },
181
+ {}
182
+ );
183
+ let formatted = Object.keys(grouped).sort((a, b) => Number(a) - Number(b)).reduce(
184
+ (accumulator, group) => [
185
+ ...accumulator,
186
+ ...grouped[group]
187
+ ],
188
+ []
189
+ );
190
+ for (let i = 0, max = formatted.length; i < max; i++) {
191
+ fixes.push(
192
+ fixer.replaceTextRange(
193
+ getNodeRange.getNodeRange(nodes.at(i).node, context.sourceCode),
194
+ context.sourceCode.text.slice(
195
+ ...getNodeRange.getNodeRange(
196
+ formatted.at(i).node,
197
+ context.sourceCode
198
+ )
199
+ )
200
+ )
201
+ );
202
+ }
203
+ return fixes;
204
+ }
205
+ });
206
+ }
207
+ });
208
+ }
209
+ }
210
+ })
211
+ });
212
+ exports.RULE_NAME = RULE_NAME;
213
+ exports.default = sortClasses;
@@ -0,0 +1,213 @@
1
+ import { createEslintRule } from "../utils/create-eslint-rule.mjs";
2
+ import { getGroupNumber } from "../utils/get-group-number.mjs";
3
+ import { getNodeRange } from "../utils/get-node-range.mjs";
4
+ import { toSingleLine } from "../utils/to-single-line.mjs";
5
+ import { rangeToDiff } from "../utils/range-to-diff.mjs";
6
+ import { isPositive } from "../utils/is-positive.mjs";
7
+ import { SortType, SortOrder } from "../typings/index.mjs";
8
+ import { useGroups } from "../utils/use-groups.mjs";
9
+ import { sortNodes } from "../utils/sort-nodes.mjs";
10
+ import { complete } from "../utils/complete.mjs";
11
+ import { pairwise } from "../utils/pairwise.mjs";
12
+ import { compare } from "../utils/compare.mjs";
13
+ const RULE_NAME = "sort-classes";
14
+ const sortClasses = createEslintRule({
15
+ name: RULE_NAME,
16
+ meta: {
17
+ type: "suggestion",
18
+ docs: {
19
+ description: "enforce sorted classes"
20
+ },
21
+ fixable: "code",
22
+ schema: [
23
+ {
24
+ type: "object",
25
+ properties: {
26
+ type: {
27
+ enum: [
28
+ SortType.alphabetical,
29
+ SortType.natural,
30
+ SortType["line-length"]
31
+ ],
32
+ default: SortType.alphabetical,
33
+ type: "string"
34
+ },
35
+ "ignore-case": {
36
+ type: "boolean",
37
+ default: false
38
+ },
39
+ order: {
40
+ enum: [SortOrder.asc, SortOrder.desc],
41
+ default: SortOrder.asc,
42
+ type: "string"
43
+ },
44
+ groups: {
45
+ type: "array",
46
+ default: []
47
+ }
48
+ },
49
+ additionalProperties: false
50
+ }
51
+ ],
52
+ messages: {
53
+ unexpectedClassesOrder: 'Expected "{{right}}" to come before "{{left}}"'
54
+ }
55
+ },
56
+ defaultOptions: [
57
+ {
58
+ type: SortType.alphabetical,
59
+ order: SortOrder.asc
60
+ }
61
+ ],
62
+ create: (context) => ({
63
+ ClassBody: (node) => {
64
+ if (node.body.length > 1) {
65
+ let options = complete(context.options.at(0), {
66
+ type: SortType.alphabetical,
67
+ order: SortOrder.asc,
68
+ "ignore-case": false,
69
+ groups: ["property", "constructor", "method", "unknown"]
70
+ });
71
+ let nodes = node.body.map((member) => {
72
+ var _a;
73
+ let name;
74
+ let { getGroup, defineGroup } = useGroups(options.groups);
75
+ if (member.type === "StaticBlock") {
76
+ name = "static";
77
+ } else if (member.type === "TSIndexSignature") {
78
+ name = context.sourceCode.text.slice(
79
+ member.range.at(0),
80
+ ((_a = member.typeAnnotation) == null ? void 0 : _a.range.at(0)) ?? member.range.at(1)
81
+ );
82
+ } else {
83
+ if (member.key.type === "Identifier") {
84
+ ({ name } = member.key);
85
+ } else {
86
+ name = context.sourceCode.text.slice(...member.key.range);
87
+ }
88
+ }
89
+ let isPrivate = name.startsWith("_") || name.startsWith("#");
90
+ let decorated = "decorators" in member && member.decorators.length > 0;
91
+ if (member.type === "MethodDefinition") {
92
+ if (member.kind === "constructor") {
93
+ defineGroup("constructor");
94
+ }
95
+ let isPrivateMethod = member.accessibility === "private" || isPrivate;
96
+ let isStaticMethod = member.static;
97
+ if (decorated) {
98
+ if (member.kind === "get") {
99
+ defineGroup("decorated-get-method");
100
+ }
101
+ if (member.kind === "set") {
102
+ defineGroup("decorated-set-method");
103
+ }
104
+ defineGroup("decorated-method");
105
+ }
106
+ if (isPrivateMethod && isStaticMethod) {
107
+ defineGroup("static-private-method");
108
+ }
109
+ if (isPrivateMethod) {
110
+ defineGroup("private-method");
111
+ }
112
+ if (isStaticMethod) {
113
+ defineGroup("static-method");
114
+ }
115
+ if (member.kind === "get") {
116
+ defineGroup("get-method");
117
+ }
118
+ if (member.kind === "set") {
119
+ defineGroup("set-method");
120
+ }
121
+ defineGroup("method");
122
+ } else if (member.type === "TSIndexSignature") {
123
+ defineGroup("index-signature");
124
+ } else if (member.type === "AccessorProperty") {
125
+ if (decorated) {
126
+ if (member.accessibility === "private" || isPrivate) {
127
+ defineGroup("private-decorated-accessor-property");
128
+ }
129
+ defineGroup("decorated-accessor-property");
130
+ }
131
+ } else if (member.type === "PropertyDefinition") {
132
+ if (decorated) {
133
+ if (member.accessibility === "private" || isPrivate) {
134
+ defineGroup("private-decorated-property");
135
+ }
136
+ defineGroup("decorated-property");
137
+ }
138
+ if (member.accessibility === "private" || isPrivate) {
139
+ defineGroup("private-property");
140
+ }
141
+ if (member.static) {
142
+ defineGroup("static-property");
143
+ }
144
+ defineGroup("property");
145
+ }
146
+ return {
147
+ size: rangeToDiff(member.range),
148
+ group: getGroup(),
149
+ node: member,
150
+ name
151
+ };
152
+ });
153
+ pairwise(nodes, (left, right) => {
154
+ let leftNum = getGroupNumber(options.groups, left);
155
+ let rightNum = getGroupNumber(options.groups, right);
156
+ if (left.name !== right.name && (leftNum > rightNum || leftNum === rightNum && isPositive(compare(left, right, options)))) {
157
+ context.report({
158
+ messageId: "unexpectedClassesOrder",
159
+ data: {
160
+ left: toSingleLine(left.name),
161
+ right: toSingleLine(right.name)
162
+ },
163
+ node: right.node,
164
+ fix: (fixer) => {
165
+ let fixes = [];
166
+ let grouped = nodes.reduce(
167
+ (accumulator, sortingNode) => {
168
+ let groupNum = getGroupNumber(options.groups, sortingNode);
169
+ if (!(groupNum in accumulator)) {
170
+ accumulator[groupNum] = [sortingNode];
171
+ } else {
172
+ accumulator[groupNum] = sortNodes(
173
+ [...accumulator[groupNum], sortingNode],
174
+ options
175
+ );
176
+ }
177
+ return accumulator;
178
+ },
179
+ {}
180
+ );
181
+ let formatted = Object.keys(grouped).sort((a, b) => Number(a) - Number(b)).reduce(
182
+ (accumulator, group) => [
183
+ ...accumulator,
184
+ ...grouped[group]
185
+ ],
186
+ []
187
+ );
188
+ for (let i = 0, max = formatted.length; i < max; i++) {
189
+ fixes.push(
190
+ fixer.replaceTextRange(
191
+ getNodeRange(nodes.at(i).node, context.sourceCode),
192
+ context.sourceCode.text.slice(
193
+ ...getNodeRange(
194
+ formatted.at(i).node,
195
+ context.sourceCode
196
+ )
197
+ )
198
+ )
199
+ );
200
+ }
201
+ return fixes;
202
+ }
203
+ });
204
+ }
205
+ });
206
+ }
207
+ }
208
+ })
209
+ });
210
+ export {
211
+ RULE_NAME,
212
+ sortClasses as default
213
+ };
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const isPartitionComment = require("../utils/is-partition-comment.js");
4
+ const createEslintRule = require("../utils/create-eslint-rule.js");
5
+ const getCommentBefore = require("../utils/get-comment-before.js");
6
+ const toSingleLine = require("../utils/to-single-line.js");
7
+ const rangeToDiff = require("../utils/range-to-diff.js");
8
+ const isPositive = require("../utils/is-positive.js");
9
+ const index = require("../typings/index.js");
10
+ const sortNodes = require("../utils/sort-nodes.js");
11
+ const makeFixes = require("../utils/make-fixes.js");
12
+ const complete = require("../utils/complete.js");
13
+ const pairwise = require("../utils/pairwise.js");
14
+ const compare = require("../utils/compare.js");
15
+ const RULE_NAME = "sort-enums";
16
+ const sortEnums = createEslintRule.createEslintRule({
17
+ name: RULE_NAME,
18
+ meta: {
19
+ type: "suggestion",
20
+ docs: {
21
+ description: "enforce sorted TypeScript enums"
22
+ },
23
+ fixable: "code",
24
+ schema: [
25
+ {
26
+ type: "object",
27
+ properties: {
28
+ "partition-by-comment": {
29
+ default: false,
30
+ type: ["boolean", "string", "array"]
31
+ },
32
+ type: {
33
+ enum: [
34
+ index.SortType.alphabetical,
35
+ index.SortType.natural,
36
+ index.SortType["line-length"]
37
+ ],
38
+ default: index.SortType.alphabetical,
39
+ type: "string"
40
+ },
41
+ "ignore-case": {
42
+ type: "boolean",
43
+ default: false
44
+ },
45
+ order: {
46
+ enum: [index.SortOrder.asc, index.SortOrder.desc],
47
+ default: index.SortOrder.asc,
48
+ type: "string"
49
+ }
50
+ },
51
+ additionalProperties: false
52
+ }
53
+ ],
54
+ messages: {
55
+ unexpectedEnumsOrder: 'Expected "{{right}}" to come before "{{left}}"'
56
+ }
57
+ },
58
+ defaultOptions: [
59
+ {
60
+ type: index.SortType.alphabetical,
61
+ order: index.SortOrder.asc
62
+ }
63
+ ],
64
+ create: (context) => ({
65
+ TSEnumDeclaration: (node) => {
66
+ if (node.members.length > 1 && node.members.every(({ initializer }) => initializer)) {
67
+ let options = complete.complete(context.options.at(0), {
68
+ type: index.SortType.alphabetical,
69
+ order: index.SortOrder.asc,
70
+ "ignore-case": false,
71
+ "partition-by-comment": false
72
+ });
73
+ let partitionComment = options["partition-by-comment"];
74
+ let formattedMembers = node.members.reduce(
75
+ (accumulator, member) => {
76
+ let comment = getCommentBefore.getCommentBefore(member, context.sourceCode);
77
+ if (partitionComment && comment && isPartitionComment.isPartitionComment(partitionComment, comment.value)) {
78
+ accumulator.push([]);
79
+ }
80
+ let name = member.id.type === "Literal" ? `${member.id.value}` : `${context.sourceCode.text.slice(...member.id.range)}`;
81
+ let sortingNode = {
82
+ name,
83
+ node: member,
84
+ size: rangeToDiff.rangeToDiff(member.range)
85
+ };
86
+ accumulator.at(-1).push(sortingNode);
87
+ return accumulator;
88
+ },
89
+ [[]]
90
+ );
91
+ for (let nodes of formattedMembers) {
92
+ pairwise.pairwise(nodes, (left, right) => {
93
+ if (isPositive.isPositive(compare.compare(left, right, options))) {
94
+ context.report({
95
+ messageId: "unexpectedEnumsOrder",
96
+ data: {
97
+ left: toSingleLine.toSingleLine(left.name),
98
+ right: toSingleLine.toSingleLine(right.name)
99
+ },
100
+ node: right.node,
101
+ fix: (fixer) => makeFixes.makeFixes(
102
+ fixer,
103
+ nodes,
104
+ sortNodes.sortNodes(nodes, options),
105
+ context.sourceCode,
106
+ { partitionComment }
107
+ )
108
+ });
109
+ }
110
+ });
111
+ }
112
+ }
113
+ }
114
+ })
115
+ });
116
+ exports.RULE_NAME = RULE_NAME;
117
+ exports.default = sortEnums;
@@ -0,0 +1,117 @@
1
+ import { isPartitionComment } from "../utils/is-partition-comment.mjs";
2
+ import { createEslintRule } from "../utils/create-eslint-rule.mjs";
3
+ import { getCommentBefore } from "../utils/get-comment-before.mjs";
4
+ import { toSingleLine } from "../utils/to-single-line.mjs";
5
+ import { rangeToDiff } from "../utils/range-to-diff.mjs";
6
+ import { isPositive } from "../utils/is-positive.mjs";
7
+ import { SortType, SortOrder } from "../typings/index.mjs";
8
+ import { sortNodes } from "../utils/sort-nodes.mjs";
9
+ import { makeFixes } from "../utils/make-fixes.mjs";
10
+ import { complete } from "../utils/complete.mjs";
11
+ import { pairwise } from "../utils/pairwise.mjs";
12
+ import { compare } from "../utils/compare.mjs";
13
+ const RULE_NAME = "sort-enums";
14
+ const sortEnums = createEslintRule({
15
+ name: RULE_NAME,
16
+ meta: {
17
+ type: "suggestion",
18
+ docs: {
19
+ description: "enforce sorted TypeScript enums"
20
+ },
21
+ fixable: "code",
22
+ schema: [
23
+ {
24
+ type: "object",
25
+ properties: {
26
+ "partition-by-comment": {
27
+ default: false,
28
+ type: ["boolean", "string", "array"]
29
+ },
30
+ type: {
31
+ enum: [
32
+ SortType.alphabetical,
33
+ SortType.natural,
34
+ SortType["line-length"]
35
+ ],
36
+ default: SortType.alphabetical,
37
+ type: "string"
38
+ },
39
+ "ignore-case": {
40
+ type: "boolean",
41
+ default: false
42
+ },
43
+ order: {
44
+ enum: [SortOrder.asc, SortOrder.desc],
45
+ default: SortOrder.asc,
46
+ type: "string"
47
+ }
48
+ },
49
+ additionalProperties: false
50
+ }
51
+ ],
52
+ messages: {
53
+ unexpectedEnumsOrder: 'Expected "{{right}}" to come before "{{left}}"'
54
+ }
55
+ },
56
+ defaultOptions: [
57
+ {
58
+ type: SortType.alphabetical,
59
+ order: SortOrder.asc
60
+ }
61
+ ],
62
+ create: (context) => ({
63
+ TSEnumDeclaration: (node) => {
64
+ if (node.members.length > 1 && node.members.every(({ initializer }) => initializer)) {
65
+ let options = complete(context.options.at(0), {
66
+ type: SortType.alphabetical,
67
+ order: SortOrder.asc,
68
+ "ignore-case": false,
69
+ "partition-by-comment": false
70
+ });
71
+ let partitionComment = options["partition-by-comment"];
72
+ let formattedMembers = node.members.reduce(
73
+ (accumulator, member) => {
74
+ let comment = getCommentBefore(member, context.sourceCode);
75
+ if (partitionComment && comment && isPartitionComment(partitionComment, comment.value)) {
76
+ accumulator.push([]);
77
+ }
78
+ let name = member.id.type === "Literal" ? `${member.id.value}` : `${context.sourceCode.text.slice(...member.id.range)}`;
79
+ let sortingNode = {
80
+ name,
81
+ node: member,
82
+ size: rangeToDiff(member.range)
83
+ };
84
+ accumulator.at(-1).push(sortingNode);
85
+ return accumulator;
86
+ },
87
+ [[]]
88
+ );
89
+ for (let nodes of formattedMembers) {
90
+ pairwise(nodes, (left, right) => {
91
+ if (isPositive(compare(left, right, options))) {
92
+ context.report({
93
+ messageId: "unexpectedEnumsOrder",
94
+ data: {
95
+ left: toSingleLine(left.name),
96
+ right: toSingleLine(right.name)
97
+ },
98
+ node: right.node,
99
+ fix: (fixer) => makeFixes(
100
+ fixer,
101
+ nodes,
102
+ sortNodes(nodes, options),
103
+ context.sourceCode,
104
+ { partitionComment }
105
+ )
106
+ });
107
+ }
108
+ });
109
+ }
110
+ }
111
+ }
112
+ })
113
+ });
114
+ export {
115
+ RULE_NAME,
116
+ sortEnums as default
117
+ };