55'use strict'
66
77/**
8+ * @typedef {import('../utils').ComponentArrayProp } ComponentArrayProp
89 * @typedef {import('../utils').ComponentObjectProp } ComponentObjectProp
10+ * @typedef {import('../utils').ComponentTypeProp } ComponentTypeProp
911 * @typedef {ComponentObjectProp & { value: ObjectExpression} } ComponentObjectPropObject
1012 */
1113
@@ -35,7 +37,10 @@ module.exports = {
3537 url : 'https://eslint.vuejs.org/rules/require-default-prop.html'
3638 } ,
3739 fixable : null , // or "code" or "whitespace"
38- schema : [ ]
40+ schema : [ ] ,
41+ messages : {
42+ missingDefault : `Prop '{{propName}}' requires default value to be set.`
43+ }
3944 } ,
4045 /** @param {RuleContext } context */
4146 create ( context ) {
@@ -45,11 +50,11 @@ module.exports = {
4550
4651 /**
4752 * 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
4954 * @return {boolean }
5055 */
51- function propIsRequired ( prop ) {
52- const propRequiredNode = prop . value . properties . find (
56+ function propIsRequired ( propValue ) {
57+ const propRequiredNode = propValue . properties . find (
5358 ( p ) =>
5459 p . type === 'Property' &&
5560 utils . getStaticPropertyName ( p ) === 'required' &&
@@ -62,11 +67,11 @@ module.exports = {
6267
6368 /**
6469 * 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
6671 * @return {boolean }
6772 */
68- function propHasDefault ( prop ) {
69- const propDefaultNode = prop . value . properties . find (
73+ function propHasDefault ( propValue ) {
74+ const propDefaultNode = propValue . properties . find (
7075 ( p ) =>
7176 p . type === 'Property' && utils . getStaticPropertyName ( p ) === 'default'
7277 )
@@ -75,32 +80,27 @@ module.exports = {
7580 }
7681
7782 /**
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 }
8186 */
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
9798 }
99+ // NG
100+ return true
101+ }
98102
99- return (
100- ! propIsRequired ( /** @type {ComponentObjectPropObject } */ ( prop ) ) &&
101- ! propHasDefault ( /** @type {ComponentObjectPropObject } */ ( prop ) )
102- )
103- } )
103+ return ! propIsRequired ( prop . value ) && ! propHasDefault ( prop . value )
104104 }
105105
106106 /**
@@ -145,46 +145,66 @@ module.exports = {
145145 }
146146
147147 /**
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]
151151 */
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+ }
154189 }
155190
156191 // ----------------------------------------------------------------------
157192 // Public
158193 // ----------------------------------------------------------------------
159194
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+ )
189209 }
190210}
0 commit comments