effect 4.0.0-beta.79 → 4.0.0-beta.80
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/Duration.d.ts +8 -1
- package/dist/Duration.d.ts.map +1 -1
- package/dist/Duration.js +26 -25
- package/dist/Duration.js.map +1 -1
- package/dist/Graph.d.ts +173 -14
- package/dist/Graph.d.ts.map +1 -1
- package/dist/Graph.js +155 -66
- package/dist/Graph.js.map +1 -1
- package/dist/Schema.d.ts +7 -0
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +7 -0
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts +24 -0
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +24 -0
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/Stream.js +1 -1
- package/dist/Stream.js.map +1 -1
- package/dist/internal/schema/representation.js +8 -1
- package/dist/internal/schema/representation.js.map +1 -1
- package/dist/unstable/cli/Prompt.d.ts +74 -5
- package/dist/unstable/cli/Prompt.d.ts.map +1 -1
- package/dist/unstable/cli/Prompt.js +23 -3
- package/dist/unstable/cli/Prompt.js.map +1 -1
- package/package.json +1 -1
- package/src/Duration.ts +42 -32
- package/src/Graph.ts +309 -88
- package/src/Schema.ts +7 -0
- package/src/SchemaRepresentation.ts +24 -0
- package/src/Stream.ts +1 -1
- package/src/internal/schema/representation.ts +2 -1
- package/src/unstable/cli/Prompt.ts +102 -9
package/src/Graph.ts
CHANGED
|
@@ -1386,6 +1386,31 @@ export const mapEdges = <N, E, T extends Kind = "directed">(
|
|
|
1386
1386
|
}
|
|
1387
1387
|
}
|
|
1388
1388
|
|
|
1389
|
+
/**
|
|
1390
|
+
* @internal
|
|
1391
|
+
*/
|
|
1392
|
+
const rebuildAdjacency = <N, E, T extends Kind = "directed">(
|
|
1393
|
+
mutable: MutableGraph<N, E, T>
|
|
1394
|
+
): void => {
|
|
1395
|
+
mutable.adjacency.clear()
|
|
1396
|
+
mutable.reverseAdjacency.clear()
|
|
1397
|
+
|
|
1398
|
+
for (const nodeIndex of mutable.nodes.keys()) {
|
|
1399
|
+
mutable.adjacency.set(nodeIndex, [])
|
|
1400
|
+
mutable.reverseAdjacency.set(nodeIndex, [])
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
for (const [edgeIndex, edgeData] of mutable.edges) {
|
|
1404
|
+
mutable.adjacency.get(edgeData.source)!.push(edgeIndex)
|
|
1405
|
+
mutable.reverseAdjacency.get(edgeData.target)!.push(edgeIndex)
|
|
1406
|
+
|
|
1407
|
+
if (mutable.type === "undirected") {
|
|
1408
|
+
mutable.adjacency.get(edgeData.target)!.push(edgeIndex)
|
|
1409
|
+
mutable.reverseAdjacency.get(edgeData.source)!.push(edgeIndex)
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1389
1414
|
/**
|
|
1390
1415
|
* Swaps source and target nodes for every edge in a mutable graph.
|
|
1391
1416
|
*
|
|
@@ -1413,6 +1438,10 @@ export const mapEdges = <N, E, T extends Kind = "directed">(
|
|
|
1413
1438
|
export const reverse = <N, E, T extends Kind = "directed">(
|
|
1414
1439
|
mutable: MutableGraph<N, E, T>
|
|
1415
1440
|
): void => {
|
|
1441
|
+
if (mutable.type === "undirected") {
|
|
1442
|
+
return
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1416
1445
|
// Reverse all edges by swapping source and target
|
|
1417
1446
|
for (const [index, edgeData] of mutable.edges) {
|
|
1418
1447
|
mutable.edges.set(
|
|
@@ -1425,22 +1454,7 @@ export const reverse = <N, E, T extends Kind = "directed">(
|
|
|
1425
1454
|
)
|
|
1426
1455
|
}
|
|
1427
1456
|
|
|
1428
|
-
|
|
1429
|
-
mutable.adjacency.clear()
|
|
1430
|
-
mutable.reverseAdjacency.clear()
|
|
1431
|
-
|
|
1432
|
-
// Rebuild adjacency lists with reversed directions
|
|
1433
|
-
for (const [edgeIndex, edgeData] of mutable.edges) {
|
|
1434
|
-
// Add to forward adjacency (source -> target)
|
|
1435
|
-
const sourceEdges = mutable.adjacency.get(edgeData.source) || []
|
|
1436
|
-
sourceEdges.push(edgeIndex)
|
|
1437
|
-
mutable.adjacency.set(edgeData.source, sourceEdges)
|
|
1438
|
-
|
|
1439
|
-
// Add to reverse adjacency (target <- source)
|
|
1440
|
-
const targetEdges = mutable.reverseAdjacency.get(edgeData.target) || []
|
|
1441
|
-
targetEdges.push(edgeIndex)
|
|
1442
|
-
mutable.reverseAdjacency.set(edgeData.target, targetEdges)
|
|
1443
|
-
}
|
|
1457
|
+
rebuildAdjacency(mutable)
|
|
1444
1458
|
|
|
1445
1459
|
// Invalidate cycle flag since edge directions changed
|
|
1446
1460
|
mutable.acyclic = Option.none()
|
|
@@ -2131,8 +2145,11 @@ export const hasEdge: {
|
|
|
2131
2145
|
// Check if any edge in the adjacency list connects to the target
|
|
2132
2146
|
for (const edgeIndex of adjacencyList) {
|
|
2133
2147
|
const edge = graph.edges.get(edgeIndex)
|
|
2134
|
-
if (edge !== undefined
|
|
2135
|
-
|
|
2148
|
+
if (edge !== undefined) {
|
|
2149
|
+
const neighbor = graph.type === "undirected" && edge.target === source ? edge.source : edge.target
|
|
2150
|
+
if (neighbor === target) {
|
|
2151
|
+
return true
|
|
2152
|
+
}
|
|
2136
2153
|
}
|
|
2137
2154
|
}
|
|
2138
2155
|
|
|
@@ -2169,6 +2186,31 @@ export const edgeCount = <N, E, T extends Kind = "directed">(
|
|
|
2169
2186
|
graph: Graph<N, E, T> | MutableGraph<N, E, T>
|
|
2170
2187
|
): number => graph.edges.size
|
|
2171
2188
|
|
|
2189
|
+
const getDirectedNeighbors = <N, E>(
|
|
2190
|
+
graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
2191
|
+
nodeIndex: NodeIndex,
|
|
2192
|
+
direction: Direction
|
|
2193
|
+
): Array<NodeIndex> => {
|
|
2194
|
+
const adjacencyMap = direction === "incoming"
|
|
2195
|
+
? graph.reverseAdjacency
|
|
2196
|
+
: graph.adjacency
|
|
2197
|
+
|
|
2198
|
+
const adjacencyList = adjacencyMap.get(nodeIndex)
|
|
2199
|
+
if (adjacencyList === undefined) {
|
|
2200
|
+
return []
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
const result: Array<NodeIndex> = []
|
|
2204
|
+
for (const edgeIndex of adjacencyList) {
|
|
2205
|
+
const edge = graph.edges.get(edgeIndex)
|
|
2206
|
+
if (edge !== undefined) {
|
|
2207
|
+
result.push(direction === "incoming" ? edge.source : edge.target)
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
return result
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2172
2214
|
/**
|
|
2173
2215
|
* Returns the neighboring node indices for a node.
|
|
2174
2216
|
*
|
|
@@ -2286,24 +2328,160 @@ export const neighbors: {
|
|
|
2286
2328
|
return getUndirectedNeighbors(graph as any, nodeIndex)
|
|
2287
2329
|
}
|
|
2288
2330
|
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
return []
|
|
2292
|
-
}
|
|
2331
|
+
return getDirectedNeighbors(graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">, nodeIndex, "outgoing")
|
|
2332
|
+
})
|
|
2293
2333
|
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2334
|
+
/**
|
|
2335
|
+
* Returns the outgoing neighbor node indices for a node in a directed graph.
|
|
2336
|
+
*
|
|
2337
|
+
* **When to use**
|
|
2338
|
+
*
|
|
2339
|
+
* Use when you need the nodes reached by following outgoing edges from a node in
|
|
2340
|
+
* a directed graph.
|
|
2341
|
+
*
|
|
2342
|
+
* **Gotchas**
|
|
2343
|
+
*
|
|
2344
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
2345
|
+
*
|
|
2346
|
+
* @see {@link predecessors} for incoming neighbors in a directed graph
|
|
2347
|
+
* @see {@link neighbors} for generic neighbor lookup across graph kinds
|
|
2348
|
+
*
|
|
2349
|
+
* @category queries
|
|
2350
|
+
* @since 4.0.0
|
|
2351
|
+
*/
|
|
2352
|
+
export const successors: {
|
|
2353
|
+
/**
|
|
2354
|
+
* Returns the outgoing neighbor node indices for a node in a directed graph.
|
|
2355
|
+
*
|
|
2356
|
+
* **When to use**
|
|
2357
|
+
*
|
|
2358
|
+
* Use when you need the nodes reached by following outgoing edges from a node in
|
|
2359
|
+
* a directed graph.
|
|
2360
|
+
*
|
|
2361
|
+
* **Gotchas**
|
|
2362
|
+
*
|
|
2363
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
2364
|
+
*
|
|
2365
|
+
* @see {@link predecessors} for incoming neighbors in a directed graph
|
|
2366
|
+
* @see {@link neighbors} for generic neighbor lookup across graph kinds
|
|
2367
|
+
*
|
|
2368
|
+
* @category queries
|
|
2369
|
+
* @since 4.0.0
|
|
2370
|
+
*/
|
|
2371
|
+
(nodeIndex: NodeIndex): <N, E>(graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">) => Array<NodeIndex>
|
|
2372
|
+
/**
|
|
2373
|
+
* Returns the outgoing neighbor node indices for a node in a directed graph.
|
|
2374
|
+
*
|
|
2375
|
+
* **When to use**
|
|
2376
|
+
*
|
|
2377
|
+
* Use when you need the nodes reached by following outgoing edges from a node in
|
|
2378
|
+
* a directed graph.
|
|
2379
|
+
*
|
|
2380
|
+
* **Gotchas**
|
|
2381
|
+
*
|
|
2382
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
2383
|
+
*
|
|
2384
|
+
* @see {@link predecessors} for incoming neighbors in a directed graph
|
|
2385
|
+
* @see {@link neighbors} for generic neighbor lookup across graph kinds
|
|
2386
|
+
*
|
|
2387
|
+
* @category queries
|
|
2388
|
+
* @since 4.0.0
|
|
2389
|
+
*/
|
|
2390
|
+
<N, E>(
|
|
2391
|
+
graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
2392
|
+
nodeIndex: NodeIndex
|
|
2393
|
+
): Array<NodeIndex>
|
|
2394
|
+
} = dual(2, <N, E, T extends Kind = "directed">(
|
|
2395
|
+
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
|
|
2396
|
+
nodeIndex: NodeIndex
|
|
2397
|
+
): Array<NodeIndex> => {
|
|
2398
|
+
if (graph.type === "undirected") {
|
|
2399
|
+
throw new GraphError({ message: "Cannot get successors of undirected graph" })
|
|
2300
2400
|
}
|
|
2401
|
+
return getDirectedNeighbors(graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">, nodeIndex, "outgoing")
|
|
2402
|
+
})
|
|
2301
2403
|
|
|
2302
|
-
|
|
2404
|
+
/**
|
|
2405
|
+
* Returns the incoming neighbor node indices for a node in a directed graph.
|
|
2406
|
+
*
|
|
2407
|
+
* **When to use**
|
|
2408
|
+
*
|
|
2409
|
+
* Use when you need the nodes that reach a node by following incoming edges in a
|
|
2410
|
+
* directed graph.
|
|
2411
|
+
*
|
|
2412
|
+
* **Gotchas**
|
|
2413
|
+
*
|
|
2414
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
2415
|
+
*
|
|
2416
|
+
* @see {@link successors} for outgoing neighbors in a directed graph
|
|
2417
|
+
* @see {@link neighbors} for generic neighbor lookup across graph kinds
|
|
2418
|
+
*
|
|
2419
|
+
* @category queries
|
|
2420
|
+
* @since 4.0.0
|
|
2421
|
+
*/
|
|
2422
|
+
export const predecessors: {
|
|
2423
|
+
/**
|
|
2424
|
+
* Returns the incoming neighbor node indices for a node in a directed graph.
|
|
2425
|
+
*
|
|
2426
|
+
* **When to use**
|
|
2427
|
+
*
|
|
2428
|
+
* Use when you need the nodes that reach a node by following incoming edges in a
|
|
2429
|
+
* directed graph.
|
|
2430
|
+
*
|
|
2431
|
+
* **Gotchas**
|
|
2432
|
+
*
|
|
2433
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
2434
|
+
*
|
|
2435
|
+
* @see {@link successors} for outgoing neighbors in a directed graph
|
|
2436
|
+
* @see {@link neighbors} for generic neighbor lookup across graph kinds
|
|
2437
|
+
*
|
|
2438
|
+
* @category queries
|
|
2439
|
+
* @since 4.0.0
|
|
2440
|
+
*/
|
|
2441
|
+
(nodeIndex: NodeIndex): <N, E>(graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">) => Array<NodeIndex>
|
|
2442
|
+
/**
|
|
2443
|
+
* Returns the incoming neighbor node indices for a node in a directed graph.
|
|
2444
|
+
*
|
|
2445
|
+
* **When to use**
|
|
2446
|
+
*
|
|
2447
|
+
* Use when you need the nodes that reach a node by following incoming edges in a
|
|
2448
|
+
* directed graph.
|
|
2449
|
+
*
|
|
2450
|
+
* **Gotchas**
|
|
2451
|
+
*
|
|
2452
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
2453
|
+
*
|
|
2454
|
+
* @see {@link successors} for outgoing neighbors in a directed graph
|
|
2455
|
+
* @see {@link neighbors} for generic neighbor lookup across graph kinds
|
|
2456
|
+
*
|
|
2457
|
+
* @category queries
|
|
2458
|
+
* @since 4.0.0
|
|
2459
|
+
*/
|
|
2460
|
+
<N, E>(
|
|
2461
|
+
graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
2462
|
+
nodeIndex: NodeIndex
|
|
2463
|
+
): Array<NodeIndex>
|
|
2464
|
+
} = dual(2, <N, E, T extends Kind = "directed">(
|
|
2465
|
+
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
|
|
2466
|
+
nodeIndex: NodeIndex
|
|
2467
|
+
): Array<NodeIndex> => {
|
|
2468
|
+
if (graph.type === "undirected") {
|
|
2469
|
+
throw new GraphError({ message: "Cannot get predecessors of undirected graph" })
|
|
2470
|
+
}
|
|
2471
|
+
return getDirectedNeighbors(graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">, nodeIndex, "incoming")
|
|
2303
2472
|
})
|
|
2304
2473
|
|
|
2305
2474
|
/**
|
|
2306
|
-
* Gets neighbors of a node in a specific direction
|
|
2475
|
+
* Gets directed neighbors of a node in a specific direction.
|
|
2476
|
+
*
|
|
2477
|
+
* **When to use**
|
|
2478
|
+
*
|
|
2479
|
+
* Use when maintaining existing code that already passes an explicit traversal
|
|
2480
|
+
* direction. New code should prefer `successors` or `predecessors`.
|
|
2481
|
+
*
|
|
2482
|
+
* **Gotchas**
|
|
2483
|
+
*
|
|
2484
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
2307
2485
|
*
|
|
2308
2486
|
* **Example** (Traversing directed neighbors)
|
|
2309
2487
|
*
|
|
@@ -2326,12 +2504,24 @@ export const neighbors: {
|
|
|
2326
2504
|
* const incoming = Graph.neighborsDirected(graph, nodeB, "incoming")
|
|
2327
2505
|
* ```
|
|
2328
2506
|
*
|
|
2507
|
+
* @deprecated Use {@link successors} for outgoing neighbors or {@link predecessors} for incoming neighbors.
|
|
2508
|
+
* @see {@link successors} for outgoing neighbors in a directed graph
|
|
2509
|
+
* @see {@link predecessors} for incoming neighbors in a directed graph
|
|
2329
2510
|
* @category queries
|
|
2330
2511
|
* @since 3.18.0
|
|
2331
2512
|
*/
|
|
2332
2513
|
export const neighborsDirected: {
|
|
2333
2514
|
/**
|
|
2334
|
-
* Gets neighbors of a node in a specific direction
|
|
2515
|
+
* Gets directed neighbors of a node in a specific direction.
|
|
2516
|
+
*
|
|
2517
|
+
* **When to use**
|
|
2518
|
+
*
|
|
2519
|
+
* Use when maintaining existing code that already passes an explicit traversal
|
|
2520
|
+
* direction. New code should prefer `successors` or `predecessors`.
|
|
2521
|
+
*
|
|
2522
|
+
* **Gotchas**
|
|
2523
|
+
*
|
|
2524
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
2335
2525
|
*
|
|
2336
2526
|
* **Example** (Traversing directed neighbors)
|
|
2337
2527
|
*
|
|
@@ -2354,12 +2544,24 @@ export const neighborsDirected: {
|
|
|
2354
2544
|
* const incoming = Graph.neighborsDirected(graph, nodeB, "incoming")
|
|
2355
2545
|
* ```
|
|
2356
2546
|
*
|
|
2547
|
+
* @deprecated Use {@link successors} for outgoing neighbors or {@link predecessors} for incoming neighbors.
|
|
2548
|
+
* @see {@link successors} for outgoing neighbors in a directed graph
|
|
2549
|
+
* @see {@link predecessors} for incoming neighbors in a directed graph
|
|
2357
2550
|
* @category queries
|
|
2358
2551
|
* @since 3.18.0
|
|
2359
2552
|
*/
|
|
2360
|
-
(nodeIndex: NodeIndex, direction: Direction): <N, E
|
|
2553
|
+
(nodeIndex: NodeIndex, direction: Direction): <N, E>(graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">) => Array<NodeIndex>
|
|
2361
2554
|
/**
|
|
2362
|
-
* Gets neighbors of a node in a specific direction
|
|
2555
|
+
* Gets directed neighbors of a node in a specific direction.
|
|
2556
|
+
*
|
|
2557
|
+
* **When to use**
|
|
2558
|
+
*
|
|
2559
|
+
* Use when maintaining existing code that already passes an explicit traversal
|
|
2560
|
+
* direction. New code should prefer `successors` or `predecessors`.
|
|
2561
|
+
*
|
|
2562
|
+
* **Gotchas**
|
|
2563
|
+
*
|
|
2564
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
2363
2565
|
*
|
|
2364
2566
|
* **Example** (Traversing directed neighbors)
|
|
2365
2567
|
*
|
|
@@ -2382,11 +2584,14 @@ export const neighborsDirected: {
|
|
|
2382
2584
|
* const incoming = Graph.neighborsDirected(graph, nodeB, "incoming")
|
|
2383
2585
|
* ```
|
|
2384
2586
|
*
|
|
2587
|
+
* @deprecated Use {@link successors} for outgoing neighbors or {@link predecessors} for incoming neighbors.
|
|
2588
|
+
* @see {@link successors} for outgoing neighbors in a directed graph
|
|
2589
|
+
* @see {@link predecessors} for incoming neighbors in a directed graph
|
|
2385
2590
|
* @category queries
|
|
2386
2591
|
* @since 3.18.0
|
|
2387
2592
|
*/
|
|
2388
|
-
<N, E
|
|
2389
|
-
graph: Graph<N, E,
|
|
2593
|
+
<N, E>(
|
|
2594
|
+
graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
2390
2595
|
nodeIndex: NodeIndex,
|
|
2391
2596
|
direction: Direction
|
|
2392
2597
|
): Array<NodeIndex>
|
|
@@ -2395,28 +2600,10 @@ export const neighborsDirected: {
|
|
|
2395
2600
|
nodeIndex: NodeIndex,
|
|
2396
2601
|
direction: Direction
|
|
2397
2602
|
): Array<NodeIndex> => {
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
: graph.adjacency
|
|
2401
|
-
|
|
2402
|
-
const adjacencyList = adjacencyMap.get(nodeIndex)
|
|
2403
|
-
if (adjacencyList === undefined) {
|
|
2404
|
-
return []
|
|
2405
|
-
}
|
|
2406
|
-
|
|
2407
|
-
const result: Array<NodeIndex> = []
|
|
2408
|
-
for (const edgeIndex of adjacencyList) {
|
|
2409
|
-
const edge = graph.edges.get(edgeIndex)
|
|
2410
|
-
if (edge !== undefined) {
|
|
2411
|
-
// For incoming direction, we want the source node instead of target
|
|
2412
|
-
const neighborNode = direction === "incoming"
|
|
2413
|
-
? edge.source
|
|
2414
|
-
: edge.target
|
|
2415
|
-
result.push(neighborNode)
|
|
2416
|
-
}
|
|
2603
|
+
if (graph.type === "undirected") {
|
|
2604
|
+
throw new GraphError({ message: "Cannot get directed neighbors of undirected graph" })
|
|
2417
2605
|
}
|
|
2418
|
-
|
|
2419
|
-
return result
|
|
2606
|
+
return getDirectedNeighbors(graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">, nodeIndex, direction)
|
|
2420
2607
|
})
|
|
2421
2608
|
|
|
2422
2609
|
// =============================================================================
|
|
@@ -3603,7 +3790,11 @@ export const isAcyclic = <N, E, T extends Kind = "directed">(
|
|
|
3603
3790
|
recursionStack.add(node)
|
|
3604
3791
|
|
|
3605
3792
|
// Get neighbors for this node
|
|
3606
|
-
const nodeNeighbors =
|
|
3793
|
+
const nodeNeighbors = getDirectedNeighbors(
|
|
3794
|
+
graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
3795
|
+
node,
|
|
3796
|
+
"outgoing"
|
|
3797
|
+
)
|
|
3607
3798
|
stack[stack.length - 1] = [node, nodeNeighbors, 0, false]
|
|
3608
3799
|
continue
|
|
3609
3800
|
}
|
|
@@ -3757,7 +3948,7 @@ const getTraversalNeighbors = <N, E, T extends Kind>(
|
|
|
3757
3948
|
): Array<NodeIndex> =>
|
|
3758
3949
|
graph.type === "undirected"
|
|
3759
3950
|
? getUndirectedNeighbors(graph as any, nodeIndex)
|
|
3760
|
-
:
|
|
3951
|
+
: getDirectedNeighbors(graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">, nodeIndex, direction)
|
|
3761
3952
|
|
|
3762
3953
|
const getTraversableNeighbor = <E, T extends Kind>(
|
|
3763
3954
|
graph: Graph<unknown, E, T> | MutableGraph<unknown, E, T>,
|
|
@@ -3828,6 +4019,10 @@ export const connectedComponents = <N, E>(
|
|
|
3828
4019
|
* Finds strongly connected components in a directed graph using Kosaraju's algorithm.
|
|
3829
4020
|
* Each SCC is represented as an array of node indices.
|
|
3830
4021
|
*
|
|
4022
|
+
* **Gotchas**
|
|
4023
|
+
*
|
|
4024
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
4025
|
+
*
|
|
3831
4026
|
* **Example** (Finding strongly connected components)
|
|
3832
4027
|
*
|
|
3833
4028
|
* ```ts
|
|
@@ -3849,9 +4044,13 @@ export const connectedComponents = <N, E>(
|
|
|
3849
4044
|
* @category algorithms
|
|
3850
4045
|
* @since 3.18.0
|
|
3851
4046
|
*/
|
|
3852
|
-
export const stronglyConnectedComponents = <N, E
|
|
3853
|
-
graph: Graph<N, E,
|
|
4047
|
+
export const stronglyConnectedComponents = <N, E>(
|
|
4048
|
+
graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">
|
|
3854
4049
|
): Array<Array<NodeIndex>> => {
|
|
4050
|
+
if ((graph as Graph<N, E, Kind> | MutableGraph<N, E, Kind>).type === "undirected") {
|
|
4051
|
+
throw new GraphError({ message: "Cannot find strongly connected components of undirected graph" })
|
|
4052
|
+
}
|
|
4053
|
+
|
|
3855
4054
|
const visited = new Set<NodeIndex>()
|
|
3856
4055
|
const finishOrder: Array<NodeIndex> = []
|
|
3857
4056
|
// Iterate directly over node keys
|
|
@@ -3877,7 +4076,7 @@ export const stronglyConnectedComponents = <N, E, T extends Kind = "directed">(
|
|
|
3877
4076
|
}
|
|
3878
4077
|
|
|
3879
4078
|
visited.add(node)
|
|
3880
|
-
const nodeNeighborsList =
|
|
4079
|
+
const nodeNeighborsList = getDirectedNeighbors(graph, node, "outgoing")
|
|
3881
4080
|
stack[stack.length - 1] = [node, nodeNeighborsList, 0, false]
|
|
3882
4081
|
continue
|
|
3883
4082
|
}
|
|
@@ -4010,6 +4209,22 @@ export interface DijkstraConfig<E> {
|
|
|
4010
4209
|
cost: (edgeData: E) => number
|
|
4011
4210
|
}
|
|
4012
4211
|
|
|
4212
|
+
const validateNonNegativeEdgeWeights = <N, E, T extends Kind = "directed">(
|
|
4213
|
+
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
|
|
4214
|
+
cost: (edgeData: E) => number,
|
|
4215
|
+
algorithm: string
|
|
4216
|
+
): Map<EdgeIndex, number> => {
|
|
4217
|
+
const edgeWeights = new Map<EdgeIndex, number>()
|
|
4218
|
+
for (const [edgeIndex, edgeData] of graph.edges) {
|
|
4219
|
+
const weight = cost(edgeData.data)
|
|
4220
|
+
if (weight < 0 || Number.isNaN(weight)) {
|
|
4221
|
+
throw new GraphError({ message: `${algorithm} requires non-negative edge weights` })
|
|
4222
|
+
}
|
|
4223
|
+
edgeWeights.set(edgeIndex, weight)
|
|
4224
|
+
}
|
|
4225
|
+
return edgeWeights
|
|
4226
|
+
}
|
|
4227
|
+
|
|
4013
4228
|
/**
|
|
4014
4229
|
* Finds the shortest path from the configured source node to the target node
|
|
4015
4230
|
* using Dijkstra's algorithm.
|
|
@@ -4142,6 +4357,8 @@ export const dijkstra: {
|
|
|
4142
4357
|
throw missingNode(config.target)
|
|
4143
4358
|
}
|
|
4144
4359
|
|
|
4360
|
+
const edgeWeights = validateNonNegativeEdgeWeights(graph, config.cost, "Dijkstra's algorithm")
|
|
4361
|
+
|
|
4145
4362
|
// Early return if source equals target
|
|
4146
4363
|
if (config.source === config.target) {
|
|
4147
4364
|
return Option.some({
|
|
@@ -4202,12 +4419,7 @@ export const dijkstra: {
|
|
|
4202
4419
|
const edge = graph.edges.get(edgeIndex)
|
|
4203
4420
|
if (edge !== undefined) {
|
|
4204
4421
|
const neighbor = getTraversableNeighbor(graph, currentNode, edge)
|
|
4205
|
-
const cost =
|
|
4206
|
-
|
|
4207
|
-
// Validate non-negative weights
|
|
4208
|
-
if (cost < 0) {
|
|
4209
|
-
throw new GraphError({ message: "Dijkstra's algorithm requires non-negative edge weights" })
|
|
4210
|
-
}
|
|
4422
|
+
const cost = edgeWeights.get(edgeIndex)!
|
|
4211
4423
|
|
|
4212
4424
|
const newDistance = currentDistance + cost
|
|
4213
4425
|
const neighborDistance = distances.get(neighbor)!
|
|
@@ -4538,7 +4750,7 @@ export interface AstarConfig<E, N> {
|
|
|
4538
4750
|
* **Details**
|
|
4539
4751
|
*
|
|
4540
4752
|
* The edge-cost function must return non-negative weights, and the heuristic
|
|
4541
|
-
* should be
|
|
4753
|
+
* should be consistent to preserve shortest-path guarantees. Returns
|
|
4542
4754
|
* `Option.none()` when the target is not reachable, and throws a `GraphError`
|
|
4543
4755
|
* when either endpoint is missing or a negative edge cost is encountered.
|
|
4544
4756
|
*
|
|
@@ -4585,7 +4797,7 @@ export const astar: {
|
|
|
4585
4797
|
* **Details**
|
|
4586
4798
|
*
|
|
4587
4799
|
* The edge-cost function must return non-negative weights, and the heuristic
|
|
4588
|
-
* should be
|
|
4800
|
+
* should be consistent to preserve shortest-path guarantees. Returns
|
|
4589
4801
|
* `Option.none()` when the target is not reachable, and throws a `GraphError`
|
|
4590
4802
|
* when either endpoint is missing or a negative edge cost is encountered.
|
|
4591
4803
|
*
|
|
@@ -4632,7 +4844,7 @@ export const astar: {
|
|
|
4632
4844
|
* **Details**
|
|
4633
4845
|
*
|
|
4634
4846
|
* The edge-cost function must return non-negative weights, and the heuristic
|
|
4635
|
-
* should be
|
|
4847
|
+
* should be consistent to preserve shortest-path guarantees. Returns
|
|
4636
4848
|
* `Option.none()` when the target is not reachable, and throws a `GraphError`
|
|
4637
4849
|
* when either endpoint is missing or a negative edge cost is encountered.
|
|
4638
4850
|
*
|
|
@@ -4684,6 +4896,8 @@ export const astar: {
|
|
|
4684
4896
|
throw missingNode(config.target)
|
|
4685
4897
|
}
|
|
4686
4898
|
|
|
4899
|
+
const edgeWeights = validateNonNegativeEdgeWeights(graph, config.cost, "A* algorithm")
|
|
4900
|
+
|
|
4687
4901
|
// Early return if source equals target
|
|
4688
4902
|
if (config.source === config.target) {
|
|
4689
4903
|
return Option.some({
|
|
@@ -4759,12 +4973,7 @@ export const astar: {
|
|
|
4759
4973
|
const edge = graph.edges.get(edgeIndex)
|
|
4760
4974
|
if (edge !== undefined) {
|
|
4761
4975
|
const neighbor = getTraversableNeighbor(graph, currentNode, edge)
|
|
4762
|
-
const weight =
|
|
4763
|
-
|
|
4764
|
-
// Validate non-negative weights
|
|
4765
|
-
if (weight < 0) {
|
|
4766
|
-
throw new GraphError({ message: "A* algorithm requires non-negative edge weights" })
|
|
4767
|
-
}
|
|
4976
|
+
const weight = edgeWeights.get(edgeIndex)!
|
|
4768
4977
|
|
|
4769
4978
|
const tentativeGScore = currentGScore + weight
|
|
4770
4979
|
const neighborGScore = gScore.get(neighbor)!
|
|
@@ -5697,14 +5906,17 @@ export const bfs: {
|
|
|
5697
5906
|
*
|
|
5698
5907
|
* **When to use**
|
|
5699
5908
|
*
|
|
5700
|
-
* Use to
|
|
5701
|
-
* starting from every zero in-degree node.
|
|
5909
|
+
* Use to prioritize specific zero in-degree nodes in a topological sort.
|
|
5702
5910
|
*
|
|
5703
5911
|
* **Details**
|
|
5704
5912
|
*
|
|
5705
|
-
* `initials` optionally supplies
|
|
5706
|
-
* entries.
|
|
5707
|
-
* in-degree.
|
|
5913
|
+
* `initials` optionally supplies zero in-degree node indices used as
|
|
5914
|
+
* prioritized initial queue entries. Topological sorting still includes the
|
|
5915
|
+
* other zero in-degree nodes and produces a complete topological order.
|
|
5916
|
+
*
|
|
5917
|
+
* **Gotchas**
|
|
5918
|
+
*
|
|
5919
|
+
* Throws a `GraphError` when any initial node has incoming edges.
|
|
5708
5920
|
*
|
|
5709
5921
|
* @see {@link topo} for the iterator that consumes this configuration
|
|
5710
5922
|
*
|
|
@@ -5882,6 +6094,7 @@ export const topo: {
|
|
|
5882
6094
|
[Symbol.iterator]: () => {
|
|
5883
6095
|
const inDegree = new Map<NodeIndex, number>()
|
|
5884
6096
|
const remaining = new Set<NodeIndex>()
|
|
6097
|
+
const initialSet = new Set(initials)
|
|
5885
6098
|
const queue = [...initials]
|
|
5886
6099
|
|
|
5887
6100
|
// Initialize in-degree counts
|
|
@@ -5896,12 +6109,16 @@ export const topo: {
|
|
|
5896
6109
|
inDegree.set(edgeData.target, currentInDegree + 1)
|
|
5897
6110
|
}
|
|
5898
6111
|
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
6112
|
+
for (const nodeIndex of initials) {
|
|
6113
|
+
if (inDegree.get(nodeIndex)! !== 0) {
|
|
6114
|
+
throw new GraphError({ message: `Initial node ${nodeIndex} has incoming edges` })
|
|
6115
|
+
}
|
|
6116
|
+
}
|
|
6117
|
+
|
|
6118
|
+
// Add remaining zero in-degree nodes after prioritized initials.
|
|
6119
|
+
for (const [nodeIndex, degree] of inDegree) {
|
|
6120
|
+
if (degree === 0 && !initialSet.has(nodeIndex)) {
|
|
6121
|
+
queue.push(nodeIndex)
|
|
5905
6122
|
}
|
|
5906
6123
|
}
|
|
5907
6124
|
|
|
@@ -5913,7 +6130,11 @@ export const topo: {
|
|
|
5913
6130
|
remaining.delete(current)
|
|
5914
6131
|
|
|
5915
6132
|
// Process outgoing edges, reducing in-degree of targets
|
|
5916
|
-
const neighbors =
|
|
6133
|
+
const neighbors = getDirectedNeighbors(
|
|
6134
|
+
graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
6135
|
+
current,
|
|
6136
|
+
"outgoing"
|
|
6137
|
+
)
|
|
5917
6138
|
for (const neighbor of neighbors) {
|
|
5918
6139
|
if (remaining.has(neighbor)) {
|
|
5919
6140
|
const currentInDegree = inDegree.get(neighbor) || 0
|
package/src/Schema.ts
CHANGED
|
@@ -13258,6 +13258,13 @@ export interface ToJsonSchemaOptions {
|
|
|
13258
13258
|
* properties and synthesized check descriptions; it does not change the draft
|
|
13259
13259
|
* target.
|
|
13260
13260
|
*
|
|
13261
|
+
* **Gotchas**
|
|
13262
|
+
*
|
|
13263
|
+
* JSON Schema generation is best-effort. Some Effect schema semantics cannot
|
|
13264
|
+
* be represented exactly in JSON Schema, and importing an emitted JSON Schema
|
|
13265
|
+
* may produce an equivalent approximation rather than the original schema
|
|
13266
|
+
* shape.
|
|
13267
|
+
*
|
|
13261
13268
|
* @category converting
|
|
13262
13269
|
* @since 4.0.0
|
|
13263
13270
|
*/
|
|
@@ -2179,6 +2179,13 @@ export function toSchema<S extends Schema.Top = Schema.Top>(document: Document,
|
|
|
2179
2179
|
* Use when you need to produce a standard JSON Schema document from a schema
|
|
2180
2180
|
* representation `Document`.
|
|
2181
2181
|
*
|
|
2182
|
+
* **Gotchas**
|
|
2183
|
+
*
|
|
2184
|
+
* JSON Schema generation is best-effort. Some Effect schema representation
|
|
2185
|
+
* semantics cannot be represented exactly in JSON Schema, and importing an
|
|
2186
|
+
* emitted JSON Schema may produce an equivalent approximation rather than the
|
|
2187
|
+
* original representation shape.
|
|
2188
|
+
*
|
|
2182
2189
|
* **Example** (Generating JSON Schema)
|
|
2183
2190
|
*
|
|
2184
2191
|
* ```ts
|
|
@@ -2211,6 +2218,13 @@ export const toJsonSchemaDocument: (
|
|
|
2211
2218
|
* Use when you need to export related schema representation documents together
|
|
2212
2219
|
* so shared definitions stay in multi-document JSON Schema form.
|
|
2213
2220
|
*
|
|
2221
|
+
* **Gotchas**
|
|
2222
|
+
*
|
|
2223
|
+
* JSON Schema generation is best-effort. Some Effect schema representation
|
|
2224
|
+
* semantics cannot be represented exactly in JSON Schema, and importing an
|
|
2225
|
+
* emitted JSON Schema may produce equivalent approximations rather than the
|
|
2226
|
+
* original representation shapes.
|
|
2227
|
+
*
|
|
2214
2228
|
* @see {@link MultiDocument}
|
|
2215
2229
|
* @see {@link toJsonSchemaDocument}
|
|
2216
2230
|
* @see {@link fromJsonSchemaMultiDocument}
|
|
@@ -2962,6 +2976,11 @@ function toRuntimeRegExp(regExp: RegExp): string {
|
|
|
2962
2976
|
*
|
|
2963
2977
|
* **Gotchas**
|
|
2964
2978
|
*
|
|
2979
|
+
* JSON Schema import is best-effort. Some JSON Schema constructs do not map
|
|
2980
|
+
* exactly to Effect schema representations, and importing a schema previously
|
|
2981
|
+
* emitted by `toJsonSchemaDocument` may produce an equivalent approximation
|
|
2982
|
+
* rather than the original representation shape.
|
|
2983
|
+
*
|
|
2965
2984
|
* This throws if a `$ref` cannot be resolved within the document's definitions.
|
|
2966
2985
|
* Circular `$ref`s are detected and cause an error.
|
|
2967
2986
|
*
|
|
@@ -3002,6 +3021,11 @@ export function fromJsonSchemaDocument(document: JsonSchema.Document<"draft-2020
|
|
|
3002
3021
|
*
|
|
3003
3022
|
* **Gotchas**
|
|
3004
3023
|
*
|
|
3024
|
+
* JSON Schema import is best-effort. Some JSON Schema constructs do not map
|
|
3025
|
+
* exactly to Effect schema representations, and importing schemas previously
|
|
3026
|
+
* emitted by `toJsonSchemaMultiDocument` may produce equivalent approximations
|
|
3027
|
+
* rather than the original representation shapes.
|
|
3028
|
+
*
|
|
3005
3029
|
* This throws if a `$ref` cannot be resolved.
|
|
3006
3030
|
*
|
|
3007
3031
|
* @see {@link MultiDocument}
|
package/src/Stream.ts
CHANGED
|
@@ -1416,7 +1416,7 @@ export const fromReadableStream = <A, E>(
|
|
|
1416
1416
|
scope,
|
|
1417
1417
|
options.releaseLockOnEnd
|
|
1418
1418
|
? Effect.sync(() => reader.releaseLock())
|
|
1419
|
-
: Effect.promise(() => reader.cancel())
|
|
1419
|
+
: Effect.promise(() => reader.cancel().catch(constVoid))
|
|
1420
1420
|
)
|
|
1421
1421
|
return Effect.flatMap(
|
|
1422
1422
|
Effect.tryPromise({
|
|
@@ -362,8 +362,9 @@ export function toJsonSchemaMultiDocument(
|
|
|
362
362
|
switch (schema._tag) {
|
|
363
363
|
case "Any":
|
|
364
364
|
case "Unknown":
|
|
365
|
-
case "ObjectKeyword":
|
|
366
365
|
return {}
|
|
366
|
+
case "ObjectKeyword":
|
|
367
|
+
return { anyOf: [{ type: "object" }, { type: "array" }] }
|
|
367
368
|
case "Void":
|
|
368
369
|
case "Undefined":
|
|
369
370
|
return { type: "null" }
|