@@ -230,7 +230,7 @@ module.exports = {
230
230
}
231
231
232
232
/**
233
- * @param {* } node
233
+ * @param {Expression } node
234
234
* @param {ComponentObjectProp | ComponentTypeProp | ComponentInferTypeProp } prop
235
235
* @param {Iterable<string> } expectedTypeNames
236
236
*/
@@ -249,17 +249,22 @@ module.exports = {
249
249
} )
250
250
}
251
251
252
+ /**
253
+ * @typedef {object } DefaultDefine
254
+ * @property {Expression } expression
255
+ * @property {'assignment'|'withDefaults'|'defaultProperty' } src
256
+ */
252
257
/**
253
258
* @param {(ComponentObjectProp | ComponentTypeProp | ComponentInferTypeProp)[] } props
254
- * @param {(propName: string) => Expression[] } otherDefaultProvider
259
+ * @param {(propName: string) => Iterable<DefaultDefine> } otherDefaultProvider
255
260
*/
256
261
function processPropDefs ( props , otherDefaultProvider ) {
257
262
/** @type {PropDefaultFunctionContext[] } */
258
263
const propContexts = [ ]
259
264
for ( const prop of props ) {
260
265
let typeList
261
- /** @type {Expression [] } */
262
- const defExprList = [ ]
266
+ /** @type {DefaultDefine [] } */
267
+ const defaultList = [ ]
263
268
if ( prop . type === 'object' ) {
264
269
if ( prop . value . type === 'ObjectExpression' ) {
265
270
const type = getPropertyNode ( prop . value , 'type' )
@@ -268,36 +273,44 @@ module.exports = {
268
273
typeList = getTypes ( type . value )
269
274
270
275
const def = getPropertyNode ( prop . value , 'default' )
271
- if ( ! def ) continue
272
-
273
- defExprList . push ( def . value )
276
+ if ( def ) {
277
+ defaultList . push ( {
278
+ src : 'defaultProperty' ,
279
+ expression : def . value
280
+ } )
281
+ }
274
282
} else {
275
283
typeList = getTypes ( prop . value )
276
284
}
277
285
} else {
278
286
typeList = prop . types
279
287
}
280
288
if ( prop . propName != null ) {
281
- defExprList . push ( ...otherDefaultProvider ( prop . propName ) )
289
+ defaultList . push ( ...otherDefaultProvider ( prop . propName ) )
282
290
}
283
291
284
- if ( defExprList . length === 0 ) continue
292
+ if ( defaultList . length === 0 ) continue
285
293
286
294
const typeNames = new Set (
287
295
typeList . filter ( ( item ) => NATIVE_TYPES . has ( item ) )
288
296
)
289
297
// There is no native types detected
290
298
if ( typeNames . size === 0 ) continue
291
299
292
- for ( const defExpr of defExprList ) {
293
- const defType = getValueType ( defExpr )
300
+ for ( const defaultDef of defaultList ) {
301
+ const defType = getValueType ( defaultDef . expression )
294
302
295
303
if ( ! defType ) continue
296
304
297
305
if ( defType . function ) {
298
306
if ( typeNames . has ( 'Function' ) ) {
299
307
continue
300
308
}
309
+ if ( defaultDef . src === 'assignment' ) {
310
+ // Factory functions cannot be used in default definitions with initial value assignments.
311
+ report ( defaultDef . expression , prop , typeNames )
312
+ continue
313
+ }
301
314
if ( defType . expression ) {
302
315
if ( ! defType . returnType || typeNames . has ( defType . returnType ) ) {
303
316
continue
@@ -311,18 +324,23 @@ module.exports = {
311
324
} )
312
325
}
313
326
} else {
314
- if (
315
- typeNames . has ( defType . type ) &&
316
- ! FUNCTION_VALUE_TYPES . has ( defType . type )
317
- ) {
318
- continue
327
+ if ( typeNames . has ( defType . type ) ) {
328
+ if ( defaultDef . src === 'assignment' ) {
329
+ continue
330
+ }
331
+ if ( ! FUNCTION_VALUE_TYPES . has ( defType . type ) ) {
332
+ // For Array and Object, defaults must be defined in the factory function.
333
+ continue
334
+ }
319
335
}
320
336
report (
321
- defExpr ,
337
+ defaultDef . expression ,
322
338
prop ,
323
- [ ...typeNames ] . map ( ( type ) =>
324
- FUNCTION_VALUE_TYPES . has ( type ) ? 'Function' : type
325
- )
339
+ defaultDef . src === 'assignment'
340
+ ? typeNames
341
+ : [ ...typeNames ] . map ( ( type ) =>
342
+ FUNCTION_VALUE_TYPES . has ( type ) ? 'Function' : type
343
+ )
326
344
)
327
345
}
328
346
}
@@ -425,12 +443,19 @@ module.exports = {
425
443
utils . getWithDefaultsPropExpressions ( node )
426
444
const defaultsByAssignmentPatterns =
427
445
utils . getDefaultPropExpressionsForPropsDestructure ( node )
428
- const propContexts = processPropDefs ( props , ( propName ) =>
429
- [
430
- defaultsByWithDefaults [ propName ] ,
431
- defaultsByAssignmentPatterns [ propName ] ?. expression
432
- ] . filter ( utils . isDef )
433
- )
446
+ const propContexts = processPropDefs ( props , function * ( propName ) {
447
+ const withDefaults = defaultsByWithDefaults [ propName ]
448
+ if ( withDefaults ) {
449
+ yield { src : 'withDefaults' , expression : withDefaults }
450
+ }
451
+ const assignmentPattern = defaultsByAssignmentPatterns [ propName ]
452
+ if ( assignmentPattern ) {
453
+ yield {
454
+ src : 'assignment' ,
455
+ expression : assignmentPattern . expression
456
+ }
457
+ }
458
+ } )
434
459
scriptSetupPropsContexts . push ( { node, props : propContexts } )
435
460
} ,
436
461
/**
@@ -450,7 +475,21 @@ module.exports = {
450
475
}
451
476
} ,
452
477
onDefinePropsExit ( ) {
453
- scriptSetupPropsContexts . pop ( )
478
+ const data = scriptSetupPropsContexts . pop ( )
479
+ if ( ! data ) {
480
+ return
481
+ }
482
+ for ( const {
483
+ prop,
484
+ types : typeNames ,
485
+ default : defType
486
+ } of data . props ) {
487
+ for ( const returnType of defType . returnTypes ) {
488
+ if ( typeNames . has ( returnType . type ) ) continue
489
+
490
+ report ( returnType . node , prop , typeNames )
491
+ }
492
+ }
454
493
}
455
494
} )
456
495
)
0 commit comments