Skip to content

Commit 41c13b8

Browse files
committed
Add no-deprecated-router-link-tag-prop rule
1 parent 68b184a commit 41c13b8

File tree

5 files changed

+311
-0
lines changed

5 files changed

+311
-0
lines changed

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ For example:
302302
| [vue/no-bare-strings-in-template](./no-bare-strings-in-template.md) | disallow the use of bare strings in `<template>` | |
303303
| [vue/no-boolean-default](./no-boolean-default.md) | disallow boolean defaults | :wrench: |
304304
| [vue/no-computed-properties-in-data](./no-computed-properties-in-data.md) | disallow accessing computed properties in `data`. | |
305+
| [vue/no-deprecated-router-link-tag-prop](./no-deprecated-router-link-tag-prop.md) | disallow using deprecated `tag` property on `RouterLink` (in Vue.js 3.0.0+) | |
305306
| [vue/no-deprecated-v-is](./no-deprecated-v-is.md) | disallow deprecated `v-is` directive (in Vue.js 3.1.0+) | :wrench: |
306307
| [vue/no-duplicate-attr-inheritance](./no-duplicate-attr-inheritance.md) | enforce `inheritAttrs` to be set to `false` when using `v-bind="$attrs"` | |
307308
| [vue/no-empty-component-block](./no-empty-component-block.md) | disallow the `<template>` `<script>` `<style>` block to be empty | |
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/no-deprecated-router-link-tag-prop
5+
description: disallow using deprecated `tag` property on `RouterLink` (in Vue.js 3.0.0+)
6+
---
7+
# vue/no-deprecated-router-link-tag-prop
8+
9+
> disallow using deprecated `tag` property on `RouterLink` (in Vue.js 3.0.0+)
10+
11+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
12+
13+
## :book: Rule Details
14+
15+
This rule reports deprecated the `tag` attribute on `RouterLink` elements (removed in Vue.js v3.0.0+).
16+
17+
<eslint-code-block :rules="{'vue/no-deprecated-router-link-tag-prop': ['error']}">
18+
19+
```vue
20+
<template>
21+
<!-- ✓ GOOD -->
22+
<RouterLink to="/">Home</RouterLink>
23+
24+
<RouterLink to="/">
25+
<div>Home</div>
26+
</RouterLink>
27+
28+
<NuxtLink tag="div" to="/">Home</NuxtLink>
29+
30+
<!-- ✗ BAD -->
31+
<RouterLink tag="div" to="/">Home</RouterLink>
32+
<RouterLink :tag="someVariable" to="/">Home</RouterLink>
33+
</template>
34+
```
35+
36+
</eslint-code-block>
37+
38+
## :wrench: Options
39+
40+
```json
41+
{
42+
"vue/no-deprecated-router-link-tag-prop": ["error", {
43+
"components": ['RouterLink', 'NuxtLink']
44+
}]
45+
}
46+
```
47+
48+
### `{ "components": ['RouterLink', 'NuxtLink'] }`
49+
50+
<eslint-code-block :rules="{'vue/no-deprecated-router-link-tag-prop': ['error', {'components': ['RouterLink', 'NuxtLink']}]}">
51+
52+
```vue
53+
<template>
54+
<!-- ✗ BAD -->
55+
<NuxtLink tag="div" to="/">Home</NuxtLink>
56+
<NuxtLink :tag="someVariable" to="/">Home</NuxtLink>
57+
58+
<RouterLink tag="div" to="/">Home</RouterLink>
59+
<RouterLink :tag="someVariable" to="/">Home</RouterLink>
60+
</template>
61+
```
62+
63+
</eslint-code-block>
64+
65+
## :books: Further Reading
66+
67+
- [Vue RFCs - 0021-router-link-scoped-slot](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0021-router-link-scoped-slot.md)
68+
69+
## :mag: Implementation
70+
71+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-deprecated-router-link-tag-prop.js)
72+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-deprecated-router-link-tag-prop.js)

lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ module.exports = {
7171
'no-deprecated-html-element-is': require('./rules/no-deprecated-html-element-is'),
7272
'no-deprecated-inline-template': require('./rules/no-deprecated-inline-template'),
7373
'no-deprecated-props-default-this': require('./rules/no-deprecated-props-default-this'),
74+
'no-deprecated-router-link-tag-prop': require('./rules/no-deprecated-router-link-tag-prop'),
7475
'no-deprecated-scope-attribute': require('./rules/no-deprecated-scope-attribute'),
7576
'no-deprecated-slot-attribute': require('./rules/no-deprecated-slot-attribute'),
7677
'no-deprecated-slot-scope-attribute': require('./rules/no-deprecated-slot-scope-attribute'),
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* @author Marton Csordas
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const utils = require('../utils')
12+
13+
// ------------------------------------------------------------------------------
14+
// Rule Definition
15+
// ------------------------------------------------------------------------------
16+
17+
module.exports = {
18+
meta: {
19+
type: 'problem',
20+
docs: {
21+
description:
22+
'disallow using deprecated `tag` property on `RouterLink` (in Vue.js 3.0.0+)',
23+
categories: undefined,
24+
url: 'https://eslint.vuejs.org/rules/no-deprecated-router-link-tag-prop'
25+
},
26+
fixable: null,
27+
schema: [
28+
{
29+
type: 'object',
30+
properties: {
31+
components: {
32+
type: 'array',
33+
items: {
34+
type: 'string'
35+
},
36+
uniqueItems: true,
37+
minItems: 1
38+
}
39+
}
40+
}
41+
],
42+
messages: {
43+
deprecated: "'tag' property on '{{element}}' component is deprecated. Use scoped slots instead."
44+
}
45+
},
46+
/** @param {RuleContext} context */
47+
create(context) {
48+
let components = ['RouterLink']
49+
if (context.options[0] && context.options[0].components) {
50+
components = context.options[0].components
51+
}
52+
53+
return utils.defineTemplateBodyVisitor(context, {
54+
"VElement"(node) {
55+
if (!components.includes(node.rawName)) return
56+
57+
const attributes = node.startTag.attributes
58+
attributes.forEach(attr => {
59+
/** @type VIdentifier | null */
60+
let tagAttr = null;
61+
62+
if (attr.key.type === 'VIdentifier') {
63+
tagAttr = attr.key;
64+
} else if (attr.directive && attr.key.type === 'VDirectiveKey') {
65+
const arg = attr.key.argument
66+
if (arg && arg.type === 'VIdentifier') {
67+
tagAttr = arg
68+
}
69+
}
70+
71+
if (tagAttr && tagAttr.name === 'tag') {
72+
context.report({
73+
node: tagAttr,
74+
messageId: 'deprecated',
75+
data: {
76+
element: node.rawName
77+
}
78+
})
79+
}
80+
})
81+
}
82+
})
83+
}
84+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/**
2+
* @author Marton Csordas
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const RuleTester = require('eslint').RuleTester
8+
const rule = require('../../../lib/rules/no-deprecated-router-link-tag-prop')
9+
10+
const tester = new RuleTester({
11+
parser: require.resolve('vue-eslint-parser'),
12+
parserOptions: {
13+
ecmaVersion: 2020,
14+
sourceType: 'module'
15+
}
16+
})
17+
18+
tester.run('no-deprecated-router-link-tag-prop', rule, {
19+
valid: [
20+
{
21+
filename: 'test.vue',
22+
code: `
23+
<template>
24+
<RouterLink to="/">Home</RouterLink>
25+
</template>
26+
`
27+
},
28+
{
29+
filename: 'test.vue',
30+
code: `
31+
<template>
32+
<RouterLink to="/">
33+
<div>Home</div>
34+
</RouterLink>
35+
</template>
36+
`
37+
},
38+
{
39+
filename: 'test.vue',
40+
code: `
41+
<template>
42+
<NuxtLink to="/">Home</NuxtLink>
43+
</template>
44+
`
45+
},
46+
{
47+
filename: 'test.vue',
48+
code: `
49+
<template>
50+
<NuxtLink to="/">
51+
<div>Home</div>
52+
</NuxtLink>
53+
</template>
54+
`
55+
},
56+
],
57+
invalid: [
58+
{
59+
filename: 'test.vue',
60+
code: `
61+
<template>
62+
<RouterLink tag="div" to="/">Home</RouterLink>
63+
</template>
64+
`,
65+
errors: [
66+
{
67+
message: "'tag' property on 'RouterLink' component is deprecated. Use scoped slots instead.",
68+
line: 3,
69+
column: 21
70+
},
71+
]
72+
},
73+
{
74+
filename: 'test.vue',
75+
code: `
76+
<template>
77+
<RouterLink tag="div" to="/">Home</RouterLink>
78+
</template>
79+
`,
80+
options: [{ components: ['RouterLink'] }],
81+
errors: [
82+
{
83+
message: "'tag' property on 'RouterLink' component is deprecated. Use scoped slots instead.",
84+
line: 3,
85+
column: 21
86+
},
87+
]
88+
},
89+
{
90+
filename: 'test.vue',
91+
code: `
92+
<template>
93+
<RouterLink :tag="someVariable" to="/">Home</RouterLink>
94+
</template>
95+
`,
96+
errors: [
97+
{
98+
message: "'tag' property on 'RouterLink' component is deprecated. Use scoped slots instead.",
99+
line: 3,
100+
column: 22
101+
},
102+
]
103+
},
104+
{
105+
filename: 'test.vue',
106+
code: `
107+
<template>
108+
<RouterLink :tag="someVariable" to="/">Home</RouterLink>
109+
</template>
110+
`,
111+
options: [{ components: ['RouterLink'] }],
112+
errors: [
113+
{
114+
message: "'tag' property on 'RouterLink' component is deprecated. Use scoped slots instead.",
115+
line: 3,
116+
column: 22
117+
},
118+
]
119+
},
120+
{
121+
filename: 'test.vue',
122+
code: `
123+
<template>
124+
<NuxtLink tag="div" to="/">Home</NuxtLink>
125+
</template>
126+
`,
127+
options: [{ components: ['NuxtLink'] }],
128+
errors: [
129+
{
130+
message: "'tag' property on 'NuxtLink' component is deprecated. Use scoped slots instead.",
131+
line: 3,
132+
column: 19
133+
},
134+
]
135+
},
136+
{
137+
filename: 'test.vue',
138+
code: `
139+
<template>
140+
<NuxtLink :tag="someVariable" to="/">Home</NuxtLink>
141+
</template>
142+
`,
143+
options: [{ components: ['NuxtLink'] }],
144+
errors: [
145+
{
146+
message: "'tag' property on 'NuxtLink' component is deprecated. Use scoped slots instead.",
147+
line: 3,
148+
column: 20
149+
},
150+
]
151+
},
152+
]
153+
})

0 commit comments

Comments
 (0)