vue hello world项目
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.
 
 
 

141 lines
4.4 KiB

/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
const canConvertToVSlot = require('./utils/can-convert-to-v-slot')
module.exports = {
deprecated: '2.6.0',
supported: '<3.0.0',
/** @param {RuleContext} context @returns {TemplateListener} */
createTemplateBodyVisitor(context) {
const sourceCode = context.getSourceCode()
const tokenStore =
context.parserServices.getTemplateBodyTokenStore &&
context.parserServices.getTemplateBodyTokenStore()
/**
* 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 (!canConvertToVSlot(slotAttr.parent.parent, sourceCode, tokenStore)) {
return false
}
if (!slotAttr.value) {
return true
}
const slotName = slotAttr.value.value
// If other than alphanumeric, underscore and hyphen characters are included it can not be converted.
return !/[^\w\-]/u.test(slotName)
}
/**
* Checks whether the given node can convert to the `v-slot`.
* @param {VDirective} slotAttr node of `v-bind:slot`
* @returns {boolean} `true` if the given node can convert to the `v-slot`
*/
function canConvertFromVBindSlotToVSlot(slotAttr) {
if (!canConvertToVSlot(slotAttr.parent.parent, sourceCode, tokenStore)) {
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 {RuleFixer} fixer fixer
* @param {VAttribute|VDirective} slotAttr node of `slot`
* @param {string | null} slotName name of `slot`
* @param {boolean} vBind `true` if `slotAttr` is `v-bind:slot`
* @returns {IterableIterator<Fix>} 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}`
yield fixer.replaceText(slotAttr || scopeAttr, replaceText)
if (slotAttr && scopeAttr) {
yield fixer.remove(scopeAttr)
}
}
/**
* 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
}
const slotName = slotAttr.value && slotAttr.value.value
yield* fixSlotToVSlot(fixer, slotAttr, slotName, false)
}
})
}
/**
* Reports `v-bind:slot` node
* @param {VDirective} 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
}
const slotName =
slotAttr.value &&
slotAttr.value.expression &&
sourceCode.getText(slotAttr.value.expression).trim()
yield* 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
}
}
}