Skip to content

Commit

Permalink
feat: check assignment patterns in no-underscore-dangle (#16693)
Browse files Browse the repository at this point in the history
  • Loading branch information
mdjermanovic committed Dec 28, 2022
1 parent e5ecfef commit 52c7c73
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 78 deletions.
1 change: 0 additions & 1 deletion docs/src/rules/no-underscore-dangle.md
Expand Up @@ -28,7 +28,6 @@ Examples of **incorrect** code for this rule:
var foo_;
var __proto__ = {};
foo._bar();
const [_foo, ..._bar] = list;
```

:::
Expand Down
102 changes: 25 additions & 77 deletions lib/rules/no-underscore-dangle.js
Expand Up @@ -205,60 +205,6 @@ module.exports = {
checkForDanglingUnderscoreInFunctionParameters(node);
}

/**
* Check if node has dangling underscore or if node is type of ArrayPattern check its elements recursively
* @param {ASTNode} node node to evaluate
* @param {string} parentNodeType the ASTNode['type'] of the node parent
* @returns {void}
* @private
*/
function deepCheckDestructured(node, parentNodeType) {
let identifier;

if (!node || !node.type) {
return;
}

switch (node.type) {
case "ArrayPattern":
node.elements.forEach(element => deepCheckDestructured(element, "ArrayPattern"));
break;
case "ObjectPattern":
node.properties.forEach(property => deepCheckDestructured(property, "ObjectPattern"));
break;
case "RestElement":
deepCheckDestructured(node.argument, parentNodeType);
break;
case "Property":
deepCheckDestructured(node.value, "ObjectPattern");
break;
case "Identifier":
identifier = node.name;
break;
default:
break;
}

const isFromDestructuredObject = parentNodeType === "ObjectPattern" && !allowInObjectDestructuring;
const isFromDestructuredArray = parentNodeType === "ArrayPattern" && !allowInArrayDestructuring;
const hasDisallowedDestructuring = isFromDestructuredObject || isFromDestructuredArray;

if (
identifier &&
hasDisallowedDestructuring &&
hasDanglingUnderscore(identifier) &&
!isSpecialCaseIdentifierInVariableExpression(identifier) &&
!isAllowed(identifier)
) {
context.report({
node,
messageId: "unexpectedUnderscore",
data: {
identifier
}
});
}
}

/**
* Check if variable expression has a dangling underscore
Expand All @@ -267,30 +213,32 @@ module.exports = {
* @private
*/
function checkForDanglingUnderscoreInVariableExpression(node) {
if (node.id.type === "ArrayPattern") {
node.id.elements.forEach(element => {
deepCheckDestructured(element, node.id.type);
});
}

if (node.id.type === "ObjectPattern") {
node.id.properties.forEach(element => {
deepCheckDestructured(element, node.id.type);
});
}

const identifier = node.id.name;
context.getDeclaredVariables(node).forEach(variable => {
const definition = variable.defs.find(def => def.node === node);
const identifierNode = definition.name;
const identifier = identifierNode.name;
let parent = identifierNode.parent;

while (!["VariableDeclarator", "ArrayPattern", "ObjectPattern"].includes(parent.type)) {
parent = parent.parent;
}

if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
!isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) {
context.report({
node,
messageId: "unexpectedUnderscore",
data: {
identifier
}
});
}
if (
hasDanglingUnderscore(identifier) &&
!isSpecialCaseIdentifierInVariableExpression(identifier) &&
!isAllowed(identifier) &&
!(allowInArrayDestructuring && parent.type === "ArrayPattern") &&
!(allowInObjectDestructuring && parent.type === "ObjectPattern")
) {
context.report({
node,
messageId: "unexpectedUnderscore",
data: {
identifier
}
});
}
});
}

/**
Expand Down
21 changes: 21 additions & 0 deletions tests/lib/rules/no-underscore-dangle.js
Expand Up @@ -70,8 +70,14 @@ ruleTester.run("no-underscore-dangle", rule, {
{ code: "function foo( { _bar }) {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 6 } },
{ code: "function foo( { _bar = 0 } = {}) {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 6 } },
{ code: "function foo(...[_bar]) {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 2016 } },
{ code: "const [_foo] = arr", parserOptions: { ecmaVersion: 6 } },
{ code: "const [_foo] = arr", options: [{}], parserOptions: { ecmaVersion: 6 } },
{ code: "const [_foo] = arr", options: [{ allowInArrayDestructuring: true }], parserOptions: { ecmaVersion: 6 } },
{ code: "const [foo, ...rest] = [1, 2, 3]", options: [{ allowInArrayDestructuring: false }], parserOptions: { ecmaVersion: 2022 } },
{ code: "const [foo, _bar] = [1, 2, 3]", options: [{ allowInArrayDestructuring: false, allow: ["_bar"] }], parserOptions: { ecmaVersion: 2022 } },
{ code: "const { _foo } = obj", parserOptions: { ecmaVersion: 6 } },
{ code: "const { _foo } = obj", options: [{}], parserOptions: { ecmaVersion: 6 } },
{ code: "const { _foo } = obj", options: [{ allowInObjectDestructuring: true }], parserOptions: { ecmaVersion: 6 } },
{ code: "const { foo, bar: _bar } = { foo: 1, bar: 2 }", options: [{ allowInObjectDestructuring: false, allow: ["_bar"] }], parserOptions: { ecmaVersion: 2022 } },
{ code: "const { foo, _bar } = { foo: 1, _bar: 2 }", options: [{ allowInObjectDestructuring: false, allow: ["_bar"] }], parserOptions: { ecmaVersion: 2022 } },
{ code: "const { foo, _bar: bar } = { foo: 1, _bar: 2 }", options: [{ allowInObjectDestructuring: false }], parserOptions: { ecmaVersion: 2022 } },
Expand Down Expand Up @@ -112,6 +118,11 @@ ruleTester.run("no-underscore-dangle", rule, {
options: [{ allowInArrayDestructuring: false }],
parserOptions: { ecmaVersion: 2022 },
errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_bar" } }]
}, {
code: "const [_foo = 1] = arr",
options: [{ allowInArrayDestructuring: false }],
parserOptions: { ecmaVersion: 2022 },
errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" } }]
}, {
code: "const [foo, ..._rest] = [1, 2, 3]",
options: [{ allowInArrayDestructuring: false }],
Expand All @@ -127,6 +138,16 @@ ruleTester.run("no-underscore-dangle", rule, {
options: [{ allowInObjectDestructuring: false }],
parserOptions: { ecmaVersion: 2022 },
errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" } }]
}, {
code: "const { _foo = 1 } = obj",
options: [{ allowInObjectDestructuring: false }],
parserOptions: { ecmaVersion: 2022 },
errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" } }]
}, {
code: "const { bar: _foo = 1 } = obj",
options: [{ allowInObjectDestructuring: false }],
parserOptions: { ecmaVersion: 2022 },
errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" } }]
}, {
code: "const { foo: _foo, bar } = { foo: 1, bar: 2 }",
options: [{ allowInObjectDestructuring: false }],
Expand Down

0 comments on commit 52c7c73

Please sign in to comment.