Skip to content

Commit 9b7e226

Browse files
NullVoxPopuliclaude
andcommitted
Fix: skip scope-shadowed fn in template-no-redundant-fn for gjs/gts
When `fn` is imported from a local module in gjs/gts, it shadows Ember's built-in helper. Use scope analysis to detect this and avoid false positives. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1 parent b347140 commit 9b7e226

2 files changed

Lines changed: 30 additions & 0 deletions

File tree

lib/rules/template-no-redundant-fn.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,23 @@ module.exports = {
2323
},
2424

2525
create(context) {
26+
const sourceCode = context.sourceCode;
27+
28+
/**
29+
* Check whether `fn` in the template resolves to a local/imported binding.
30+
* If it does, the user has shadowed Ember's built-in `fn` helper and we
31+
* should not flag the usage.
32+
*/
33+
function isFnShadowed(node) {
34+
const head = node.path?.head;
35+
if (!head) {
36+
return false;
37+
}
38+
const scope = sourceCode.getScope(node);
39+
const ref = scope.references.find((r) => r.identifier === head);
40+
return ref?.resolved != null;
41+
}
42+
2643
function checkFnUsage(node) {
2744
// Check if this is an (fn) call with only one argument (the function itself)
2845
if (
@@ -33,6 +50,10 @@ module.exports = {
3350
node.params.length === 1 &&
3451
!node.hash?.pairs?.length
3552
) {
53+
// In gjs/gts, `fn` may be shadowed by a local import — skip if so.
54+
if (isFnShadowed(node)) {
55+
return;
56+
}
3657
const param = node.params[0];
3758
const paramText =
3859
param.type === 'GlimmerPathExpression'

tests/lib/rules/template-no-redundant-fn.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ ruleTester.run('template-no-redundant-fn', rule, {
3535
'<template><SomeComponent @onClick={{fn this.handleClick "foo"}} /></template>',
3636
'<template>{{foo bar=this.handleClick}}></template>',
3737
'<template>{{foo bar=(fn this.handleClick "foo")}}></template>',
38+
39+
// `fn` is imported from a local module — not Ember's built-in helper.
40+
// Should NOT be flagged even with a single argument.
41+
`
42+
import { fn } from './my-utils';
43+
<template>
44+
<button {{on "click" (fn this.handleClick)}}>Click</button>
45+
</template>
46+
`,
3847
],
3948

4049
invalid: [

0 commit comments

Comments
 (0)