Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat(eslint-plugin): [no-unused-vars] add destructuredArrayIgnorePatt…
…ern options (#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>
  • Loading branch information
ALOHACREPES345 and JoshuaKGoldberg committed Mar 27, 2022
1 parent 9eab1cd commit 6f8db8b
Show file tree
Hide file tree
Showing 3 changed files with 335 additions and 14 deletions.
73 changes: 59 additions & 14 deletions packages/eslint-plugin/src/rules/no-unused-vars.ts
Expand Up @@ -14,6 +14,7 @@ export type Options = [
argsIgnorePattern?: string;
caughtErrors?: 'all' | 'none';
caughtErrorsIgnorePattern?: string;
destructuredArrayIgnorePattern?: string;
},
];

Expand All @@ -25,6 +26,7 @@ interface TranslatedOptions {
argsIgnorePattern?: RegExp;
caughtErrors: 'all' | 'none';
caughtErrorsIgnorePattern?: RegExp;
destructuredArrayIgnorePattern?: RegExp;
}

export default util.createRule<Options, MessageIds>({
Expand Down Expand Up @@ -66,6 +68,9 @@ export default util.createRule<Options, MessageIds>({
caughtErrorsIgnorePattern: {
type: 'string',
},
destructuredArrayIgnorePattern: {
type: 'string',
},
},
additionalProperties: false,
},
Expand Down Expand Up @@ -123,12 +128,33 @@ export default util.createRule<Options, MessageIds>({
'u',
);
}

if (firstOption.destructuredArrayIgnorePattern) {
options.destructuredArrayIgnorePattern = new RegExp(
firstOption.destructuredArrayIgnorePattern,
'u',
);
}
}
}
return options;
})();

function collectUnusedVariables(): TSESLint.Scope.Variable[] {
/**
* Checks whether a node is a sibling of the rest property or not.
* @param {ASTNode} node a node to check
* @returns {boolean} True if the node is a sibling of the rest property, otherwise false.
*/
function hasRestSibling(node: TSESTree.Node): boolean {
return (
node.type === AST_NODE_TYPES.Property &&
node.parent?.type === AST_NODE_TYPES.ObjectPattern &&
node.parent.properties[node.parent.properties.length - 1].type ===
AST_NODE_TYPES.RestElement
);
}

/**
* Determines if a variable has a sibling rest property
* @param variable eslint-scope variable object.
Expand All @@ -138,17 +164,14 @@ export default util.createRule<Options, MessageIds>({
variable: TSESLint.Scope.Variable,
): boolean {
if (options.ignoreRestSiblings) {
return variable.defs.some(def => {
const propertyNode = def.name.parent!;
const patternNode = propertyNode.parent!;

return (
propertyNode.type === AST_NODE_TYPES.Property &&
patternNode.type === AST_NODE_TYPES.ObjectPattern &&
patternNode.properties[patternNode.properties.length - 1].type ===
AST_NODE_TYPES.RestElement
);
});
const hasRestSiblingDefinition = variable.defs.some(def =>
hasRestSibling(def.name.parent!),
);
const hasRestSiblingReference = variable.references.some(ref =>
hasRestSibling(ref.identifier.parent!),
);

return hasRestSiblingDefinition || hasRestSiblingReference;
}

return false;
Expand Down Expand Up @@ -188,6 +211,20 @@ export default util.createRule<Options, MessageIds>({
continue;
}

const refUsedInArrayPatterns = variable.references.some(
ref => ref.identifier.parent?.type === AST_NODE_TYPES.ArrayPattern,
);

// skip elements of array destructuring patterns
if (
(def.name.parent?.type === AST_NODE_TYPES.ArrayPattern ||
refUsedInArrayPatterns) &&
'name' in def.name &&
options.destructuredArrayIgnorePattern?.test(def.name.name)
) {
continue;
}

// skip catch variables
if (def.type === TSESLint.Scope.DefinitionType.CatchClause) {
if (options.caughtErrors === 'none') {
Expand Down Expand Up @@ -361,9 +398,17 @@ export default util.createRule<Options, MessageIds>({
function getAssignedMessageData(
unusedVar: TSESLint.Scope.Variable,
): Record<string, unknown> {
const additional = options.varsIgnorePattern
? `. Allowed unused vars must match ${options.varsIgnorePattern.toString()}`
: '';
const def = unusedVar.defs[0];
let additional = '';

if (
options.destructuredArrayIgnorePattern &&
def?.name.parent?.type === AST_NODE_TYPES.ArrayPattern
) {
additional = `. Allowed unused elements of array destructuring patterns must match ${options.destructuredArrayIgnorePattern.toString()}`;
} else if (options.varsIgnorePattern) {
additional = `. Allowed unused vars must match ${options.varsIgnorePattern.toString()}`;
}

return {
varName: unusedVar.name,
Expand Down

0 comments on commit 6f8db8b

Please sign in to comment.