eslint 9.15.0 → 9.17.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.
- package/README.md +1 -1
- package/lib/linter/source-code-fixer.js +1 -1
- package/lib/rules/accessor-pairs.js +5 -4
- package/lib/rules/default-case-last.js +2 -2
- package/lib/rules/for-direction.js +2 -2
- package/lib/rules/getter-return.js +3 -1
- package/lib/rules/id-length.js +2 -1
- package/lib/rules/id-match.js +6 -1
- package/lib/rules/new-cap.js +1 -1
- package/lib/rules/no-bitwise.js +4 -1
- package/lib/rules/no-compare-neg-zero.js +1 -1
- package/lib/rules/no-duplicate-imports.js +3 -1
- package/lib/rules/no-empty-pattern.js +3 -1
- package/lib/rules/no-eval.js +3 -1
- package/lib/rules/no-implicit-globals.js +3 -1
- package/lib/rules/no-inner-declarations.js +2 -2
- package/lib/rules/no-multi-assign.js +3 -1
- package/lib/rules/no-param-reassign.js +2 -2
- package/lib/rules/no-plusplus.js +3 -1
- package/lib/rules/no-promise-executor-return.js +3 -1
- package/lib/rules/no-script-url.js +3 -3
- package/lib/rules/no-shadow.js +4 -2
- package/lib/rules/no-undef.js +3 -1
- package/lib/rules/no-underscore-dangle.js +1 -0
- package/lib/rules/no-unsafe-negation.js +3 -1
- package/lib/rules/no-unsafe-optional-chaining.js +3 -1
- package/lib/rules/no-unused-vars.js +613 -2
- package/lib/rules/no-use-before-define.js +2 -1
- package/lib/rules/no-useless-assignment.js +9 -0
- package/lib/rules/no-useless-computed-key.js +1 -1
- package/lib/rules/no-useless-rename.js +5 -1
- package/lib/rules/no-void.js +3 -1
- package/lib/rules/prefer-const.js +6 -4
- package/lib/rules/prefer-object-spread.js +2 -2
- package/lib/rules/prefer-promise-reject-errors.js +3 -1
- package/lib/rules/prefer-regex-literals.js +3 -1
- package/lib/rules/require-atomic-updates.js +3 -1
- package/lib/rules/require-unicode-regexp.js +2 -2
- package/lib/rules/sort-keys.js +10 -1
- package/lib/rules/sort-vars.js +4 -3
- package/lib/rules/use-isnan.js +1 -2
- package/lib/rules/valid-typeof.js +4 -3
- package/lib/shared/flags.js +1 -1
- package/lib/types/rules/stylistic-issues.d.ts +4 -0
- package/package.json +6 -6
@@ -50,6 +50,8 @@ module.exports = {
|
|
50
50
|
url: "https://eslint.org/docs/latest/rules/no-unused-vars"
|
51
51
|
},
|
52
52
|
|
53
|
+
hasSuggestions: true,
|
54
|
+
|
53
55
|
schema: [
|
54
56
|
{
|
55
57
|
oneOf: [
|
@@ -98,7 +100,8 @@ module.exports = {
|
|
98
100
|
|
99
101
|
messages: {
|
100
102
|
unusedVar: "'{{varName}}' is {{action}} but never used{{additional}}.",
|
101
|
-
usedIgnoredVar: "'{{varName}}' is marked as ignored but is used{{additional}}."
|
103
|
+
usedIgnoredVar: "'{{varName}}' is marked as ignored but is used{{additional}}.",
|
104
|
+
removeVar: "Remove unused variable '{{varName}}'."
|
102
105
|
}
|
103
106
|
},
|
104
107
|
|
@@ -172,6 +175,7 @@ module.exports = {
|
|
172
175
|
return "catch-clause";
|
173
176
|
case "Parameter":
|
174
177
|
return "parameter";
|
178
|
+
|
175
179
|
default:
|
176
180
|
return "variable";
|
177
181
|
}
|
@@ -832,6 +836,602 @@ module.exports = {
|
|
832
836
|
return unusedVars;
|
833
837
|
}
|
834
838
|
|
839
|
+
/**
|
840
|
+
* fixes unused variables
|
841
|
+
* @param {Object} fixer fixer object
|
842
|
+
* @param {Object} unusedVar unused variable to fix
|
843
|
+
* @returns {Object} fixer object
|
844
|
+
*/
|
845
|
+
function handleFixes(fixer, unusedVar) {
|
846
|
+
const id = unusedVar.identifiers[0];
|
847
|
+
const parent = id.parent;
|
848
|
+
const parentType = parent.type;
|
849
|
+
const tokenBefore = sourceCode.getTokenBefore(id);
|
850
|
+
const tokenAfter = sourceCode.getTokenAfter(id);
|
851
|
+
const isFunction = astUtils.isFunction;
|
852
|
+
const isLoop = astUtils.isLoop;
|
853
|
+
const allWriteReferences = unusedVar.references.filter(ref => ref.isWrite());
|
854
|
+
|
855
|
+
/**
|
856
|
+
* get range from token before of a given node
|
857
|
+
* @param {ASTNode} node node of identifier
|
858
|
+
* @param {number} skips number of token to skip
|
859
|
+
* @returns {number} start range of token before the identifier
|
860
|
+
*/
|
861
|
+
function getPreviousTokenStart(node, skips) {
|
862
|
+
return sourceCode.getTokenBefore(node, skips).range[0];
|
863
|
+
}
|
864
|
+
|
865
|
+
/**
|
866
|
+
* get range to token after of a given node
|
867
|
+
* @param {ASTNode} node node of identifier
|
868
|
+
* @param {number} skips number of token to skip
|
869
|
+
* @returns {number} end range of token after the identifier
|
870
|
+
*/
|
871
|
+
function getNextTokenEnd(node, skips) {
|
872
|
+
return sourceCode.getTokenAfter(node, skips).range[1];
|
873
|
+
}
|
874
|
+
|
875
|
+
/**
|
876
|
+
* get the value of token before of a given node
|
877
|
+
* @param {ASTNode} node node of identifier
|
878
|
+
* @returns {string} value of token before the identifier
|
879
|
+
*/
|
880
|
+
function getTokenBeforeValue(node) {
|
881
|
+
return sourceCode.getTokenBefore(node).value;
|
882
|
+
}
|
883
|
+
|
884
|
+
/**
|
885
|
+
* get the value of token after of a given node
|
886
|
+
* @param {ASTNode} node node of identifier
|
887
|
+
* @returns {string} value of token after the identifier
|
888
|
+
*/
|
889
|
+
function getTokenAfterValue(node) {
|
890
|
+
return sourceCode.getTokenAfter(node).value;
|
891
|
+
}
|
892
|
+
|
893
|
+
/**
|
894
|
+
* Check if an array has a single element with null as other element.
|
895
|
+
* @param {ASTNode} node ArrayPattern node
|
896
|
+
* @returns {boolean} true if array has single element with other null elements
|
897
|
+
*/
|
898
|
+
function hasSingleElement(node) {
|
899
|
+
return node.elements.filter(e => e !== null).length === 1;
|
900
|
+
}
|
901
|
+
|
902
|
+
/**
|
903
|
+
* check whether import specifier has an import of particular type
|
904
|
+
* @param {ASTNode} node ImportDeclaration node
|
905
|
+
* @param {string} type type of import to check
|
906
|
+
* @returns {boolean} true if import specifier has import of specified type
|
907
|
+
*/
|
908
|
+
function hasImportOfCertainType(node, type) {
|
909
|
+
return node.specifiers.some(e => e.type === type);
|
910
|
+
}
|
911
|
+
|
912
|
+
/**
|
913
|
+
* Check whether declaration is safe to remove or not
|
914
|
+
* @param {ASTNode} nextToken next token of unused variable
|
915
|
+
* @param {ASTNode} prevToken previous token of unused variable
|
916
|
+
* @returns {boolean} true if declaration is not safe to remove
|
917
|
+
*/
|
918
|
+
function isDeclarationNotSafeToRemove(nextToken, prevToken) {
|
919
|
+
return (
|
920
|
+
(nextToken.type === "String") ||
|
921
|
+
(
|
922
|
+
prevToken &&
|
923
|
+
!astUtils.isSemicolonToken(prevToken) &&
|
924
|
+
!astUtils.isOpeningBraceToken(prevToken)
|
925
|
+
)
|
926
|
+
);
|
927
|
+
}
|
928
|
+
|
929
|
+
/**
|
930
|
+
* give fixes for unused variables in function parameters
|
931
|
+
* @param {ASTNode} node node to check
|
932
|
+
* @returns {Object} fixer object
|
933
|
+
*/
|
934
|
+
function fixFunctionParameters(node) {
|
935
|
+
const parentNode = node.parent;
|
936
|
+
|
937
|
+
if (isFunction(parentNode)) {
|
938
|
+
|
939
|
+
// remove unused function parameter if there is only a single parameter
|
940
|
+
if (parentNode.params.length === 1) {
|
941
|
+
return fixer.removeRange(node.range);
|
942
|
+
}
|
943
|
+
|
944
|
+
// remove first unused function parameter when there are multiple parameters
|
945
|
+
if (getTokenBeforeValue(node) === "(" && getTokenAfterValue(node) === ",") {
|
946
|
+
return fixer.removeRange([node.range[0], getNextTokenEnd(node)]);
|
947
|
+
}
|
948
|
+
|
949
|
+
// remove unused function parameters except first one when there are multiple parameters
|
950
|
+
return fixer.removeRange([getPreviousTokenStart(node), node.range[1]]);
|
951
|
+
}
|
952
|
+
|
953
|
+
return null;
|
954
|
+
}
|
955
|
+
|
956
|
+
/**
|
957
|
+
* fix unused variable declarations and function parameters
|
958
|
+
* @param {ASTNode} node parent node to identifier
|
959
|
+
* @returns {Object} fixer object
|
960
|
+
*/
|
961
|
+
function fixVariables(node) {
|
962
|
+
const parentNode = node.parent;
|
963
|
+
|
964
|
+
// remove unused declared variables such as var a = b; or var a = b, c;
|
965
|
+
if (parentNode.type === "VariableDeclarator") {
|
966
|
+
|
967
|
+
// skip variable in for (const [ foo ] of bar);
|
968
|
+
if (isLoop(parentNode.parent.parent)) {
|
969
|
+
return null;
|
970
|
+
}
|
971
|
+
|
972
|
+
/*
|
973
|
+
* remove unused declared variable with single declaration such as 'var a = b;'
|
974
|
+
* remove complete declaration when there is an unused variable in 'const { a } = foo;', same for arrays.
|
975
|
+
*/
|
976
|
+
if (parentNode.parent.declarations.length === 1) {
|
977
|
+
|
978
|
+
// if next token is a string it could become a directive if node is removed -> no suggestion.
|
979
|
+
const nextToken = sourceCode.getTokenAfter(parentNode.parent);
|
980
|
+
|
981
|
+
// if previous token exists and is not ";" or "{" not sure about ASI rules -> no suggestion.
|
982
|
+
const prevToken = sourceCode.getTokenBefore(parentNode.parent);
|
983
|
+
|
984
|
+
if (nextToken && isDeclarationNotSafeToRemove(nextToken, prevToken)) {
|
985
|
+
return null;
|
986
|
+
}
|
987
|
+
|
988
|
+
return fixer.removeRange(parentNode.parent.range);
|
989
|
+
}
|
990
|
+
|
991
|
+
/*
|
992
|
+
* remove unused declared variable with multiple declaration except first one such as 'var a = b, c = d;'
|
993
|
+
* fix 'let bar = "hello", { a } = foo;' to 'let bar = "hello";' if 'a' is unused, same for arrays.
|
994
|
+
*/
|
995
|
+
if (getTokenBeforeValue(parentNode) === ",") {
|
996
|
+
return fixer.removeRange([getPreviousTokenStart(parentNode), parentNode.range[1]]);
|
997
|
+
}
|
998
|
+
|
999
|
+
/*
|
1000
|
+
* remove first unused declared variable when there are multiple declarations
|
1001
|
+
* fix 'let { a } = foo, bar = "hello";' to 'let bar = "hello";' if 'a' is unused, same for arrays.
|
1002
|
+
*/
|
1003
|
+
return fixer.removeRange([parentNode.range[0], getNextTokenEnd(parentNode)]);
|
1004
|
+
}
|
1005
|
+
|
1006
|
+
// fixes [{a: {k}}], [{a: [k]}]
|
1007
|
+
if (getTokenBeforeValue(node) === ":") {
|
1008
|
+
if (parentNode.parent.type === "ObjectPattern") {
|
1009
|
+
// eslint-disable-next-line no-use-before-define -- due to interdependency of functions
|
1010
|
+
return fixObjectWithValueSeparator(node);
|
1011
|
+
}
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
// fix unused function parameters
|
1015
|
+
return fixFunctionParameters(node);
|
1016
|
+
}
|
1017
|
+
|
1018
|
+
/**
|
1019
|
+
* fix nested object like { a: { b } }
|
1020
|
+
* @param {ASTNode} node parent node to check
|
1021
|
+
* @returns {Object} fixer object
|
1022
|
+
*/
|
1023
|
+
function fixNestedObjectVariable(node) {
|
1024
|
+
const parentNode = node.parent;
|
1025
|
+
|
1026
|
+
// fix for { a: { b: { c: { d } } } }
|
1027
|
+
if (
|
1028
|
+
parentNode.parent.parent.parent.type === "ObjectPattern" &&
|
1029
|
+
parentNode.parent.properties.length === 1
|
1030
|
+
) {
|
1031
|
+
return fixNestedObjectVariable(parentNode.parent);
|
1032
|
+
}
|
1033
|
+
|
1034
|
+
// fix for { a: { b } }
|
1035
|
+
if (parentNode.parent.type === "ObjectPattern") {
|
1036
|
+
|
1037
|
+
// fix for unused variables in dectructured object with single property in variable decalartion and function parameter
|
1038
|
+
if (parentNode.parent.properties.length === 1) {
|
1039
|
+
return fixVariables(parentNode.parent);
|
1040
|
+
}
|
1041
|
+
|
1042
|
+
// fix for first unused property when there are multiple properties such as '{ a: { b }, c }'
|
1043
|
+
if (getTokenBeforeValue(parentNode) === "{") {
|
1044
|
+
return fixer.removeRange(
|
1045
|
+
[parentNode.range[0], getNextTokenEnd(parentNode)]
|
1046
|
+
);
|
1047
|
+
}
|
1048
|
+
|
1049
|
+
// fix for unused property except first one when there are multiple properties such as '{ k, a: { b } }'
|
1050
|
+
return fixer.removeRange([getPreviousTokenStart(parentNode), parentNode.range[1]]);
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
return null;
|
1054
|
+
}
|
1055
|
+
|
1056
|
+
/**
|
1057
|
+
* fix unused variables in array and nested array
|
1058
|
+
* @param {ASTNode} node parent node to check
|
1059
|
+
* @returns {Object} fixer object
|
1060
|
+
*/
|
1061
|
+
function fixNestedArrayVariable(node) {
|
1062
|
+
const parentNode = node.parent;
|
1063
|
+
|
1064
|
+
// fix for nested arrays [[ a ]]
|
1065
|
+
if (parentNode.parent.type === "ArrayPattern" && hasSingleElement(parentNode)) {
|
1066
|
+
return fixNestedArrayVariable(parentNode);
|
1067
|
+
}
|
1068
|
+
|
1069
|
+
if (hasSingleElement(parentNode)) {
|
1070
|
+
|
1071
|
+
// fixes { a: [{ b }] } or { a: [[ b ]] }
|
1072
|
+
if (getTokenBeforeValue(parentNode) === ":") {
|
1073
|
+
return fixVariables(parentNode);
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
// fixes [a, ...[[ b ]]] or [a, ...[{ b }]]
|
1077
|
+
if (parentNode.parent.type === "RestElement") {
|
1078
|
+
// eslint-disable-next-line no-use-before-define -- due to interdependency of functions
|
1079
|
+
return fixRestInPattern(parentNode.parent);
|
1080
|
+
}
|
1081
|
+
|
1082
|
+
// fix unused variables in destructured array in variable declaration or function parameter
|
1083
|
+
return fixVariables(parentNode);
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
// remove last unused array element
|
1087
|
+
if (
|
1088
|
+
getTokenBeforeValue(node) === "," &&
|
1089
|
+
getTokenAfterValue(node) === "]"
|
1090
|
+
) {
|
1091
|
+
return fixer.removeRange([getPreviousTokenStart(node), node.range[1]]);
|
1092
|
+
}
|
1093
|
+
|
1094
|
+
// remove unused array element
|
1095
|
+
return fixer.removeRange(node.range);
|
1096
|
+
}
|
1097
|
+
|
1098
|
+
/**
|
1099
|
+
* fix cases like {a: {k}} or {a: [k]}
|
1100
|
+
* @param {ASTNode} node parent node to check
|
1101
|
+
* @returns {Object} fixer object
|
1102
|
+
*/
|
1103
|
+
function fixObjectWithValueSeparator(node) {
|
1104
|
+
const parentNode = node.parent.parent;
|
1105
|
+
|
1106
|
+
// fix cases like [{a : { b }}] or [{a : [ b ]}]
|
1107
|
+
if (
|
1108
|
+
parentNode.parent.type === "ArrayPattern" &&
|
1109
|
+
parentNode.properties.length === 1
|
1110
|
+
) {
|
1111
|
+
return fixNestedArrayVariable(parentNode);
|
1112
|
+
}
|
1113
|
+
|
1114
|
+
// fix cases like {a: {k}} or {a: [k]}
|
1115
|
+
return fixNestedObjectVariable(node);
|
1116
|
+
}
|
1117
|
+
|
1118
|
+
/**
|
1119
|
+
* fix ...[[a]] or ...[{a}] like patterns
|
1120
|
+
* @param {ASTNode} node parent node to check
|
1121
|
+
* @returns {Object} fixer object
|
1122
|
+
*/
|
1123
|
+
function fixRestInPattern(node) {
|
1124
|
+
const parentNode = node.parent;
|
1125
|
+
|
1126
|
+
// fix ...[[a]] or ...[{a}] in function parameters
|
1127
|
+
if (isFunction(parentNode)) {
|
1128
|
+
if (parentNode.params.length === 1) {
|
1129
|
+
return fixer.removeRange(node.range);
|
1130
|
+
}
|
1131
|
+
|
1132
|
+
return fixer.removeRange([getPreviousTokenStart(node), node.range[1]]);
|
1133
|
+
}
|
1134
|
+
|
1135
|
+
// fix rest in nested array pattern like [[a, ...[b]]]
|
1136
|
+
if (parentNode.type === "ArrayPattern") {
|
1137
|
+
|
1138
|
+
// fix [[...[b]]]
|
1139
|
+
if (hasSingleElement(parentNode)) {
|
1140
|
+
if (parentNode.parent.type === "ArrayPattern") {
|
1141
|
+
return fixNestedArrayVariable(parentNode);
|
1142
|
+
}
|
1143
|
+
|
1144
|
+
// fix 'const [...[b]] = foo; and function foo([...[b]]) {}
|
1145
|
+
return fixVariables(parentNode);
|
1146
|
+
}
|
1147
|
+
|
1148
|
+
// fix [[a, ...[b]]]
|
1149
|
+
return fixer.removeRange([getPreviousTokenStart(node), node.range[1]]);
|
1150
|
+
}
|
1151
|
+
|
1152
|
+
return null;
|
1153
|
+
}
|
1154
|
+
|
1155
|
+
// skip fix when variable has references that would be left behind
|
1156
|
+
if (allWriteReferences.some(ref => ref.identifier.range[0] !== id.range[0])) {
|
1157
|
+
return null;
|
1158
|
+
}
|
1159
|
+
|
1160
|
+
// remove declared variables such as var a; or var a, b;
|
1161
|
+
if (parentType === "VariableDeclarator") {
|
1162
|
+
if (parent.parent.declarations.length === 1) {
|
1163
|
+
|
1164
|
+
// prevent fix of variable in forOf and forIn loops.
|
1165
|
+
if (isLoop(parent.parent.parent) && parent.parent.parent.body !== parent.parent) {
|
1166
|
+
return null;
|
1167
|
+
}
|
1168
|
+
|
1169
|
+
// removes only variable not semicolon in 'if (foo()) var bar;' or in 'loops' or in 'with' statement.
|
1170
|
+
if (
|
1171
|
+
parent.parent.parent.type === "IfStatement" ||
|
1172
|
+
isLoop(parent.parent.parent) ||
|
1173
|
+
(parent.parent.parent.type === "WithStatement" && parent.parent.parent.body === parent.parent)
|
1174
|
+
) {
|
1175
|
+
return fixer.replaceText(parent.parent, ";");
|
1176
|
+
}
|
1177
|
+
|
1178
|
+
// if next token is a string it could become a directive if node is removed -> no suggestion.
|
1179
|
+
const nextToken = sourceCode.getTokenAfter(parent.parent);
|
1180
|
+
|
1181
|
+
// if previous token exists and is not ";" or "{" not sure about ASI rules -> no suggestion.
|
1182
|
+
const prevToken = sourceCode.getTokenBefore(parent.parent);
|
1183
|
+
|
1184
|
+
if (nextToken && isDeclarationNotSafeToRemove(nextToken, prevToken)) {
|
1185
|
+
return null;
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
// remove unused declared variable with single declaration like 'var a = b;'
|
1189
|
+
return fixer.removeRange(parent.parent.range);
|
1190
|
+
}
|
1191
|
+
|
1192
|
+
// remove unused declared variable with multiple declaration except first one like 'var a = b, c = d;'
|
1193
|
+
if (tokenBefore.value === ",") {
|
1194
|
+
return fixer.removeRange([tokenBefore.range[0], parent.range[1]]);
|
1195
|
+
}
|
1196
|
+
|
1197
|
+
// remove first unused declared variable when there are multiple declarations
|
1198
|
+
return fixer.removeRange([parent.range[0], getNextTokenEnd(parent)]);
|
1199
|
+
}
|
1200
|
+
|
1201
|
+
// remove variables in object patterns
|
1202
|
+
if (parent.parent.type === "ObjectPattern") {
|
1203
|
+
if (parent.parent.properties.length === 1) {
|
1204
|
+
|
1205
|
+
// fix [a, ...{b}]
|
1206
|
+
if (parent.parent.parent.type === "RestElement") {
|
1207
|
+
return fixRestInPattern(parent.parent.parent);
|
1208
|
+
}
|
1209
|
+
|
1210
|
+
// fix [{ a }]
|
1211
|
+
if (parent.parent.parent.type === "ArrayPattern") {
|
1212
|
+
return fixNestedArrayVariable(parent.parent);
|
1213
|
+
}
|
1214
|
+
|
1215
|
+
/*
|
1216
|
+
* var {a} = foo;
|
1217
|
+
* function a({a}) {}
|
1218
|
+
* fix const { a: { b } } = foo;
|
1219
|
+
*/
|
1220
|
+
return fixVariables(parent.parent);
|
1221
|
+
}
|
1222
|
+
|
1223
|
+
// fix const { a:b } = foo;
|
1224
|
+
if (tokenBefore.value === ":") {
|
1225
|
+
|
1226
|
+
// remove first unused variable in const { a:b } = foo;
|
1227
|
+
if (getTokenBeforeValue(parent) === "{" && getTokenAfterValue(parent) === ",") {
|
1228
|
+
return fixer.removeRange([parent.range[0], getNextTokenEnd(parent)]);
|
1229
|
+
}
|
1230
|
+
|
1231
|
+
// remove unused variables in const { a: b, c: d } = foo; except first one
|
1232
|
+
return fixer.removeRange([getPreviousTokenStart(parent), id.range[1]]);
|
1233
|
+
}
|
1234
|
+
}
|
1235
|
+
|
1236
|
+
// remove unused variables inside an array
|
1237
|
+
if (parentType === "ArrayPattern") {
|
1238
|
+
if (hasSingleElement(parent)) {
|
1239
|
+
|
1240
|
+
// fix [a, ...[b]]
|
1241
|
+
if (parent.parent.type === "RestElement") {
|
1242
|
+
return fixRestInPattern(parent.parent);
|
1243
|
+
}
|
1244
|
+
|
1245
|
+
// fix [ [a] ]
|
1246
|
+
if (parent.parent.type === "ArrayPattern") {
|
1247
|
+
return fixNestedArrayVariable(parent);
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
/*
|
1251
|
+
* fix var [a] = foo;
|
1252
|
+
* fix function foo([a]) {}
|
1253
|
+
* fix const { a: [b] } = foo;
|
1254
|
+
*/
|
1255
|
+
return fixVariables(parent);
|
1256
|
+
}
|
1257
|
+
|
1258
|
+
// if "a" is unused in [a, b ,c] fixes to [, b, c]
|
1259
|
+
if (tokenBefore.value === "," && tokenAfter.value === ",") {
|
1260
|
+
return fixer.removeRange(id.range);
|
1261
|
+
}
|
1262
|
+
}
|
1263
|
+
|
1264
|
+
// remove unused rest elements
|
1265
|
+
if (parentType === "RestElement") {
|
1266
|
+
|
1267
|
+
// fix [a, ...rest]
|
1268
|
+
if (parent.parent.type === "ArrayPattern") {
|
1269
|
+
if (hasSingleElement(parent.parent)) {
|
1270
|
+
|
1271
|
+
// fix [[...rest]] when there is only rest element
|
1272
|
+
if (
|
1273
|
+
parent.parent.parent.type === "ArrayPattern"
|
1274
|
+
) {
|
1275
|
+
return fixNestedArrayVariable(parent.parent);
|
1276
|
+
}
|
1277
|
+
|
1278
|
+
// fix 'const [...rest] = foo;' and 'function foo([...rest]) {}'
|
1279
|
+
return fixVariables(parent.parent);
|
1280
|
+
}
|
1281
|
+
|
1282
|
+
// fix [a, ...rest]
|
1283
|
+
return fixer.removeRange([getPreviousTokenStart(id, 1), id.range[1]]);
|
1284
|
+
}
|
1285
|
+
|
1286
|
+
// fix { a, ...rest}
|
1287
|
+
if (parent.parent.type === "ObjectPattern") {
|
1288
|
+
|
1289
|
+
// fix 'const {...rest} = foo;' and 'function foo({...rest}) {}'
|
1290
|
+
if (parent.parent.properties.length === 1) {
|
1291
|
+
return fixVariables(parent.parent);
|
1292
|
+
}
|
1293
|
+
|
1294
|
+
// fix { a, ...rest} when there are multiple properties
|
1295
|
+
return fixer.removeRange([getPreviousTokenStart(id, 1), id.range[1]]);
|
1296
|
+
}
|
1297
|
+
|
1298
|
+
// fix function foo(...rest) {}
|
1299
|
+
if (isFunction(parent.parent)) {
|
1300
|
+
|
1301
|
+
// remove unused rest in function parameter if there is only single parameter
|
1302
|
+
if (parent.parent.params.length === 1) {
|
1303
|
+
return fixer.removeRange(parent.range);
|
1304
|
+
}
|
1305
|
+
|
1306
|
+
// remove unused rest in function parameter if there multiple parameter
|
1307
|
+
return fixer.removeRange([getPreviousTokenStart(parent), parent.range[1]]);
|
1308
|
+
}
|
1309
|
+
}
|
1310
|
+
|
1311
|
+
if (parentType === "AssignmentPattern") {
|
1312
|
+
|
1313
|
+
// fix [a = aDefault]
|
1314
|
+
if (parent.parent.type === "ArrayPattern") {
|
1315
|
+
return fixNestedArrayVariable(parent);
|
1316
|
+
}
|
1317
|
+
|
1318
|
+
// fix {a = aDefault}
|
1319
|
+
if (parent.parent.parent.type === "ObjectPattern") {
|
1320
|
+
if (parent.parent.parent.properties.length === 1) {
|
1321
|
+
|
1322
|
+
// fixes [{a = aDefault}]
|
1323
|
+
if (parent.parent.parent.parent.type === "ArrayPattern") {
|
1324
|
+
return fixNestedArrayVariable(parent.parent.parent);
|
1325
|
+
}
|
1326
|
+
|
1327
|
+
// fix 'const {a = aDefault} = foo;' and 'function foo({a = aDefault}) {}'
|
1328
|
+
return fixVariables(parent.parent.parent);
|
1329
|
+
}
|
1330
|
+
|
1331
|
+
// fix unused 'a' in {a = aDefault} if it is the first property
|
1332
|
+
if (
|
1333
|
+
getTokenBeforeValue(parent.parent) === "{" &&
|
1334
|
+
getTokenAfterValue(parent.parent) === ","
|
1335
|
+
) {
|
1336
|
+
return fixer.removeRange([parent.parent.range[0], getNextTokenEnd(parent.parent)]);
|
1337
|
+
}
|
1338
|
+
|
1339
|
+
// fix unused 'b' in {a, b = aDefault} if it is not the first property
|
1340
|
+
return fixer.removeRange([getPreviousTokenStart(parent.parent), parent.parent.range[1]]);
|
1341
|
+
}
|
1342
|
+
|
1343
|
+
// fix unused assignment patterns in function parameters
|
1344
|
+
if (isFunction(parent.parent)) {
|
1345
|
+
return fixFunctionParameters(parent);
|
1346
|
+
}
|
1347
|
+
}
|
1348
|
+
|
1349
|
+
// remove unused functions
|
1350
|
+
if (parentType === "FunctionDeclaration" && parent.id === id) {
|
1351
|
+
return fixer.removeRange(parent.range);
|
1352
|
+
}
|
1353
|
+
|
1354
|
+
// remove unused default import
|
1355
|
+
if (parentType === "ImportDefaultSpecifier") {
|
1356
|
+
|
1357
|
+
// remove unused default import when there are not other imports
|
1358
|
+
if (
|
1359
|
+
!hasImportOfCertainType(parent.parent, "ImportSpecifier") &&
|
1360
|
+
!hasImportOfCertainType(parent.parent, "ImportNamespaceSpecifier")
|
1361
|
+
) {
|
1362
|
+
return fixer.removeRange([parent.range[0], parent.parent.source.range[0]]);
|
1363
|
+
}
|
1364
|
+
|
1365
|
+
// remove unused default import when there are other imports also
|
1366
|
+
return fixer.removeRange([id.range[0], tokenAfter.range[1]]);
|
1367
|
+
}
|
1368
|
+
|
1369
|
+
if (parentType === "ImportSpecifier") {
|
1370
|
+
|
1371
|
+
// remove unused imports when there is a single import
|
1372
|
+
if (parent.parent.specifiers.filter(e => e.type === "ImportSpecifier").length === 1) {
|
1373
|
+
|
1374
|
+
// remove unused import when there is no default import
|
1375
|
+
if (!hasImportOfCertainType(parent.parent, "ImportDefaultSpecifier")) {
|
1376
|
+
return fixer.removeRange(parent.parent.range);
|
1377
|
+
}
|
1378
|
+
|
1379
|
+
// fixes "import foo from 'module';" to "import 'module';"
|
1380
|
+
return fixer.removeRange([getPreviousTokenStart(parent, 1), tokenAfter.range[1]]);
|
1381
|
+
}
|
1382
|
+
|
1383
|
+
if (getTokenBeforeValue(parent) === "{") {
|
1384
|
+
return fixer.removeRange([parent.range[0], getNextTokenEnd(parent)]);
|
1385
|
+
}
|
1386
|
+
|
1387
|
+
return fixer.removeRange([getPreviousTokenStart(parent), parent.range[1]]);
|
1388
|
+
}
|
1389
|
+
|
1390
|
+
if (parentType === "ImportNamespaceSpecifier") {
|
1391
|
+
if (hasImportOfCertainType(parent.parent, "ImportDefaultSpecifier")) {
|
1392
|
+
return fixer.removeRange([getPreviousTokenStart(parent), parent.range[1]]);
|
1393
|
+
}
|
1394
|
+
|
1395
|
+
// fixes "import * as foo from 'module';" to "import 'module';"
|
1396
|
+
return fixer.removeRange([parent.range[0], parent.parent.source.range[0]]);
|
1397
|
+
}
|
1398
|
+
|
1399
|
+
// skip error in catch(error) variable
|
1400
|
+
if (parentType === "CatchClause") {
|
1401
|
+
return null;
|
1402
|
+
}
|
1403
|
+
|
1404
|
+
// remove unused declared classes
|
1405
|
+
if (parentType === "ClassDeclaration") {
|
1406
|
+
return fixer.removeRange(parent.range);
|
1407
|
+
}
|
1408
|
+
|
1409
|
+
// remove unused varible that is in a sequence [a,b] fixes to [a]
|
1410
|
+
if (tokenBefore?.value === ",") {
|
1411
|
+
return fixer.removeRange([tokenBefore.range[0], id.range[1]]);
|
1412
|
+
}
|
1413
|
+
|
1414
|
+
// remove unused varible that is in a sequence inside function arguments and object pattern
|
1415
|
+
if (tokenAfter.value === ",") {
|
1416
|
+
|
1417
|
+
// fix function foo(a, b) {}
|
1418
|
+
if (tokenBefore.value === "(") {
|
1419
|
+
return fixer.removeRange([id.range[0], tokenAfter.range[1]]);
|
1420
|
+
}
|
1421
|
+
|
1422
|
+
// fix const {a, b} = foo;
|
1423
|
+
if (tokenBefore.value === "{") {
|
1424
|
+
return fixer.removeRange([id.range[0], tokenAfter.range[1]]);
|
1425
|
+
}
|
1426
|
+
}
|
1427
|
+
|
1428
|
+
if (parentType === "ArrowFunctionExpression" && parent.params.length === 1 && tokenAfter?.value !== ")") {
|
1429
|
+
return fixer.replaceText(id, "()");
|
1430
|
+
}
|
1431
|
+
|
1432
|
+
return fixer.removeRange(id.range);
|
1433
|
+
}
|
1434
|
+
|
835
1435
|
//--------------------------------------------------------------------------
|
836
1436
|
// Public
|
837
1437
|
//--------------------------------------------------------------------------
|
@@ -860,7 +1460,18 @@ module.exports = {
|
|
860
1460
|
messageId: "unusedVar",
|
861
1461
|
data: unusedVar.references.some(ref => ref.isWrite())
|
862
1462
|
? getAssignedMessageData(unusedVar)
|
863
|
-
: getDefinedMessageData(unusedVar)
|
1463
|
+
: getDefinedMessageData(unusedVar),
|
1464
|
+
suggest: [
|
1465
|
+
{
|
1466
|
+
messageId: "removeVar",
|
1467
|
+
data: {
|
1468
|
+
varName: unusedVar.name
|
1469
|
+
},
|
1470
|
+
fix(fixer) {
|
1471
|
+
return handleFixes(fixer, unusedVar);
|
1472
|
+
}
|
1473
|
+
}
|
1474
|
+
]
|
864
1475
|
});
|
865
1476
|
|
866
1477
|
// If there are no regular declaration, report the first `/*globals*/` comment directive.
|
@@ -309,6 +309,15 @@ module.exports = {
|
|
309
309
|
}
|
310
310
|
|
311
311
|
|
312
|
+
if (targetAssignment.variable.references.some(ref => ref.identifier.type !== "Identifier")) {
|
313
|
+
|
314
|
+
/**
|
315
|
+
* Skip checking for a variable that has at least one non-identifier reference.
|
316
|
+
* It's generated by plugins and cannot be handled reliably in the core rule.
|
317
|
+
*/
|
318
|
+
return;
|
319
|
+
}
|
320
|
+
|
312
321
|
const readReferences = targetAssignment.variable.references.filter(reference => reference.isRead());
|
313
322
|
|
314
323
|
if (!readReferences.length) {
|
@@ -120,7 +120,7 @@ module.exports = {
|
|
120
120
|
},
|
121
121
|
create(context) {
|
122
122
|
const sourceCode = context.sourceCode;
|
123
|
-
const enforceForClassMembers = context.options
|
123
|
+
const [{ enforceForClassMembers }] = context.options;
|
124
124
|
|
125
125
|
/**
|
126
126
|
* Reports a given node if it violated this rule.
|