• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

graphty-org / graphty-element / 20390753610

20 Dec 2025 06:53AM UTC coverage: 82.423% (-1.2%) from 83.666%
20390753610

push

github

apowers313
Merge branch 'master' of https://github.com/graphty-org/graphty-element

5162 of 6088 branches covered (84.79%)

Branch coverage included in aggregate %.

24775 of 30233 relevant lines covered (81.95%)

6480.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.1
/src/algorithms/DijkstraAlgorithm.ts
1
import {dijkstra, dijkstraPath} from "@graphty/algorithms";
3✔
2
import {z} from "zod/v4";
3✔
3

4
import {defineOptions, type OptionsSchema as ZodOptionsSchema, type SuggestedStylesConfig} from "../config";
3✔
5
import {Algorithm} from "./Algorithm";
3✔
6
import {type OptionsSchema} from "./types/OptionSchema";
7
import {toAlgorithmGraph} from "./utils/graphConverter";
3✔
8

9
/**
10
 * Zod-based options schema for Dijkstra algorithm
11
 */
12
export const dijkstraOptionsSchema = defineOptions({
3✔
13
    source: {
3✔
14
        schema: z.union([z.string(), z.number()]).nullable().default(null),
3✔
15
        meta: {
3✔
16
            label: "Source Node",
3✔
17
            description: "Starting node for shortest path (uses first node if not set)",
3✔
18
        },
3✔
19
    },
3✔
20
    target: {
3✔
21
        schema: z.union([z.string(), z.number()]).nullable().default(null),
3✔
22
        meta: {
3✔
23
            label: "Target Node",
3✔
24
            description: "Destination node for shortest path (uses last node if not set)",
3✔
25
        },
3✔
26
    },
3✔
27
    bidirectional: {
3✔
28
        schema: z.boolean().default(true),
3✔
29
        meta: {
3✔
30
            label: "Bidirectional Search",
3✔
31
            description: "Use bidirectional search optimization for faster point-to-point queries",
3✔
32
            advanced: true,
3✔
33
        },
3✔
34
    },
3✔
35
});
3✔
36

37
/**
38
 * Options for Dijkstra algorithm
39
 */
40
export interface DijkstraOptions extends Record<string, unknown> {
41
    /** Starting node for shortest path (defaults to first node if not provided) */
42
    source: number | string | null;
43
    /** Destination node for shortest path (defaults to last node if not provided) */
44
    target: number | string | null;
45
    /** Use bidirectional search optimization for point-to-point queries */
46
    bidirectional: boolean;
47
}
48

49
export class DijkstraAlgorithm extends Algorithm<DijkstraOptions> {
3✔
50
    static namespace = "graphty";
11✔
51
    static type = "dijkstra";
11✔
52

53
    static zodOptionsSchema: ZodOptionsSchema = dijkstraOptionsSchema;
11✔
54

55
    /**
56
     * Options schema for Dijkstra algorithm
57
     */
58
    static optionsSchema: OptionsSchema = {
11✔
59
        source: {
11✔
60
            type: "nodeId",
11✔
61
            default: null,
11✔
62
            label: "Source Node",
11✔
63
            description: "Starting node for shortest path (uses first node if not set)",
11✔
64
            required: false,
11✔
65
        },
11✔
66
        target: {
11✔
67
            type: "nodeId",
11✔
68
            default: null,
11✔
69
            label: "Target Node",
11✔
70
            description: "Destination node for shortest path (uses last node if not set)",
11✔
71
            required: false,
11✔
72
        },
11✔
73
        bidirectional: {
11✔
74
            type: "boolean",
11✔
75
            default: true,
11✔
76
            label: "Bidirectional Search",
11✔
77
            description: "Use bidirectional search optimization for faster point-to-point queries",
11✔
78
            advanced: true,
11✔
79
        },
11✔
80
    };
11✔
81

82
    /**
83
     * Legacy options set via configure() for backward compatibility
84
     */
85
    private legacyOptions: {source: number | string, target?: number | string} | null = null;
11✔
86

87
    static suggestedStyles = (): SuggestedStylesConfig => ({
108✔
88
        layers: [
14✔
89
            {
14✔
90
                edge: {
14✔
91
                    selector: "",
14✔
92
                    style: {enabled: true},
14✔
93
                    calculatedStyle: {
14✔
94
                        inputs: ["algorithmResults.graphty.dijkstra.isInPath"],
14✔
95
                        output: "style.line.color",
14✔
96
                        expr: "{ return StyleHelpers.color.binary.blueHighlight(arguments[0]) }",
14✔
97
                    },
14✔
98
                },
14✔
99
                metadata: {
14✔
100
                    name: "Dijkstra - Path Edges",
14✔
101
                    description: "Highlights edges that are part of the shortest path (blue) - colorblind-safe",
14✔
102
                },
14✔
103
            },
14✔
104
            {
14✔
105
                node: {
14✔
106
                    selector: "",
14✔
107
                    style: {enabled: true},
14✔
108
                    calculatedStyle: {
14✔
109
                        inputs: ["algorithmResults.graphty.dijkstra.isInPath"],
14✔
110
                        output: "style.texture.color",
14✔
111
                        expr: "{ return StyleHelpers.color.binary.blueHighlight(arguments[0]) }",
14✔
112
                    },
14✔
113
                },
14✔
114
                metadata: {
14✔
115
                    name: "Dijkstra - Path Nodes",
14✔
116
                    description: "Highlights nodes that are part of the shortest path (blue) - colorblind-safe",
14✔
117
                },
14✔
118
            },
14✔
119
        ],
14✔
120
        description: "Visualizes shortest path by highlighting path edges and nodes",
14✔
121
        category: "path",
14✔
122
    });
14✔
123

124
    /**
125
     * Configure the algorithm with source and optional target nodes
126
     *
127
     * @deprecated Use constructor options instead. This method is kept for backward compatibility.
128
     */
129
    configure(options: {source: number | string, target?: number | string}): this {
7✔
130
        this.legacyOptions = options;
1✔
131
        return this;
1✔
132
    }
1✔
133

134
    // eslint-disable-next-line @typescript-eslint/require-await
135
    async run(): Promise<void> {
7✔
136
        const g = this.graph;
7✔
137
        const nodes = Array.from(g.getDataManager().nodes.keys());
7✔
138
        const n = nodes.length;
7✔
139

140
        if (n === 0) {
7!
141
            return;
×
142
        }
×
143

144
        // Get source and target from legacy options, schema options, or use defaults
145
        // Legacy configure() takes precedence for backward compatibility
146
        const source = this.legacyOptions?.source ?? this._schemaOptions.source ?? nodes[0];
7✔
147
        const target = this.legacyOptions?.target ?? this._schemaOptions.target ?? nodes[nodes.length - 1];
7✔
148
        const {bidirectional} = this._schemaOptions;
7✔
149

150
        // Convert to @graphty/algorithms format (undirected for path finding)
151
        const graphData = toAlgorithmGraph(g);
7✔
152

153
        // Run Dijkstra to get path from source to target
154
        const pathResult = dijkstraPath(graphData, source, target, {bidirectional});
7✔
155
        const path = pathResult?.path ?? [];
7✔
156

157
        // Run Dijkstra once from source to get all distances
158
        const allDistances = dijkstra(graphData, source);
7✔
159

160
        // Store path information on nodes
161
        const pathNodeSet = new Set(path);
7✔
162
        for (const nodeId of nodes) {
7✔
163
            const isInPath = pathNodeSet.has(nodeId);
90✔
164
            this.addNodeResult(nodeId, "isInPath", isInPath);
90✔
165

166
            // Get distance from the single Dijkstra run
167
            const nodeResult = allDistances.get(nodeId);
90✔
168
            const distance = nodeResult?.distance ?? Infinity;
90✔
169
            this.addNodeResult(nodeId, "distance", distance);
90✔
170
        }
90✔
171

172
        // Store path information on edges
173
        const pathEdges = this.getPathEdges(path);
7✔
174
        for (const edge of g.getDataManager().edges.values()) {
7✔
175
            const edgeKey = `${edge.srcId}:${edge.dstId}`;
94✔
176
            const reverseEdgeKey = `${edge.dstId}:${edge.srcId}`;
94✔
177
            const isInPath = pathEdges.has(edgeKey) || pathEdges.has(reverseEdgeKey);
94✔
178
            this.addEdgeResult(edge, "isInPath", isInPath);
94✔
179
        }
94✔
180
    }
7✔
181

182
    /**
183
     * Get set of edge keys that are part of the path
184
     */
185
    private getPathEdges(path: (number | string)[]): Set<string> {
7✔
186
        const edges = new Set<string>();
7✔
187

188
        for (let i = 0; i < path.length - 1; i++) {
7✔
189
            edges.add(`${path[i]}:${path[i + 1]}`);
10✔
190
        }
10✔
191

192
        return edges;
7✔
193
    }
7✔
194
}
7✔
195

196
// Auto-register this algorithm when the module is imported
197
Algorithm.register(DijkstraAlgorithm);
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc