first commit

This commit is contained in:
jefferyzhao
2025-07-31 17:44:12 +08:00
commit b9bdc8598b
42390 changed files with 4467935 additions and 0 deletions

View File

@ -0,0 +1,25 @@
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
module.exports = {
supported: '2.6.0',
createTemplateBodyVisitor (context) {
/**
* Reports dynamic argument node
* @param {VExpressionContainer} dinamicArgument node of dynamic argument
* @returns {void}
*/
function reportDynamicArgument (dinamicArgument) {
context.report({
node: dinamicArgument,
messageId: 'forbiddenDynamicDirectiveArguments'
})
}
return {
'VAttribute[directive=true] > VDirectiveKey > VExpressionContainer': reportDynamicArgument
}
}
}

View File

@ -0,0 +1,27 @@
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
module.exports = {
deprecated: '2.5.0',
createTemplateBodyVisitor (context) {
/**
* Reports `scope` node
* @param {VDirectiveKey} scopeKey node of `scope`
* @returns {void}
*/
function reportScope (scopeKey) {
context.report({
node: scopeKey,
messageId: 'forbiddenScopeAttribute',
// fix to use `slot-scope`
fix: fixer => fixer.replaceText(scopeKey, 'slot-scope')
})
}
return {
"VAttribute[directive=true] > VDirectiveKey[name.name='scope']": reportScope
}
}
}

View File

@ -0,0 +1,128 @@
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
module.exports = {
deprecated: '2.6.0',
createTemplateBodyVisitor (context) {
const sourceCode = context.getSourceCode()
/**
* Checks whether the given node can convert to the `v-slot`.
* @param {VAttribute} slotAttr node of `slot`
* @returns {boolean} `true` if the given node can convert to the `v-slot`
*/
function canConvertFromSlotToVSlot (slotAttr) {
if (slotAttr.parent.parent.name !== 'template') {
return false
}
if (!slotAttr.value) {
return true
}
const slotName = slotAttr.value.value
// If non-Latin characters are included it can not be converted.
return !/[^a-z]/i.test(slotName)
}
/**
* Checks whether the given node can convert to the `v-slot`.
* @param {VAttribute} slotAttr node of `v-bind:slot`
* @returns {boolean} `true` if the given node can convert to the `v-slot`
*/
function canConvertFromVBindSlotToVSlot (slotAttr) {
if (slotAttr.parent.parent.name !== 'template') {
return false
}
if (!slotAttr.value) {
return true
}
if (!slotAttr.value.expression) {
// parse error or empty expression
return false
}
const slotName = sourceCode.getText(slotAttr.value.expression).trim()
// If non-Latin characters are included it can not be converted.
// It does not check the space only because `a>b?c:d` should be rejected.
return !/[^a-z]/i.test(slotName)
}
/**
* Convert to `v-slot`.
* @param {object} fixer fixer
* @param {VAttribute} slotAttr node of `slot`
* @param {string | null} slotName name of `slot`
* @param {boolean} vBind `true` if `slotAttr` is `v-bind:slot`
* @returns {*} fix data
*/
function fixSlotToVSlot (fixer, slotAttr, slotName, vBind) {
const element = slotAttr.parent
const scopeAttr = element.attributes
.find(attr => attr.directive === true && attr.key.name && (
attr.key.name.name === 'slot-scope' ||
attr.key.name.name === 'scope'
))
const nameArgument = slotName ? (vBind ? `:[${slotName}]` : `:${slotName}`) : ''
const scopeValue = scopeAttr && scopeAttr.value
? `=${sourceCode.getText(scopeAttr.value)}`
: ''
const replaceText = `v-slot${nameArgument}${scopeValue}`
const fixers = [
fixer.replaceText(slotAttr || scopeAttr, replaceText)
]
if (slotAttr && scopeAttr) {
fixers.push(fixer.remove(scopeAttr))
}
return fixers
}
/**
* Reports `slot` node
* @param {VAttribute} slotAttr node of `slot`
* @returns {void}
*/
function reportSlot (slotAttr) {
context.report({
node: slotAttr.key,
messageId: 'forbiddenSlotAttribute',
// fix to use `v-slot`
fix (fixer) {
if (!canConvertFromSlotToVSlot(slotAttr)) {
return null
}
const slotName = slotAttr.value &&
slotAttr.value.value
return fixSlotToVSlot(fixer, slotAttr, slotName, false)
}
})
}
/**
* Reports `v-bind:slot` node
* @param {VAttribute} slotAttr node of `v-bind:slot`
* @returns {void}
*/
function reportVBindSlot (slotAttr) {
context.report({
node: slotAttr.key,
messageId: 'forbiddenSlotAttribute',
// fix to use `v-slot`
fix (fixer) {
if (!canConvertFromVBindSlotToVSlot(slotAttr)) {
return null
}
const slotName = slotAttr.value &&
slotAttr.value.expression &&
sourceCode.getText(slotAttr.value.expression).trim()
return fixSlotToVSlot(fixer, slotAttr, slotName, true)
}
})
}
return {
"VAttribute[directive=false][key.name='slot']": reportSlot,
"VAttribute[directive=true][key.name.name='bind'][key.argument.name='slot']": reportVBindSlot
}
}
}

View File

@ -0,0 +1,84 @@
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
module.exports = {
deprecated: '2.6.0',
supported: '2.5.0',
createTemplateBodyVisitor (context, { fixToUpgrade } = {}) {
const sourceCode = context.getSourceCode()
/**
* Checks whether the given node can convert to the `v-slot`.
* @param {VStartTag} startTag node of `<element v-slot ... >`
* @returns {boolean} `true` if the given node can convert to the `v-slot`
*/
function canConvertToVSlot (startTag) {
if (startTag.parent.name !== 'template') {
return false
}
const slotAttr = startTag.attributes
.find(attr => attr.directive === false && attr.key.name === 'slot')
if (slotAttr) {
// if the element have `slot` it can not be converted.
// Conversion of `slot` is done with `vue/no-deprecated-slot-attribute`.
return false
}
const vBindSlotAttr = startTag.attributes
.find(attr =>
attr.directive === true &&
attr.key.name.name === 'bind' &&
attr.key.argument &&
attr.key.argument.name === 'slot')
if (vBindSlotAttr) {
// if the element have `v-bind:slot` it can not be converted.
// Conversion of `v-bind:slot` is done with `vue/no-deprecated-slot-attribute`.
return false
}
return true
}
/**
* Convert to `v-slot`.
* @param {object} fixer fixer
* @param {VAttribute | null} scopeAttr node of `slot-scope`
* @returns {*} fix data
*/
function fixSlotScopeToVSlot (fixer, scopeAttr) {
const scopeValue = scopeAttr && scopeAttr.value
? `=${sourceCode.getText(scopeAttr.value)}`
: ''
const replaceText = `v-slot${scopeValue}`
return fixer.replaceText(scopeAttr, replaceText)
}
/**
* Reports `slot-scope` node
* @param {VAttribute} scopeAttr node of `slot-scope`
* @returns {void}
*/
function reportSlotScope (scopeAttr) {
context.report({
node: scopeAttr.key,
messageId: 'forbiddenSlotScopeAttribute',
fix: fixToUpgrade
// fix to use `v-slot`
? (fixer) => {
const startTag = scopeAttr.parent
if (!canConvertToVSlot(startTag)) {
return null
}
return fixSlotScopeToVSlot(fixer, scopeAttr)
}
: null
})
}
return {
"VAttribute[directive=true][key.name.name='slot-scope']": reportSlotScope
}
}
}

View File

@ -0,0 +1,33 @@
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
const { Range } = require('semver')
const unsupported = new Range('<=2.5 || >=2.6.0')
module.exports = {
// >=2.6.0-beta.1 <=2.6.0-beta.3
supported: (versionRange) => {
return !versionRange.intersects(unsupported)
},
createTemplateBodyVisitor (context) {
/**
* Reports `.prop` shorthand node
* @param {VDirectiveKey} bindPropKey node of `.prop` shorthand
* @returns {void}
*/
function reportPropModifierShorthand (bindPropKey) {
context.report({
node: bindPropKey,
messageId: 'forbiddenVBindPropModifierShorthand',
// fix to use `:x.prop` (downgrade)
fix: fixer => fixer.replaceText(bindPropKey, `:${bindPropKey.argument.rawName}.prop`)
})
}
return {
"VAttribute[directive=true] > VDirectiveKey[name.name='bind'][name.rawName='.']": reportPropModifierShorthand
}
}
}

View File

@ -0,0 +1,83 @@
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
module.exports = {
supported: '2.6.0',
createTemplateBodyVisitor (context) {
const sourceCode = context.getSourceCode()
/**
* Checks whether the given node can convert to the `slot`.
* @param {VAttribute} vSlotAttr node of `v-slot`
* @returns {boolean} `true` if the given node can convert to the `slot`
*/
function canConvertToSlot (vSlotAttr) {
if (vSlotAttr.parent.parent.name !== 'template') {
return false
}
return true
}
/**
* Convert to `slot` and `slot-scope`.
* @param {object} fixer fixer
* @param {VAttribute} vSlotAttr node of `v-slot`
* @returns {*} fix data
*/
function fixVSlotToSlot (fixer, vSlotAttr) {
const key = vSlotAttr.key
if (key.modifiers.length) {
// unknown modifiers
return null
}
const attrs = []
const argument = key.argument
if (argument) {
if (argument.type === 'VIdentifier') {
const name = argument.rawName
attrs.push(`slot="${name}"`)
} else if (argument.type === 'VExpressionContainer' && argument.expression) {
const expression = sourceCode.getText(argument.expression)
attrs.push(`:slot="${expression}"`)
} else {
// unknown or syntax error
return null
}
}
const scopedValueNode = vSlotAttr.value
if (scopedValueNode) {
attrs.push(
`slot-scope=${sourceCode.getText(scopedValueNode)}`
)
}
if (!attrs.length) {
attrs.push('slot') // useless
}
return fixer.replaceText(vSlotAttr, attrs.join(' '))
}
/**
* Reports `v-slot` node
* @param {VAttribute} vSlotAttr node of `v-slot`
* @returns {void}
*/
function reportVSlot (vSlotAttr) {
context.report({
node: vSlotAttr.key,
messageId: 'forbiddenVSlot',
// fix to use `slot` (downgrade)
fix: fixer => {
if (!canConvertToSlot(vSlotAttr)) {
return null
}
return fixVSlotToSlot(fixer, vSlotAttr)
}
})
}
return {
"VAttribute[directive=true][key.name.name='slot']": reportVSlot
}
}
}