@@ -374,9 +374,28 @@ export function normalizeSourceFile(f: ts.SourceFile, fc: FacadeConverter) {
374
374
if ( base . ident ( member . name ) === 'prototype' ) {
375
375
break ;
376
376
}
377
- addModifier ( member , ts . createNode ( ts . SyntaxKind . StaticKeyword ) ) ;
378
- member . parent = existing ;
379
- Array . prototype . push . call ( members , member ) ;
377
+
378
+ // Finds all existing declarations of this property in the inheritance
379
+ // hierarchy of this class
380
+ const existingDeclarations =
381
+ findPropertyInHierarchy ( base . ident ( member . name ) , existing , classes ) ;
382
+
383
+ if ( existingDeclarations . size ) {
384
+ // TODO(derekx): For dom.d.ts it makes sense to make all properties that are
385
+ // declared on the anonymous types of top level variable declarations
386
+ // static, but this may not always be correct
387
+ for ( const existingDecl of existingDeclarations ) {
388
+ addModifier ( existingDecl , ts . createModifier ( ts . SyntaxKind . StaticKeyword ) ) ;
389
+ }
390
+ }
391
+
392
+ // If needed, add declaration of property to the interface that we are
393
+ // currently handling
394
+ if ( ! findPropertyInClass ( base . ident ( member . name ) , existing ) ) {
395
+ addModifier ( member , ts . createModifier ( ts . SyntaxKind . StaticKeyword ) ) ;
396
+ member . parent = existing ;
397
+ Array . prototype . push . call ( members , member ) ;
398
+ }
380
399
break ;
381
400
case ts . SyntaxKind . IndexSignature :
382
401
member . parent = existing . parent ;
@@ -402,6 +421,37 @@ export function normalizeSourceFile(f: ts.SourceFile, fc: FacadeConverter) {
402
421
}
403
422
}
404
423
424
+ function findPropertyInClass ( propName : string , classLike : base . ClassLike ) : ts . ClassElement |
425
+ undefined {
426
+ const members = classLike . members as ts . NodeArray < ts . ClassElement > ;
427
+ return members . find ( ( member : ts . ClassElement ) => {
428
+ if ( base . ident ( member . name ) === propName ) {
429
+ return true ;
430
+ }
431
+ } ) ;
432
+ }
433
+
434
+ function findPropertyInHierarchy (
435
+ propName : string , classLike : base . ClassLike ,
436
+ classes : Map < string , base . ClassLike > ) : Set < ts . ClassElement > {
437
+ const propertyDeclarations = new Set < ts . ClassElement > ( ) ;
438
+ const declaration = findPropertyInClass ( propName , classLike ) ;
439
+ if ( declaration ) propertyDeclarations . add ( declaration ) ;
440
+
441
+ const heritageClauses = classLike . heritageClauses || ts . createNodeArray ( ) ;
442
+ for ( const clause of heritageClauses ) {
443
+ if ( clause . token !== ts . SyntaxKind . ExtendsKeyword ) {
444
+ continue ;
445
+ }
446
+ const name = base . ident ( clause . types [ 0 ] . expression ) ;
447
+ const declarationsInAncestors = findPropertyInHierarchy ( propName , classes . get ( name ) , classes ) ;
448
+ if ( declarationsInAncestors . size ) {
449
+ declarationsInAncestors . forEach ( decl => propertyDeclarations . add ( decl ) ) ;
450
+ }
451
+ }
452
+ return propertyDeclarations ;
453
+ }
454
+
405
455
function removeFromArray ( nodes : ts . NodeArray < ts . Node > , v : ts . Node ) {
406
456
for ( let i = 0 , len = nodes . length ; i < len ; ++ i ) {
407
457
if ( nodes [ i ] === v ) {
0 commit comments