1 | "use strict";
|
2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3 | if (k2 === undefined) k2 = k;
|
4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
5 | }) : (function(o, m, k, k2) {
|
6 | if (k2 === undefined) k2 = k;
|
7 | o[k2] = m[k];
|
8 | }));
|
9 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
10 | Object.defineProperty(o, "default", { enumerable: true, value: v });
|
11 | }) : function(o, v) {
|
12 | o["default"] = v;
|
13 | });
|
14 | var __importStar = (this && this.__importStar) || function (mod) {
|
15 | if (mod && mod.__esModule) return mod;
|
16 | var result = {};
|
17 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
18 | __setModuleDefault(result, mod);
|
19 | return result;
|
20 | };
|
21 | Object.defineProperty(exports, "__esModule", { value: true });
|
22 | const utils_1 = require("@typescript-eslint/utils");
|
23 | const util = __importStar(require("../util"));
|
24 | const util_1 = require("../util");
|
25 | var Group;
|
26 | (function (Group) {
|
27 | Group["conditional"] = "conditional";
|
28 | Group["function"] = "function";
|
29 | Group["import"] = "import";
|
30 | Group["intersection"] = "intersection";
|
31 | Group["keyword"] = "keyword";
|
32 | Group["nullish"] = "nullish";
|
33 | Group["literal"] = "literal";
|
34 | Group["named"] = "named";
|
35 | Group["object"] = "object";
|
36 | Group["operator"] = "operator";
|
37 | Group["tuple"] = "tuple";
|
38 | Group["union"] = "union";
|
39 | })(Group || (Group = {}));
|
40 | function getGroup(node) {
|
41 | switch (node.type) {
|
42 | case utils_1.AST_NODE_TYPES.TSConditionalType:
|
43 | return Group.conditional;
|
44 | case utils_1.AST_NODE_TYPES.TSConstructorType:
|
45 | case utils_1.AST_NODE_TYPES.TSFunctionType:
|
46 | return Group.function;
|
47 | case utils_1.AST_NODE_TYPES.TSImportType:
|
48 | return Group.import;
|
49 | case utils_1.AST_NODE_TYPES.TSIntersectionType:
|
50 | return Group.intersection;
|
51 | case utils_1.AST_NODE_TYPES.TSAnyKeyword:
|
52 | case utils_1.AST_NODE_TYPES.TSBigIntKeyword:
|
53 | case utils_1.AST_NODE_TYPES.TSBooleanKeyword:
|
54 | case utils_1.AST_NODE_TYPES.TSNeverKeyword:
|
55 | case utils_1.AST_NODE_TYPES.TSNumberKeyword:
|
56 | case utils_1.AST_NODE_TYPES.TSObjectKeyword:
|
57 | case utils_1.AST_NODE_TYPES.TSStringKeyword:
|
58 | case utils_1.AST_NODE_TYPES.TSSymbolKeyword:
|
59 | case utils_1.AST_NODE_TYPES.TSThisType:
|
60 | case utils_1.AST_NODE_TYPES.TSUnknownKeyword:
|
61 | case utils_1.AST_NODE_TYPES.TSIntrinsicKeyword:
|
62 | return Group.keyword;
|
63 | case utils_1.AST_NODE_TYPES.TSNullKeyword:
|
64 | case utils_1.AST_NODE_TYPES.TSUndefinedKeyword:
|
65 | case utils_1.AST_NODE_TYPES.TSVoidKeyword:
|
66 | return Group.nullish;
|
67 | case utils_1.AST_NODE_TYPES.TSLiteralType:
|
68 | case utils_1.AST_NODE_TYPES.TSTemplateLiteralType:
|
69 | return Group.literal;
|
70 | case utils_1.AST_NODE_TYPES.TSArrayType:
|
71 | case utils_1.AST_NODE_TYPES.TSIndexedAccessType:
|
72 | case utils_1.AST_NODE_TYPES.TSInferType:
|
73 | case utils_1.AST_NODE_TYPES.TSTypeReference:
|
74 | return Group.named;
|
75 | case utils_1.AST_NODE_TYPES.TSMappedType:
|
76 | case utils_1.AST_NODE_TYPES.TSTypeLiteral:
|
77 | return Group.object;
|
78 | case utils_1.AST_NODE_TYPES.TSTypeOperator:
|
79 | case utils_1.AST_NODE_TYPES.TSTypeQuery:
|
80 | return Group.operator;
|
81 | case utils_1.AST_NODE_TYPES.TSTupleType:
|
82 | return Group.tuple;
|
83 | case utils_1.AST_NODE_TYPES.TSUnionType:
|
84 | return Group.union;
|
85 |
|
86 | case utils_1.AST_NODE_TYPES.TSNamedTupleMember:
|
87 | case utils_1.AST_NODE_TYPES.TSOptionalType:
|
88 | case utils_1.AST_NODE_TYPES.TSRestType:
|
89 | case utils_1.AST_NODE_TYPES.TSTypePredicate:
|
90 |
|
91 | throw new Error(`Unexpected Type ${node.type}`);
|
92 | }
|
93 | }
|
94 | function requiresParentheses(node) {
|
95 | return node.type === utils_1.AST_NODE_TYPES.TSFunctionType;
|
96 | }
|
97 | exports.default = util.createRule({
|
98 | name: 'sort-type-union-intersection-members',
|
99 | meta: {
|
100 | type: 'suggestion',
|
101 | docs: {
|
102 | description: 'Enforces that members of a type union/intersection are sorted alphabetically',
|
103 | recommended: false,
|
104 | },
|
105 | fixable: 'code',
|
106 | hasSuggestions: true,
|
107 | messages: {
|
108 | notSorted: '{{type}} type members must be sorted.',
|
109 | notSortedNamed: '{{type}} type {{name}} members must be sorted.',
|
110 | suggestFix: 'Sort members of type (removes all comments).',
|
111 | },
|
112 | schema: [
|
113 | {
|
114 | type: 'object',
|
115 | properties: {
|
116 | checkIntersections: {
|
117 | type: 'boolean',
|
118 | },
|
119 | checkUnions: {
|
120 | type: 'boolean',
|
121 | },
|
122 | groupOrder: {
|
123 | type: 'array',
|
124 | items: {
|
125 | type: 'string',
|
126 | enum: (0, util_1.getEnumNames)(Group),
|
127 | },
|
128 | },
|
129 | },
|
130 | },
|
131 | ],
|
132 | },
|
133 | defaultOptions: [
|
134 | {
|
135 | checkIntersections: true,
|
136 | checkUnions: true,
|
137 | groupOrder: [
|
138 | Group.named,
|
139 | Group.keyword,
|
140 | Group.operator,
|
141 | Group.literal,
|
142 | Group.function,
|
143 | Group.import,
|
144 | Group.conditional,
|
145 | Group.object,
|
146 | Group.tuple,
|
147 | Group.intersection,
|
148 | Group.union,
|
149 | Group.nullish,
|
150 | ],
|
151 | },
|
152 | ],
|
153 | create(context, [{ checkIntersections, checkUnions, groupOrder }]) {
|
154 | const sourceCode = context.getSourceCode();
|
155 | const collator = new Intl.Collator('en', {
|
156 | sensitivity: 'base',
|
157 | numeric: true,
|
158 | });
|
159 | function checkSorting(node) {
|
160 | var _a;
|
161 | const sourceOrder = node.types.map(type => {
|
162 | var _a;
|
163 | const group = (_a = groupOrder === null || groupOrder === void 0 ? void 0 : groupOrder.indexOf(getGroup(type))) !== null && _a !== void 0 ? _a : -1;
|
164 | return {
|
165 | group: group === -1 ? Number.MAX_SAFE_INTEGER : group,
|
166 | node: type,
|
167 | text: sourceCode.getText(type),
|
168 | };
|
169 | });
|
170 | const expectedOrder = [...sourceOrder].sort((a, b) => {
|
171 | if (a.group !== b.group) {
|
172 | return a.group - b.group;
|
173 | }
|
174 | return (collator.compare(a.text, b.text) ||
|
175 | (a.text < b.text ? -1 : a.text > b.text ? 1 : 0));
|
176 | });
|
177 | const hasComments = node.types.some(type => {
|
178 | const count = sourceCode.getCommentsBefore(type).length +
|
179 | sourceCode.getCommentsAfter(type).length;
|
180 | return count > 0;
|
181 | });
|
182 | for (let i = 0; i < expectedOrder.length; i += 1) {
|
183 | if (expectedOrder[i].node !== sourceOrder[i].node) {
|
184 | let messageId = 'notSorted';
|
185 | const data = {
|
186 | name: '',
|
187 | type: node.type === utils_1.AST_NODE_TYPES.TSIntersectionType
|
188 | ? 'Intersection'
|
189 | : 'Union',
|
190 | };
|
191 | if (((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) === utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration) {
|
192 | messageId = 'notSortedNamed';
|
193 | data.name = node.parent.id.name;
|
194 | }
|
195 | const fix = fixer => {
|
196 | const sorted = expectedOrder
|
197 | .map(t => (requiresParentheses(t.node) ? `(${t.text})` : t.text))
|
198 | .join(node.type === utils_1.AST_NODE_TYPES.TSIntersectionType ? ' & ' : ' | ');
|
199 | return fixer.replaceText(node, sorted);
|
200 | };
|
201 | return context.report(Object.assign({ node,
|
202 | messageId,
|
203 | data }, (hasComments
|
204 | ? {
|
205 | suggest: [
|
206 | {
|
207 | messageId: 'suggestFix',
|
208 | fix,
|
209 | },
|
210 | ],
|
211 | }
|
212 | : { fix })));
|
213 | }
|
214 | }
|
215 | }
|
216 | return Object.assign(Object.assign({}, (checkIntersections && {
|
217 | TSIntersectionType(node) {
|
218 | checkSorting(node);
|
219 | },
|
220 | })), (checkUnions && {
|
221 | TSUnionType(node) {
|
222 | checkSorting(node);
|
223 | },
|
224 | }));
|
225 | },
|
226 | });
|
227 |
|
\ | No newline at end of file |