Skip to content

Commit

Permalink
[Fix] destructuring-assignment: fix false negative when using typeo…
Browse files Browse the repository at this point in the history
…f props.a

Fixes #3828
  • Loading branch information
golopot committed Sep 30, 2024
1 parent 4abcf14 commit 1a1eb4b
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 8 deletions.
45 changes: 39 additions & 6 deletions lib/rules/destructuring-assignment.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,25 @@ module.exports = {
}
}

// valid-jsdoc cannot read function types
// eslint-disable-next-line valid-jsdoc
/**
* Find a parent that satisfy the given predicate
* @param {ASTNode} node
* @param {(node: ASTNode) => boolean} predicate
* @returns {ASTNode | undefined}
*/
function findParent(node, predicate) {
let n = node;
while (n) {
if (predicate(n)) {
return n;

Check warning on line 196 in lib/rules/destructuring-assignment.js

View check run for this annotation

Codecov / codecov/patch

lib/rules/destructuring-assignment.js#L193-L196

Added lines #L193 - L196 were not covered by tests
}
n = n.parent;

Check warning on line 198 in lib/rules/destructuring-assignment.js

View check run for this annotation

Codecov / codecov/patch

lib/rules/destructuring-assignment.js#L198

Added line #L198 was not covered by tests
}
return undefined;

Check warning on line 200 in lib/rules/destructuring-assignment.js

View check run for this annotation

Codecov / codecov/patch

lib/rules/destructuring-assignment.js#L200

Added line #L200 was not covered by tests
}

return {

FunctionDeclaration: handleStatelessComponent,
Expand All @@ -196,12 +215,7 @@ module.exports = {
'FunctionExpression:exit': handleStatelessComponentExit,

MemberExpression(node) {
let scope = getScope(context, node);
let SFCComponent = components.get(scope.block);
while (!SFCComponent && scope.upper && scope.upper !== scope) {
SFCComponent = components.get(scope.upper.block);
scope = scope.upper;
}
const SFCComponent = utils.getParentStatelessComponent(node);
if (SFCComponent) {
handleSFCUsage(node);
}
Expand All @@ -212,6 +226,25 @@ module.exports = {
}
},

TSQualifiedName(node) {
if (configuration !== 'always') {
return;

Check warning on line 231 in lib/rules/destructuring-assignment.js

View check run for this annotation

Codecov / codecov/patch

lib/rules/destructuring-assignment.js#L229-L231

Added lines #L229 - L231 were not covered by tests
}
// handle `typeof props.a.b`
if (node.left.type === 'Identifier'
&& node.left.name === sfcParams.propsName()
&& findParent(node, (n) => n.type === 'TSTypeQuery')
&& utils.getParentStatelessComponent(node)

Check warning on line 237 in lib/rules/destructuring-assignment.js

View check run for this annotation

Codecov / codecov/patch

lib/rules/destructuring-assignment.js#L234-L237

Added lines #L234 - L237 were not covered by tests
) {
report(context, messages.useDestructAssignment, 'useDestructAssignment', {

Check warning on line 239 in lib/rules/destructuring-assignment.js

View check run for this annotation

Codecov / codecov/patch

lib/rules/destructuring-assignment.js#L239

Added line #L239 was not covered by tests
node,
data: {
type: 'props',
},
});
}
},

VariableDeclarator(node) {
const classComponent = utils.getParentComponent(node);
const SFCComponent = components.get(getScope(context, node).block);
Expand Down
32 changes: 30 additions & 2 deletions tests/lib/rules/destructuring-assignment.js
Original file line number Diff line number Diff line change
Expand Up @@ -882,10 +882,16 @@ ${' '}
};
`,
options: ['always', { destructureInSignature: 'always' }],
features: ['types'],
features: ['types', 'no-babel'],
errors: [
{
messageId: 'useDestructAssignment',
type: 'TSQualifiedName',
data: { type: 'props' },
},
{
messageId: 'useDestructAssignment',
type: 'MemberExpression',
data: { type: 'props' },
},
],
Expand All @@ -900,10 +906,32 @@ ${' '}
};
`,
options: ['always', { destructureInSignature: 'always' }],
features: ['types', 'no-babel'],
errors: [
{
messageId: 'useDestructAssignment',
type: 'TSQualifiedName',
data: { type: 'props' },
},
],
},
{
code: `
function C(props: Props) {
void props.a
typeof props.b
return <div />
}
`,
options: ['always'],
features: ['types'],
errors: [
{
messageId: 'destructureInSignature',
messageId: 'useDestructAssignment',
data: { type: 'props' },
},
{
messageId: 'useDestructAssignment',
data: { type: 'props' },
},
],
Expand Down

0 comments on commit 1a1eb4b

Please sign in to comment.