Skip to content

Commit 09e0547

Browse files
committed
Skip builtin-component-arguments in GJS/GTS when not imported from @ember/component
In strict mode (GJS/GTS), a component named Input or Textarea might be a custom component, not Ember's built-in. Only flag when explicitly imported from @ember/component. See ember-template-lint/ember-template-lint#2786
1 parent 131cd12 commit 09e0547

2 files changed

Lines changed: 111 additions & 4 deletions

File tree

lib/rules/template-builtin-component-arguments.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,53 @@ module.exports = {
2424
},
2525

2626
create(context) {
27+
const filename = context.filename ?? context.getFilename();
28+
const isStrictMode = filename.endsWith('.gjs') || filename.endsWith('.gts');
29+
30+
// In GJS/GTS, track imports from @ember/component to distinguish
31+
// Ember's built-in Input/Textarea from custom components with the same name.
32+
// See https://github.com/ember-template-lint/ember-template-lint/issues/2786
33+
const importedComponents = new Map();
34+
2735
return {
36+
ImportDeclaration(node) {
37+
if (node.source.value === '@ember/component') {
38+
for (const specifier of node.specifiers) {
39+
if (specifier.type === 'ImportSpecifier') {
40+
const original = specifier.imported.name;
41+
if (original === 'Input' || original === 'Textarea') {
42+
importedComponents.set(specifier.local.name, original);
43+
}
44+
}
45+
}
46+
}
47+
},
48+
2849
GlimmerElementNode(node) {
2950
const { tag, attributes } = node;
30-
const forbiddenAttributes = FORBIDDEN_ATTRIBUTES[tag];
3151

52+
// In strict mode (GJS/GTS), only flag if the component was imported from @ember/component
53+
if (isStrictMode) {
54+
const original = importedComponents.get(tag);
55+
if (!original) {
56+
return;
57+
}
58+
const forbiddenAttributes = FORBIDDEN_ATTRIBUTES[original];
59+
if (forbiddenAttributes && attributes) {
60+
for (const attribute of attributes) {
61+
if (attribute.name && forbiddenAttributes.has(attribute.name)) {
62+
context.report({
63+
node: attribute,
64+
message: generateErrorMessage(original, attribute.name),
65+
});
66+
}
67+
}
68+
}
69+
return;
70+
}
71+
72+
// In loose mode (HBS), check by tag name directly
73+
const forbiddenAttributes = FORBIDDEN_ATTRIBUTES[tag];
3274
if (forbiddenAttributes && attributes) {
3375
for (const attribute of attributes) {
3476
if (attribute.name && forbiddenAttributes.has(attribute.name)) {

tests/lib/rules/template-builtin-component-arguments.js

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,75 @@ ruleTester.run('template-builtin-component-arguments', rule, {
1212
'<template><Input @type="text" size="10" /></template>',
1313
'<template><Input @type="checkbox" @checked={{true}} /></template>',
1414
'<template><Textarea @value="Tomster" /></template>',
15+
// In GJS/GTS: custom Input/Textarea components (not imported from @ember/component) are fine
16+
// https://github.com/ember-template-lint/ember-template-lint/issues/2786
17+
{
18+
filename: 'test.gjs',
19+
code: 'import { Input } from "my-custom-lib"; <template><Input type="text" /></template>',
20+
},
21+
{
22+
filename: 'test.gjs',
23+
code: '<template><Input type="text" /></template>',
24+
},
25+
{
26+
filename: 'test.gts',
27+
code: '<template><Textarea value="text" /></template>',
28+
},
29+
],
30+
invalid: [
31+
// In GJS/GTS: only flag when imported from @ember/component
32+
{
33+
filename: 'test.gjs',
34+
code: 'import { Input } from "@ember/component"; <template><Input type="text" size="10" /></template>',
35+
output: null,
36+
errors: [
37+
{
38+
message:
39+
'Setting the `type` attribute on the builtin <Input> component is not allowed. Did you mean `@type`?',
40+
},
41+
],
42+
},
43+
{
44+
filename: 'test.gjs',
45+
code: 'import { Input as MyInput } from "@ember/component"; <template><MyInput type="text" /></template>',
46+
output: null,
47+
errors: [
48+
{
49+
message:
50+
'Setting the `type` attribute on the builtin <Input> component is not allowed. Did you mean `@type`?',
51+
},
52+
],
53+
},
54+
{
55+
filename: 'test.gjs',
56+
code: 'import { Textarea } from "@ember/component"; <template><Textarea value="Tomster" /></template>',
57+
output: null,
58+
errors: [
59+
{
60+
message:
61+
'Setting the `value` attribute on the builtin <Textarea> component is not allowed. Did you mean `@value`?',
62+
},
63+
],
64+
},
65+
],
66+
});
67+
68+
// HBS tests — loose mode, always checks by tag name
69+
const hbsRuleTester = new RuleTester({
70+
parser: require.resolve('ember-eslint-parser/hbs'),
71+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
72+
});
73+
74+
hbsRuleTester.run('template-builtin-component-arguments (hbs)', rule, {
75+
valid: [
76+
'<input type="text" size="10" />',
77+
'<Input @type="text" size="10" />',
78+
'<Input @type="checkbox" @checked={{true}} />',
79+
'<Textarea @value="Tomster" />',
1580
],
1681
invalid: [
1782
{
18-
code: '<template><Input type="text" size="10" /></template>',
83+
code: '<Input type="text" size="10" />',
1984
output: null,
2085
errors: [
2186
{
@@ -25,7 +90,7 @@ ruleTester.run('template-builtin-component-arguments', rule, {
2590
],
2691
},
2792
{
28-
code: '<template><Input @type="checkbox" checked /></template>',
93+
code: '<Input @type="checkbox" checked />',
2994
output: null,
3095
errors: [
3196
{
@@ -35,7 +100,7 @@ ruleTester.run('template-builtin-component-arguments', rule, {
35100
],
36101
},
37102
{
38-
code: '<template><Textarea value="Tomster" /></template>',
103+
code: '<Textarea value="Tomster" />',
39104
output: null,
40105
errors: [
41106
{

0 commit comments

Comments
 (0)