@3plate/graph-core 0.1.0 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2717 -1352
- package/dist/index.d.cts +193 -0
- package/dist/index.d.ts +186 -44
- package/dist/index.js +2710 -1346
- package/package.json +10 -3
- package/dist/index.d.mts +0 -51
- package/dist/index.mjs +0 -323
package/package.json
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@3plate/graph-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/3plt/graph",
|
|
9
|
+
"directory": "packages/core"
|
|
10
|
+
},
|
|
6
11
|
"main": "./dist/index.js",
|
|
7
12
|
"module": "./dist/index.mjs",
|
|
8
13
|
"exports": {
|
|
9
14
|
".": {
|
|
15
|
+
"source": "./src/index.ts",
|
|
10
16
|
"import": "./dist/index.mjs",
|
|
11
17
|
"require": "./dist/index.js"
|
|
12
18
|
}
|
|
@@ -24,12 +30,13 @@
|
|
|
24
30
|
},
|
|
25
31
|
"dependencies": {
|
|
26
32
|
"immutable": "^5.1.4",
|
|
33
|
+
"jsx-dom": "^8.1.6",
|
|
27
34
|
"winston": "^3.18.3",
|
|
28
35
|
"winston-transport": "^4.9.0"
|
|
29
36
|
},
|
|
30
37
|
"scripts": {
|
|
31
|
-
"build": "tsup
|
|
32
|
-
"dev": "tsup
|
|
38
|
+
"build": "tsup",
|
|
39
|
+
"dev": "tsup --watch",
|
|
33
40
|
"test": "vitest run",
|
|
34
41
|
"test:watch": "vitest"
|
|
35
42
|
}
|
package/dist/index.d.mts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
interface EdgeProps {
|
|
2
|
-
sourceId: string;
|
|
3
|
-
targetId: string;
|
|
4
|
-
label?: string;
|
|
5
|
-
sourcePort?: string;
|
|
6
|
-
targetPort?: string;
|
|
7
|
-
}
|
|
8
|
-
type EdgeExtractor<E> = (edge: E) => EdgeProps;
|
|
9
|
-
declare class GraphEdge<N, E> {
|
|
10
|
-
id: string;
|
|
11
|
-
props: EdgeProps;
|
|
12
|
-
data: E;
|
|
13
|
-
source: GraphNode<N, E>;
|
|
14
|
-
target: GraphNode<N, E>;
|
|
15
|
-
constructor(props: EdgeProps, data: E, source: GraphNode<N, E>, target: GraphNode<N, E>);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface NodeProps {
|
|
19
|
-
id: string;
|
|
20
|
-
inPorts?: string[];
|
|
21
|
-
outPorts?: string[];
|
|
22
|
-
}
|
|
23
|
-
type NodeExtractor<N> = (node: N) => NodeProps;
|
|
24
|
-
declare class GraphNode<N, E> {
|
|
25
|
-
props: NodeProps;
|
|
26
|
-
data: N;
|
|
27
|
-
pred: Map<GraphEdge<N, E>, GraphNode<N, E> | null> | undefined;
|
|
28
|
-
succ: Map<GraphEdge<N, E>, GraphNode<N, E> | null> | undefined;
|
|
29
|
-
prior: GraphNode<N, E> | undefined;
|
|
30
|
-
constructor(props: NodeProps, data: N);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
declare class Graph<N, E> {
|
|
34
|
-
nodeMap: Map<string, GraphNode<N, E> | null> | undefined;
|
|
35
|
-
edgeMap: Map<string, GraphEdge<N, E> | null> | undefined;
|
|
36
|
-
prior: Graph<N, E> | undefined;
|
|
37
|
-
complete: boolean;
|
|
38
|
-
numNodes: number;
|
|
39
|
-
numEdges: number;
|
|
40
|
-
constructor();
|
|
41
|
-
isEmpty(): boolean;
|
|
42
|
-
_walk<T>(mapFn: (graph: Graph<N, E>) => Map<string, T | null> | undefined): IterableIterator<T>;
|
|
43
|
-
nodes(): IterableIterator<GraphNode<N, E>>;
|
|
44
|
-
edges(): IterableIterator<GraphEdge<N, E>>;
|
|
45
|
-
getNode(id: string): GraphNode<N, E> | undefined;
|
|
46
|
-
getEdge(id: string): GraphEdge<N, E> | undefined;
|
|
47
|
-
hasNode(id: string): boolean;
|
|
48
|
-
hasEdge(id: string): boolean;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export { type EdgeExtractor, type EdgeProps, Graph, GraphEdge, GraphNode, type NodeExtractor, type NodeProps };
|
package/dist/index.mjs
DELETED
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
// src/node.js
|
|
2
|
-
var GraphNode = class {
|
|
3
|
-
constructor(props, data) {
|
|
4
|
-
this.props = props;
|
|
5
|
-
this.data = data;
|
|
6
|
-
this.sourceMap = /* @__PURE__ */ new Map();
|
|
7
|
-
this.targetMap = /* @__PURE__ */ new Map();
|
|
8
|
-
this.complete = true;
|
|
9
|
-
}
|
|
10
|
-
*_walk(mapFn) {
|
|
11
|
-
let current = this;
|
|
12
|
-
const seen = /* @__PURE__ */ new Set();
|
|
13
|
-
while (current) {
|
|
14
|
-
const map = mapFn(current);
|
|
15
|
-
if (map) {
|
|
16
|
-
for (const [edge, node] of map) {
|
|
17
|
-
if (!seen.has(edge.id)) {
|
|
18
|
-
seen.add(edge.id);
|
|
19
|
-
if (node !== null) {
|
|
20
|
-
yield edge;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
if (current.complete) break;
|
|
26
|
-
current = current.prior;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
sourceEdges() {
|
|
30
|
-
return this._walk((node) => node.sourceMap);
|
|
31
|
-
}
|
|
32
|
-
targetEdges() {
|
|
33
|
-
return this._walk((node) => node.targetMap);
|
|
34
|
-
}
|
|
35
|
-
*sourceNodes() {
|
|
36
|
-
for (const edge of this.sourceEdges()) {
|
|
37
|
-
yield edge.source;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
*targetNodes() {
|
|
41
|
-
for (const edge of this.targetEdges()) {
|
|
42
|
-
yield edge.target;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// src/edge.js
|
|
48
|
-
var GraphEdge = class {
|
|
49
|
-
constructor(props, data, source, target) {
|
|
50
|
-
this.id = `${props.sourceId}-${props.targetId}`;
|
|
51
|
-
this.props = props;
|
|
52
|
-
this.data = data;
|
|
53
|
-
this.source = source;
|
|
54
|
-
this.target = target;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// src/graph.js
|
|
59
|
-
var Graph = class {
|
|
60
|
-
constructor() {
|
|
61
|
-
this.nodeMap = /* @__PURE__ */ new Map();
|
|
62
|
-
this.edgeMap = /* @__PURE__ */ new Map();
|
|
63
|
-
this.numNodes = 0;
|
|
64
|
-
this.numEdges = 0;
|
|
65
|
-
this.complete = true;
|
|
66
|
-
}
|
|
67
|
-
isEmpty() {
|
|
68
|
-
return this.numNodes === 0 && this.numEdges === 0;
|
|
69
|
-
}
|
|
70
|
-
*_walk(mapFn) {
|
|
71
|
-
const seen = /* @__PURE__ */ new Set();
|
|
72
|
-
let current = this;
|
|
73
|
-
while (current) {
|
|
74
|
-
const map = mapFn(current);
|
|
75
|
-
if (map) {
|
|
76
|
-
for (const [id, node] of map) {
|
|
77
|
-
if (!seen.has(id)) {
|
|
78
|
-
seen.add(id);
|
|
79
|
-
if (node !== null) {
|
|
80
|
-
yield node;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
if (current.complete) break;
|
|
86
|
-
current = current.prior;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
nodes() {
|
|
90
|
-
return this._walk((graph) => graph.nodeMap);
|
|
91
|
-
}
|
|
92
|
-
edges() {
|
|
93
|
-
return this._walk((graph) => graph.edgeMap);
|
|
94
|
-
}
|
|
95
|
-
getNode(id) {
|
|
96
|
-
let current = this;
|
|
97
|
-
while (current) {
|
|
98
|
-
const node = current.nodeMap?.get(id);
|
|
99
|
-
if (node === null) return void 0;
|
|
100
|
-
else if (node !== void 0) return node;
|
|
101
|
-
if (current.complete) break;
|
|
102
|
-
current = current.prior;
|
|
103
|
-
}
|
|
104
|
-
return void 0;
|
|
105
|
-
}
|
|
106
|
-
getEdge(id) {
|
|
107
|
-
let current = this;
|
|
108
|
-
while (current) {
|
|
109
|
-
const edge = current.edgeMap?.get(id);
|
|
110
|
-
if (edge === null) return void 0;
|
|
111
|
-
else if (edge !== void 0) return edge;
|
|
112
|
-
if (current.complete) break;
|
|
113
|
-
current = current.prior;
|
|
114
|
-
}
|
|
115
|
-
return void 0;
|
|
116
|
-
}
|
|
117
|
-
hasNode(id) {
|
|
118
|
-
const node = this.getNode(id);
|
|
119
|
-
return node !== void 0;
|
|
120
|
-
}
|
|
121
|
-
hasEdge(id) {
|
|
122
|
-
const edge = this.getEdge(id);
|
|
123
|
-
return edge !== void 0;
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
// src/topo-sort.js
|
|
128
|
-
var TopoSort = class {
|
|
129
|
-
constructor(graph, prior) {
|
|
130
|
-
this.graph = graph;
|
|
131
|
-
this.prior = prior;
|
|
132
|
-
this.dirty = true;
|
|
133
|
-
}
|
|
134
|
-
computeIncremental() {
|
|
135
|
-
if (!this.prior || this.graph.complete) {
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
this.levelMap = /* @__PURE__ */ new Map();
|
|
139
|
-
const addedNodes = /* @__PURE__ */ new Set();
|
|
140
|
-
const deletedNodes = /* @__PURE__ */ new Set();
|
|
141
|
-
const affectedNodes = /* @__PURE__ */ new Set();
|
|
142
|
-
if (this.graph.nodeMap) {
|
|
143
|
-
for (const [id, node] of this.graph.nodeMap) {
|
|
144
|
-
if (node === null) {
|
|
145
|
-
deletedNodes.add(id);
|
|
146
|
-
this.levelMap.delete(id);
|
|
147
|
-
} else if (!this.levelMap.has(id)) {
|
|
148
|
-
addedNodes.add(id);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
const totalNodes = Array.from(this.graph.nodes()).length;
|
|
153
|
-
const changeRatio = (addedNodes.size + deletedNodes.size) / totalNodes;
|
|
154
|
-
if (changeRatio > 0.3 || totalNodes < 20) {
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
for (const nodeId of deletedNodes) {
|
|
158
|
-
const priorNode = this.graph.prior.getNode(nodeId);
|
|
159
|
-
if (priorNode) {
|
|
160
|
-
for (const targetNode of priorNode.targetNodes()) {
|
|
161
|
-
affectedNodes.add(targetNode.props.id);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
for (const nodeId of addedNodes) {
|
|
166
|
-
const node = this.graph.getNode(nodeId);
|
|
167
|
-
if (!node) continue;
|
|
168
|
-
let maxPredLevel = -1;
|
|
169
|
-
for (const sourceNode of node.sourceNodes()) {
|
|
170
|
-
const sourceLevel = this.levelMap.get(sourceNode.props.id);
|
|
171
|
-
if (sourceLevel !== void 0) {
|
|
172
|
-
maxPredLevel = Math.max(maxPredLevel, sourceLevel);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
this.levelMap.set(nodeId, maxPredLevel + 1);
|
|
176
|
-
for (const targetNode of node.targetNodes()) {
|
|
177
|
-
affectedNodes.add(targetNode.props.id);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
const queue = Array.from(affectedNodes);
|
|
181
|
-
const visited = /* @__PURE__ */ new Set();
|
|
182
|
-
while (queue.length > 0) {
|
|
183
|
-
const nodeId = queue.shift();
|
|
184
|
-
if (visited.has(nodeId)) continue;
|
|
185
|
-
visited.add(nodeId);
|
|
186
|
-
const node = this.graph.getNode(nodeId);
|
|
187
|
-
if (!node) continue;
|
|
188
|
-
let maxPredLevel = -1;
|
|
189
|
-
for (const sourceNode of node.sourceNodes()) {
|
|
190
|
-
const sourceLevel = this.levelMap.get(sourceNode.props.id);
|
|
191
|
-
if (sourceLevel !== void 0) {
|
|
192
|
-
maxPredLevel = Math.max(maxPredLevel, sourceLevel);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
const oldLevel = this.levelMap.get(nodeId) ?? -1;
|
|
196
|
-
const newLevel = maxPredLevel + 1;
|
|
197
|
-
if (newLevel !== oldLevel) {
|
|
198
|
-
this.levelMap.set(nodeId, newLevel);
|
|
199
|
-
for (const targetNode of node.targetNodes()) {
|
|
200
|
-
if (!visited.has(targetNode.props.id)) {
|
|
201
|
-
queue.push(targetNode.props.id);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
computeFull() {
|
|
209
|
-
this.levelMap = /* @__PURE__ */ new Map();
|
|
210
|
-
const inDegree = /* @__PURE__ */ new Map();
|
|
211
|
-
const queue = [];
|
|
212
|
-
for (const node of this.graph.nodes()) {
|
|
213
|
-
let degree = 0;
|
|
214
|
-
for (const _ of node.sourceEdges()) {
|
|
215
|
-
degree++;
|
|
216
|
-
}
|
|
217
|
-
inDegree.set(node.props.id, degree);
|
|
218
|
-
if (degree === 0) {
|
|
219
|
-
this.levelMap.set(node.props.id, 0);
|
|
220
|
-
queue.push(node);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
let processed = 0;
|
|
224
|
-
while (queue.length > 0) {
|
|
225
|
-
const node = queue.shift();
|
|
226
|
-
const currentLevel = this.levelMap.get(node.props.id);
|
|
227
|
-
processed++;
|
|
228
|
-
for (const targetNode of node.targetNodes()) {
|
|
229
|
-
const targetId = targetNode.props.id;
|
|
230
|
-
const degree = inDegree.get(targetId) - 1;
|
|
231
|
-
inDegree.set(targetId, degree);
|
|
232
|
-
if (degree === 0) {
|
|
233
|
-
this.levelMap.set(targetId, currentLevel + 1);
|
|
234
|
-
queue.push(targetNode);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
const totalNodes = Array.from(this.graph.nodes()).length;
|
|
239
|
-
if (processed !== totalNodes) {
|
|
240
|
-
throw new Error("Graph contains a cycle - topological sort not possible");
|
|
241
|
-
}
|
|
242
|
-
this.dirty = false;
|
|
243
|
-
}
|
|
244
|
-
compute() {
|
|
245
|
-
if (this.computeIncremental()) {
|
|
246
|
-
this.dirty = false;
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
this.computeFull();
|
|
250
|
-
}
|
|
251
|
-
getLevel(nodeId) {
|
|
252
|
-
if (this.dirty) {
|
|
253
|
-
this.compute();
|
|
254
|
-
}
|
|
255
|
-
return this.levelMap?.get(nodeId);
|
|
256
|
-
}
|
|
257
|
-
getLevels() {
|
|
258
|
-
if (this.dirty) {
|
|
259
|
-
this.compute();
|
|
260
|
-
}
|
|
261
|
-
return new Map(this.levelMap);
|
|
262
|
-
}
|
|
263
|
-
*nodes() {
|
|
264
|
-
if (this.dirty) {
|
|
265
|
-
this.compute();
|
|
266
|
-
}
|
|
267
|
-
const nodesByLevel = /* @__PURE__ */ new Map();
|
|
268
|
-
for (const node of this.graph.nodes()) {
|
|
269
|
-
const level = this.levelMap?.get(node.props.id);
|
|
270
|
-
if (level !== void 0) {
|
|
271
|
-
if (!nodesByLevel.has(level)) {
|
|
272
|
-
nodesByLevel.set(level, []);
|
|
273
|
-
}
|
|
274
|
-
nodesByLevel.get(level).push(node);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
const levels = Array.from(nodesByLevel.keys()).sort((a, b) => a - b);
|
|
278
|
-
for (const level of levels) {
|
|
279
|
-
for (const node of nodesByLevel.get(level)) {
|
|
280
|
-
yield node;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
getNodesByLevel() {
|
|
285
|
-
if (this.dirty) {
|
|
286
|
-
this.compute();
|
|
287
|
-
}
|
|
288
|
-
const result = [];
|
|
289
|
-
for (const node of this.graph.nodes()) {
|
|
290
|
-
const level = this.levelMap?.get(node.props.id);
|
|
291
|
-
if (level !== void 0) {
|
|
292
|
-
if (!result[level]) {
|
|
293
|
-
result[level] = [];
|
|
294
|
-
}
|
|
295
|
-
result[level].push(node);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
return result;
|
|
299
|
-
}
|
|
300
|
-
invalidate() {
|
|
301
|
-
this.dirty = true;
|
|
302
|
-
}
|
|
303
|
-
hasCycle() {
|
|
304
|
-
try {
|
|
305
|
-
if (this.dirty) {
|
|
306
|
-
this.compute();
|
|
307
|
-
}
|
|
308
|
-
return false;
|
|
309
|
-
} catch (e) {
|
|
310
|
-
return true;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
function createTopoSort(graph, priorTopo) {
|
|
315
|
-
return new TopoSort(graph, priorTopo);
|
|
316
|
-
}
|
|
317
|
-
export {
|
|
318
|
-
Graph,
|
|
319
|
-
GraphEdge,
|
|
320
|
-
GraphNode,
|
|
321
|
-
TopoSort,
|
|
322
|
-
createTopoSort
|
|
323
|
-
};
|