-
-
Notifications
You must be signed in to change notification settings - Fork 681
/
Copy pathrequire-prop-type-constructor.js
117 lines (103 loc) · 3.1 KB
/
require-prop-type-constructor.js
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
/**
* @fileoverview require prop type to be a constructor
* @author Michał Sajnóg
*/
'use strict'
const utils = require('../utils')
const { isDef } = require('../utils')
/**
* @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
*/
// ------------------------------------------------------------------------------
// 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
}
})
)
}
/** @param {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props */
function verifyProps(props) {
for (const prop of props) {
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)
}
}
}
return utils.compositingVisitors(
utils.defineScriptSetupVisitor(context, {
onDefinePropsEnter(_node, props) {
verifyProps(props)
}
}),
utils.executeOnVueComponent(context, (obj) => {
verifyProps(utils.getComponentProps(obj))
})
)
}
}