@@ -110,8 +110,10 @@ export class ImplementsPlugin extends ConverterComponent {
110
110
project : ProjectReflection ,
111
111
reflection : DeclarationReflection ,
112
112
) {
113
+ if ( ! reflection . extendedTypes ) return ;
114
+
113
115
const extendedTypes = filterMap (
114
- reflection . extendedTypes ?? [ ] ,
116
+ reflection . extendedTypes ,
115
117
( type ) => {
116
118
return type instanceof ReferenceType &&
117
119
type . reflection instanceof DeclarationReflection
@@ -139,23 +141,54 @@ export class ImplementsPlugin extends ConverterComponent {
139
141
parentMember . signatures ?? [ ] ,
140
142
)
141
143
) {
142
- childSig [ key ] = ReferenceType . createResolvedReference (
144
+ // If we're already pointing at something because TS said we should reference
145
+ // it, then don't overwrite the reference.
146
+ if ( ! childSig [ key ] ?. reflection ) {
147
+ childSig [ key ] = ReferenceType . createResolvedReference (
148
+ `${ parent . name } .${ parentMember . name } ` ,
149
+ parentSig ,
150
+ project ,
151
+ ) ;
152
+ }
153
+ }
154
+
155
+ if ( ! child [ key ] ?. reflection ) {
156
+ child [ key ] = ReferenceType . createResolvedReference (
143
157
`${ parent . name } .${ parentMember . name } ` ,
144
- parentSig ,
158
+ parentMember ,
145
159
project ,
146
160
) ;
147
161
}
148
162
149
- child [ key ] = ReferenceType . createResolvedReference (
150
- `${ parent . name } .${ parentMember . name } ` ,
151
- parentMember ,
152
- project ,
153
- ) ;
154
-
155
163
this . handleInheritedComments ( child , parentMember ) ;
156
164
}
157
165
}
158
166
}
167
+
168
+ // #2978, this is very unfortunate. If a child's parent links are broken at this point,
169
+ // we replace them with an intentionally broken link so that they won't ever be resolved.
170
+ // This is done because if we don't do it then we run into issues where we have a link which
171
+ // points to some ReflectionSymbolId which might not exist now, but once we've gone through
172
+ // serialization/deserialization, might point to an unexpected location. (See the mixin
173
+ // converter tests, I suspect this might actually be an indication of something else slightly
174
+ // broken there, but don't want to spend more time with this right now.)
175
+ for ( const child of reflection . children || [ ] ) {
176
+ if ( child . inheritedFrom && ! child . inheritedFrom . reflection ) {
177
+ child . inheritedFrom = ReferenceType . createBrokenReference ( child . inheritedFrom . name , project ) ;
178
+ }
179
+ if ( child . overwrites && ! child . overwrites . reflection ) {
180
+ child . overwrites = ReferenceType . createBrokenReference ( child . overwrites . name , project ) ;
181
+ }
182
+
183
+ for ( const childSig of child . getAllSignatures ( ) ) {
184
+ if ( childSig . inheritedFrom && ! childSig . inheritedFrom . reflection ) {
185
+ childSig . inheritedFrom = ReferenceType . createBrokenReference ( childSig . inheritedFrom . name , project ) ;
186
+ }
187
+ if ( childSig . overwrites && ! childSig . overwrites . reflection ) {
188
+ childSig . overwrites = ReferenceType . createBrokenReference ( childSig . overwrites . name , project ) ;
189
+ }
190
+ }
191
+ }
159
192
}
160
193
161
194
private onResolveEnd ( context : Context ) {
@@ -522,9 +555,21 @@ function createLink(
522
555
symbol : ts . Symbol ,
523
556
isInherit : boolean ,
524
557
) {
525
- const project = context . project ;
526
558
const name = `${ expr . expression . getText ( ) } .${ getHumanName ( symbol . name ) } ` ;
527
559
560
+ // We should always have rootSymbols, but check just in case. We use the first
561
+ // symbol here as TypeDoc's models don't have multiple symbols for the parent
562
+ // reference. This is technically wrong because symbols might be declared in
563
+ // multiple locations (interface declaration merging), but that's an uncommon
564
+ // enough use case that it doesn't seem worthwhile to complicate the rest of the
565
+ // world to deal with it.
566
+ // Note that we also need to check that the root symbol isn't this symbol.
567
+ // This seems to happen sometimes when dealing with interface inheritance.
568
+ const rootSymbols = context . checker . getRootSymbols ( symbol ) ;
569
+ const ref = rootSymbols . length && rootSymbols [ 0 ] != symbol
570
+ ? context . createSymbolReference ( rootSymbols [ 0 ] , context , name )
571
+ : ReferenceType . createBrokenReference ( name , context . project ) ;
572
+
528
573
link ( reflection ) ;
529
574
link ( reflection . getSignature ) ;
530
575
link ( reflection . setSignature ) ;
@@ -535,34 +580,21 @@ function createLink(
535
580
link ( sig ) ;
536
581
}
537
582
538
- // Intentionally create broken links here. These will be replaced with real links during
539
- // resolution if we can do so. We create broken links rather than real links because in the
540
- // case of an inherited symbol, we'll end up referencing a single symbol ID rather than one
541
- // for each class.
542
583
function link (
543
584
target : DeclarationReflection | SignatureReflection | undefined ,
544
585
) {
545
586
if ( ! target ) return ;
546
587
547
588
if ( clause . token === ts . SyntaxKind . ImplementsKeyword ) {
548
- target . implementationOf ??= ReferenceType . createBrokenReference (
549
- name ,
550
- project ,
551
- ) ;
589
+ target . implementationOf ??= ref ;
552
590
return ;
553
591
}
554
592
555
593
if ( isInherit ) {
556
594
target . setFlag ( ReflectionFlag . Inherited ) ;
557
- target . inheritedFrom ??= ReferenceType . createBrokenReference (
558
- name ,
559
- project ,
560
- ) ;
595
+ target . inheritedFrom ??= ref ;
561
596
} else {
562
- target . overwrites ??= ReferenceType . createBrokenReference (
563
- name ,
564
- project ,
565
- ) ;
597
+ target . overwrites ??= ref ;
566
598
}
567
599
}
568
600
}
0 commit comments