effect 3.21.5 → 3.22.1
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/cjs/Context.js +1 -1
- package/dist/cjs/Graph.js +123 -66
- package/dist/cjs/Graph.js.map +1 -1
- package/dist/cjs/Mailbox.js +3 -2
- package/dist/cjs/Mailbox.js.map +1 -1
- package/dist/cjs/ParseResult.js +18 -0
- package/dist/cjs/ParseResult.js.map +1 -1
- package/dist/cjs/internal/config.js +5 -1
- package/dist/cjs/internal/config.js.map +1 -1
- package/dist/cjs/internal/configProvider.js +14 -1
- package/dist/cjs/internal/configProvider.js.map +1 -1
- package/dist/cjs/internal/effect/circular.js +5 -4
- package/dist/cjs/internal/effect/circular.js.map +1 -1
- package/dist/cjs/internal/mailbox.js +11 -19
- package/dist/cjs/internal/mailbox.js.map +1 -1
- package/dist/cjs/internal/opCodes/config.js +3 -1
- package/dist/cjs/internal/opCodes/config.js.map +1 -1
- package/dist/cjs/internal/stream/emit.js +6 -34
- package/dist/cjs/internal/stream/emit.js.map +1 -1
- package/dist/cjs/internal/stream.js +26 -16
- package/dist/cjs/internal/stream.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/Context.d.ts +1 -1
- package/dist/dts/Graph.d.ts +22 -3
- package/dist/dts/Graph.d.ts.map +1 -1
- package/dist/dts/Mailbox.d.ts.map +1 -1
- package/dist/dts/ParseResult.d.ts.map +1 -1
- package/dist/dts/internal/stream.d.ts.map +1 -1
- package/dist/esm/Context.js +1 -1
- package/dist/esm/Graph.js +116 -61
- package/dist/esm/Graph.js.map +1 -1
- package/dist/esm/Mailbox.js +3 -2
- package/dist/esm/Mailbox.js.map +1 -1
- package/dist/esm/ParseResult.js +18 -0
- package/dist/esm/ParseResult.js.map +1 -1
- package/dist/esm/internal/config.js +5 -1
- package/dist/esm/internal/config.js.map +1 -1
- package/dist/esm/internal/configProvider.js +14 -1
- package/dist/esm/internal/configProvider.js.map +1 -1
- package/dist/esm/internal/effect/circular.js +5 -4
- package/dist/esm/internal/effect/circular.js.map +1 -1
- package/dist/esm/internal/mailbox.js +10 -17
- package/dist/esm/internal/mailbox.js.map +1 -1
- package/dist/esm/internal/opCodes/config.js +2 -0
- package/dist/esm/internal/opCodes/config.js.map +1 -1
- package/dist/esm/internal/stream/emit.js +6 -34
- package/dist/esm/internal/stream/emit.js.map +1 -1
- package/dist/esm/internal/stream.js +22 -13
- package/dist/esm/internal/stream.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/package.json +1 -1
- package/src/Context.ts +1 -1
- package/src/Graph.ts +149 -77
- package/src/Mailbox.ts +3 -2
- package/src/ParseResult.ts +18 -0
- package/src/internal/config.ts +14 -1
- package/src/internal/configProvider.ts +24 -1
- package/src/internal/effect/circular.ts +5 -4
- package/src/internal/mailbox.ts +13 -52
- package/src/internal/opCodes/config.ts +6 -0
- package/src/internal/stream/emit.ts +7 -39
- package/src/internal/stream.ts +62 -24
- package/src/internal/version.ts +1 -1
package/package.json
CHANGED
package/src/Context.ts
CHANGED
package/src/Graph.ts
CHANGED
|
@@ -872,6 +872,29 @@ export const mapEdges = <N, E, T extends Kind = "directed">(
|
|
|
872
872
|
}
|
|
873
873
|
}
|
|
874
874
|
|
|
875
|
+
/** @internal */
|
|
876
|
+
const rebuildAdjacency = <N, E, T extends Kind = "directed">(
|
|
877
|
+
mutable: MutableGraph<N, E, T>
|
|
878
|
+
): void => {
|
|
879
|
+
mutable.adjacency.clear()
|
|
880
|
+
mutable.reverseAdjacency.clear()
|
|
881
|
+
|
|
882
|
+
for (const nodeIndex of mutable.nodes.keys()) {
|
|
883
|
+
mutable.adjacency.set(nodeIndex, [])
|
|
884
|
+
mutable.reverseAdjacency.set(nodeIndex, [])
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
for (const [edgeIndex, edgeData] of mutable.edges) {
|
|
888
|
+
mutable.adjacency.get(edgeData.source)!.push(edgeIndex)
|
|
889
|
+
mutable.reverseAdjacency.get(edgeData.target)!.push(edgeIndex)
|
|
890
|
+
|
|
891
|
+
if (mutable.type === "undirected") {
|
|
892
|
+
mutable.adjacency.get(edgeData.target)!.push(edgeIndex)
|
|
893
|
+
mutable.reverseAdjacency.get(edgeData.source)!.push(edgeIndex)
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
875
898
|
/**
|
|
876
899
|
* Reverses all edge directions in a mutable graph by swapping source and target nodes.
|
|
877
900
|
*
|
|
@@ -898,6 +921,10 @@ export const mapEdges = <N, E, T extends Kind = "directed">(
|
|
|
898
921
|
export const reverse = <N, E, T extends Kind = "directed">(
|
|
899
922
|
mutable: MutableGraph<N, E, T>
|
|
900
923
|
): void => {
|
|
924
|
+
if (mutable.type === "undirected") {
|
|
925
|
+
return
|
|
926
|
+
}
|
|
927
|
+
|
|
901
928
|
// Reverse all edges by swapping source and target
|
|
902
929
|
for (const [index, edgeData] of mutable.edges) {
|
|
903
930
|
mutable.edges.set(index, {
|
|
@@ -907,22 +934,7 @@ export const reverse = <N, E, T extends Kind = "directed">(
|
|
|
907
934
|
})
|
|
908
935
|
}
|
|
909
936
|
|
|
910
|
-
|
|
911
|
-
mutable.adjacency.clear()
|
|
912
|
-
mutable.reverseAdjacency.clear()
|
|
913
|
-
|
|
914
|
-
// Rebuild adjacency lists with reversed directions
|
|
915
|
-
for (const [edgeIndex, edgeData] of mutable.edges) {
|
|
916
|
-
// Add to forward adjacency (source -> target)
|
|
917
|
-
const sourceEdges = mutable.adjacency.get(edgeData.source) || []
|
|
918
|
-
sourceEdges.push(edgeIndex)
|
|
919
|
-
mutable.adjacency.set(edgeData.source, sourceEdges)
|
|
920
|
-
|
|
921
|
-
// Add to reverse adjacency (target <- source)
|
|
922
|
-
const targetEdges = mutable.reverseAdjacency.get(edgeData.target) || []
|
|
923
|
-
targetEdges.push(edgeIndex)
|
|
924
|
-
mutable.reverseAdjacency.set(edgeData.target, targetEdges)
|
|
925
|
-
}
|
|
937
|
+
rebuildAdjacency(mutable)
|
|
926
938
|
|
|
927
939
|
// Invalidate cycle flag since edge directions changed
|
|
928
940
|
mutable.isAcyclic = Option.none()
|
|
@@ -1452,8 +1464,11 @@ export const hasEdge = <N, E, T extends Kind = "directed">(
|
|
|
1452
1464
|
// Check if any edge in the adjacency list connects to the target
|
|
1453
1465
|
for (const edgeIndex of adjacencyList) {
|
|
1454
1466
|
const edge = graph.edges.get(edgeIndex)
|
|
1455
|
-
if (edge !== undefined
|
|
1456
|
-
|
|
1467
|
+
if (edge !== undefined) {
|
|
1468
|
+
const neighbor = graph.type === "undirected" && edge.target === source ? edge.source : edge.target
|
|
1469
|
+
if (neighbor === target) {
|
|
1470
|
+
return true
|
|
1471
|
+
}
|
|
1457
1472
|
}
|
|
1458
1473
|
}
|
|
1459
1474
|
|
|
@@ -1489,6 +1504,31 @@ export const edgeCount = <N, E, T extends Kind = "directed">(
|
|
|
1489
1504
|
graph: Graph<N, E, T> | MutableGraph<N, E, T>
|
|
1490
1505
|
): number => graph.edges.size
|
|
1491
1506
|
|
|
1507
|
+
const getDirectedNeighbors = <N, E>(
|
|
1508
|
+
graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
1509
|
+
nodeIndex: NodeIndex,
|
|
1510
|
+
direction: Direction
|
|
1511
|
+
): Array<NodeIndex> => {
|
|
1512
|
+
const adjacencyMap = direction === "incoming"
|
|
1513
|
+
? graph.reverseAdjacency
|
|
1514
|
+
: graph.adjacency
|
|
1515
|
+
|
|
1516
|
+
const adjacencyList = adjacencyMap.get(nodeIndex)
|
|
1517
|
+
if (adjacencyList === undefined) {
|
|
1518
|
+
return []
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
const result: Array<NodeIndex> = []
|
|
1522
|
+
for (const edgeIndex of adjacencyList) {
|
|
1523
|
+
const edge = graph.edges.get(edgeIndex)
|
|
1524
|
+
if (edge !== undefined) {
|
|
1525
|
+
result.push(direction === "incoming" ? edge.source : edge.target)
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
return result
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1492
1532
|
/**
|
|
1493
1533
|
* Returns the neighboring nodes (targets of outgoing edges) for a given node.
|
|
1494
1534
|
*
|
|
@@ -1527,24 +1567,47 @@ export const neighbors = <N, E, T extends Kind = "directed">(
|
|
|
1527
1567
|
return getUndirectedNeighbors(graph as any, nodeIndex)
|
|
1528
1568
|
}
|
|
1529
1569
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
return []
|
|
1533
|
-
}
|
|
1570
|
+
return getDirectedNeighbors(graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">, nodeIndex, "outgoing")
|
|
1571
|
+
}
|
|
1534
1572
|
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1573
|
+
/**
|
|
1574
|
+
* Returns the outgoing neighbor node indices for a node in a directed graph.
|
|
1575
|
+
*
|
|
1576
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
1577
|
+
*
|
|
1578
|
+
* @since 3.22.0
|
|
1579
|
+
* @category queries
|
|
1580
|
+
*/
|
|
1581
|
+
export const successors = <N, E>(
|
|
1582
|
+
graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
1583
|
+
nodeIndex: NodeIndex
|
|
1584
|
+
): Array<NodeIndex> => {
|
|
1585
|
+
if ((graph as Graph<N, E, Kind> | MutableGraph<N, E, Kind>).type === "undirected") {
|
|
1586
|
+
throw new GraphError({ message: "Cannot get successors of undirected graph" })
|
|
1541
1587
|
}
|
|
1588
|
+
return getDirectedNeighbors(graph, nodeIndex, "outgoing")
|
|
1589
|
+
}
|
|
1542
1590
|
|
|
1543
|
-
|
|
1591
|
+
/**
|
|
1592
|
+
* Returns the incoming neighbor node indices for a node in a directed graph.
|
|
1593
|
+
*
|
|
1594
|
+
* Throws a `GraphError` when used with an undirected graph.
|
|
1595
|
+
*
|
|
1596
|
+
* @since 3.22.0
|
|
1597
|
+
* @category queries
|
|
1598
|
+
*/
|
|
1599
|
+
export const predecessors = <N, E>(
|
|
1600
|
+
graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
1601
|
+
nodeIndex: NodeIndex
|
|
1602
|
+
): Array<NodeIndex> => {
|
|
1603
|
+
if ((graph as Graph<N, E, Kind> | MutableGraph<N, E, Kind>).type === "undirected") {
|
|
1604
|
+
throw new GraphError({ message: "Cannot get predecessors of undirected graph" })
|
|
1605
|
+
}
|
|
1606
|
+
return getDirectedNeighbors(graph, nodeIndex, "incoming")
|
|
1544
1607
|
}
|
|
1545
1608
|
|
|
1546
1609
|
/**
|
|
1547
|
-
* Get neighbors of a node in a specific direction
|
|
1610
|
+
* Get directed neighbors of a node in a specific direction.
|
|
1548
1611
|
*
|
|
1549
1612
|
* @example
|
|
1550
1613
|
* ```ts
|
|
@@ -1566,36 +1629,19 @@ export const neighbors = <N, E, T extends Kind = "directed">(
|
|
|
1566
1629
|
* const incoming = Graph.neighborsDirected(graph, nodeB, "incoming")
|
|
1567
1630
|
* ```
|
|
1568
1631
|
*
|
|
1632
|
+
* @deprecated Use {@link successors} for outgoing neighbors or {@link predecessors} for incoming neighbors.
|
|
1569
1633
|
* @since 3.18.0
|
|
1570
1634
|
* @category queries
|
|
1571
1635
|
*/
|
|
1572
|
-
export const neighborsDirected = <N, E
|
|
1573
|
-
graph: Graph<N, E,
|
|
1636
|
+
export const neighborsDirected = <N, E>(
|
|
1637
|
+
graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
1574
1638
|
nodeIndex: NodeIndex,
|
|
1575
1639
|
direction: Direction
|
|
1576
1640
|
): Array<NodeIndex> => {
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
: graph.adjacency
|
|
1580
|
-
|
|
1581
|
-
const adjacencyList = adjacencyMap.get(nodeIndex)
|
|
1582
|
-
if (adjacencyList === undefined) {
|
|
1583
|
-
return []
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
const result: Array<NodeIndex> = []
|
|
1587
|
-
for (const edgeIndex of adjacencyList) {
|
|
1588
|
-
const edge = graph.edges.get(edgeIndex)
|
|
1589
|
-
if (edge !== undefined) {
|
|
1590
|
-
// For incoming direction, we want the source node instead of target
|
|
1591
|
-
const neighborNode = direction === "incoming"
|
|
1592
|
-
? edge.source
|
|
1593
|
-
: edge.target
|
|
1594
|
-
result.push(neighborNode)
|
|
1595
|
-
}
|
|
1641
|
+
if ((graph as Graph<N, E, Kind> | MutableGraph<N, E, Kind>).type === "undirected") {
|
|
1642
|
+
throw new GraphError({ message: "Cannot get directed neighbors of undirected graph" })
|
|
1596
1643
|
}
|
|
1597
|
-
|
|
1598
|
-
return result
|
|
1644
|
+
return getDirectedNeighbors(graph, nodeIndex, direction)
|
|
1599
1645
|
}
|
|
1600
1646
|
|
|
1601
1647
|
// =============================================================================
|
|
@@ -1990,7 +2036,11 @@ export const isAcyclic = <N, E, T extends Kind = "directed">(
|
|
|
1990
2036
|
recursionStack.add(node)
|
|
1991
2037
|
|
|
1992
2038
|
// Get neighbors for this node
|
|
1993
|
-
const nodeNeighbors =
|
|
2039
|
+
const nodeNeighbors = getDirectedNeighbors(
|
|
2040
|
+
graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
2041
|
+
node,
|
|
2042
|
+
"outgoing"
|
|
2043
|
+
)
|
|
1994
2044
|
stack[stack.length - 1] = [node, nodeNeighbors, 0, false]
|
|
1995
2045
|
continue
|
|
1996
2046
|
}
|
|
@@ -2141,7 +2191,7 @@ const getTraversalNeighbors = <N, E, T extends Kind>(
|
|
|
2141
2191
|
): Array<NodeIndex> =>
|
|
2142
2192
|
graph.type === "undirected"
|
|
2143
2193
|
? getUndirectedNeighbors(graph as any, nodeIndex)
|
|
2144
|
-
:
|
|
2194
|
+
: getDirectedNeighbors(graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">, nodeIndex, direction)
|
|
2145
2195
|
|
|
2146
2196
|
const getTraversableNeighbor = <N, E, T extends Kind>(
|
|
2147
2197
|
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
|
|
@@ -2231,9 +2281,13 @@ export const connectedComponents = <N, E>(
|
|
|
2231
2281
|
* @since 3.18.0
|
|
2232
2282
|
* @category algorithms
|
|
2233
2283
|
*/
|
|
2234
|
-
export const stronglyConnectedComponents = <N, E
|
|
2235
|
-
graph: Graph<N, E,
|
|
2284
|
+
export const stronglyConnectedComponents = <N, E>(
|
|
2285
|
+
graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">
|
|
2236
2286
|
): Array<Array<NodeIndex>> => {
|
|
2287
|
+
if ((graph as Graph<N, E, Kind> | MutableGraph<N, E, Kind>).type === "undirected") {
|
|
2288
|
+
throw new GraphError({ message: "Cannot find strongly connected components of undirected graph" })
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2237
2291
|
const visited = new Set<NodeIndex>()
|
|
2238
2292
|
const finishOrder: Array<NodeIndex> = []
|
|
2239
2293
|
// Iterate directly over node keys
|
|
@@ -2259,7 +2313,7 @@ export const stronglyConnectedComponents = <N, E, T extends Kind = "directed">(
|
|
|
2259
2313
|
}
|
|
2260
2314
|
|
|
2261
2315
|
visited.add(node)
|
|
2262
|
-
const nodeNeighborsList =
|
|
2316
|
+
const nodeNeighborsList = getDirectedNeighbors(graph, node, "outgoing")
|
|
2263
2317
|
stack[stack.length - 1] = [node, nodeNeighborsList, 0, false]
|
|
2264
2318
|
continue
|
|
2265
2319
|
}
|
|
@@ -2377,6 +2431,22 @@ export interface BellmanFordConfig<E> {
|
|
|
2377
2431
|
cost: (edgeData: E) => number
|
|
2378
2432
|
}
|
|
2379
2433
|
|
|
2434
|
+
const validateNonNegativeEdgeWeights = <N, E, T extends Kind = "directed">(
|
|
2435
|
+
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
|
|
2436
|
+
cost: (edgeData: E) => number,
|
|
2437
|
+
algorithm: string
|
|
2438
|
+
): Map<EdgeIndex, number> => {
|
|
2439
|
+
const edgeWeights = new Map<EdgeIndex, number>()
|
|
2440
|
+
for (const [edgeIndex, edgeData] of graph.edges) {
|
|
2441
|
+
const weight = cost(edgeData.data)
|
|
2442
|
+
if (weight < 0 || Number.isNaN(weight)) {
|
|
2443
|
+
throw new GraphError({ message: `${algorithm} requires non-negative edge weights` })
|
|
2444
|
+
}
|
|
2445
|
+
edgeWeights.set(edgeIndex, weight)
|
|
2446
|
+
}
|
|
2447
|
+
return edgeWeights
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2380
2450
|
/**
|
|
2381
2451
|
* Find the shortest path between two nodes using Dijkstra's algorithm.
|
|
2382
2452
|
*
|
|
@@ -2419,6 +2489,8 @@ export const dijkstra = <N, E, T extends Kind = "directed">(
|
|
|
2419
2489
|
throw missingNode(target)
|
|
2420
2490
|
}
|
|
2421
2491
|
|
|
2492
|
+
const edgeWeights = validateNonNegativeEdgeWeights(graph, cost, "Dijkstra's algorithm")
|
|
2493
|
+
|
|
2422
2494
|
// Early return if source equals target
|
|
2423
2495
|
if (source === target) {
|
|
2424
2496
|
return Option.some({
|
|
@@ -2479,12 +2551,7 @@ export const dijkstra = <N, E, T extends Kind = "directed">(
|
|
|
2479
2551
|
const edge = graph.edges.get(edgeIndex)
|
|
2480
2552
|
if (edge !== undefined) {
|
|
2481
2553
|
const neighbor = getTraversableNeighbor(graph, currentNode, edge)
|
|
2482
|
-
const weight =
|
|
2483
|
-
|
|
2484
|
-
// Validate non-negative weights
|
|
2485
|
-
if (weight < 0) {
|
|
2486
|
-
throw new Error(`Dijkstra's algorithm requires non-negative edge weights, found ${weight}`)
|
|
2487
|
-
}
|
|
2554
|
+
const weight = edgeWeights.get(edgeIndex)!
|
|
2488
2555
|
|
|
2489
2556
|
const newDistance = currentDistance + weight
|
|
2490
2557
|
const neighborDistance = distances.get(neighbor)!
|
|
@@ -2738,6 +2805,8 @@ export const astar = <N, E, T extends Kind = "directed">(
|
|
|
2738
2805
|
throw missingNode(target)
|
|
2739
2806
|
}
|
|
2740
2807
|
|
|
2808
|
+
const edgeWeights = validateNonNegativeEdgeWeights(graph, cost, "A* algorithm")
|
|
2809
|
+
|
|
2741
2810
|
// Early return if source equals target
|
|
2742
2811
|
if (source === target) {
|
|
2743
2812
|
return Option.some({
|
|
@@ -2813,12 +2882,7 @@ export const astar = <N, E, T extends Kind = "directed">(
|
|
|
2813
2882
|
const edge = graph.edges.get(edgeIndex)
|
|
2814
2883
|
if (edge !== undefined) {
|
|
2815
2884
|
const neighbor = getTraversableNeighbor(graph, currentNode, edge)
|
|
2816
|
-
const weight =
|
|
2817
|
-
|
|
2818
|
-
// Validate non-negative weights
|
|
2819
|
-
if (weight < 0) {
|
|
2820
|
-
throw new Error(`A* algorithm requires non-negative edge weights, found ${weight}`)
|
|
2821
|
-
}
|
|
2885
|
+
const weight = edgeWeights.get(edgeIndex)!
|
|
2822
2886
|
|
|
2823
2887
|
const tentativeGScore = currentGScore + weight
|
|
2824
2888
|
const neighborGScore = gScore.get(neighbor)!
|
|
@@ -3497,6 +3561,7 @@ export const topo = <N, E, T extends Kind = "directed">(
|
|
|
3497
3561
|
[Symbol.iterator]: () => {
|
|
3498
3562
|
const inDegree = new Map<NodeIndex, number>()
|
|
3499
3563
|
const remaining = new Set<NodeIndex>()
|
|
3564
|
+
const initialSet = new Set(initials)
|
|
3500
3565
|
const queue = [...initials]
|
|
3501
3566
|
|
|
3502
3567
|
// Initialize in-degree counts
|
|
@@ -3511,12 +3576,15 @@ export const topo = <N, E, T extends Kind = "directed">(
|
|
|
3511
3576
|
inDegree.set(edgeData.target, currentInDegree + 1)
|
|
3512
3577
|
}
|
|
3513
3578
|
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3579
|
+
for (const nodeIndex of initials) {
|
|
3580
|
+
if (inDegree.get(nodeIndex)! !== 0) {
|
|
3581
|
+
throw new GraphError({ message: `Initial node ${nodeIndex} has incoming edges` })
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3584
|
+
|
|
3585
|
+
for (const [nodeIndex, degree] of inDegree) {
|
|
3586
|
+
if (degree === 0 && !initialSet.has(nodeIndex)) {
|
|
3587
|
+
queue.push(nodeIndex)
|
|
3520
3588
|
}
|
|
3521
3589
|
}
|
|
3522
3590
|
|
|
@@ -3528,7 +3596,11 @@ export const topo = <N, E, T extends Kind = "directed">(
|
|
|
3528
3596
|
remaining.delete(current)
|
|
3529
3597
|
|
|
3530
3598
|
// Process outgoing edges, reducing in-degree of targets
|
|
3531
|
-
const neighbors =
|
|
3599
|
+
const neighbors = getDirectedNeighbors(
|
|
3600
|
+
graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
|
|
3601
|
+
current,
|
|
3602
|
+
"outgoing"
|
|
3603
|
+
)
|
|
3532
3604
|
for (const neighbor of neighbors) {
|
|
3533
3605
|
if (remaining.has(neighbor)) {
|
|
3534
3606
|
const currentInDegree = inDegree.get(neighbor) || 0
|
package/src/Mailbox.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { Effect } from "./Effect.js"
|
|
|
9
9
|
import type { Exit } from "./Exit.js"
|
|
10
10
|
import type { Inspectable } from "./Inspectable.js"
|
|
11
11
|
import * as internal from "./internal/mailbox.js"
|
|
12
|
+
import * as internalStream from "./internal/stream.js"
|
|
12
13
|
import type { Option } from "./Option.js"
|
|
13
14
|
import { hasProperty } from "./Predicate.js"
|
|
14
15
|
import type { Scope } from "./Scope.js"
|
|
@@ -258,7 +259,7 @@ export const toChannel: <A, E>(self: ReadonlyMailbox<A, E>) => Channel<Chunk<A>,
|
|
|
258
259
|
* @experimental
|
|
259
260
|
* @category conversions
|
|
260
261
|
*/
|
|
261
|
-
export const toStream: <A, E>(self: ReadonlyMailbox<A, E>) => Stream<A, E> =
|
|
262
|
+
export const toStream: <A, E>(self: ReadonlyMailbox<A, E>) => Stream<A, E> = internalStream.mailboxToStream
|
|
262
263
|
|
|
263
264
|
/**
|
|
264
265
|
* Create a `ReadonlyMailbox` from a `Stream`.
|
|
@@ -295,4 +296,4 @@ export const fromStream: {
|
|
|
295
296
|
readonly strategy?: "suspend" | "dropping" | "sliding" | undefined
|
|
296
297
|
}
|
|
297
298
|
): Effect<ReadonlyMailbox<A, E>, never, R | Scope>
|
|
298
|
-
} =
|
|
299
|
+
} = internalStream.mailboxFromStream
|
package/src/ParseResult.ts
CHANGED
|
@@ -914,6 +914,24 @@ const go = (ast: AST.AST, isDecoding: boolean): Parser => {
|
|
|
914
914
|
case "Enums":
|
|
915
915
|
return fromRefinement(ast, (u): u is any => ast.enums.some(([_, value]) => value === u))
|
|
916
916
|
case "TemplateLiteral": {
|
|
917
|
+
if (ast.spans.every((span) => AST.isStringKeyword(span.type))) {
|
|
918
|
+
return fromRefinement(ast, (u): u is any => {
|
|
919
|
+
if (!Predicate.isString(u) || !u.startsWith(ast.head)) {
|
|
920
|
+
return false
|
|
921
|
+
}
|
|
922
|
+
let position = ast.head.length
|
|
923
|
+
for (let i = 0; i < ast.spans.length - 1; i++) {
|
|
924
|
+
const literal = ast.spans[i].literal
|
|
925
|
+
const index = u.indexOf(literal, position)
|
|
926
|
+
if (index === -1) {
|
|
927
|
+
return false
|
|
928
|
+
}
|
|
929
|
+
position = index + literal.length
|
|
930
|
+
}
|
|
931
|
+
const literal = ast.spans[ast.spans.length - 1].literal
|
|
932
|
+
return u.endsWith(literal) && u.length - literal.length >= position
|
|
933
|
+
})
|
|
934
|
+
}
|
|
917
935
|
const regex = AST.getTemplateLiteralRegExp(ast)
|
|
918
936
|
return fromRefinement(ast, (u): u is any => Predicate.isString(u) && regex.test(u))
|
|
919
937
|
}
|
package/src/internal/config.ts
CHANGED
|
@@ -39,6 +39,7 @@ export type ConfigPrimitive =
|
|
|
39
39
|
| MapOrFail
|
|
40
40
|
| Nested
|
|
41
41
|
| Primitive
|
|
42
|
+
| RedactedConfig
|
|
42
43
|
| Sequence
|
|
43
44
|
| Table
|
|
44
45
|
| Zipped
|
|
@@ -125,6 +126,14 @@ export interface Primitive extends
|
|
|
125
126
|
}>
|
|
126
127
|
{}
|
|
127
128
|
|
|
129
|
+
/** @internal */
|
|
130
|
+
export interface RedactedConfig extends
|
|
131
|
+
Op<OpCodes.OP_REDACTED, {
|
|
132
|
+
readonly original: Config.Config<unknown>
|
|
133
|
+
redact(value: unknown): Redacted.Redacted<unknown>
|
|
134
|
+
}>
|
|
135
|
+
{}
|
|
136
|
+
|
|
128
137
|
/** @internal */
|
|
129
138
|
export interface Sequence extends
|
|
130
139
|
Op<OpCodes.OP_SEQUENCE, {
|
|
@@ -475,7 +484,11 @@ export const redacted = <A>(
|
|
|
475
484
|
nameOrConfig?: string | Config.Config<A>
|
|
476
485
|
): Config.Config<Redacted.Redacted<A | string>> => {
|
|
477
486
|
const config: Config.Config<A | string> = isConfig(nameOrConfig) ? nameOrConfig : string(nameOrConfig)
|
|
478
|
-
|
|
487
|
+
const redacted = Object.create(proto)
|
|
488
|
+
redacted._tag = OpCodes.OP_REDACTED
|
|
489
|
+
redacted.original = config
|
|
490
|
+
redacted.redact = redacted_.make
|
|
491
|
+
return redacted
|
|
479
492
|
}
|
|
480
493
|
|
|
481
494
|
/** @internal */
|
|
@@ -236,6 +236,18 @@ const appendConfigPath = (path: ReadonlyArray<string>, config: Config.Config<unk
|
|
|
236
236
|
return path
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
const RedactedConfigErrorReducer: ConfigError.ConfigErrorReducer<unknown, ConfigError.ConfigError> = {
|
|
240
|
+
andCase: (_, left, right) => configError.And(left, right),
|
|
241
|
+
orCase: (_, left, right) => configError.Or(left, right),
|
|
242
|
+
invalidDataCase: (_, path) => configError.InvalidData(path, "<redacted>"),
|
|
243
|
+
missingDataCase: (_, path) => configError.MissingData(path, "<redacted>"),
|
|
244
|
+
sourceUnavailableCase: (_, path, _message, cause) => configError.SourceUnavailable(path, "<redacted>", cause),
|
|
245
|
+
unsupportedCase: (_, path) => configError.Unsupported(path, "<redacted>")
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const redactConfigError = (error: ConfigError.ConfigError): ConfigError.ConfigError =>
|
|
249
|
+
configError.reduceWithContext(error, void 0, RedactedConfigErrorReducer)
|
|
250
|
+
|
|
239
251
|
const fromFlatLoop = <A>(
|
|
240
252
|
flat: ConfigProvider.ConfigProvider.Flat,
|
|
241
253
|
prefix: ReadonlyArray<string>,
|
|
@@ -320,6 +332,15 @@ const fromFlatLoop = <A>(
|
|
|
320
332
|
)
|
|
321
333
|
) as unknown as Effect.Effect<Array<A>, ConfigError.ConfigError>
|
|
322
334
|
}
|
|
335
|
+
case OpCodes.OP_REDACTED: {
|
|
336
|
+
return core.suspend(() =>
|
|
337
|
+
pipe(
|
|
338
|
+
fromFlatLoop(flat, prefix, op.original, split),
|
|
339
|
+
core.mapError(redactConfigError),
|
|
340
|
+
core.map(Arr.map(op.redact))
|
|
341
|
+
)
|
|
342
|
+
) as unknown as Effect.Effect<Array<A>, ConfigError.ConfigError>
|
|
343
|
+
}
|
|
323
344
|
case OpCodes.OP_SEQUENCE: {
|
|
324
345
|
return pipe(
|
|
325
346
|
pathPatch.patch(prefix, flat.patch),
|
|
@@ -719,7 +740,9 @@ interface JsonArray extends Array<string | number | boolean | null | JsonArray |
|
|
|
719
740
|
export const fromJson = (json: unknown): ConfigProvider.ConfigProvider => {
|
|
720
741
|
const hiddenDelimiter = "\ufeff"
|
|
721
742
|
const indexedEntries = Arr.map(
|
|
722
|
-
getIndexedEntries(json as JsonMap)
|
|
743
|
+
getIndexedEntries(json as JsonMap).filter(([path]) =>
|
|
744
|
+
path.every((component) => component._tag === "KeyIndex" || !component.name.includes(hiddenDelimiter))
|
|
745
|
+
),
|
|
723
746
|
([key, value]): [string, string] => [configPathToString(key).join(hiddenDelimiter), value]
|
|
724
747
|
)
|
|
725
748
|
return fromMap(new Map(indexedEntries), {
|
|
@@ -604,26 +604,27 @@ export const timeoutTo = dual<
|
|
|
604
604
|
core.fiberIdWith((parentFiberId) =>
|
|
605
605
|
core.uninterruptibleMask((restore) =>
|
|
606
606
|
fiberRuntime.raceFibersWith(
|
|
607
|
-
restore(self),
|
|
607
|
+
core.exit(restore(self)),
|
|
608
608
|
core.interruptible(effect.sleep(duration)),
|
|
609
609
|
{
|
|
610
610
|
onSelfWin: (winner, loser) =>
|
|
611
611
|
core.flatMap(
|
|
612
612
|
winner.await,
|
|
613
613
|
(exit) => {
|
|
614
|
-
|
|
614
|
+
const selfExit = core.exitFlatten(exit)
|
|
615
|
+
if (selfExit._tag === "Success") {
|
|
615
616
|
return core.flatMap(
|
|
616
617
|
winner.inheritAll,
|
|
617
618
|
() =>
|
|
618
619
|
core.as(
|
|
619
620
|
core.interruptAsFiber(loser, parentFiberId),
|
|
620
|
-
onSuccess(
|
|
621
|
+
onSuccess(selfExit.value)
|
|
621
622
|
)
|
|
622
623
|
)
|
|
623
624
|
} else {
|
|
624
625
|
return core.flatMap(
|
|
625
626
|
core.interruptAsFiber(loser, parentFiberId),
|
|
626
|
-
() => core.exitFailCause(
|
|
627
|
+
() => core.exitFailCause(selfExit.cause)
|
|
627
628
|
)
|
|
628
629
|
}
|
|
629
630
|
}
|
package/src/internal/mailbox.ts
CHANGED
|
@@ -13,15 +13,9 @@ import * as Option from "../Option.js"
|
|
|
13
13
|
import { pipeArguments } from "../Pipeable.js"
|
|
14
14
|
import { hasProperty } from "../Predicate.js"
|
|
15
15
|
import type { Scheduler } from "../Scheduler.js"
|
|
16
|
-
import type { Scope } from "../Scope.js"
|
|
17
|
-
import type { Stream } from "../Stream.js"
|
|
18
16
|
import * as channel from "./channel.js"
|
|
19
|
-
import * as channelExecutor from "./channel/channelExecutor.js"
|
|
20
17
|
import * as coreChannel from "./core-stream.js"
|
|
21
18
|
import * as core from "./core.js"
|
|
22
|
-
import * as circular from "./effect/circular.js"
|
|
23
|
-
import * as fiberRuntime from "./fiberRuntime.js"
|
|
24
|
-
import * as stream from "./stream.js"
|
|
25
19
|
|
|
26
20
|
/** @internal */
|
|
27
21
|
export const TypeId: Api.TypeId = Symbol.for("effect/Mailbox") as Api.TypeId
|
|
@@ -255,8 +249,17 @@ class MailboxImpl<A, E> extends Effectable.Class<readonly [messages: Chunk.Chunk
|
|
|
255
249
|
return core.exitAs(this.state.exit, constDone)
|
|
256
250
|
} else if (n <= 0) {
|
|
257
251
|
return core.succeed([empty, false])
|
|
252
|
+
} else if (
|
|
253
|
+
this.capacity <= 0 && this.messages.length === 0 && this.messagesChunk.length === 0 &&
|
|
254
|
+
this.state.offers.size > 0
|
|
255
|
+
) {
|
|
256
|
+
this.capacity = 1
|
|
257
|
+
this.releaseCapacity()
|
|
258
|
+
this.capacity = 0
|
|
259
|
+
const messages = Chunk.of(this.messages.pop()!)
|
|
260
|
+
return core.succeed([messages, this.releaseCapacity()])
|
|
258
261
|
}
|
|
259
|
-
n = Math.min(n, this.capacity)
|
|
262
|
+
n = Math.min(n, this.capacity || 1)
|
|
260
263
|
let messages: Chunk.Chunk<A>
|
|
261
264
|
if (n <= this.messagesChunk.length) {
|
|
262
265
|
messages = Chunk.take(this.messagesChunk, n)
|
|
@@ -288,7 +291,9 @@ class MailboxImpl<A, E> extends Effectable.Class<readonly [messages: Chunk.Chunk
|
|
|
288
291
|
this.capacity = 1
|
|
289
292
|
this.releaseCapacity()
|
|
290
293
|
this.capacity = 0
|
|
291
|
-
|
|
294
|
+
const message = this.messages.pop()!
|
|
295
|
+
this.releaseCapacity()
|
|
296
|
+
return core.exitSucceed(message)
|
|
292
297
|
} else {
|
|
293
298
|
return undefined
|
|
294
299
|
}
|
|
@@ -515,47 +520,3 @@ export const toChannel = <A, E>(self: Api.ReadonlyMailbox<A, E>): Channel<Chunk.
|
|
|
515
520
|
: channel.zipRight(coreChannel.write(messages), loop))
|
|
516
521
|
return loop
|
|
517
522
|
}
|
|
518
|
-
|
|
519
|
-
/** @internal */
|
|
520
|
-
export const toStream = <A, E>(self: Api.ReadonlyMailbox<A, E>): Stream<A, E> => stream.fromChannel(toChannel(self))
|
|
521
|
-
|
|
522
|
-
/** @internal */
|
|
523
|
-
export const fromStream: {
|
|
524
|
-
(options?: {
|
|
525
|
-
readonly capacity?: number | undefined
|
|
526
|
-
readonly strategy?: "suspend" | "dropping" | "sliding" | undefined
|
|
527
|
-
}): <A, E, R>(self: Stream<A, E, R>) => Effect<Api.ReadonlyMailbox<A, E>, never, R | Scope>
|
|
528
|
-
<A, E, R>(
|
|
529
|
-
self: Stream<A, E, R>,
|
|
530
|
-
options?: {
|
|
531
|
-
readonly capacity?: number | undefined
|
|
532
|
-
readonly strategy?: "suspend" | "dropping" | "sliding" | undefined
|
|
533
|
-
}
|
|
534
|
-
): Effect<Api.ReadonlyMailbox<A, E>, never, R | Scope>
|
|
535
|
-
} = dual((args) => stream.isStream(args[0]), <A, E, R>(
|
|
536
|
-
self: Stream<A, E, R>,
|
|
537
|
-
options?: {
|
|
538
|
-
readonly capacity?: number | undefined
|
|
539
|
-
readonly strategy?: "suspend" | "dropping" | "sliding" | undefined
|
|
540
|
-
}
|
|
541
|
-
): Effect<Api.ReadonlyMailbox<A, E>, never, R | Scope> =>
|
|
542
|
-
core.tap(
|
|
543
|
-
fiberRuntime.acquireRelease(
|
|
544
|
-
make<A, E>(options),
|
|
545
|
-
(mailbox) => mailbox.shutdown
|
|
546
|
-
),
|
|
547
|
-
(mailbox) => {
|
|
548
|
-
const writer: Channel<never, Chunk.Chunk<A>, never, E> = coreChannel.readWithCause({
|
|
549
|
-
onInput: (input: Chunk.Chunk<A>) => coreChannel.flatMap(mailbox.offerAll(input), () => writer),
|
|
550
|
-
onFailure: (cause: Cause<E>) => mailbox.failCause(cause),
|
|
551
|
-
onDone: () => mailbox.end
|
|
552
|
-
})
|
|
553
|
-
return fiberRuntime.scopeWith((scope) =>
|
|
554
|
-
stream.toChannel(self).pipe(
|
|
555
|
-
coreChannel.pipeTo(writer),
|
|
556
|
-
channelExecutor.runIn(scope),
|
|
557
|
-
circular.forkIn(scope)
|
|
558
|
-
)
|
|
559
|
-
)
|
|
560
|
-
}
|
|
561
|
-
))
|
|
@@ -46,6 +46,12 @@ export type OP_PRIMITIVE = typeof OP_PRIMITIVE
|
|
|
46
46
|
/** @internal */
|
|
47
47
|
export const OP_PRIMITIVE = "Primitive" as const
|
|
48
48
|
|
|
49
|
+
/** @internal */
|
|
50
|
+
export type OP_REDACTED = typeof OP_REDACTED
|
|
51
|
+
|
|
52
|
+
/** @internal */
|
|
53
|
+
export const OP_REDACTED = "Redacted" as const
|
|
54
|
+
|
|
49
55
|
/** @internal */
|
|
50
56
|
export type OP_SEQUENCE = typeof OP_SEQUENCE
|
|
51
57
|
|