liusuyi
2023-04-24 4737f1e038743ced243c9e52423404d9034d6107
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
 * @author Yosuke Ota
 * See LICENSE file in root directory for full license.
 */
'use strict'
module.exports = {
  deprecated: '2.6.0',
  supported: '>=2.5.0 <3.0.0',
  /**
   * @param {RuleContext} context
   * @param {object} option
   * @param {boolean} [option.fixToUpgrade]
   * @returns {TemplateListener}
   */
  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.type === 'VIdentifier' &&
          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 {RuleFixer} fixer fixer
     * @param {VDirective} scopeAttr node of `slot-scope`
     * @returns {Fix} 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 {VDirective} scopeAttr node of `slot-scope`
     * @returns {void}
     */
    function reportSlotScope(scopeAttr) {
      context.report({
        node: scopeAttr.key,
        messageId: 'forbiddenSlotScopeAttribute',
        fix(fixer) {
          if (!fixToUpgrade) {
            return null
          }
          // fix to use `v-slot`
          const startTag = scopeAttr.parent
          if (!canConvertToVSlot(startTag)) {
            return null
          }
          return fixSlotScopeToVSlot(fixer, scopeAttr)
        }
      })
    }
 
    return {
      "VAttribute[directive=true][key.name.name='slot-scope']": reportSlotScope
    }
  }
}