Skip to content

Commit 47270f3

Browse files
committed
Fix review comments for no-deprecated-router-link-tag-prop
- Use helper functions from utils to get attributes for nodes. - Add more test cases. - Handle both kebab-case and PascalCase version of components.
1 parent 3d970ba commit 47270f3

File tree

3 files changed

+218
-28
lines changed

3 files changed

+218
-28
lines changed

docs/rules/no-deprecated-router-link-tag-prop.md

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,24 @@ This rule reports deprecated the `tag` attribute on `RouterLink` elements (remov
2020
<template>
2121
<!-- ✓ GOOD -->
2222
<RouterLink to="/">Home</RouterLink>
23+
<router-link to="/">Home</router-link>
2324
2425
<RouterLink to="/">
2526
<div>Home</div>
2627
</RouterLink>
2728
29+
<router-link to="/">
30+
<div>Home</div>
31+
</router-link>
32+
2833
<NuxtLink tag="div" to="/">Home</NuxtLink>
34+
<nuxt-link tag="div" to="/">Home</nuxt-link>
2935
3036
<!-- ✗ BAD -->
3137
<RouterLink tag="div" to="/">Home</RouterLink>
38+
<router-link tag="div" to="/">Home</router-link>
3239
<RouterLink :tag="someVariable" to="/">Home</RouterLink>
40+
<router-link :tag="someVariable" to="/">Home</router-link>
3341
</template>
3442
```
3543

@@ -40,23 +48,34 @@ This rule reports deprecated the `tag` attribute on `RouterLink` elements (remov
4048
```json
4149
{
4250
"vue/no-deprecated-router-link-tag-prop": ["error", {
43-
"components": ['RouterLink', 'NuxtLink']
51+
"components": ['RouterLink']
4452
}]
4553
}
4654
```
4755

56+
- `components` (`string[]`) ... Component names which will be checked with the `tag` attribute. default `['RouterLink']`.
57+
58+
Note: this rule will check both `CamelCase` and `PascalCase` versions of the
59+
given component names.
60+
4861
### `{ "components": ['RouterLink', 'NuxtLink'] }`
4962

5063
<eslint-code-block :rules="{'vue/no-deprecated-router-link-tag-prop': ['error', {'components': ['RouterLink', 'NuxtLink']}]}">
5164

5265
```vue
5366
<template>
5467
<!-- ✗ BAD -->
55-
<NuxtLink tag="div" to="/">Home</NuxtLink>
56-
<NuxtLink :tag="someVariable" to="/">Home</NuxtLink>
57-
5868
<RouterLink tag="div" to="/">Home</RouterLink>
69+
<router-link tag="div" to="/">Home</router-link>
70+
5971
<RouterLink :tag="someVariable" to="/">Home</RouterLink>
72+
<router-link :tag="someVariable" to="/">Home</router-link>
73+
74+
<NuxtLink tag="div" to="/">Home</NuxtLink>
75+
<nuxt-link tag="div" to="/">Home</nuxt-link>
76+
77+
<NuxtLink :tag="someVariable" to="/">Home</NuxtLink>
78+
<nuxt-link :tag="someVariable" to="/">Home</nuxt-link>
6079
</template>
6180
```
6281

lib/rules/no-deprecated-router-link-tag-prop.js

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@
99
// ------------------------------------------------------------------------------
1010

1111
const utils = require('../utils')
12+
const casing = require('../utils/casing')
13+
14+
// --------------------------------------------------------------------------
15+
// Helpers
16+
// --------------------------------------------------------------------------
17+
18+
/** @param {RuleContext} context */
19+
function getComponentNames(context) {
20+
let components = ['RouterLink']
21+
22+
if (context.options[0] && context.options[0].components) {
23+
components = context.options[0].components
24+
}
25+
26+
return components.reduce((prev, curr) => {
27+
prev.add(casing.kebabCase(curr))
28+
prev.add(casing.pascalCase(curr))
29+
return prev
30+
}, new Set())
31+
}
1232

1333
// ------------------------------------------------------------------------------
1434
// Rule Definition
@@ -46,39 +66,37 @@ module.exports = {
4666
},
4767
/** @param {RuleContext} context */
4868
create(context) {
49-
let components = ['RouterLink']
50-
if (context.options[0] && context.options[0].components) {
51-
components = context.options[0].components
52-
}
69+
const components = getComponentNames(context)
5370

5471
return utils.defineTemplateBodyVisitor(context, {
5572
VElement(node) {
56-
if (!components.includes(node.rawName)) return
73+
if (!components.has(node.rawName)) return
5774

58-
const attributes = node.startTag.attributes
59-
attributes.forEach((attr) => {
60-
/** @type VIdentifier | null */
61-
let tagAttr = null
75+
/** @type VIdentifier | null */
76+
let tagKey = null
6277

63-
if (attr.key.type === 'VIdentifier') {
64-
tagAttr = attr.key
65-
} else if (attr.directive && attr.key.type === 'VDirectiveKey') {
66-
const arg = attr.key.argument
78+
const tagAttr = utils.getAttribute(node, 'tag')
79+
if (tagAttr) {
80+
tagKey = tagAttr.key
81+
} else {
82+
const directive = utils.getDirective(node, 'bind', 'tag')
83+
if (directive) {
84+
const arg = directive.key.argument
6785
if (arg && arg.type === 'VIdentifier') {
68-
tagAttr = arg
86+
tagKey = arg
6987
}
7088
}
89+
}
7190

72-
if (tagAttr && tagAttr.name === 'tag') {
73-
context.report({
74-
node: tagAttr,
75-
messageId: 'deprecated',
76-
data: {
77-
element: node.rawName
78-
}
79-
})
80-
}
81-
})
91+
if (tagKey) {
92+
context.report({
93+
node: tagKey,
94+
messageId: 'deprecated',
95+
data: {
96+
element: node.rawName
97+
}
98+
})
99+
}
82100
}
83101
})
84102
}

tests/lib/rules/no-deprecated-router-link-tag-prop.js

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ tester.run('no-deprecated-router-link-tag-prop', rule, {
2525
</template>
2626
`
2727
},
28+
{
29+
filename: 'test.vue',
30+
code: `
31+
<template>
32+
<router-link to="/">Home</router-link>
33+
</template>
34+
`
35+
},
2836
{
2937
filename: 'test.vue',
3038
code: `
@@ -35,6 +43,16 @@ tester.run('no-deprecated-router-link-tag-prop', rule, {
3543
</template>
3644
`
3745
},
46+
{
47+
filename: 'test.vue',
48+
code: `
49+
<template>
50+
<router-link to="/">
51+
<div>Home</div>
52+
</router-link>
53+
</template>
54+
`
55+
},
3856
{
3957
filename: 'test.vue',
4058
code: `
@@ -43,6 +61,14 @@ tester.run('no-deprecated-router-link-tag-prop', rule, {
4361
</template>
4462
`
4563
},
64+
{
65+
filename: 'test.vue',
66+
code: `
67+
<template>
68+
<nuxt-link to="/">Home</nuxt-link>
69+
</template>
70+
`
71+
},
4672
{
4773
filename: 'test.vue',
4874
code: `
@@ -52,6 +78,16 @@ tester.run('no-deprecated-router-link-tag-prop', rule, {
5278
</NuxtLink>
5379
</template>
5480
`
81+
},
82+
{
83+
filename: 'test.vue',
84+
code: `
85+
<template>
86+
<nuxt-link to="/">
87+
<div>Home</div>
88+
</nuxt-link>
89+
</template>
90+
`
5591
}
5692
],
5793
invalid: [
@@ -71,6 +107,22 @@ tester.run('no-deprecated-router-link-tag-prop', rule, {
71107
}
72108
]
73109
},
110+
{
111+
filename: 'test.vue',
112+
code: `
113+
<template>
114+
<router-link tag="div" to="/">Home</router-link>
115+
</template>
116+
`,
117+
errors: [
118+
{
119+
message:
120+
"'tag' property on 'router-link' component is deprecated. Use scoped slots instead.",
121+
line: 3,
122+
column: 22
123+
}
124+
]
125+
},
74126
{
75127
filename: 'test.vue',
76128
code: `
@@ -88,6 +140,40 @@ tester.run('no-deprecated-router-link-tag-prop', rule, {
88140
}
89141
]
90142
},
143+
{
144+
filename: 'test.vue',
145+
code: `
146+
<template>
147+
<RouterLink tag="div" to="/">Home</RouterLink>
148+
</template>
149+
`,
150+
options: [{ components: ['router-link'] }],
151+
errors: [
152+
{
153+
message:
154+
"'tag' property on 'RouterLink' component is deprecated. Use scoped slots instead.",
155+
line: 3,
156+
column: 21
157+
}
158+
]
159+
},
160+
{
161+
filename: 'test.vue',
162+
code: `
163+
<template>
164+
<router-link tag="div" to="/">Home</router-link>
165+
</template>
166+
`,
167+
options: [{ components: ['RouterLink'] }],
168+
errors: [
169+
{
170+
message:
171+
"'tag' property on 'router-link' component is deprecated. Use scoped slots instead.",
172+
line: 3,
173+
column: 22
174+
}
175+
]
176+
},
91177
{
92178
filename: 'test.vue',
93179
code: `
@@ -104,6 +190,22 @@ tester.run('no-deprecated-router-link-tag-prop', rule, {
104190
}
105191
]
106192
},
193+
{
194+
filename: 'test.vue',
195+
code: `
196+
<template>
197+
<router-link :tag="someVariable" to="/">Home</router-link>
198+
</template>
199+
`,
200+
errors: [
201+
{
202+
message:
203+
"'tag' property on 'router-link' component is deprecated. Use scoped slots instead.",
204+
line: 3,
205+
column: 23
206+
}
207+
]
208+
},
107209
{
108210
filename: 'test.vue',
109211
code: `
@@ -121,6 +223,23 @@ tester.run('no-deprecated-router-link-tag-prop', rule, {
121223
}
122224
]
123225
},
226+
{
227+
filename: 'test.vue',
228+
code: `
229+
<template>
230+
<router-link :tag="someVariable" to="/">Home</router-link>
231+
</template>
232+
`,
233+
options: [{ components: ['RouterLink'] }],
234+
errors: [
235+
{
236+
message:
237+
"'tag' property on 'router-link' component is deprecated. Use scoped slots instead.",
238+
line: 3,
239+
column: 23
240+
}
241+
]
242+
},
124243
{
125244
filename: 'test.vue',
126245
code: `
@@ -138,6 +257,23 @@ tester.run('no-deprecated-router-link-tag-prop', rule, {
138257
}
139258
]
140259
},
260+
{
261+
filename: 'test.vue',
262+
code: `
263+
<template>
264+
<nuxt-link tag="div" to="/">Home</nuxt-link>
265+
</template>
266+
`,
267+
options: [{ components: ['NuxtLink'] }],
268+
errors: [
269+
{
270+
message:
271+
"'tag' property on 'nuxt-link' component is deprecated. Use scoped slots instead.",
272+
line: 3,
273+
column: 20
274+
}
275+
]
276+
},
141277
{
142278
filename: 'test.vue',
143279
code: `
@@ -154,6 +290,23 @@ tester.run('no-deprecated-router-link-tag-prop', rule, {
154290
column: 20
155291
}
156292
]
293+
},
294+
{
295+
filename: 'test.vue',
296+
code: `
297+
<template>
298+
<nuxt-link :tag="someVariable" to="/">Home</nuxt-link>
299+
</template>
300+
`,
301+
options: [{ components: ['NuxtLink'] }],
302+
errors: [
303+
{
304+
message:
305+
"'tag' property on 'nuxt-link' component is deprecated. Use scoped slots instead.",
306+
line: 3,
307+
column: 21
308+
}
309+
]
157310
}
158311
]
159312
})

0 commit comments

Comments
 (0)