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

typeorm / typeorm / 19549987525

20 Nov 2025 08:11PM UTC coverage: 80.769% (+4.3%) from 76.433%
19549987525

push

github

web-flow
ci: run tests on commits to master and next (#11783)

Co-authored-by: Oleg "OSA413" Sokolov <OSA413@users.noreply.github.com>

26500 of 32174 branches covered (82.36%)

Branch coverage included in aggregate %.

91252 of 113615 relevant lines covered (80.32%)

88980.79 hits per line

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

70.44
/src/util/DepGraph.ts
1
/**
26✔
2
 * This source code is from https://github.com/jriecken/dependency-graph
26✔
3
 * Just added "any" types here, wrapper everything into exported class.
26✔
4
 * We cant use a package itself because we want to package "everything-in-it" for the frontend users of TypeORM.
26✔
5
 */
26✔
6

26✔
7
/**
26✔
8
 * A simple dependency graph
26✔
9
 */
26✔
10

26✔
11
import { TypeORMError } from "../error"
26✔
12

26✔
13
/**
26✔
14
 * Helper for creating a Depth-First-Search on
26✔
15
 * a set of edges.
26✔
16
 *
26✔
17
 * Detects cycles and throws an Error if one is detected.
26✔
18
 *
26✔
19
 * @param edges The set of edges to DFS through
26✔
20
 * @param leavesOnly Whether to only return "leaf" nodes (ones who have no edges)
26✔
21
 * @param result An array in which the results will be populated
26✔
22
 */
26✔
23
function createDFS(edges: any, leavesOnly: any, result: any) {
28,378✔
24
    const currentPath: any[] = []
28,378✔
25
    const visited: any = {}
28,378✔
26
    return function DFS(currentNode: any) {
28,378✔
27
        visited[currentNode] = true
71,842✔
28
        currentPath.push(currentNode)
71,842✔
29
        edges[currentNode].forEach(function (node: any) {
71,842✔
30
            if (!visited[node]) {
816✔
31
                DFS(node)
472✔
32
            } else if (currentPath.indexOf(node) >= 0) {
816✔
33
                currentPath.push(node)
26✔
34
                throw new TypeORMError(
26✔
35
                    `Dependency Cycle Found: ${currentPath.join(" -> ")}`,
26✔
36
                )
26✔
37
            }
26✔
38
        })
71,842✔
39
        currentPath.pop()
71,842✔
40
        if (
71,842✔
41
            (!leavesOnly || edges[currentNode].length === 0) &&
71,842!
42
            result.indexOf(currentNode) === -1
71,764✔
43
        ) {
71,842✔
44
            result.push(currentNode)
71,690✔
45
        }
71,690✔
46
    }
71,842✔
47
}
28,378✔
48

26✔
49
export class DepGraph {
14,441✔
50
    nodes: any = {}
14,441✔
51
    outgoingEdges: any = {} // Node -> [Dependency Node]
14,441✔
52
    incomingEdges: any = {} // Node -> [Dependant Node]
14,441✔
53

14,441✔
54
    /**
14,441✔
55
     * Add a node to the dependency graph. If a node already exists, this method will do nothing.
14,441✔
56
     */
14,441✔
57
    addNode(node: any, data?: any) {
14,441✔
58
        if (!this.hasNode(node)) {
36,092✔
59
            // Checking the arguments length allows the user to add a node with undefined data
35,949✔
60
            if (arguments.length === 2) {
35,949!
61
                this.nodes[node] = data
×
62
            } else {
35,949✔
63
                this.nodes[node] = node
35,949✔
64
            }
35,949✔
65
            this.outgoingEdges[node] = []
35,949✔
66
            this.incomingEdges[node] = []
35,949✔
67
        }
35,949✔
68
    }
36,092✔
69

14,441✔
70
    /**
14,441✔
71
     * Remove a node from the dependency graph. If a node does not exist, this method will do nothing.
14,441✔
72
     */
14,441✔
73
    removeNode(node: any) {
14,441✔
74
        if (this.hasNode(node)) {
×
75
            delete this.nodes[node]
×
76
            delete this.outgoingEdges[node]
×
77
            delete this.incomingEdges[node]
×
78
            ;[this.incomingEdges, this.outgoingEdges].forEach(function (
×
79
                edgeList,
×
80
            ) {
×
81
                Object.keys(edgeList).forEach(function (key: any) {
×
82
                    const idx = edgeList[key].indexOf(node)
×
83
                    if (idx >= 0) {
×
84
                        edgeList[key].splice(idx, 1)
×
85
                    }
×
86
                })
×
87
            })
×
88
        }
×
89
    }
×
90

14,441✔
91
    /**
14,441✔
92
     * Check if a node exists in the graph
14,441✔
93
     */
14,441✔
94
    hasNode(node: any) {
14,441✔
95
        return this.nodes.hasOwnProperty(node)
37,038✔
96
    }
37,038✔
97

14,441✔
98
    /**
14,441✔
99
     * Get the data associated with a node name
14,441✔
100
     */
14,441✔
101
    getNodeData(node: any) {
14,441✔
102
        if (this.hasNode(node)) {
×
103
            return this.nodes[node]
×
104
        } else {
×
105
            throw new TypeORMError(`Node does not exist: ${node}`)
×
106
        }
×
107
    }
×
108

14,441✔
109
    /**
14,441✔
110
     * Set the associated data for a given node name. If the node does not exist, this method will throw an error
14,441✔
111
     */
14,441✔
112
    setNodeData(node: any, data: any) {
14,441✔
113
        if (this.hasNode(node)) {
×
114
            this.nodes[node] = data
×
115
        } else {
×
116
            throw new TypeORMError(`Node does not exist: ${node}`)
×
117
        }
×
118
    }
×
119

14,441✔
120
    /**
14,441✔
121
     * Add a dependency between two nodes. If either of the nodes does not exist,
14,441✔
122
     * an Error will be thrown.
14,441✔
123
     */
14,441✔
124
    addDependency(from: any, to: any) {
14,441✔
125
        if (!this.hasNode(from)) {
473!
126
            throw new TypeORMError(`Node does not exist: ${from}`)
×
127
        }
×
128
        if (!this.hasNode(to)) {
473!
129
            throw new TypeORMError(`Node does not exist: ${to}`)
×
130
        }
×
131
        if (this.outgoingEdges[from].indexOf(to) === -1) {
473✔
132
            this.outgoingEdges[from].push(to)
473✔
133
        }
473✔
134
        if (this.incomingEdges[to].indexOf(from) === -1) {
473✔
135
            this.incomingEdges[to].push(from)
473✔
136
        }
473✔
137
        return true
473✔
138
    }
473✔
139

14,441✔
140
    /**
14,441✔
141
     * Remove a dependency between two nodes.
14,441✔
142
     */
14,441✔
143
    removeDependency(from: any, to: any) {
14,441✔
144
        let idx: any
×
145
        if (this.hasNode(from)) {
×
146
            idx = this.outgoingEdges[from].indexOf(to)
×
147
            if (idx >= 0) {
×
148
                this.outgoingEdges[from].splice(idx, 1)
×
149
            }
×
150
        }
×
151

×
152
        if (this.hasNode(to)) {
×
153
            idx = this.incomingEdges[to].indexOf(from)
×
154
            if (idx >= 0) {
×
155
                this.incomingEdges[to].splice(idx, 1)
×
156
            }
×
157
        }
×
158
    }
×
159

14,441✔
160
    /**
14,441✔
161
     * Get an array containing the nodes that the specified node depends on (transitively).
14,441✔
162
     *
14,441✔
163
     * Throws an Error if the graph has a cycle, or the specified node does not exist.
14,441✔
164
     *
14,441✔
165
     * If `leavesOnly` is true, only nodes that do not depend on any other nodes will be returned
14,441✔
166
     * in the array.
14,441✔
167
     */
14,441✔
168
    dependenciesOf(node: any, leavesOnly: any) {
14,441✔
169
        if (this.hasNode(node)) {
×
170
            const result: any[] = []
×
171
            const DFS = createDFS(this.outgoingEdges, leavesOnly, result)
×
172
            DFS(node)
×
173
            const idx = result.indexOf(node)
×
174
            if (idx >= 0) {
×
175
                result.splice(idx, 1)
×
176
            }
×
177
            return result
×
178
        } else {
×
179
            throw new TypeORMError(`Node does not exist: ${node}`)
×
180
        }
×
181
    }
×
182

14,441✔
183
    /**
14,441✔
184
     * get an array containing the nodes that depend on the specified node (transitively).
14,441✔
185
     *
14,441✔
186
     * Throws an Error if the graph has a cycle, or the specified node does not exist.
14,441✔
187
     *
14,441✔
188
     * If `leavesOnly` is true, only nodes that do not have any dependants will be returned in the array.
14,441✔
189
     */
14,441✔
190
    dependantsOf(node: any, leavesOnly: any) {
14,441✔
191
        if (this.hasNode(node)) {
×
192
            const result: any[] = []
×
193
            const DFS = createDFS(this.incomingEdges, leavesOnly, result)
×
194
            DFS(node)
×
195
            const idx = result.indexOf(node)
×
196
            if (idx >= 0) {
×
197
                result.splice(idx, 1)
×
198
            }
×
199
            return result
×
200
        } else {
×
201
            throw new TypeORMError(`Node does not exist: ${node}`)
×
202
        }
×
203
    }
×
204

14,441✔
205
    /**
14,441✔
206
     * Construct the overall processing order for the dependency graph.
14,441✔
207
     *
14,441✔
208
     * Throws an Error if the graph has a cycle.
14,441✔
209
     *
14,441✔
210
     * If `leavesOnly` is true, only nodes that do not depend on any other nodes will be returned.
14,441✔
211
     */
14,441✔
212
    overallOrder(leavesOnly?: any) {
14,441✔
213
        const self = this
14,441✔
214
        const result: any[] = []
14,441✔
215
        const keys = Object.keys(this.nodes)
14,441✔
216
        if (keys.length === 0) {
14,441✔
217
            return result // Empty graph
239✔
218
        } else {
14,441✔
219
            // Look for cycles - we run the DFS starting at all the nodes in case there
14,202✔
220
            // are several disconnected subgraphs inside this dependency graph.
14,202✔
221
            const CycleDFS = createDFS(this.outgoingEdges, false, [])
14,202✔
222
            keys.forEach(function (n: any) {
14,202✔
223
                CycleDFS(n)
35,871✔
224
            })
14,202✔
225

14,202✔
226
            const DFS = createDFS(this.outgoingEdges, leavesOnly, result)
14,202✔
227
            // Find all potential starting points (nodes with nothing depending on them) an
14,202✔
228
            // run a DFS starting at these points to get the order
14,202✔
229
            keys.filter(function (node) {
14,202✔
230
                return self.incomingEdges[node].length === 0
35,845✔
231
            }).forEach(function (n) {
14,202✔
232
                DFS(n)
35,499✔
233
            })
14,202✔
234

14,202✔
235
            return result
14,202✔
236
        }
14,202✔
237
    }
14,441✔
238
}
14,441✔
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