@@ -384,12 +384,14 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
384
384
// valid overlaps, with some parameters that can also be represented as body properties.
385
385
// Client generators will have to take care of this.
386
386
387
+ const inheritedProps = inheritedProperties ( typeDef )
388
+
387
389
context . push ( 'path' )
388
- validateProperties ( typeDef . path , openGenerics )
390
+ validateProperties ( typeDef . path , openGenerics , inheritedProps )
389
391
context . pop ( )
390
392
391
393
context . push ( 'query' )
392
- validateProperties ( typeDef . query , openGenerics )
394
+ validateProperties ( typeDef . query , openGenerics , inheritedProps )
393
395
context . pop ( )
394
396
395
397
context . push ( 'body' )
@@ -400,7 +402,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
400
402
}
401
403
switch ( typeDef . body . kind ) {
402
404
case 'properties' :
403
- validateProperties ( typeDef . body . properties , openGenerics )
405
+ validateProperties ( typeDef . body . properties , openGenerics , inheritedProps )
404
406
break
405
407
case 'value' :
406
408
validateValueOf ( typeDef . body . value , openGenerics )
@@ -435,7 +437,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
435
437
}
436
438
switch ( typeDef . body . kind ) {
437
439
case 'properties' :
438
- validateProperties ( typeDef . body . properties , openGenerics )
440
+ validateProperties ( typeDef . body . properties , openGenerics , inheritedProperties ( typeDef ) )
439
441
break
440
442
case 'value' :
441
443
validateValueOf ( typeDef . body . value , openGenerics )
@@ -451,13 +453,65 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
451
453
context . pop ( )
452
454
}
453
455
456
+ /** Collects the name of inherited properties. Names are normalized to lower case (see also validateProperties) */
457
+ function inheritedProperties ( typeDef : model . Interface | model . Request | model . Response , accum ?: Set < string > ) : Set < string > {
458
+ const result = accum ?? new Set < string > ( )
459
+
460
+ function addProperties ( props : model . Property [ ] ) : void {
461
+ props . forEach ( prop => result . add ( ( prop . identifier ?? prop . name ) . toLowerCase ( ) ) )
462
+ }
463
+
464
+ function addInherits ( inherits ?: model . Inherits ) : void {
465
+ if ( inherits == null ) {
466
+ return
467
+ }
468
+
469
+ const typeDef = getTypeDef ( inherits . type )
470
+ if ( typeDef == null ) {
471
+ modelError ( `No type definition for parent '${ fqn ( inherits . type ) } '` )
472
+ return
473
+ }
474
+
475
+ switch ( typeDef ?. kind ) {
476
+ case 'request' :
477
+ inheritedProperties ( typeDef , result )
478
+ addProperties ( typeDef . path )
479
+ addProperties ( typeDef . query )
480
+ if ( typeDef . body . kind === 'properties' ) {
481
+ addProperties ( typeDef . body . properties )
482
+ }
483
+ break
484
+
485
+ case 'response' :
486
+ inheritedProperties ( typeDef , result )
487
+ if ( typeDef . body . kind === 'properties' ) {
488
+ addProperties ( typeDef . body . properties )
489
+ }
490
+ break
491
+
492
+ case 'interface' :
493
+ inheritedProperties ( typeDef , result )
494
+ addProperties ( typeDef . properties )
495
+ break
496
+ }
497
+ }
498
+
499
+ if ( typeDef . inherits != null ) {
500
+ addInherits ( typeDef . inherits )
501
+ }
502
+ typeDef . implements ?. forEach ( addInherits )
503
+ typeDef . behaviors ?. forEach ( addInherits )
504
+
505
+ return result
506
+ }
507
+
454
508
function validateInterface ( typeDef : model . Interface ) : void {
455
509
const openGenerics = openGenericSet ( typeDef )
456
510
457
511
validateImplements ( typeDef . implements , openGenerics )
458
512
validateInherits ( typeDef . inherits , openGenerics )
459
513
validateBehaviors ( typeDef , openGenerics )
460
- validateProperties ( typeDef . properties , openGenerics )
514
+ validateProperties ( typeDef . properties , openGenerics , inheritedProperties ( typeDef ) )
461
515
462
516
if ( typeDef . variants ?. kind === 'container' ) {
463
517
const variants = typeDef . properties . filter ( prop => ! ( prop . containerProperty ?? false ) )
@@ -639,7 +693,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
639
693
return false
640
694
}
641
695
642
- function validateProperties ( props : model . Property [ ] , openGenerics : Set < string > ) : void {
696
+ function validateProperties ( props : model . Property [ ] , openGenerics : Set < string > , inheritedProperties : Set < string > ) : void {
643
697
const allIdentifiers = new Set < string > ( )
644
698
const allNames = new Set < string > ( )
645
699
@@ -651,6 +705,10 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
651
705
}
652
706
allIdentifiers . add ( identifier )
653
707
708
+ if ( inheritedProperties . has ( identifier ) ) {
709
+ modelError ( `Property '${ prop . name } ' is already defined in an ancestor class` )
710
+ }
711
+
654
712
// Names and aliases must be unique among all items (case sensitive)
655
713
const names = [ prop . name ] . concat ( prop . aliases ?? [ ] )
656
714
for ( const name of names ) {
0 commit comments