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
96
97
98
99
/**
 * @fileoverview require prop type to be a constructor
 * @author Michał Sajnóg
 */
'use strict'
 
const utils = require('../utils')
const { isDef } = require('../utils')
 
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
 
const message = 'The "{{name}}" property should be a constructor.'
 
const forbiddenTypes = [
  'Literal',
  'TemplateLiteral',
  'BinaryExpression',
  'UpdateExpression'
]
 
/**
 * @param {ESNode} node
 */
function isForbiddenType(node) {
  return (
    forbiddenTypes.indexOf(node.type) > -1 &&
    !(node.type === 'Literal' && node.value == null && !node.bigint)
  )
}
 
module.exports = {
  meta: {
    type: 'suggestion',
    docs: {
      description: 'require prop type to be a constructor',
      categories: ['vue3-essential', 'essential'],
      url: 'https://eslint.vuejs.org/rules/require-prop-type-constructor.html'
    },
    fixable: 'code', // or "code" or "whitespace"
    schema: []
  },
 
  /** @param {RuleContext} context */
  create(context) {
    /**
     * @param {string} propName
     * @param {ESNode} node
     */
    function checkPropertyNode(propName, node) {
      /** @type {ESNode[]} */
      const nodes =
        node.type === 'ArrayExpression' ? node.elements.filter(isDef) : [node]
 
      nodes
        .filter((prop) => isForbiddenType(prop))
        .forEach((prop) =>
          context.report({
            node: prop,
            message,
            data: {
              name: propName
            },
            fix: (fixer) => {
              if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') {
                const newText = utils.getStringLiteralValue(prop, true)
 
                if (newText) {
                  return fixer.replaceText(prop, newText)
                }
              }
              return null
            }
          })
        )
    }
 
    return utils.executeOnVueComponent(context, (obj) => {
      for (const prop of utils.getComponentProps(obj)) {
        if (!prop.value || prop.propName == null) {
          continue
        }
        if (
          isForbiddenType(prop.value) ||
          prop.value.type === 'ArrayExpression'
        ) {
          checkPropertyNode(prop.propName, prop.value)
        } else if (prop.value.type === 'ObjectExpression') {
          const typeProperty = utils.findProperty(prop.value, 'type')
 
          if (!typeProperty) continue
 
          checkPropertyNode(prop.propName, typeProperty.value)
        }
      }
    })
  }
}