22// Requirements
33//------------------------------------------------------------------------------
44
5- const path = require ( 'node:path' ) ;
65const rule = require ( '../../../lib/rules/template-missing-invokable' ) ;
76const RuleTester = require ( 'eslint' ) . RuleTester ;
87
9- //------------------------------------------------------------------------------
10- // Helpers
11- //------------------------------------------------------------------------------
12-
13- // A filename inside a fixture project that has ember-truth-helpers installed.
14- const filenameInProjectWithTruthHelpers = path . join (
15- __dirname ,
16- '../../fixtures/projects/has-ember-truth-helpers/test.gjs'
17- ) ;
18-
198//------------------------------------------------------------------------------
209// Tests
2110//------------------------------------------------------------------------------
@@ -76,33 +65,25 @@ ruleTester.run('template-missing-invokable', rule, {
7665 <button {{on "click" doSomething}}>Go</button>
7766 </template>
7867 ` ,
79- ] ,
8068
81- invalid : [
82- // Subexpression invocations — no auto-fix when package is not in project deps
83- {
84- code : `
69+ // Built-in invokables are not reported when already imported
70+ `
71+ import { fn } from '@ember/helper';
8572 <template>
86- {{#if (eq 1 1)}}
87- They're equal
88- {{/if}}
73+ {{fn myFunc 1}}
8974 </template>
90- ` ,
91- output : null ,
92- options : [
93- {
94- invokables : {
95- eq : [ 'eq' , 'ember-truth-helpers' ] ,
96- } ,
97- } ,
98- ] ,
99-
100- errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
101- } ,
75+ ` ,
76+ `
77+ import { LinkTo } from '@ember/routing';
78+ <template>
79+ <LinkTo @route="index">Home</LinkTo>
80+ </template>
81+ ` ,
82+ ] ,
10283
103- // Subexpression invocations — auto-fix when package IS in project deps
84+ invalid : [
85+ // Subexpression invocations — always auto-fixes when invokable is configured
10486 {
105- filename : filenameInProjectWithTruthHelpers ,
10687 code : `
10788 <template>
10889 {{#if (eq 1 1)}}
@@ -129,25 +110,8 @@ ruleTester.run('template-missing-invokable', rule, {
129110 errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
130111 } ,
131112
132- // Mustache Invocations — no auto-fix when package is not in project deps
113+ // Mustache Invocations — always auto-fixes when invokable is configured
133114 {
134- code : `
135- <template>
136- {{eq 1 1}}
137- </template>
138- ` ,
139- output : null ,
140- options : [
141- {
142- invokables : {
143- eq : [ 'eq' , 'ember-truth-helpers' ] ,
144- } ,
145- } ,
146- ] ,
147- errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
148- } ,
149- {
150- filename : filenameInProjectWithTruthHelpers ,
151115 code : `
152116 import MyComponent from 'somewhere';
153117 <template>
@@ -171,7 +135,7 @@ ruleTester.run('template-missing-invokable', rule, {
171135 errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
172136 } ,
173137
174- // Modifier Invocations — built-in package always auto-fixes
138+ // Modifier Invocations — always auto-fixes when invokable is configured
175139 {
176140 code : `
177141 function doSomething() {}
@@ -196,9 +160,8 @@ ruleTester.run('template-missing-invokable', rule, {
196160 errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
197161 } ,
198162
199- // Multiple copies of a fixable invocation — with package installed
163+ // Multiple copies of a fixable invocation
200164 {
201- filename : filenameInProjectWithTruthHelpers ,
202165 code : `
203166 let other = <template>
204167 {{#if (eq 3 3) }}
@@ -246,9 +209,8 @@ ruleTester.run('template-missing-invokable', rule, {
246209 ] ,
247210 } ,
248211
249- // Auto-fix with a default export — package installed
212+ // Auto-fix with a default export
250213 {
251- filename : filenameInProjectWithTruthHelpers ,
252214 code : `
253215 <template>
254216 {{#if (eq 1 1)}}
@@ -274,5 +236,96 @@ ruleTester.run('template-missing-invokable', rule, {
274236
275237 errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
276238 } ,
239+
240+ // Built-in: fn — auto-fixes without any user config
241+ {
242+ code : `
243+ <template>
244+ {{fn myFunc 1}}
245+ </template>
246+ ` ,
247+ output : `import { fn } from '@ember/helper';
248+
249+ <template>
250+ {{fn myFunc 1}}
251+ </template>
252+ ` ,
253+ errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
254+ } ,
255+
256+ // Built-in: hash — auto-fixes without any user config
257+ {
258+ code : `
259+ <template>
260+ <MyComp @opts={{hash a=1}} />
261+ </template>
262+ ` ,
263+ output : `import { hash } from '@ember/helper';
264+
265+ <template>
266+ <MyComp @opts={{hash a=1}} />
267+ </template>
268+ ` ,
269+ errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
270+ } ,
271+
272+ // Built-in: on modifier — auto-fixes without any user config
273+ {
274+ code : `
275+ function doSomething() {}
276+ <template>
277+ <button {{on "click" doSomething}}>Go</button>
278+ </template>
279+ ` ,
280+ output : `import { on } from '@ember/modifier';
281+
282+ function doSomething() {}
283+ <template>
284+ <button {{on "click" doSomething}}>Go</button>
285+ </template>
286+ ` ,
287+ errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
288+ } ,
289+
290+ // Built-in: LinkTo — auto-fixes without any user config
291+ {
292+ code : `
293+ <template>
294+ <LinkTo @route="index">Home</LinkTo>
295+ </template>
296+ ` ,
297+ output : `import { LinkTo } from '@ember/routing';
298+
299+ <template>
300+ <LinkTo @route="index">Home</LinkTo>
301+ </template>
302+ ` ,
303+ errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
304+ } ,
305+
306+ // User config overrides a built-in
307+ {
308+ code : `
309+ function doSomething() {}
310+ <template>
311+ <button {{on "click" doSomething}}>Go</button>
312+ </template>
313+ ` ,
314+ output : `import { on } from 'my-custom-modifier-package';
315+
316+ function doSomething() {}
317+ <template>
318+ <button {{on "click" doSomething}}>Go</button>
319+ </template>
320+ ` ,
321+ options : [
322+ {
323+ invokables : {
324+ on : [ 'on' , 'my-custom-modifier-package' ] ,
325+ } ,
326+ } ,
327+ ] ,
328+ errors : [ { type : 'GlimmerPathExpression' , message : rule . meta . messages [ 'missing-invokable' ] } ] ,
329+ } ,
277330 ] ,
278331} ) ;
0 commit comments