eslint-plugin-power-esrules 0.1.9 → 0.1.11
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/index.js +1 -1
- package/lib/rules/use-state-naming.js +129 -122
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -20,7 +20,7 @@ module.exports = {
|
|
|
20
20
|
"power-esrules/use-state-naming": "warn",
|
|
21
21
|
"power-esrules/class-to-functional": "error",
|
|
22
22
|
"power-esrules/import-sorting": "error",
|
|
23
|
-
"power-esrules/require-data-testid": "
|
|
23
|
+
"power-esrules/require-data-testid": "warn",
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
26
|
},
|
|
@@ -6,149 +6,156 @@
|
|
|
6
6
|
* Названия переменных созданных через useState по возможности должны иметь окончание State
|
|
7
7
|
* (например innerModalState, setInnerModalState).
|
|
8
8
|
*/
|
|
9
|
+
String.prototype.firstLetterToUppercase = function () {
|
|
10
|
+
return this[0].toUpperCase() + this.slice(1);
|
|
11
|
+
};
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Проверяет, является ли узел вызовом useState
|
|
12
15
|
*/
|
|
13
16
|
function isUseStateCall(node) {
|
|
14
|
-
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
const { callee } = node;
|
|
18
|
-
if (callee.type === 'Identifier' && callee.name === 'useState') {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
if (
|
|
22
|
-
callee.type === 'MemberExpression' &&
|
|
23
|
-
callee.property &&
|
|
24
|
-
callee.property.type === 'Identifier' &&
|
|
25
|
-
callee.property.name === 'useState'
|
|
26
|
-
) {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
17
|
+
if (!node || node.type !== "CallExpression") {
|
|
29
18
|
return false;
|
|
19
|
+
}
|
|
20
|
+
const { callee } = node;
|
|
21
|
+
if (callee.type === "Identifier" && callee.name === "useState") {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
if (
|
|
25
|
+
callee.type === "MemberExpression" &&
|
|
26
|
+
callee.property &&
|
|
27
|
+
callee.property.type === "Identifier" &&
|
|
28
|
+
callee.property.name === "useState"
|
|
29
|
+
) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
/**
|
|
33
36
|
* Проверяет, заканчивается ли имя на "State"
|
|
34
37
|
*/
|
|
35
38
|
function endsWithState(name) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
if (!name || typeof name !== "string") {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return name.endsWith("State");
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
/**
|
|
43
46
|
* Генерирует правильное имя с окончанием State
|
|
44
47
|
*/
|
|
45
48
|
function fixStateName(name) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
if (!name || typeof name !== "string") {
|
|
50
|
+
return name;
|
|
51
|
+
}
|
|
52
|
+
if (endsWithState(name)) {
|
|
53
|
+
return name;
|
|
54
|
+
}
|
|
55
|
+
return `${name}State`;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
module.exports = {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
},
|
|
63
|
-
// fixable: 'code', // OLD: auto-fixable (eslint --fix)
|
|
64
|
-
hasSuggestions: true, // NEW: quick-fix suggestions (not applied by eslint --fix)
|
|
65
|
-
schema: [],
|
|
66
|
-
messages: {
|
|
67
|
-
useStateShouldEndWithState:
|
|
68
|
-
'Переменные useState должны иметь окончание "State". ' +
|
|
69
|
-
'Вместо "{{variableName}}" используйте "{{suggestedName}}"',
|
|
70
|
-
suggestRenameTo: 'Переименовать в "{{suggestedName}}"',
|
|
71
|
-
},
|
|
59
|
+
meta: {
|
|
60
|
+
type: "suggestion",
|
|
61
|
+
docs: {
|
|
62
|
+
description: "Проверяет, что переменные useState имеют окончание State",
|
|
63
|
+
category: "Stylistic Issues",
|
|
64
|
+
recommended: false,
|
|
72
65
|
},
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (!init || !isUseStateCall(init)) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const { elements } = node.id;
|
|
85
|
-
if (!elements || elements.length < 1) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const stateElement = elements[0];
|
|
89
|
-
let stateName = null;
|
|
90
|
-
if (stateElement && stateElement.type === 'Identifier') {
|
|
91
|
-
stateName = stateElement.name;
|
|
92
|
-
if (!endsWithState(stateName)) {
|
|
93
|
-
const suggestedName = fixStateName(stateName);
|
|
94
|
-
context.report({
|
|
95
|
-
node: stateElement,
|
|
96
|
-
messageId: 'useStateShouldEndWithState',
|
|
97
|
-
data: {
|
|
98
|
-
variableName: stateName,
|
|
99
|
-
suggestedName,
|
|
100
|
-
},
|
|
101
|
-
/*
|
|
102
|
-
* OLD auto-fix:
|
|
103
|
-
* fix(fixer) {
|
|
104
|
-
* return fixer.replaceText(stateElement, suggestedName);
|
|
105
|
-
* },
|
|
106
|
-
*/
|
|
107
|
-
suggest: [
|
|
108
|
-
{
|
|
109
|
-
messageId: 'suggestRenameTo',
|
|
110
|
-
data: { suggestedName },
|
|
111
|
-
fix(fixer) {
|
|
112
|
-
return fixer.replaceText(stateElement, suggestedName);
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
],
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
const setterElement = elements[1];
|
|
120
|
-
if (setterElement && setterElement.type === 'Identifier' && stateName) {
|
|
121
|
-
const setterName = setterElement.name;
|
|
122
|
-
const correctedStateName = endsWithState(stateName) ? stateName : fixStateName(stateName);
|
|
123
|
-
const stateNameWithoutState = correctedStateName.replace(/State$/, '');
|
|
124
|
-
const expectedSetterName = `set${stateNameWithoutState}State`;
|
|
125
|
-
if (setterName !== expectedSetterName) {
|
|
126
|
-
context.report({
|
|
127
|
-
node: setterElement,
|
|
128
|
-
messageId: 'useStateShouldEndWithState',
|
|
129
|
-
data: {
|
|
130
|
-
variableName: setterName,
|
|
131
|
-
suggestedName: expectedSetterName,
|
|
132
|
-
},
|
|
133
|
-
/*
|
|
134
|
-
* OLD auto-fix:
|
|
135
|
-
* fix(fixer) {
|
|
136
|
-
* return fixer.replaceText(setterElement, expectedSetterName);
|
|
137
|
-
* },
|
|
138
|
-
*/
|
|
139
|
-
suggest: [
|
|
140
|
-
{
|
|
141
|
-
messageId: 'suggestRenameTo',
|
|
142
|
-
data: { suggestedName: expectedSetterName },
|
|
143
|
-
fix(fixer) {
|
|
144
|
-
return fixer.replaceText(setterElement, expectedSetterName);
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
],
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
};
|
|
66
|
+
// fixable: 'code', // OLD: auto-fixable (eslint --fix)
|
|
67
|
+
hasSuggestions: true, // NEW: quick-fix suggestions (not applied by eslint --fix)
|
|
68
|
+
schema: [],
|
|
69
|
+
messages: {
|
|
70
|
+
useStateShouldEndWithState:
|
|
71
|
+
'Переменные useState должны иметь окончание "State". ' +
|
|
72
|
+
'Вместо "{{variableName}}" используйте "{{suggestedName}}"',
|
|
73
|
+
suggestRenameTo: 'Переименовать в "{{suggestedName}}"',
|
|
153
74
|
},
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
create(context) {
|
|
78
|
+
return {
|
|
79
|
+
VariableDeclarator(node) {
|
|
80
|
+
if (!node.id || node.id.type !== "ArrayPattern") {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const { init } = node;
|
|
84
|
+
if (!init || !isUseStateCall(init)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const { elements } = node.id;
|
|
88
|
+
if (!elements || elements.length < 1) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const stateElement = elements[0];
|
|
92
|
+
let stateName = null;
|
|
93
|
+
if (stateElement && stateElement.type === "Identifier") {
|
|
94
|
+
stateName = stateElement.name;
|
|
95
|
+
if (!endsWithState(stateName)) {
|
|
96
|
+
const suggestedName = fixStateName(stateName);
|
|
97
|
+
context.report({
|
|
98
|
+
node: stateElement,
|
|
99
|
+
messageId: "useStateShouldEndWithState",
|
|
100
|
+
data: {
|
|
101
|
+
variableName: stateName,
|
|
102
|
+
suggestedName,
|
|
103
|
+
},
|
|
104
|
+
/*
|
|
105
|
+
* OLD auto-fix:
|
|
106
|
+
* fix(fixer) {
|
|
107
|
+
* return fixer.replaceText(stateElement, suggestedName);
|
|
108
|
+
* },
|
|
109
|
+
*/
|
|
110
|
+
suggest: [
|
|
111
|
+
{
|
|
112
|
+
messageId: "suggestRenameTo",
|
|
113
|
+
data: { suggestedName },
|
|
114
|
+
fix(fixer) {
|
|
115
|
+
return fixer.replaceText(stateElement, suggestedName);
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const setterElement = elements[1];
|
|
123
|
+
if (setterElement && setterElement.type === "Identifier" && stateName) {
|
|
124
|
+
const setterName = setterElement.name;
|
|
125
|
+
const correctedStateName = endsWithState(stateName)
|
|
126
|
+
? stateName
|
|
127
|
+
: fixStateName(stateName);
|
|
128
|
+
const stateNameWithoutState = correctedStateName
|
|
129
|
+
.replace(/State$/, "")
|
|
130
|
+
.firstLetterToUppercase();
|
|
131
|
+
const expectedSetterName = `set${stateNameWithoutState}State`;
|
|
132
|
+
if (setterName !== expectedSetterName) {
|
|
133
|
+
context.report({
|
|
134
|
+
node: setterElement,
|
|
135
|
+
messageId: "useStateShouldEndWithState",
|
|
136
|
+
data: {
|
|
137
|
+
variableName: setterName,
|
|
138
|
+
suggestedName: expectedSetterName,
|
|
139
|
+
},
|
|
140
|
+
/*
|
|
141
|
+
* OLD auto-fix:
|
|
142
|
+
* fix(fixer) {
|
|
143
|
+
* return fixer.replaceText(setterElement, expectedSetterName);
|
|
144
|
+
* },
|
|
145
|
+
*/
|
|
146
|
+
suggest: [
|
|
147
|
+
{
|
|
148
|
+
messageId: "suggestRenameTo",
|
|
149
|
+
data: { suggestedName: expectedSetterName },
|
|
150
|
+
fix(fixer) {
|
|
151
|
+
return fixer.replaceText(setterElement, expectedSetterName);
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
},
|
|
154
161
|
};
|