From b8814c765da6427d8554ccf251e68939c3ce3d38 Mon Sep 17 00:00:00 2001 From: Flo Edelmann Date: Sat, 29 Jul 2023 11:15:36 +0200 Subject: [PATCH] Only allow modelValue in `vue/no-deprecated-model-definition` (#2255) --- docs/rules/no-deprecated-model-definition.md | 6 +- lib/rules/no-deprecated-model-definition.js | 83 +++++++---- .../rules/no-deprecated-model-definition.js | 140 ++++++++++++++++-- 3 files changed, 184 insertions(+), 45 deletions(-) diff --git a/docs/rules/no-deprecated-model-definition.md b/docs/rules/no-deprecated-model-definition.md index bb2777d69..b213c7c44 100644 --- a/docs/rules/no-deprecated-model-definition.md +++ b/docs/rules/no-deprecated-model-definition.md @@ -44,7 +44,7 @@ export default defineComponent({ ### `"allowVue3Compat": true` -Allow `model` definitions with prop/event names that match the Vue.js 3.0.0+ `v-model` syntax, e.g. `fooBar`/`update:fooBar`. +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`. @@ -52,8 +52,8 @@ Allow `model` definitions with prop/event names that match the Vue.js 3.0.0+ `v- diff --git a/lib/rules/no-deprecated-model-definition.js b/lib/rules/no-deprecated-model-definition.js index f1561c202..9540ffc06 100644 --- a/lib/rules/no-deprecated-model-definition.js +++ b/lib/rules/no-deprecated-model-definition.js @@ -6,16 +6,8 @@ const utils = require('../utils') -/** - * @param {RuleContext} context - * @param {ASTNode} node - */ -function reportWithoutSuggestion(context, node) { - context.report({ - node, - messageId: 'deprecatedModel' - }) -} +const allowedPropNames = new Set(['modelValue', 'model-value']) +const allowedEventNames = new Set(['update:modelValue', 'update:model-value']) /** * @param {ObjectExpression} node @@ -39,6 +31,15 @@ function findPropertyValue(node, key) { return property.value } +/** + * @param {RuleFixer} fixer + * @param {Literal} node + * @param {string} text + */ +function replaceLiteral(fixer, node, text) { + return fixer.replaceTextRange([node.range[0] + 1, node.range[1] - 1], text) +} + module.exports = { meta: { type: 'problem', @@ -62,7 +63,10 @@ module.exports = { ], messages: { deprecatedModel: '`model` definition is deprecated.', - renameEvent: 'Rename event to `{{expectedEventName}}`.' + vue3Compat: + '`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.', + changeToModelValue: 'Change to `modelValue`/`update:modelValue`.', + changeToKebabModelValue: 'Change to `model-value`/`update:model-value`.' } }, /** @param {RuleContext} context */ @@ -76,35 +80,50 @@ module.exports = { } if (!allowVue3Compat) { - reportWithoutSuggestion(context, modelProperty) + context.report({ + node: modelProperty, + messageId: 'deprecatedModel' + }) return } const propName = findPropertyValue(modelProperty.value, 'prop') const eventName = findPropertyValue(modelProperty.value, 'event') - if (!propName || !eventName) { - reportWithoutSuggestion(context, modelProperty) - return - } - - const expectedEventName = `update:${propName.value}` - if (eventName.value !== expectedEventName) { + if ( + !propName || + !eventName || + typeof propName.value !== 'string' || + typeof eventName.value !== 'string' || + !allowedPropNames.has(propName.value) || + !allowedEventNames.has(eventName.value) + ) { context.report({ node: modelProperty, - messageId: 'deprecatedModel', - suggest: [ - { - messageId: 'renameEvent', - data: { expectedEventName }, - fix(fixer) { - return fixer.replaceTextRange( - [eventName.range[0] + 1, eventName.range[1] - 1], - expectedEventName - ) - } - } - ] + messageId: 'vue3Compat', + suggest: + propName && eventName + ? [ + { + messageId: 'changeToModelValue', + *fix(fixer) { + const newPropName = 'modelValue' + const newEventName = 'update:modelValue' + yield replaceLiteral(fixer, propName, newPropName) + yield replaceLiteral(fixer, eventName, newEventName) + } + }, + { + messageId: 'changeToKebabModelValue', + *fix(fixer) { + const newPropName = 'model-value' + const newEventName = 'update:model-value' + yield replaceLiteral(fixer, propName, newPropName) + yield replaceLiteral(fixer, eventName, newEventName) + } + } + ] + : [] }) } }) diff --git a/tests/lib/rules/no-deprecated-model-definition.js b/tests/lib/rules/no-deprecated-model-definition.js index 71adb34f5..908be654a 100644 --- a/tests/lib/rules/no-deprecated-model-definition.js +++ b/tests/lib/rules/no-deprecated-model-definition.js @@ -31,8 +31,8 @@ tester.run('no-deprecated-model-definition', rule, { @@ -45,8 +45,8 @@ tester.run('no-deprecated-model-definition', rule, { @@ -133,7 +133,8 @@ tester.run('no-deprecated-model-definition', rule, { options: [{ allowVue3Compat: true }], errors: [ { - message: '`model` definition is deprecated.', + message: + '`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.', line: 4, column: 11, endLine: 6, @@ -155,7 +156,8 @@ tester.run('no-deprecated-model-definition', rule, { options: [{ allowVue3Compat: true }], errors: [ { - message: '`model` definition is deprecated.', + message: + '`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.', line: 4, column: 11, endLine: 6, @@ -178,20 +180,138 @@ tester.run('no-deprecated-model-definition', rule, { options: [{ allowVue3Compat: true }], errors: [ { - message: '`model` definition is deprecated.', + message: + '`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.', line: 4, column: 11, endLine: 7, endColumn: 12, suggestions: [ { - desc: 'Rename event to `update:foo`.', + desc: 'Change to `modelValue`/`update:modelValue`.', output: ` + ` + }, + { + desc: 'Change to `model-value`/`update:model-value`.', + output: ` + + ` + } + ] + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ allowVue3Compat: true }], + errors: [ + { + message: + '`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.', + line: 4, + column: 11, + endLine: 7, + endColumn: 12, + suggestions: [ + { + desc: 'Change to `modelValue`/`update:modelValue`.', + output: ` + + ` + }, + { + desc: 'Change to `model-value`/`update:model-value`.', + output: ` + + ` + } + ] + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ allowVue3Compat: true }], + errors: [ + { + message: + '`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.', + line: 4, + column: 11, + endLine: 7, + endColumn: 12, + suggestions: [ + { + desc: 'Change to `modelValue`/`update:modelValue`.', + output: ` + + ` + }, + { + desc: 'Change to `model-value`/`update:model-value`.', + output: ` +