eslint-plugin-absolute 0.2.0 → 0.2.1
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.
- package/.absolutejs/eslint.cache.json +49 -0
- package/.absolutejs/prettier.cache.json +49 -0
- package/.absolutejs/tsconfig.tsbuildinfo +1 -0
- package/.claude/settings.local.json +8 -3
- package/dist/index.js +1321 -1419
- package/eslint.config.mjs +107 -0
- package/package.json +10 -8
- package/src/index.ts +15 -15
- package/src/rules/explicit-object-types.ts +42 -40
- package/src/rules/inline-style-limit.ts +56 -54
- package/src/rules/localize-react-props.ts +261 -266
- package/src/rules/max-depth-extended.ts +55 -66
- package/src/rules/max-jsx-nesting.ts +28 -36
- package/src/rules/min-var-length.ts +238 -208
- package/src/rules/no-button-navigation.ts +114 -156
- package/src/rules/no-explicit-return-types.ts +32 -36
- package/src/rules/no-inline-prop-types.ts +30 -30
- package/src/rules/no-multi-style-objects.ts +35 -42
- package/src/rules/no-nested-jsx-return.ts +100 -105
- package/src/rules/no-or-none-component.ts +17 -19
- package/src/rules/no-transition-cssproperties.ts +76 -70
- package/src/rules/no-unnecessary-div.ts +26 -34
- package/src/rules/no-unnecessary-key.ts +41 -75
- package/src/rules/no-useless-function.ts +18 -20
- package/src/rules/seperate-style-files.ts +19 -21
- package/src/rules/sort-exports.ts +252 -248
- package/src/rules/sort-keys-fixable.ts +354 -328
- package/src/rules/spring-naming-convention.ts +104 -89
- package/tsconfig.json +2 -0
|
@@ -30,52 +30,94 @@ type ExportItem = {
|
|
|
30
30
|
text: string;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
meta: {
|
|
35
|
-
type: "suggestion",
|
|
36
|
-
docs: {
|
|
37
|
-
description:
|
|
38
|
-
"Enforce that top-level export declarations are sorted by exported name and, optionally, that variable exports come before function exports"
|
|
39
|
-
},
|
|
40
|
-
fixable: "code",
|
|
41
|
-
schema: [
|
|
42
|
-
{
|
|
43
|
-
type: "object",
|
|
44
|
-
properties: {
|
|
45
|
-
order: {
|
|
46
|
-
type: "string",
|
|
47
|
-
enum: ["asc", "desc"]
|
|
48
|
-
},
|
|
49
|
-
caseSensitive: {
|
|
50
|
-
type: "boolean"
|
|
51
|
-
},
|
|
52
|
-
natural: {
|
|
53
|
-
type: "boolean"
|
|
54
|
-
},
|
|
55
|
-
minKeys: {
|
|
56
|
-
type: "integer",
|
|
57
|
-
minimum: 2
|
|
58
|
-
},
|
|
59
|
-
variablesBeforeFunctions: {
|
|
60
|
-
type: "boolean"
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
additionalProperties: false
|
|
64
|
-
}
|
|
65
|
-
],
|
|
66
|
-
messages: {
|
|
67
|
-
alphabetical:
|
|
68
|
-
"Export declarations are not sorted alphabetically. Expected order: {{expectedOrder}}.",
|
|
69
|
-
variablesBeforeFunctions:
|
|
70
|
-
"Non-function exports should come before function exports."
|
|
71
|
-
}
|
|
72
|
-
},
|
|
33
|
+
const SORT_BEFORE: -1 = -1;
|
|
73
34
|
|
|
74
|
-
|
|
35
|
+
const getVariableDeclaratorName = (
|
|
36
|
+
declaration: TSESTree.VariableDeclaration
|
|
37
|
+
) => {
|
|
38
|
+
if (declaration.declarations.length !== 1) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const [firstDeclarator] = declaration.declarations;
|
|
42
|
+
if (firstDeclarator && firstDeclarator.id.type === "Identifier") {
|
|
43
|
+
return firstDeclarator.id.name;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const getDeclarationName = (
|
|
49
|
+
declaration: TSESTree.ExportNamedDeclaration["declaration"]
|
|
50
|
+
) => {
|
|
51
|
+
if (!declaration) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (declaration.type === "VariableDeclaration") {
|
|
56
|
+
return getVariableDeclaratorName(declaration);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (
|
|
60
|
+
(declaration.type === "FunctionDeclaration" ||
|
|
61
|
+
declaration.type === "ClassDeclaration") &&
|
|
62
|
+
declaration.id &&
|
|
63
|
+
declaration.id.type === "Identifier"
|
|
64
|
+
) {
|
|
65
|
+
return declaration.id.name;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return null;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const getSpecifierName = (node: TSESTree.ExportNamedDeclaration) => {
|
|
72
|
+
if (node.specifiers.length !== 1) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const [spec] = node.specifiers;
|
|
76
|
+
if (!spec) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
if (spec.exported.type === "Identifier") {
|
|
80
|
+
return spec.exported.name;
|
|
81
|
+
}
|
|
82
|
+
if (
|
|
83
|
+
spec.exported.type === "Literal" &&
|
|
84
|
+
typeof spec.exported.value === "string"
|
|
85
|
+
) {
|
|
86
|
+
return spec.exported.value;
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const getExportName = (node: TSESTree.ExportNamedDeclaration) =>
|
|
92
|
+
getDeclarationName(node.declaration) ?? getSpecifierName(node);
|
|
93
|
+
|
|
94
|
+
const isFixableExport = (exportNode: TSESTree.ExportNamedDeclaration) => {
|
|
95
|
+
const { declaration } = exportNode;
|
|
96
|
+
|
|
97
|
+
if (!declaration) {
|
|
98
|
+
return exportNode.specifiers.length === 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
declaration.type === "VariableDeclaration" &&
|
|
103
|
+
declaration.declarations.length === 1
|
|
104
|
+
) {
|
|
105
|
+
const [firstDecl] = declaration.declarations;
|
|
106
|
+
return firstDecl !== undefined && firstDecl.id.type === "Identifier";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
(declaration.type === "FunctionDeclaration" ||
|
|
111
|
+
declaration.type === "ClassDeclaration") &&
|
|
112
|
+
declaration.id !== null &&
|
|
113
|
+
declaration.id.type === "Identifier"
|
|
114
|
+
);
|
|
115
|
+
};
|
|
75
116
|
|
|
117
|
+
export const sortExports: TSESLint.RuleModule<MessageIds, Options> = {
|
|
76
118
|
create(context) {
|
|
77
|
-
const sourceCode = context
|
|
78
|
-
const option = context.options
|
|
119
|
+
const { sourceCode } = context;
|
|
120
|
+
const [option] = context.options;
|
|
79
121
|
|
|
80
122
|
const order: "asc" | "desc" =
|
|
81
123
|
option && option.order ? option.order : "asc";
|
|
@@ -98,131 +140,87 @@ export const sortExports: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
98
140
|
? option.variablesBeforeFunctions
|
|
99
141
|
: false;
|
|
100
142
|
|
|
101
|
-
|
|
102
|
-
|
|
143
|
+
const generateExportText = (node: TSESTree.ExportNamedDeclaration) =>
|
|
144
|
+
sourceCode
|
|
103
145
|
.getText(node)
|
|
104
146
|
.trim()
|
|
105
147
|
.replace(/\s*;?\s*$/, ";");
|
|
106
|
-
}
|
|
107
148
|
|
|
108
|
-
|
|
109
|
-
let
|
|
110
|
-
let
|
|
149
|
+
const compareStrings = (strLeft: string, strRight: string) => {
|
|
150
|
+
let left = strLeft;
|
|
151
|
+
let right = strRight;
|
|
111
152
|
|
|
112
153
|
if (!caseSensitive) {
|
|
113
|
-
|
|
114
|
-
|
|
154
|
+
left = left.toLowerCase();
|
|
155
|
+
right = right.toLowerCase();
|
|
115
156
|
}
|
|
116
157
|
|
|
117
158
|
const cmp = natural
|
|
118
|
-
?
|
|
119
|
-
:
|
|
159
|
+
? left.localeCompare(right, undefined, { numeric: true })
|
|
160
|
+
: left.localeCompare(right);
|
|
120
161
|
|
|
121
162
|
return order === "asc" ? cmp : -cmp;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function getExportName(
|
|
125
|
-
node: TSESTree.ExportNamedDeclaration
|
|
126
|
-
): string | null {
|
|
127
|
-
const declaration = node.declaration;
|
|
128
|
-
|
|
129
|
-
if (declaration) {
|
|
130
|
-
if (declaration.type === "VariableDeclaration") {
|
|
131
|
-
if (declaration.declarations.length === 1) {
|
|
132
|
-
const firstDeclarator = declaration.declarations[0];
|
|
133
|
-
if (
|
|
134
|
-
firstDeclarator &&
|
|
135
|
-
firstDeclarator.id.type === "Identifier"
|
|
136
|
-
) {
|
|
137
|
-
return firstDeclarator.id.name;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
} else if (
|
|
141
|
-
declaration.type === "FunctionDeclaration" ||
|
|
142
|
-
declaration.type === "ClassDeclaration"
|
|
143
|
-
) {
|
|
144
|
-
const id = declaration.id;
|
|
145
|
-
if (id && id.type === "Identifier") {
|
|
146
|
-
return id.name;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
} else if (node.specifiers.length === 1) {
|
|
150
|
-
const spec = node.specifiers[0];
|
|
151
|
-
if (!spec) {
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
if (spec.exported.type === "Identifier") {
|
|
155
|
-
return spec.exported.name;
|
|
156
|
-
}
|
|
157
|
-
if (
|
|
158
|
-
spec.exported.type === "Literal" &&
|
|
159
|
-
typeof spec.exported.value === "string"
|
|
160
|
-
) {
|
|
161
|
-
return spec.exported.value;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
163
|
+
};
|
|
167
164
|
|
|
168
|
-
|
|
169
|
-
const declaration = node
|
|
165
|
+
const isFunctionExport = (node: TSESTree.ExportNamedDeclaration) => {
|
|
166
|
+
const { declaration } = node;
|
|
170
167
|
|
|
171
168
|
if (!declaration) {
|
|
172
169
|
return false;
|
|
173
170
|
}
|
|
174
171
|
|
|
175
|
-
if (declaration.type === "
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
const init = firstDeclarator.init;
|
|
182
|
-
if (!init) {
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
return (
|
|
186
|
-
init.type === "FunctionExpression" ||
|
|
187
|
-
init.type === "ArrowFunctionExpression"
|
|
188
|
-
);
|
|
189
|
-
}
|
|
172
|
+
if (declaration.type === "FunctionDeclaration") {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (declaration.type !== "VariableDeclaration") {
|
|
190
177
|
return false;
|
|
191
178
|
}
|
|
192
179
|
|
|
193
|
-
if (declaration.
|
|
194
|
-
return
|
|
180
|
+
if (declaration.declarations.length !== 1) {
|
|
181
|
+
return false;
|
|
195
182
|
}
|
|
196
183
|
|
|
197
|
-
|
|
198
|
-
|
|
184
|
+
const [firstDeclarator] = declaration.declarations;
|
|
185
|
+
if (!firstDeclarator) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
const { init } = firstDeclarator;
|
|
189
|
+
if (!init) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
return (
|
|
193
|
+
init.type === "FunctionExpression" ||
|
|
194
|
+
init.type === "ArrowFunctionExpression"
|
|
195
|
+
);
|
|
196
|
+
};
|
|
199
197
|
|
|
200
|
-
|
|
201
|
-
const kindA =
|
|
202
|
-
const kindB =
|
|
198
|
+
const sortComparator = (left: ExportItem, right: ExportItem) => {
|
|
199
|
+
const kindA = left.node.exportKind ?? "value";
|
|
200
|
+
const kindB = right.node.exportKind ?? "value";
|
|
203
201
|
|
|
204
202
|
if (kindA !== kindB) {
|
|
205
|
-
return kindA === "type" ?
|
|
203
|
+
return kindA === "type" ? SORT_BEFORE : 1;
|
|
206
204
|
}
|
|
207
205
|
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
206
|
+
if (
|
|
207
|
+
variablesBeforeFunctions &&
|
|
208
|
+
left.isFunction !== right.isFunction
|
|
209
|
+
) {
|
|
210
|
+
return left.isFunction ? 1 : SORT_BEFORE;
|
|
212
211
|
}
|
|
213
212
|
|
|
214
|
-
return compareStrings(
|
|
215
|
-
}
|
|
213
|
+
return compareStrings(left.name, right.name);
|
|
214
|
+
};
|
|
216
215
|
|
|
217
216
|
/**
|
|
218
217
|
* Very lightweight dependency check: look at the text of the node and see
|
|
219
|
-
* if it references any of the later export names.
|
|
220
|
-
* when there might be a forward dependency.
|
|
218
|
+
* if it references any of the later export names.
|
|
221
219
|
*/
|
|
222
|
-
|
|
220
|
+
const hasForwardDependency = (
|
|
223
221
|
node: TSESTree.Node,
|
|
224
222
|
laterNames: Set<string>
|
|
225
|
-
) {
|
|
223
|
+
) => {
|
|
226
224
|
const text = sourceCode.getText(node);
|
|
227
225
|
for (const name of laterNames) {
|
|
228
226
|
if (text.includes(name)) {
|
|
@@ -230,85 +228,91 @@ export const sortExports: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
230
228
|
}
|
|
231
229
|
}
|
|
232
230
|
return false;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function processExportBlock(block: TSESTree.ExportNamedDeclaration[]) {
|
|
236
|
-
if (block.length < minKeys) {
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
231
|
+
};
|
|
239
232
|
|
|
240
|
-
|
|
233
|
+
const buildItems = (block: TSESTree.ExportNamedDeclaration[]) =>
|
|
234
|
+
block
|
|
235
|
+
.map((node) => {
|
|
236
|
+
const name = getExportName(node);
|
|
237
|
+
if (!name) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
const item: ExportItem = {
|
|
241
|
+
isFunction: isFunctionExport(node),
|
|
242
|
+
name,
|
|
243
|
+
node,
|
|
244
|
+
text: sourceCode.getText(node)
|
|
245
|
+
};
|
|
246
|
+
return item;
|
|
247
|
+
})
|
|
248
|
+
.filter((item): item is ExportItem => item !== null);
|
|
249
|
+
|
|
250
|
+
const findFirstUnsorted = (items: ExportItem[]) => {
|
|
251
|
+
let messageId: MessageIds = "alphabetical";
|
|
241
252
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
continue;
|
|
253
|
+
const unsorted = items.some((current, idx) => {
|
|
254
|
+
if (idx === 0) {
|
|
255
|
+
return false;
|
|
246
256
|
}
|
|
257
|
+
const prev = items[idx - 1];
|
|
258
|
+
if (!prev) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
if (sortComparator(prev, current) <= 0) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
if (
|
|
265
|
+
variablesBeforeFunctions &&
|
|
266
|
+
prev.isFunction &&
|
|
267
|
+
!current.isFunction
|
|
268
|
+
) {
|
|
269
|
+
messageId = "variablesBeforeFunctions";
|
|
270
|
+
}
|
|
271
|
+
return true;
|
|
272
|
+
});
|
|
247
273
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
node,
|
|
251
|
-
isFunction: isFunctionExport(node),
|
|
252
|
-
text: sourceCode.getText(node)
|
|
253
|
-
});
|
|
254
|
-
}
|
|
274
|
+
return unsorted ? messageId : null;
|
|
275
|
+
};
|
|
255
276
|
|
|
256
|
-
|
|
277
|
+
const checkForwardDependencies = (items: ExportItem[]) => {
|
|
278
|
+
const exportNames = items.map((item) => item.name);
|
|
279
|
+
return items.some((item, idx) => {
|
|
280
|
+
const laterNames = new Set(exportNames.slice(idx + 1));
|
|
281
|
+
const nodeToCheck: TSESTree.Node =
|
|
282
|
+
item.node.declaration ?? item.node;
|
|
283
|
+
return hasForwardDependency(nodeToCheck, laterNames);
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const processExportBlock = (
|
|
288
|
+
block: TSESTree.ExportNamedDeclaration[]
|
|
289
|
+
) => {
|
|
290
|
+
if (block.length < minKeys) {
|
|
257
291
|
return;
|
|
258
292
|
}
|
|
259
293
|
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
let reportNeeded = false;
|
|
263
|
-
let messageId: MessageIds = "alphabetical";
|
|
264
|
-
|
|
265
|
-
for (let i = 1; i < items.length; i++) {
|
|
266
|
-
const prev = items[i - 1];
|
|
267
|
-
const current = items[i];
|
|
268
|
-
|
|
269
|
-
if (!prev || !current) {
|
|
270
|
-
continue;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (sortComparator(prev, current) > 0) {
|
|
274
|
-
reportNeeded = true;
|
|
294
|
+
const items = buildItems(block);
|
|
275
295
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
prev.isFunction &&
|
|
279
|
-
!current.isFunction
|
|
280
|
-
) {
|
|
281
|
-
messageId = "variablesBeforeFunctions";
|
|
282
|
-
}
|
|
283
|
-
break;
|
|
284
|
-
}
|
|
296
|
+
if (items.length < minKeys) {
|
|
297
|
+
return;
|
|
285
298
|
}
|
|
286
299
|
|
|
287
|
-
|
|
300
|
+
const messageId = findFirstUnsorted(items);
|
|
301
|
+
if (!messageId) {
|
|
288
302
|
return;
|
|
289
303
|
}
|
|
290
304
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
for (let i = 0; i < items.length; i++) {
|
|
294
|
-
const item = items[i];
|
|
295
|
-
if (!item) {
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
const laterNames = new Set(exportNames.slice(i + 1));
|
|
299
|
-
const nodeToCheck: TSESTree.Node =
|
|
300
|
-
item.node.declaration ?? item.node;
|
|
301
|
-
|
|
302
|
-
if (hasForwardDependency(nodeToCheck, laterNames)) {
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
+
if (checkForwardDependencies(items)) {
|
|
306
|
+
return;
|
|
305
307
|
}
|
|
306
308
|
|
|
309
|
+
const sortedItems = items.slice().sort(sortComparator);
|
|
310
|
+
|
|
307
311
|
const expectedOrder = sortedItems
|
|
308
312
|
.map((item) => item.name)
|
|
309
313
|
.join(", ");
|
|
310
314
|
|
|
311
|
-
const firstNode = block
|
|
315
|
+
const [firstNode] = block;
|
|
312
316
|
const lastNode = block[block.length - 1];
|
|
313
317
|
|
|
314
318
|
if (!firstNode || !lastNode) {
|
|
@@ -316,49 +320,11 @@ export const sortExports: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
316
320
|
}
|
|
317
321
|
|
|
318
322
|
context.report({
|
|
319
|
-
node: firstNode,
|
|
320
|
-
messageId,
|
|
321
323
|
data: {
|
|
322
324
|
expectedOrder
|
|
323
325
|
},
|
|
324
326
|
fix(fixer) {
|
|
325
|
-
const fixableNodes
|
|
326
|
-
|
|
327
|
-
for (const n of block) {
|
|
328
|
-
const declaration = n.declaration;
|
|
329
|
-
|
|
330
|
-
if (declaration) {
|
|
331
|
-
if (
|
|
332
|
-
declaration.type === "VariableDeclaration" &&
|
|
333
|
-
declaration.declarations.length === 1
|
|
334
|
-
) {
|
|
335
|
-
const firstDecl = declaration.declarations[0];
|
|
336
|
-
if (
|
|
337
|
-
firstDecl &&
|
|
338
|
-
firstDecl.id.type === "Identifier"
|
|
339
|
-
) {
|
|
340
|
-
fixableNodes.push(n);
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
if (
|
|
346
|
-
(declaration.type === "FunctionDeclaration" ||
|
|
347
|
-
declaration.type === "ClassDeclaration") &&
|
|
348
|
-
declaration.id &&
|
|
349
|
-
declaration.id.type === "Identifier"
|
|
350
|
-
) {
|
|
351
|
-
fixableNodes.push(n);
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
continue;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (n.specifiers.length === 1) {
|
|
359
|
-
fixableNodes.push(n);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
327
|
+
const fixableNodes = block.filter(isFixableExport);
|
|
362
328
|
|
|
363
329
|
if (fixableNodes.length < minKeys) {
|
|
364
330
|
return null;
|
|
@@ -368,8 +334,8 @@ export const sortExports: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
368
334
|
.map((item) => generateExportText(item.node))
|
|
369
335
|
.join("\n");
|
|
370
336
|
|
|
371
|
-
const rangeStart = firstNode.range
|
|
372
|
-
const rangeEnd = lastNode.range
|
|
337
|
+
const [rangeStart] = firstNode.range;
|
|
338
|
+
const [, rangeEnd] = lastNode.range;
|
|
373
339
|
|
|
374
340
|
const fullText = sourceCode.getText();
|
|
375
341
|
const originalText = fullText.slice(rangeStart, rangeEnd);
|
|
@@ -382,39 +348,77 @@ export const sortExports: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
382
348
|
[rangeStart, rangeEnd],
|
|
383
349
|
sortedText
|
|
384
350
|
);
|
|
385
|
-
}
|
|
351
|
+
},
|
|
352
|
+
messageId,
|
|
353
|
+
node: firstNode
|
|
386
354
|
});
|
|
387
|
-
}
|
|
355
|
+
};
|
|
388
356
|
|
|
389
357
|
return {
|
|
390
358
|
"Program:exit"(node: TSESTree.Program) {
|
|
391
|
-
const body = node
|
|
359
|
+
const { body } = node;
|
|
392
360
|
const block: TSESTree.ExportNamedDeclaration[] = [];
|
|
393
361
|
|
|
394
|
-
|
|
395
|
-
const stmt = body[i];
|
|
396
|
-
if (!stmt) {
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
|
|
362
|
+
body.forEach((stmt) => {
|
|
400
363
|
if (
|
|
401
364
|
stmt.type === "ExportNamedDeclaration" &&
|
|
402
365
|
!stmt.source &&
|
|
403
366
|
getExportName(stmt) !== null
|
|
404
367
|
) {
|
|
405
368
|
block.push(stmt);
|
|
406
|
-
|
|
407
|
-
if (block.length > 0) {
|
|
408
|
-
processExportBlock(block);
|
|
409
|
-
block.length = 0;
|
|
410
|
-
}
|
|
369
|
+
return;
|
|
411
370
|
}
|
|
412
|
-
|
|
371
|
+
|
|
372
|
+
if (block.length > 0) {
|
|
373
|
+
processExportBlock(block);
|
|
374
|
+
block.length = 0;
|
|
375
|
+
}
|
|
376
|
+
});
|
|
413
377
|
|
|
414
378
|
if (block.length > 0) {
|
|
415
379
|
processExportBlock(block);
|
|
416
380
|
}
|
|
417
381
|
}
|
|
418
382
|
};
|
|
383
|
+
},
|
|
384
|
+
defaultOptions: [{}],
|
|
385
|
+
meta: {
|
|
386
|
+
docs: {
|
|
387
|
+
description:
|
|
388
|
+
"Enforce that top-level export declarations are sorted by exported name and, optionally, that variable exports come before function exports"
|
|
389
|
+
},
|
|
390
|
+
fixable: "code",
|
|
391
|
+
messages: {
|
|
392
|
+
alphabetical:
|
|
393
|
+
"Export declarations are not sorted alphabetically. Expected order: {{expectedOrder}}.",
|
|
394
|
+
variablesBeforeFunctions:
|
|
395
|
+
"Non-function exports should come before function exports."
|
|
396
|
+
},
|
|
397
|
+
schema: [
|
|
398
|
+
{
|
|
399
|
+
additionalProperties: false,
|
|
400
|
+
properties: {
|
|
401
|
+
caseSensitive: {
|
|
402
|
+
type: "boolean"
|
|
403
|
+
},
|
|
404
|
+
minKeys: {
|
|
405
|
+
minimum: 2,
|
|
406
|
+
type: "integer"
|
|
407
|
+
},
|
|
408
|
+
natural: {
|
|
409
|
+
type: "boolean"
|
|
410
|
+
},
|
|
411
|
+
order: {
|
|
412
|
+
enum: ["asc", "desc"],
|
|
413
|
+
type: "string"
|
|
414
|
+
},
|
|
415
|
+
variablesBeforeFunctions: {
|
|
416
|
+
type: "boolean"
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
type: "object"
|
|
420
|
+
}
|
|
421
|
+
],
|
|
422
|
+
type: "suggestion"
|
|
419
423
|
}
|
|
420
424
|
};
|