* Create edges from resolved references
(resolved: ResolvedRef[])
| 796 | * Create edges from resolved references |
| 797 | */ |
| 798 | createEdges(resolved: ResolvedRef[]): Edge[] { |
| 799 | return resolved.map((ref) => { |
| 800 | // `function_ref` (#756) is internal-only: it persists as a `references` |
| 801 | // edge (the registration site depends on the callback), distinguishable |
| 802 | // by metadata.resolvedBy === 'function-ref'. callers/impact already |
| 803 | // traverse `references`, so registration sites surface with no |
| 804 | // graph-layer changes. |
| 805 | let kind: Edge['kind'] = |
| 806 | ref.original.referenceKind === 'function_ref' ? 'references' : ref.original.referenceKind; |
| 807 | |
| 808 | // Promote "extends" to "implements" when a class/struct targets an interface |
| 809 | if (kind === 'extends') { |
| 810 | const targetNode = this.queries.getNodeById(ref.targetNodeId); |
| 811 | if (targetNode && (targetNode.kind === 'interface' || targetNode.kind === 'protocol')) { |
| 812 | const sourceNode = this.queries.getNodeById(ref.original.fromNodeId); |
| 813 | if (sourceNode && sourceNode.kind !== 'interface' && sourceNode.kind !== 'protocol') { |
| 814 | kind = 'implements'; |
| 815 | } |
| 816 | } |
| 817 | } |
| 818 | |
| 819 | // Promote "calls" to "instantiates" when the resolved target is a |
| 820 | // class/struct. Languages without a `new` keyword (Python, Ruby) |
| 821 | // express instantiation as `Foo()` — extraction can't tell that |
| 822 | // apart from a function call without symbol info, but resolution |
| 823 | // can: if `Foo` resolves to a class, the call IS an instantiation. |
| 824 | if (kind === 'calls') { |
| 825 | const targetNode = this.queries.getNodeById(ref.targetNodeId); |
| 826 | if (targetNode && (targetNode.kind === 'class' || targetNode.kind === 'struct')) { |
| 827 | kind = 'instantiates'; |
| 828 | } |
| 829 | } |
| 830 | |
| 831 | return { |
| 832 | source: ref.original.fromNodeId, |
| 833 | target: ref.targetNodeId, |
| 834 | kind, |
| 835 | line: ref.original.line, |
| 836 | column: ref.original.column, |
| 837 | metadata: { |
| 838 | confidence: ref.confidence, |
| 839 | resolvedBy: ref.resolvedBy, |
| 840 | // Uniform marker for function-as-value edges (#756), regardless of |
| 841 | // which strategy resolved them (import vs matchFunctionRef) — lets |
| 842 | // tooling label "callback registration" and lets validation diff |
| 843 | // exactly the edges this feature added. |
| 844 | ...(ref.original.referenceKind === 'function_ref' ? { fnRef: true } : {}), |
| 845 | }, |
| 846 | }; |
| 847 | }); |
| 848 | } |
| 849 | |
| 850 | /** |
| 851 | * Resolve and persist edges to database |
no test coverage detected