You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
3.8 KiB
133 lines
3.8 KiB
/** |
|
* @author Flo Edelmann |
|
* See LICENSE file in root directory for full license. |
|
*/ |
|
'use strict' |
|
|
|
const utils = require('../utils') |
|
|
|
const allowedPropNames = new Set(['modelValue', 'model-value']) |
|
const allowedEventNames = new Set(['update:modelValue', 'update:model-value']) |
|
|
|
/** |
|
* @param {ObjectExpression} node |
|
* @param {string} key |
|
* @returns {Literal | TemplateLiteral | undefined} |
|
*/ |
|
function findPropertyValue(node, key) { |
|
const property = node.properties.find( |
|
(property) => |
|
property.type === 'Property' && |
|
property.key.type === 'Identifier' && |
|
property.key.name === key |
|
) |
|
if ( |
|
!property || |
|
property.type !== 'Property' || |
|
!utils.isStringLiteral(property.value) |
|
) { |
|
return undefined |
|
} |
|
return property.value |
|
} |
|
|
|
/** |
|
* @param {RuleFixer} fixer |
|
* @param {Literal | TemplateLiteral} 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', |
|
docs: { |
|
description: 'disallow deprecated `model` definition (in Vue.js 3.0.0+)', |
|
categories: undefined, |
|
url: 'https://eslint.vuejs.org/rules/no-deprecated-model-definition.html' |
|
}, |
|
fixable: null, |
|
hasSuggestions: true, |
|
schema: [ |
|
{ |
|
type: 'object', |
|
additionalProperties: false, |
|
properties: { |
|
allowVue3Compat: { |
|
type: 'boolean' |
|
} |
|
} |
|
} |
|
], |
|
messages: { |
|
deprecatedModel: '`model` definition is deprecated.', |
|
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 */ |
|
create(context) { |
|
const allowVue3Compat = Boolean(context.options[0]?.allowVue3Compat) |
|
|
|
return utils.executeOnVue(context, (obj) => { |
|
const modelProperty = utils.findProperty(obj, 'model') |
|
if (!modelProperty || modelProperty.value.type !== 'ObjectExpression') { |
|
return |
|
} |
|
|
|
if (!allowVue3Compat) { |
|
context.report({ |
|
node: modelProperty, |
|
messageId: 'deprecatedModel' |
|
}) |
|
return |
|
} |
|
|
|
const propName = findPropertyValue(modelProperty.value, 'prop') |
|
const eventName = findPropertyValue(modelProperty.value, 'event') |
|
|
|
if ( |
|
!propName || |
|
!eventName || |
|
!allowedPropNames.has( |
|
utils.getStringLiteralValue(propName, true) ?? '' |
|
) || |
|
!allowedEventNames.has( |
|
utils.getStringLiteralValue(eventName, true) ?? '' |
|
) |
|
) { |
|
context.report({ |
|
node: modelProperty, |
|
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) |
|
} |
|
} |
|
] |
|
: [] |
|
}) |
|
} |
|
}) |
|
} |
|
}
|
|
|