5
5
'use strict'
6
6
7
7
/**
8
+ * @typedef {import('../utils').ComponentArrayProp } ComponentArrayProp
8
9
* @typedef {import('../utils').ComponentObjectProp } ComponentObjectProp
10
+ * @typedef {import('../utils').ComponentTypeProp } ComponentTypeProp
9
11
* @typedef {ComponentObjectProp & { value: ObjectExpression} } ComponentObjectPropObject
10
12
*/
11
13
@@ -35,7 +37,10 @@ module.exports = {
35
37
url : 'https://eslint.vuejs.org/rules/require-default-prop.html'
36
38
} ,
37
39
fixable : null , // or "code" or "whitespace"
38
- schema : [ ]
40
+ schema : [ ] ,
41
+ messages : {
42
+ missingDefault : `Prop '{{propName}}' requires default value to be set.`
43
+ }
39
44
} ,
40
45
/** @param {RuleContext } context */
41
46
create ( context ) {
@@ -45,11 +50,11 @@ module.exports = {
45
50
46
51
/**
47
52
* Checks if the passed prop is required
48
- * @param {ComponentObjectPropObject } prop - Property AST node for a single prop
53
+ * @param {ObjectExpression } propValue - ObjectExpression AST node for a single prop
49
54
* @return {boolean }
50
55
*/
51
- function propIsRequired ( prop ) {
52
- const propRequiredNode = prop . value . properties . find (
56
+ function propIsRequired ( propValue ) {
57
+ const propRequiredNode = propValue . properties . find (
53
58
( p ) =>
54
59
p . type === 'Property' &&
55
60
utils . getStaticPropertyName ( p ) === 'required' &&
@@ -62,11 +67,11 @@ module.exports = {
62
67
63
68
/**
64
69
* Checks if the passed prop has a default value
65
- * @param {ComponentObjectPropObject } prop - Property AST node for a single prop
70
+ * @param {ObjectExpression } propValue - ObjectExpression AST node for a single prop
66
71
* @return {boolean }
67
72
*/
68
- function propHasDefault ( prop ) {
69
- const propDefaultNode = prop . value . properties . find (
73
+ function propHasDefault ( propValue ) {
74
+ const propDefaultNode = propValue . properties . find (
70
75
( p ) =>
71
76
p . type === 'Property' && utils . getStaticPropertyName ( p ) === 'default'
72
77
)
@@ -75,32 +80,27 @@ module.exports = {
75
80
}
76
81
77
82
/**
78
- * Finds all props that don't have a default value set
79
- * @param {ComponentObjectProp[] } props - Vue component's "props" node
80
- * @return {ComponentObjectProp[] } Array of props without "default" value
83
+ * Checks whether the given props that don't have a default value
84
+ * @param {ComponentObjectProp } prop Vue component's "props" node
85
+ * @return {boolean }
81
86
*/
82
- function findPropsWithoutDefaultValue ( props ) {
83
- return props . filter ( ( prop ) => {
84
- if ( prop . value . type !== 'ObjectExpression' ) {
85
- if ( prop . value . type === 'Identifier' ) {
86
- return NATIVE_TYPES . has ( prop . value . name )
87
- }
88
- if (
89
- prop . value . type === 'CallExpression' ||
90
- prop . value . type === 'MemberExpression'
91
- ) {
92
- // OK
93
- return false
94
- }
95
- // NG
96
- return true
87
+ function isWithoutDefaultValue ( prop ) {
88
+ if ( prop . value . type !== 'ObjectExpression' ) {
89
+ if ( prop . value . type === 'Identifier' ) {
90
+ return NATIVE_TYPES . has ( prop . value . name )
91
+ }
92
+ if (
93
+ prop . value . type === 'CallExpression' ||
94
+ prop . value . type === 'MemberExpression'
95
+ ) {
96
+ // OK
97
+ return false
97
98
}
99
+ // NG
100
+ return true
101
+ }
98
102
99
- return (
100
- ! propIsRequired ( /** @type {ComponentObjectPropObject } */ ( prop ) ) &&
101
- ! propHasDefault ( /** @type {ComponentObjectPropObject } */ ( prop ) )
102
- )
103
- } )
103
+ return ! propIsRequired ( prop . value ) && ! propHasDefault ( prop . value )
104
104
}
105
105
106
106
/**
@@ -145,46 +145,66 @@ module.exports = {
145
145
}
146
146
147
147
/**
148
- * Excludes purely Boolean props from the Array
149
- * @param {ComponentObjectProp[] } props - Array with props
150
- * @return { ComponentObjectProp[] }
148
+ * @param { (ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[] } props
149
+ * @param {boolean } [withDefaults]
150
+ * @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions]
151
151
*/
152
- function excludeBooleanProps ( props ) {
153
- return props . filter ( ( prop ) => ! isBooleanProp ( prop ) )
152
+ function processProps ( props , withDefaults , withDefaultsExpressions ) {
153
+ for ( const prop of props ) {
154
+ if ( prop . type === 'object' && ! prop . node . shorthand ) {
155
+ if ( ! isWithoutDefaultValue ( prop ) ) {
156
+ continue
157
+ }
158
+ if ( isBooleanProp ( prop ) ) {
159
+ continue
160
+ }
161
+ const propName =
162
+ prop . propName != null
163
+ ? prop . propName
164
+ : `[${ context . getSourceCode ( ) . getText ( prop . node . key ) } ]`
165
+
166
+ context . report ( {
167
+ node : prop . node ,
168
+ messageId : `missingDefault` ,
169
+ data : {
170
+ propName
171
+ }
172
+ } )
173
+ } else if (
174
+ prop . type === 'type' &&
175
+ withDefaults &&
176
+ withDefaultsExpressions
177
+ ) {
178
+ if ( ! withDefaultsExpressions [ prop . propName ] ) {
179
+ context . report ( {
180
+ node : prop . node ,
181
+ messageId : `missingDefault` ,
182
+ data : {
183
+ propName : prop . propName
184
+ }
185
+ } )
186
+ }
187
+ }
188
+ }
154
189
}
155
190
156
191
// ----------------------------------------------------------------------
157
192
// Public
158
193
// ----------------------------------------------------------------------
159
194
160
- return utils . executeOnVue ( context , ( obj ) => {
161
- const props = utils
162
- . getComponentProps ( obj )
163
- . filter (
164
- ( prop ) =>
165
- prop . value &&
166
- ! ( prop . node . type === 'Property' && prop . node . shorthand )
167
- )
168
-
169
- const propsWithoutDefault = findPropsWithoutDefaultValue (
170
- /** @type {ComponentObjectProp[] } */ ( props )
171
- )
172
- const propsToReport = excludeBooleanProps ( propsWithoutDefault )
173
-
174
- for ( const prop of propsToReport ) {
175
- const propName =
176
- prop . propName != null
177
- ? prop . propName
178
- : `[${ context . getSourceCode ( ) . getText ( prop . node . key ) } ]`
179
-
180
- context . report ( {
181
- node : prop . node ,
182
- message : `Prop '{{propName}}' requires default value to be set.` ,
183
- data : {
184
- propName
185
- }
186
- } )
187
- }
188
- } )
195
+ return utils . compositingVisitors (
196
+ utils . defineScriptSetupVisitor ( context , {
197
+ onDefinePropsEnter ( node , props ) {
198
+ processProps (
199
+ props ,
200
+ utils . hasWithDefaults ( node ) ,
201
+ utils . getWithDefaultsPropExpressions ( node )
202
+ )
203
+ }
204
+ } ) ,
205
+ utils . executeOnVue ( context , ( obj ) => {
206
+ processProps ( utils . getComponentProps ( obj ) )
207
+ } )
208
+ )
189
209
}
190
210
}
0 commit comments