Skip to content

Commit 140ae42

Browse files
Merge pull request #2478 from NullVoxPopuli/nvp/template-lint-extract-rule-template-no-link-to-tagname
Extract rule: template-no-link-to-tagname
2 parents 055f60b + 2d713d4 commit 140ae42

4 files changed

Lines changed: 241 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ rules in templates can be disabled with eslint directives with mustache or html
274274
| [no-string-prototype-extensions](docs/rules/no-string-prototype-extensions.md) | disallow usage of `String` prototype extensions || | |
275275
| [template-no-action](docs/rules/template-no-action.md) | disallow {{action}} helper | | | |
276276
| [template-no-attrs-in-components](docs/rules/template-no-attrs-in-components.md) | disallow attrs in component templates | | | |
277+
| [template-no-link-to-tagname](docs/rules/template-no-link-to-tagname.md) | disallow tagName attribute on LinkTo component | | | |
277278

278279
### Ember Data
279280

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# ember/template-no-link-to-tagname
2+
3+
<!-- end auto-generated rule header -->
4+
5+
> Disallow tagName attribute on LinkTo component
6+
7+
## Rule Details
8+
9+
The `tagName` attribute on `<LinkTo>` components is deprecated. Use the appropriate HTML element or component instead.
10+
11+
## Examples
12+
13+
Examples of **incorrect** code for this rule:
14+
15+
```gjs
16+
<template>
17+
<LinkTo @route="index" tagName="button">Home</LinkTo>
18+
</template>
19+
```
20+
21+
```gjs
22+
<template>
23+
<LinkTo @route="about" @tagName="span">About</LinkTo>
24+
</template>
25+
```
26+
27+
Examples of **correct** code for this rule:
28+
29+
```gjs
30+
<template>
31+
<LinkTo @route="index">Home</LinkTo>
32+
</template>
33+
```
34+
35+
```gjs
36+
<template>
37+
<button type="button" {{on "click" (fn this.transitionTo "index")}}>Home</button>
38+
</template>
39+
```
40+
41+
## Migration
42+
43+
- Remove the `tagName` overrides and, if you need it, adjust the styling of the
44+
`<a>` elements to make them look like buttons
45+
46+
## Related rules
47+
48+
- [no-input-tagname](template-no-input-tagname.md)
49+
- [no-unknown-arguments-for-builtin-components](template-no-unknown-arguments-for-builtin-components.md)
50+
51+
## References
52+
53+
- [eslint-plugin-ember template-no-link-to-tagname](https://github.com/ember-cli/eslint-plugin-ember/blob/master/docs/rules/template-no-link-to-tagname.md)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* @param {any} node
3+
* @returns {boolean}
4+
*/
5+
function isLinkToComponent(node) {
6+
if (node.type === 'GlimmerElementNode') {
7+
return node.tag === 'LinkTo' || node.tag === 'link-to';
8+
}
9+
return false;
10+
}
11+
12+
/** @type {import('eslint').Rule.RuleModule} */
13+
module.exports = {
14+
meta: {
15+
type: 'problem',
16+
docs: {
17+
description: 'disallow tagName attribute on LinkTo component',
18+
category: 'Deprecations',
19+
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-link-to-tagname.md',
20+
templateMode: 'both',
21+
},
22+
schema: [],
23+
messages: {
24+
noLinkToTagname: 'tagName attribute on LinkTo is deprecated',
25+
},
26+
originallyFrom: {
27+
name: 'ember-template-lint',
28+
rule: 'lib/rules/no-link-to-tagname.js',
29+
docs: 'docs/rule/no-link-to-tagname.md',
30+
tests: 'test/unit/rules/no-link-to-tagname-test.js',
31+
},
32+
},
33+
34+
create(context) {
35+
function checkHashPairsForTagName(node) {
36+
if (!node.hash || !node.hash.pairs) {
37+
return;
38+
}
39+
const tagNamePair = node.hash.pairs.find((pair) => pair.key === 'tagName');
40+
if (tagNamePair) {
41+
context.report({
42+
node: tagNamePair,
43+
messageId: 'noLinkToTagname',
44+
});
45+
}
46+
}
47+
48+
return {
49+
GlimmerElementNode(node) {
50+
if (!isLinkToComponent(node)) {
51+
return;
52+
}
53+
54+
const tagNameAttr = node.attributes.find(
55+
(attr) =>
56+
attr.type === 'GlimmerAttrNode' && (attr.name === 'tagName' || attr.name === '@tagName')
57+
);
58+
59+
if (tagNameAttr) {
60+
context.report({
61+
node: tagNameAttr,
62+
messageId: 'noLinkToTagname',
63+
});
64+
}
65+
},
66+
67+
GlimmerMustacheStatement(node) {
68+
if (node.path?.original === 'link-to') {
69+
checkHashPairsForTagName(node);
70+
}
71+
},
72+
73+
GlimmerBlockStatement(node) {
74+
if (node.path?.original === 'link-to') {
75+
checkHashPairsForTagName(node);
76+
}
77+
},
78+
};
79+
},
80+
};
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
const rule = require('../../../lib/rules/template-no-link-to-tagname');
2+
const RuleTester = require('eslint').RuleTester;
3+
4+
const ruleTester = new RuleTester({
5+
parser: require.resolve('ember-eslint-parser'),
6+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
7+
});
8+
9+
ruleTester.run('template-no-link-to-tagname', rule, {
10+
valid: [
11+
{
12+
filename: 'test.gjs',
13+
code: '<template><LinkTo @route="index">Home</LinkTo></template>',
14+
output: null,
15+
},
16+
{
17+
filename: 'test.gjs',
18+
code: '<template><link-to @route="about">About</link-to></template>',
19+
output: null,
20+
},
21+
{
22+
filename: 'test.gjs',
23+
code: '<template><a href="/home">Home</a></template>',
24+
output: null,
25+
},
26+
27+
'<template><Foo @route="routeName" @tagName="button">Link text</Foo></template>',
28+
'<template><LinkTo @route="routeName">Link text</LinkTo></template>',
29+
'<template>{{#link-to "routeName"}}Link text{{/link-to}}</template>',
30+
'<template>{{#foo "routeName" tagName="button"}}Link text{{/foo}}</template>',
31+
'<template>{{link-to "Link text" "routeName"}}</template>',
32+
'<template>{{foo "Link text" "routeName" tagName="button"}}</template>',
33+
],
34+
35+
invalid: [
36+
{
37+
filename: 'test.gjs',
38+
code: '<template><LinkTo @route="index" tagName="button">Home</LinkTo></template>',
39+
output: null,
40+
errors: [{ messageId: 'noLinkToTagname' }],
41+
},
42+
{
43+
filename: 'test.gjs',
44+
code: '<template><LinkTo @route="about" @tagName="span">About</LinkTo></template>',
45+
output: null,
46+
errors: [{ messageId: 'noLinkToTagname' }],
47+
},
48+
{
49+
filename: 'test.gjs',
50+
code: '<template><link-to @route="contact" tagName="div">Contact</link-to></template>',
51+
output: null,
52+
errors: [{ messageId: 'noLinkToTagname' }],
53+
},
54+
55+
{
56+
code: '<template><LinkTo @route="routeName" @tagName="button">Link text</LinkTo></template>',
57+
output: null,
58+
errors: [{ messageId: 'noLinkToTagname' }],
59+
},
60+
{
61+
code: '<template>{{#link-to "routeName" tagName="button"}}Link text{{/link-to}}</template>',
62+
output: null,
63+
errors: [{ messageId: 'noLinkToTagname' }],
64+
},
65+
{
66+
code: '<template>{{link-to "Link text" "routeName" tagName="button"}}</template>',
67+
output: null,
68+
errors: [{ messageId: 'noLinkToTagname' }],
69+
},
70+
],
71+
});
72+
73+
const hbsRuleTester = new RuleTester({
74+
parser: require.resolve('ember-eslint-parser/hbs'),
75+
parserOptions: {
76+
ecmaVersion: 2022,
77+
sourceType: 'module',
78+
},
79+
});
80+
81+
hbsRuleTester.run('template-no-link-to-tagname', rule, {
82+
valid: [
83+
'<Foo @route="routeName" @tagName="button">Link text</Foo>',
84+
'<LinkTo @route="routeName">Link text</LinkTo>',
85+
'{{#link-to "routeName"}}Link text{{/link-to}}',
86+
'{{#foo "routeName" tagName="button"}}Link text{{/foo}}',
87+
'{{link-to "Link text" "routeName"}}',
88+
'{{foo "Link text" "routeName" tagName="button"}}',
89+
],
90+
invalid: [
91+
{
92+
code: '<LinkTo @route="routeName" @tagName="button">Link text</LinkTo>',
93+
output: null,
94+
errors: [{ message: 'tagName attribute on LinkTo is deprecated' }],
95+
},
96+
{
97+
code: '{{#link-to "routeName" tagName="button"}}Link text{{/link-to}}',
98+
output: null,
99+
errors: [{ message: 'tagName attribute on LinkTo is deprecated' }],
100+
},
101+
{
102+
code: '{{link-to "Link text" "routeName" tagName="button"}}',
103+
output: null,
104+
errors: [{ message: 'tagName attribute on LinkTo is deprecated' }],
105+
},
106+
],
107+
});

0 commit comments

Comments
 (0)