8000 feat(eslint-plugin): [no-unused-vars] add destructuredArrayIgnorePatt… · alandotcom/typescript-eslint@6f8db8b · GitHub
[go: up one dir, main page]

Skip to content

Commit 6f8db8b

Browse files
feat(eslint-plugin): [no-unused-vars] add destructuredArrayIgnorePattern options (typescript-eslint#4748)
* feat(eslint-plugin): [no-unused-vars] add destructuredArrayIgnorePattern options * feat(eslint-plugin): added typing * Update packages/eslint-plugin/src/rules/no-unused-vars.ts Co-authored-by: Josh Goldberg <me@joshuakgoldberg.com>
1 parent 9eab1cd commit 6f8db8b

File tree

3 files changed

+335
-14
lines changed

3 files changed

+335
-14
lines changed

packages/eslint-plugin/src/rules/no-unused-vars.ts

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export type Options = [
1414
argsIgnorePattern?: string;
1515
caughtErrors?: 'all' | 'none';
1616
caughtErrorsIgnorePattern?: string;
17+
destructuredArrayIgnorePattern?: string;
1718
},
1819
];
1920

@@ -25,6 +26,7 @@ interface TranslatedOptions {
2526
argsIgnorePattern?: RegExp;
2627
caughtErrors: 'all' | 'none';
2728
caughtErrorsIgnorePattern?: RegExp;
29+
destructuredArrayIgnorePattern?: RegExp;
2830
}
2931

3032
export default util.createRule<Options, MessageIds>({
@@ -66,6 +68,9 @@ export default util.createRule<Options, MessageIds>({
6668
caughtErrorsIgnorePattern: {
6769
type: 'string',
6870
},
71+
destructuredArrayIgnorePattern: {
72+
type: 'string',
73+
},
6974
},
7075
additionalProperties: false,
7176
},
@@ -123,12 +128,33 @@ export default util.createRule<Options, MessageIds>({
123128
'u',
124129
);
125130
}
131+
132+
if (firstOption.destructuredArrayIgnorePattern) {
133+
options.destructuredArrayIgnorePattern = new RegExp(
134+
firstOption.destructuredArrayIgnorePattern,
135+
'u',
136+
);
137+
}
126138
}
127139
}
128140
return options;
129141
})();
130142

131143
function collectUnusedVariables(): TSESLint.Scope.Variable[] {
144+
/**
145+
* Checks whether a node is a sibling of the rest property or not.
146+
* @param {ASTNode} node a node to check
147+
* @returns {boolean} True if the node is a sibling of the rest property, otherwise false.
148+
*/
149+
function hasRestSibling(node: TSESTree.Node): boolean {
150+
return (
151+
node.type === AST_NODE_TYPES.Property &&
152+
node.parent?.type === AST_NODE_TYPES.ObjectPattern &&
153+
node.parent.properties[node.parent.properties.length - 1].type ===
154+
AST_NODE_TYPES.RestElement
155+
);
156+
}
157+
132158
/**
133159
* Determines if a variable has a sibling rest property
134160
* @param variable eslint-scope variable object.
@@ -138,17 +164,14 @@ export default util.createRule<Options, MessageIds>({
138164
variable: TSESLint.Scope.Variable,
139165
): boolean {
140166
if (options.ignoreRestSiblings) {
141-
return variable.defs.some(def => {
142-
const propertyNode = def.name.parent!;
143-
const patternNode = propertyNode.parent!;
144-
145-
return (
146-
propertyNode.type === AST_NODE_TYPES.Property &&
147-
patternNode.type === AST_NODE_TYPES.ObjectPattern &&
148-
patternNode.properties[patternNode.properties.length - 1].type ===
149-
AST_NODE_TYPES.RestElement
150-
);
151-
});
167+
const hasRestSiblingDefinition = variable.defs.some(def =>
168+
hasRestSibling(def.name.parent!),
169+
);
170+
const hasRestSiblingReference = variable.references.some(ref =>
171+
hasRestSibling(ref.identifier.parent!),
172+
);
173+
174+
return hasRestSiblingDefinition || hasRestSiblingReference;
152175
}
153176

154177
return false;
@@ -188,6 +211,20 @@ export default util.createRule<Options, MessageIds>({
188211
continue;
189212
}
190213

214+
const refUsedInArrayPatterns = variable.references.some(
215+
ref => ref.identifier.parent?.type === AST_NODE_TYPES.ArrayPattern,
216+
);
217+
218+
// skip elements of array destructuring patterns
219+
if (
220+
(def.name.parent?.type === AST_NODE_TYPES.ArrayPattern ||
221+
refUsedInArrayPatterns) &&
222+
'name' in def.name &&
223+
options.destructuredArrayIgnorePattern?.test(def.name.name)
224+
) {
225+
continue;
226+
}
227+
191228
// skip catch variables
192229
if (def.type === TSESLint.Scope.DefinitionType.CatchClause) {
193230
if (options.caughtErrors === 'none') {
@@ -361,9 +398,17 @@ export default util.createRule<Options, MessageIds>({
361398
function getAssignedMessageData(
362399
unusedVar: TSESLint.Scope.Variable,
363400
): Record<string, unknown> {
364-
const additional = options.varsIgnorePattern
365-
? `. Allowed unused vars must match ${options.varsIgnorePattern.toString()}`
366-
: '';
401+
const def = unusedVar.defs[0];
402+
let additional = '';
403+
404+
if (
405+
options.destructuredArrayIgnorePattern &&
406+
def?.name.parent?.type === AST_NODE_TYPES.ArrayPattern
407+
) {
408+
additional = `. Allowed unused elements of array destructuring patterns must match ${options.destructuredArrayIgnorePattern.toString()}`;
409+
} else if (options.varsIgnorePattern) {
410+
additional = `. Allowed unused vars must match ${options.varsIgnorePattern.toString()}`;
411+
}
367412

368413
return {
369414
varName: unusedVar.name,

0 commit comments

Comments
 (0)
0