Skip to content

Commit

Permalink
fix(eslint-plugin): [prefer-optional-chain] collect MetaProperty type (
Browse files Browse the repository at this point in the history
…#6083)

* fix(eslint-plugin): [prefer-optional-chain] collect MetaProperty type

* fix(eslint-plugin): [prefer-optional-chain] collect MetaProperty type

* Added a few more tests

Co-authored-by: Josh Goldberg <git@joshuakgoldberg.com>
  • Loading branch information
YuseiUeno and JoshuaKGoldberg committed Nov 29, 2022
1 parent 76aacc0 commit d7114d3
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 4 deletions.
20 changes: 16 additions & 4 deletions packages/eslint-plugin/src/rules/prefer-optional-chain.ts
Expand Up @@ -11,7 +11,8 @@ type ValidChainTarget =
| TSESTree.ChainExpression
| TSESTree.Identifier
| TSESTree.MemberExpression
| TSESTree.ThisExpression;
| TSESTree.ThisExpression
| TSESTree.MetaProperty;

/*
The AST is always constructed such the first element is always the deepest element.
Expand Down Expand Up @@ -115,10 +116,12 @@ export default util.createRule({
'LogicalExpression[operator="||"] > UnaryExpression[operator="!"] > Identifier',
'LogicalExpression[operator="||"] > UnaryExpression[operator="!"] > MemberExpression',
'LogicalExpression[operator="||"] > UnaryExpression[operator="!"] > ChainExpression > MemberExpression',
'LogicalExpression[operator="||"] > UnaryExpression[operator="!"] > MetaProperty',
].join(',')](
initialIdentifierOrNotEqualsExpr:
| TSESTree.Identifier
| TSESTree.MemberExpression,
| TSESTree.MemberExpression
| TSESTree.MetaProperty,
): void {
// selector guarantees this cast
const initialExpression = (
Expand Down Expand Up @@ -190,13 +193,15 @@ export default util.createRule({
'LogicalExpression[operator="&&"] > Identifier',
'LogicalExpression[operator="&&"] > MemberExpression',
'LogicalExpression[operator="&&"] > ChainExpression > MemberExpression',
'LogicalExpression[operator="&&"] > MetaProperty',
'LogicalExpression[operator="&&"] > BinaryExpression[operator="!=="]',
'LogicalExpression[operator="&&"] > BinaryExpression[operator="!="]',
].join(',')](
initialIdentifierOrNotEqualsExpr:
| TSESTree.BinaryExpression
| TSESTree.Identifier
| TSESTree.MemberExpression,
| TSESTree.MemberExpression
| TSESTree.MetaProperty,
): void {
// selector guarantees this cast
const initialExpression = (
Expand Down Expand Up @@ -342,6 +347,10 @@ export default util.createRule({
return node.name;
}

if (node.type === AST_NODE_TYPES.MetaProperty) {
return `${node.meta.name}.${node.property.name}`;
}

if (node.type === AST_NODE_TYPES.ThisExpression) {
return 'this';
}
Expand Down Expand Up @@ -381,6 +390,7 @@ export default util.createRule({
objectText = getMemberExpressionText(node.object);
break;

case AST_NODE_TYPES.MetaProperty:
case AST_NODE_TYPES.ThisExpression:
objectText = getText(node.object);
break;
Expand Down Expand Up @@ -441,6 +451,7 @@ const ALLOWED_MEMBER_OBJECT_TYPES: ReadonlySet<AST_NODE_TYPES> = new Set([
AST_NODE_TYPES.Identifier,
AST_NODE_TYPES.MemberExpression,
AST_NODE_TYPES.ThisExpression,
AST_NODE_TYPES.MetaProperty,
]);
const ALLOWED_COMPUTED_PROP_TYPES: ReadonlySet<AST_NODE_TYPES> = new Set([
AST_NODE_TYPES.Identifier,
Expand Down Expand Up @@ -609,7 +620,8 @@ function isValidChainTarget(
if (
allowIdentifier &&
(node.type === AST_NODE_TYPES.Identifier ||
node.type === AST_NODE_TYPES.ThisExpression)
node.type === AST_NODE_TYPES.ThisExpression ||
node.type === AST_NODE_TYPES.MetaProperty)
) {
return true;
}
Expand Down
79 changes: 79 additions & 0 deletions packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts
Expand Up @@ -211,6 +211,12 @@ ruleTester.run('prefer-optional-chain', rule, {
'!foo!.bar || !foo!.bar.baz;',
'!foo!.bar!.baz || !foo!.bar!.baz!.paz;',
'!foo.bar!.baz || !foo.bar!.baz!.paz;',
'import.meta || true;',
'import.meta || import.meta.foo;',
'!import.meta && false;',
'!import.meta && !import.meta.foo;',
'new.target || new.target.length;',
'!new.target || true;',
],
invalid: [
...baseCases,
Expand Down Expand Up @@ -1321,5 +1327,78 @@ foo?.bar(/* comment */a,
},
],
},
{
code: `
class Foo {
constructor() {
new.target && new.target.length;
}
}
`,
output: null,
errors: [
{
messageId: 'preferOptionalChain',
suggestions: [
{
messageId: 'optionalChainSuggest',
output: `
class Foo {
constructor() {
new.target?.length;
}
}
`,
},
],
},
],
},
{
code: noFormat`import.meta && import.meta?.baz;`,
output: null,
errors: [
{
messageId: 'preferOptionalChain',
suggestions: [
{
messageId: 'optionalChainSuggest',
output: noFormat`import.meta?.baz;`,
},
],
},
],
},
{
code: noFormat`!import.meta || !import.meta?.baz;`,
output: null,
errors: [
{
messageId: 'preferOptionalChain',
suggestions: [
{
messageId: 'optionalChainSuggest',
output: noFormat`!import.meta?.baz;`,
},
],
},
],
},

{
code: noFormat`import.meta && import.meta?.() && import.meta?.().baz;`,
output: null,
errors: [
{
messageId: 'preferOptionalChain',
suggestions: [
{
messageId: 'optionalChainSuggest',
output: noFormat`import.meta?.()?.baz;`,
},
],
},
],
},
],
});

0 comments on commit d7114d3

Please sign in to comment.