@@ -51,6 +51,12 @@ export class TypeScriptParser {
5151 private frameworkSchemas : FrameworkSchema [ ] ;
5252 private parsedNodes : Map < string , ParsedNode > = new Map ( ) ;
5353 private parsedEdges : Map < string , ParsedEdge > = new Map ( ) ;
54+ private deferredEdges : Array < {
55+ edgeType : CoreEdgeType ;
56+ sourceNodeId : string ;
57+ targetName : string ;
58+ targetType : CoreNodeType ;
59+ } > = [ ] ;
5460 private sharedContext : ParsingContext = new Map ( ) ; // Shared context for custom data
5561
5662 constructor (
@@ -88,6 +94,9 @@ export class TypeScriptParser {
8894 await this . parseCoreTypeScriptV2 ( sourceFile ) ;
8995 }
9096
97+ // Phase 1.5: Resolve deferred relationship edges (EXTENDS, IMPLEMENTS)
98+ this . resolveDeferredEdges ( ) ;
99+
91100 // Phase 2: Apply context extractors
92101 await this . applyContextExtractors ( ) ;
93102
@@ -181,12 +190,84 @@ export class TypeScriptParser {
181190
182191 const childNodeConfig = this . coreSchema . nodeTypes [ type ] ;
183192 if ( childNodeConfig ) {
193+ this . queueRelationshipNodes ( childNodeConfig , coreNode , child ) ;
184194 await this . parseChildNodes ( childNodeConfig , coreNode , child ) ;
185195 }
186196 }
187197 }
188198 }
189199
200+ /**
201+ * Queue relationship edges for deferred processing
202+ * These are resolved after all nodes are parsed since the target may not exist yet
203+ */
204+ private queueRelationshipNodes ( nodeConfig : CoreNode , parsedNode : ParsedNode , astNode : Node ) : void {
205+ if ( ! nodeConfig . relationships || nodeConfig . relationships . length === 0 ) return ;
206+
207+ for ( const relationship of nodeConfig . relationships ) {
208+ const { edgeType, method, cardinality, targetNodeType } = relationship ;
209+ const astGetter = ( astNode as any ) [ method ] ;
210+
211+ if ( typeof astGetter !== 'function' ) continue ;
212+
213+ const result = astGetter . call ( astNode ) ;
214+ if ( ! result ) continue ;
215+
216+ const targets = cardinality === 'single' ? [ result ] : result ;
217+
218+ for ( const target of targets ) {
219+ if ( ! target ) continue ;
220+
221+ const targetName = this . extractRelationshipTargetName ( target ) ;
222+ if ( ! targetName ) continue ;
223+
224+ this . deferredEdges . push ( {
225+ edgeType : edgeType as CoreEdgeType ,
226+ sourceNodeId : parsedNode . id ,
227+ targetName,
228+ targetType : targetNodeType ,
229+ } ) ;
230+ }
231+ }
232+ }
233+
234+ /**
235+ * Extract the target name from an AST node returned by relationship methods
236+ */
237+ private extractRelationshipTargetName ( target : Node ) : string | undefined {
238+ if ( Node . isClassDeclaration ( target ) ) return target . getName ( ) ;
239+ if ( Node . isInterfaceDeclaration ( target ) ) return target . getName ( ) ;
240+ if ( Node . isExpressionWithTypeArguments ( target ) ) return target . getExpression ( ) . getText ( ) ;
241+ return undefined ;
242+ }
243+
244+ /**
245+ * Find a parsed node by name and core type
246+ */
247+ private findNodeByNameAndType ( name : string , coreType : CoreNodeType ) : ParsedNode | undefined {
248+ for ( const node of this . parsedNodes . values ( ) ) {
249+ if ( node . coreType === coreType && node . properties . name === name ) {
250+ return node ;
251+ }
252+ }
253+ return undefined ;
254+ }
255+
256+ /**
257+ * Resolve deferred edges after all nodes have been parsed
258+ */
259+ private resolveDeferredEdges ( ) : void {
260+ for ( const deferred of this . deferredEdges ) {
261+ const targetNode = this . findNodeByNameAndType ( deferred . targetName , deferred . targetType ) ;
262+ if ( targetNode ) {
263+ const edge = this . createCoreEdge ( deferred . edgeType , deferred . sourceNodeId , targetNode . id ) ;
264+ this . addEdge ( edge ) ;
265+ }
266+ // If not found, it's likely an external type (from node_modules) - skip silently
267+ }
268+ this . deferredEdges = [ ] ;
269+ }
270+
190271 private async parseCoreTypeScript ( sourceFile : SourceFile ) : Promise < void > {
191272 try {
192273 // Create source file node
@@ -402,6 +483,10 @@ export class TypeScriptParser {
402483 }
403484
404485 private createCoreEdge ( relationshipType : CoreEdgeType , sourceNodeId : string , targetNodeId : string ) : ParsedEdge {
486+ // Get the weight from the core schema
487+ const coreEdgeSchema = CORE_TYPESCRIPT_SCHEMA . edgeTypes [ relationshipType ] ;
488+ const relationshipWeight = coreEdgeSchema ?. relationshipWeight ?? 0.5 ;
489+
405490 return {
406491 id : `${ relationshipType } :${ uuidv4 ( ) } ` ,
407492 relationshipType,
@@ -411,6 +496,7 @@ export class TypeScriptParser {
411496 coreType : relationshipType ,
412497 source : 'ast' ,
413498 confidence : 1.0 ,
499+ relationshipWeight,
414500 filePath : '' ,
415501 createdAt : new Date ( ) . toISOString ( ) ,
416502 } ,
@@ -565,6 +651,7 @@ export class TypeScriptParser {
565651 sourceId ,
566652 targetId ,
567653 context ,
654+ edgeEnhancement . relationshipWeight ,
568655 ) ;
569656 this . addEdge ( edge ) ;
570657 }
@@ -581,6 +668,7 @@ export class TypeScriptParser {
581668 sourceNodeId : string ,
582669 targetNodeId : string ,
583670 context : Record < string , any > = { } ,
671+ relationshipWeight : number = 0.5 ,
584672 ) : ParsedEdge {
585673 const edgeId = `${ semanticType } :${ uuidv4 ( ) } ` ;
586674
@@ -589,6 +677,7 @@ export class TypeScriptParser {
589677 semanticType,
590678 source : 'pattern' ,
591679 confidence : 0.8 ,
680+ relationshipWeight,
592681 filePath : '' ,
593682 createdAt : new Date ( ) . toISOString ( ) ,
594683 context,
0 commit comments