eslint-plugin-power-esrules 0.1.6 → 0.1.8
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/lib/rules/import-sorting.js +48 -30
- package/package.json +1 -1
|
@@ -13,48 +13,62 @@
|
|
|
13
13
|
/**
|
|
14
14
|
* Определяет тип импорта
|
|
15
15
|
* @param {Object} node - AST узел ImportDeclaration
|
|
16
|
-
* @returns {string} - 'external', 'internal', или '
|
|
16
|
+
* @returns {string} - 'external', 'internal', 'component', или 'relative'
|
|
17
17
|
*/
|
|
18
18
|
function getImportType(node) {
|
|
19
19
|
const source = node.source.value;
|
|
20
|
-
// Относительные импорты (./ или ../) всегда
|
|
20
|
+
// Относительные импорты (./ или ../) должны быть всегда самыми последними.
|
|
21
|
+
// Поэтому выделяем их в отдельный тип с самым низким приоритетом сортировки.
|
|
21
22
|
if (source.startsWith("./") || source.startsWith("../")) {
|
|
22
|
-
|
|
23
|
-
// Компоненты обычно импортируются как default или с большой буквы
|
|
24
|
-
const isDefaultImport = node.specifiers.some(
|
|
25
|
-
(spec) => spec.type === "ImportDefaultSpecifier"
|
|
26
|
-
);
|
|
27
|
-
const hasComponentName = node.specifiers.some(
|
|
28
|
-
(spec) =>
|
|
29
|
-
spec.type === "ImportSpecifier" &&
|
|
30
|
-
spec.imported &&
|
|
31
|
-
/^[A-Z]/.test(spec.imported.name)
|
|
32
|
-
);
|
|
33
|
-
if (isDefaultImport || hasComponentName) {
|
|
34
|
-
return "component";
|
|
35
|
-
}
|
|
36
|
-
return "internal";
|
|
23
|
+
return "relative";
|
|
37
24
|
}
|
|
25
|
+
// Старое поведение (оставлено для истории):
|
|
26
|
+
// Относительные импорты (./ или ../) всегда внутренние
|
|
27
|
+
// if (source.startsWith("./") || source.startsWith("../")) {
|
|
28
|
+
// // Проверяем, является ли это компонентом
|
|
29
|
+
// // Компоненты обычно импортируются как default или с большой буквы
|
|
30
|
+
// const isDefaultImport = node.specifiers.some(
|
|
31
|
+
// (spec) => spec.type === "ImportDefaultSpecifier"
|
|
32
|
+
// );
|
|
33
|
+
// const hasComponentName = node.specifiers.some(
|
|
34
|
+
// (spec) =>
|
|
35
|
+
// spec.type === "ImportSpecifier" &&
|
|
36
|
+
// spec.imported &&
|
|
37
|
+
// /^[A-Z]/.test(spec.imported.name)
|
|
38
|
+
// );
|
|
39
|
+
// if (isDefaultImport || hasComponentName) {
|
|
40
|
+
// return "component";
|
|
41
|
+
// }
|
|
42
|
+
// return "internal";
|
|
43
|
+
// }
|
|
38
44
|
|
|
39
45
|
// Сторонние библиотеки (не относительные и не начинаются с внутренних путей)
|
|
40
46
|
const internalPathPatterns = [
|
|
47
|
+
/^actions/,
|
|
48
|
+
/^api/,
|
|
49
|
+
/^base/,
|
|
41
50
|
/^components/,
|
|
42
|
-
/^
|
|
51
|
+
/^containers/,
|
|
52
|
+
/^hooks/,
|
|
53
|
+
/^layouts/,
|
|
54
|
+
/^locales/,
|
|
55
|
+
/^middlewares/,
|
|
43
56
|
/^modules/,
|
|
44
57
|
/^pages/,
|
|
58
|
+
/^reducers/,
|
|
59
|
+
/^sagas/,
|
|
60
|
+
/^selectors/,
|
|
61
|
+
/^theme/,
|
|
62
|
+
/^utils/,
|
|
63
|
+
//
|
|
45
64
|
/^services/,
|
|
46
65
|
/^store/,
|
|
47
66
|
/^types/,
|
|
48
67
|
/^constants/,
|
|
49
|
-
/^hooks/,
|
|
50
68
|
/^helpers/,
|
|
51
|
-
/^selectors/,
|
|
52
|
-
/^base/,
|
|
53
|
-
/^actions/,
|
|
54
|
-
/^containers/,
|
|
55
69
|
];
|
|
56
70
|
const isInternalPath = internalPathPatterns.some((pattern) =>
|
|
57
|
-
pattern.test(source)
|
|
71
|
+
pattern.test(source),
|
|
58
72
|
);
|
|
59
73
|
if (!isInternalPath) {
|
|
60
74
|
return "external";
|
|
@@ -70,14 +84,14 @@ function getImportType(node) {
|
|
|
70
84
|
}
|
|
71
85
|
// Проверяем, является ли это компонентом
|
|
72
86
|
const isDefaultImport = node.specifiers.some(
|
|
73
|
-
(spec) => spec.type === "ImportDefaultSpecifier"
|
|
87
|
+
(spec) => spec.type === "ImportDefaultSpecifier",
|
|
74
88
|
);
|
|
75
89
|
const hasComponentName = node.specifiers.some(
|
|
76
90
|
(spec) =>
|
|
77
91
|
spec.type === "ImportSpecifier" &&
|
|
78
92
|
spec.imported &&
|
|
79
93
|
/^[A-Z][a-zA-Z]*$/.test(spec.imported.name) && // Имя начинается с большой буквы и не все заглавные
|
|
80
|
-
spec.imported.name !== spec.imported.name.toUpperCase() // Не константа (не все заглавные)
|
|
94
|
+
spec.imported.name !== spec.imported.name.toUpperCase(), // Не константа (не все заглавные)
|
|
81
95
|
);
|
|
82
96
|
if (isDefaultImport || hasComponentName) {
|
|
83
97
|
return "component";
|
|
@@ -89,7 +103,7 @@ function getImportType(node) {
|
|
|
89
103
|
spec.type === "ImportSpecifier" &&
|
|
90
104
|
spec.imported &&
|
|
91
105
|
/^[A-Z][a-zA-Z]*$/.test(spec.imported.name) &&
|
|
92
|
-
spec.imported.name !== spec.imported.name.toUpperCase() // Не константа
|
|
106
|
+
spec.imported.name !== spec.imported.name.toUpperCase(), // Не константа
|
|
93
107
|
);
|
|
94
108
|
if (hasComponentName) {
|
|
95
109
|
return "component";
|
|
@@ -105,6 +119,7 @@ function getImportPriority(type) {
|
|
|
105
119
|
external: 1,
|
|
106
120
|
internal: 2,
|
|
107
121
|
component: 3,
|
|
122
|
+
relative: 4,
|
|
108
123
|
};
|
|
109
124
|
return priorities[type] || 999;
|
|
110
125
|
}
|
|
@@ -124,6 +139,9 @@ function compareImports(a, b) {
|
|
|
124
139
|
// Затем по имени источника (алфавитно)
|
|
125
140
|
const sourceA = a.source.value;
|
|
126
141
|
const sourceB = b.source.value;
|
|
142
|
+
// импорты react всегда идут первые
|
|
143
|
+
if (sourceA === "react" && sourceB !== "react") return -1;
|
|
144
|
+
if (sourceB === "react" && sourceA !== "react") return 1;
|
|
127
145
|
return sourceA.localeCompare(sourceB);
|
|
128
146
|
}
|
|
129
147
|
|
|
@@ -159,7 +177,7 @@ module.exports = {
|
|
|
159
177
|
return {
|
|
160
178
|
Program(node) {
|
|
161
179
|
const imports = node.body.filter(
|
|
162
|
-
(stmt) => stmt.type === "ImportDeclaration"
|
|
180
|
+
(stmt) => stmt.type === "ImportDeclaration",
|
|
163
181
|
);
|
|
164
182
|
|
|
165
183
|
if (imports.length === 0) {
|
|
@@ -202,7 +220,7 @@ module.exports = {
|
|
|
202
220
|
}
|
|
203
221
|
return fixer.replaceTextRange(
|
|
204
222
|
[firstToken.range[0], lastToken.range[1]],
|
|
205
|
-
sortedText
|
|
223
|
+
sortedText,
|
|
206
224
|
);
|
|
207
225
|
},
|
|
208
226
|
});
|
|
@@ -251,7 +269,7 @@ module.exports = {
|
|
|
251
269
|
const fixedText = textBetween.replace(/\n\s*\n+/g, "\n");
|
|
252
270
|
return fixer.replaceTextRange(
|
|
253
271
|
[lastTokenOfPrev.range[1], firstToken.range[0]],
|
|
254
|
-
fixedText
|
|
272
|
+
fixedText,
|
|
255
273
|
);
|
|
256
274
|
},
|
|
257
275
|
});
|