Skip to content

Commit b8814c7

Browse files
authored
Only allow modelValue in vue/no-deprecated-model-definition (#2255)
1 parent 6080fb3 commit b8814c7

File tree

3 files changed

+184
-45
lines changed

3 files changed

+184
-45
lines changed

docs/rules/no-deprecated-model-definition.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,16 @@ export default defineComponent({
4444

4545
### `"allowVue3Compat": true`
4646

47-
Allow `model` definitions with prop/event names that match the Vue.js 3.0.0+ `v-model` syntax, e.g. `fooBar`/`update:fooBar`.
47+
Allow `model` definitions with prop/event names that match the Vue.js 3.0.0+ `v-model` syntax, i.e. `modelValue`/`update:modelValue` or `model-value`/`update:model-value`.
4848

4949
<eslint-code-block :rules="{'vue/no-deprecated-model-definition': ['error', { allowVue3Compat: true }]}">
5050

5151
```vue
5252
<script>
5353
export default defineComponent({
5454
model: {
55-
prop: 'fooBar',
56-
event: 'update:fooBar'
55+
prop: 'modelValue',
56+
event: 'update:modelValue'
5757
}
5858
})
5959
</script>

lib/rules/no-deprecated-model-definition.js

+51-32
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,8 @@
66

77
const utils = require('../utils')
88

9-
/**
10-
* @param {RuleContext} context
11-
* @param {ASTNode} node
12-
*/
13-
function reportWithoutSuggestion(context, node) {
14-
context.report({
15-
node,
16-
messageId: 'deprecatedModel'
17-
})
18-
}
9+
const allowedPropNames = new Set(['modelValue', 'model-value'])
10+
const allowedEventNames = new Set(['update:modelValue', 'update:model-value'])
1911

2012
/**
2113
* @param {ObjectExpression} node
@@ -39,6 +31,15 @@ function findPropertyValue(node, key) {
3931
return property.value
4032
}
4133

34+
/**
35+
* @param {RuleFixer} fixer
36+
* @param {Literal} node
37+
* @param {string} text
38+
*/
39+
function replaceLiteral(fixer, node, text) {
40+
return fixer.replaceTextRange([node.range[0] + 1, node.range[1] - 1], text)
41+
}
42+
4243
module.exports = {
4344
meta: {
4445
type: 'problem',
@@ -62,7 +63,10 @@ module.exports = {
6263
],
6364
messages: {
6465
deprecatedModel: '`model` definition is deprecated.',
65-
renameEvent: 'Rename event to `{{expectedEventName}}`.'
66+
vue3Compat:
67+
'`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.',
68+
changeToModelValue: 'Change to `modelValue`/`update:modelValue`.',
69+
changeToKebabModelValue: 'Change to `model-value`/`update:model-value`.'
6670
}
6771
},
6872
/** @param {RuleContext} context */
@@ -76,35 +80,50 @@ module.exports = {
7680
}
7781

7882
if (!allowVue3Compat) {
79-
reportWithoutSuggestion(context, modelProperty)
83+
context.report({
84+
node: modelProperty,
85+
messageId: 'deprecatedModel'
86+
})
8087
return
8188
}
8289

8390
const propName = findPropertyValue(modelProperty.value, 'prop')
8491
const eventName = findPropertyValue(modelProperty.value, 'event')
8592

86-
if (!propName || !eventName) {
87-
reportWithoutSuggestion(context, modelProperty)
88-
return
89-
}
90-
91-
const expectedEventName = `update:${propName.value}`
92-
if (eventName.value !== expectedEventName) {
93+
if (
94+
!propName ||
95+
!eventName ||
96+
typeof propName.value !== 'string' ||
97+
typeof eventName.value !== 'string' ||
98+
!allowedPropNames.has(propName.value) ||
99+
!allowedEventNames.has(eventName.value)
100+
) {
93101
context.report({
94102
node: modelProperty,
95-
messageId: 'deprecatedModel',
96-
suggest: [
97-
{
98-
messageId: 'renameEvent',
99-
data: { expectedEventName },
100-
fix(fixer) {
101-
return fixer.replaceTextRange(
102-
[eventName.range[0] + 1, eventName.range[1] - 1],
103-
expectedEventName
104-
)
105-
}
106-
}
107-
]
103+
messageId: 'vue3Compat',
104+
suggest:
105+
propName && eventName
106+
? [
107+
{
108+
messageId: 'changeToModelValue',
109+
*fix(fixer) {
110+
const newPropName = 'modelValue'
111+
const newEventName = 'update:modelValue'
112+
yield replaceLiteral(fixer, propName, newPropName)
113+
yield replaceLiteral(fixer, eventName, newEventName)
114+
}
115+
},
116+
{
117+
messageId: 'changeToKebabModelValue',
118+
*fix(fixer) {
119+
const newPropName = 'model-value'
120+
const newEventName = 'update:model-value'
121+
yield replaceLiteral(fixer, propName, newPropName)
122+
yield replaceLiteral(fixer, eventName, newEventName)
123+
}
124+
}
125+
]
126+
: []
108127
})
109128
}
110129
})

tests/lib/rules/no-deprecated-model-definition.js

+130-10
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ tester.run('no-deprecated-model-definition', rule, {
3131
<script>
3232
export default {
3333
model: {
34-
prop: 'fooBar',
35-
event: 'update:fooBar'
34+
prop: 'modelValue',
35+
event: 'update:modelValue'
3636
}
3737
}
3838
</script>
@@ -45,8 +45,8 @@ tester.run('no-deprecated-model-definition', rule, {
4545
<script>
4646
export default defineComponent({
4747
model: {
48-
prop: 'foo-bar',
49-
event: 'update:foo-bar'
48+
prop: 'model-value',
49+
event: 'update:model-value'
5050
}
5151
})
5252
</script>
@@ -133,7 +133,8 @@ tester.run('no-deprecated-model-definition', rule, {
133133
options: [{ allowVue3Compat: true }],
134134
errors: [
135135
{
136-
message: '`model` definition is deprecated.',
136+
message:
137+
'`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.',
137138
line: 4,
138139
column: 11,
139140
endLine: 6,
@@ -155,7 +156,8 @@ tester.run('no-deprecated-model-definition', rule, {
155156
options: [{ allowVue3Compat: true }],
156157
errors: [
157158
{
158-
message: '`model` definition is deprecated.',
159+
message:
160+
'`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.',
159161
line: 4,
160162
column: 11,
161163
endLine: 6,
@@ -178,20 +180,138 @@ tester.run('no-deprecated-model-definition', rule, {
178180
options: [{ allowVue3Compat: true }],
179181
errors: [
180182
{
181-
message: '`model` definition is deprecated.',
183+
message:
184+
'`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.',
182185
line: 4,
183186
column: 11,
184187
endLine: 7,
185188
endColumn: 12,
186189
suggestions: [
187190
{
188-
desc: 'Rename event to `update:foo`.',
191+
desc: 'Change to `modelValue`/`update:modelValue`.',
189192
output: `
190193
<script>
191194
export default defineComponent({
192195
model: {
193-
prop: 'foo',
194-
event: 'update:foo'
196+
prop: 'modelValue',
197+
event: 'update:modelValue'
198+
}
199+
})
200+
</script>
201+
`
202+
},
203+
{
204+
desc: 'Change to `model-value`/`update:model-value`.',
205+
output: `
206+
<script>
207+
export default defineComponent({
208+
model: {
209+
prop: 'model-value',
210+
event: 'update:model-value'
211+
}
212+
})
213+
</script>
214+
`
215+
}
216+
]
217+
}
218+
]
219+
},
220+
{
221+
filename: 'test.vue',
222+
code: `
223+
<script>
224+
export default {
225+
model: {
226+
prop: "fooBar",
227+
event: "update:fooBar"
228+
}
229+
}
230+
</script>
231+
`,
232+
options: [{ allowVue3Compat: true }],
233+
errors: [
234+
{
235+
message:
236+
'`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.',
237+
line: 4,
238+
column: 11,
239+
endLine: 7,
240+
endColumn: 12,
241+
suggestions: [
242+
{
243+
desc: 'Change to `modelValue`/`update:modelValue`.',
244+
output: `
245+
<script>
246+
export default {
247+
model: {
248+
prop: "modelValue",
249+
event: "update:modelValue"
250+
}
251+
}
252+
</script>
253+
`
254+
},
255+
{
256+
desc: 'Change to `model-value`/`update:model-value`.',
257+
output: `
258+
<script>
259+
export default {
260+
model: {
261+
prop: "model-value",
262+
event: "update:model-value"
263+
}
264+
}
265+
</script>
266+
`
267+
}
268+
]
269+
}
270+
]
271+
},
272+
{
273+
filename: 'test.vue',
274+
code: `
275+
<script>
276+
export default defineComponent({
277+
model: {
278+
prop: 'foo-bar',
279+
event: 'update:foo-bar'
280+
}
281+
})
282+
</script>
283+
`,
284+
options: [{ allowVue3Compat: true }],
285+
errors: [
286+
{
287+
message:
288+
'`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.',
289+
line: 4,
290+
column: 11,
291+
endLine: 7,
292+
endColumn: 12,
293+
suggestions: [
294+
{
295+
desc: 'Change to `modelValue`/`update:modelValue`.',
296+
output: `
297+
<script>
298+
export default defineComponent({
299+
model: {
300+
prop: 'modelValue',
301+
event: 'update:modelValue'
302+
}
303+
})
304+
</script>
305+
`
306+
},
307+
{
308+
desc: 'Change to `model-value`/`update:model-value`.',
309+
output: `
310+
<script>
311+
export default defineComponent({
312+
model: {
313+
prop: 'model-value',
314+
event: 'update:model-value'
195315
}
196316
})
197317
</script>

0 commit comments

Comments
 (0)