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.
		
		
		
		
			
				
					129 lines
				
				4.0 KiB
			
		
		
			
		
	
	
					129 lines
				
				4.0 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * @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
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |