Skip to content

Commit

Permalink
fix(template-parser): visit receiver of Call expression
Browse files Browse the repository at this point in the history
When traversing a Call AST node, ESLint would never visit its receiver/callee.
Since Call didn't have visitor keys listed explicitly, the parser would use `getFallbackKeys`,
which seems to be buggy as it only returns `args` and not `receiver`.

Update test cases for no-call-expression to deal with new call expressions being reported.

Since convertAnnotatedSourceToFailureCase doesn't deal well with overlapping errors at the moment,
instances of `()()` were removed from existing tests and added as separate cases for nested calls.

Closes angular-eslint#1885
  • Loading branch information
Paweł Maniecki committed Jun 14, 2024
1 parent 2f9e378 commit 4292d10
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ export const invalid = [
convertAnnotatedSourceToFailureCase({
description: 'should fail for `FunctionCall` within `Interpolation`',
annotatedSource: `
<div>{{ getInfo()() }}</div>
~~~~~~~~~~~
<div>{{ getInfo() }}</div>
~~~~~~~~~
`,
messageId,
}),
Expand All @@ -86,8 +86,8 @@ export const invalid = [
description:
'should fail for `FunctionCall`, `MethodCall` and `SafeMethodCall` within `Binary`',
annotatedSource: `
<a [href]="id && createUrl() && test()($any)">info</a>
~~~~~~~~~~~ ^^^^^^^^^^^^
<a [href]="id && createUrl() && test($any)">info</a>
~~~~~~~~~~~ ^^^^^^^^^^
{{ id || obj?.nested1() }}
##############
`,
Expand All @@ -103,8 +103,8 @@ export const invalid = [
annotatedSource: `
<a [href]="id ? a?.createUrl() : editUrl(3)">info</a>
~~~~~~~~~~~~~~ ^^^^^^^^^^
{{ 1 === 2 ? 3 : obj?.nested1()() }}
################
{{ 1 === 2 ? 3 : obj?.nested1() }}
##############
`,
messages: [
{ char: '~', messageId },
Expand All @@ -117,8 +117,8 @@ export const invalid = [
annotatedSource: `
{{ obj?.nested1() }} {{ obj!.nested1() }}
~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^
<button [type]="obj!.$any(b)!.getType()()">info</button>
#########################
<button [type]="obj!.$any(b)!.getType()">info</button>
#######################
<a [href]="obj.propertyA?.href()">info</a>
%%%%%%%%%%%%%%%%%%%%%
`,
Expand Down Expand Up @@ -218,4 +218,56 @@ export const invalid = [
{ char: '*', messageId },
],
}),

convertAnnotatedSourceToFailureCase({
description: 'should fail for calls in arguments',
annotatedSource: `
{{ foo(bar(), baz()) }}
~~~~^^^^^~~#####~
`,
messages: [
{ char: '~', messageId },
{ char: '^', messageId },
{ char: '#', messageId },
],
}),
// convertAnnotatedSourceToFailureCase cannot handle multiple errors starting/ending at the same position;
// manually adjust the outer error (~) to start at the same position as the inner error (^)
...[
convertAnnotatedSourceToFailureCase({
description: 'should fail multiple times for nested calls',
annotatedSource: `
{{ foo()() }}
^^^^^~~
`,
messages: [
{ char: '~', messageId },
{ char: '^', messageId },
],
}),
convertAnnotatedSourceToFailureCase({
description: 'should fail multiple times for chained calls',
annotatedSource: `
{{ foo().bar() }}
^^^^^~~~~~~
`,
messages: [
{ char: '~', messageId },
{ char: '^', messageId },
],
}),
].map((c) => {
(c.errors[0] as any).column = c.errors[1].column;
return c;
}),

convertAnnotatedSourceToFailureCase({
description: 'should fail for nested call not in allowList',
annotatedSource: `
{{ notOk().ok() }}
~~~~~~~
`,
options: [{ allowList: ['ok'] }],
messages: [{ char: '~', messageId }],
}),
];
1 change: 1 addition & 0 deletions packages/template-parser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const KEYS: VisitorKeys = {
BoundAttribute: ['value'],
BoundEvent: ['handler'],
BoundText: ['value'],
Call: ['receiver', 'args'],
Conditional: ['condition', 'trueExp', 'falseExp'],
Element$1: ['children', 'inputs', 'outputs', 'attributes'],
Interpolation$1: ['expressions'],
Expand Down

0 comments on commit 4292d10

Please sign in to comment.