@@ -110,8 +110,10 @@ export class ImplementsPlugin extends ConverterComponent {
110110 project : ProjectReflection ,
111111 reflection : DeclarationReflection ,
112112 ) {
113+ if ( ! reflection . extendedTypes ) return ;
114+
113115 const extendedTypes = filterMap (
114- reflection . extendedTypes ?? [ ] ,
116+ reflection . extendedTypes ,
115117 ( type ) => {
116118 return type instanceof ReferenceType &&
117119 type . reflection instanceof DeclarationReflection
@@ -139,23 +141,54 @@ export class ImplementsPlugin extends ConverterComponent {
139141 parentMember . signatures ?? [ ] ,
140142 )
141143 ) {
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 (
143157 `${ parent . name } .${ parentMember . name } ` ,
144- parentSig ,
158+ parentMember ,
145159 project ,
146160 ) ;
147161 }
148162
149- child [ key ] = ReferenceType . createResolvedReference (
150- `${ parent . name } .${ parentMember . name } ` ,
151- parentMember ,
152- project ,
153- ) ;
154-
155163 this . handleInheritedComments ( child , parentMember ) ;
156164 }
157165 }
158166 }
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+ }
159192 }
160193
161194 private onResolveEnd ( context : Context ) {
@@ -522,9 +555,21 @@ function createLink(
522555 symbol : ts . Symbol ,
523556 isInherit : boolean ,
524557) {
525- const project = context . project ;
526558 const name = `${ expr . expression . getText ( ) } .${ getHumanName ( symbol . name ) } ` ;
527559
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+
528573 link ( reflection ) ;
529574 link ( reflection . getSignature ) ;
530575 link ( reflection . setSignature ) ;
@@ -535,34 +580,21 @@ function createLink(
535580 link ( sig ) ;
536581 }
537582
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.
542583 function link (
543584 target : DeclarationReflection | SignatureReflection | undefined ,
544585 ) {
545586 if ( ! target ) return ;
546587
547588 if ( clause . token === ts . SyntaxKind . ImplementsKeyword ) {
548- target . implementationOf ??= ReferenceType . createBrokenReference (
549- name ,
550- project ,
551- ) ;
589+ target . implementationOf ??= ref ;
552590 return ;
553591 }
554592
555593 if ( isInherit ) {
556594 target . setFlag ( ReflectionFlag . Inherited ) ;
557- target . inheritedFrom ??= ReferenceType . createBrokenReference (
558- name ,
559- project ,
560- ) ;
595+ target . inheritedFrom ??= ref ;
561596 } else {
562- target . overwrites ??= ReferenceType . createBrokenReference (
563- name ,
564- project ,
565- ) ;
597+ target . overwrites ??= ref ;
566598 }
567599 }
568600}
0 commit comments