‘liusuyi’
2023-10-21 94023628bd9c5e6bf724c37371a19b60d338b291
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
 * @author Yosuke Ota
 * See LICENSE file in root directory for full license.
 */
'use strict'
module.exports = {
  deprecated: '2.6.0',
  supported: '<3.0.0',
  /** @param {RuleContext} context @returns {TemplateListener} */
  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 {VDirective} 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 {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
    }
  }
}