(config?: ExternalsConfig): <N, E, T extends Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>
) => NodeWalker<N>
<N, E, T extends Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
config?: ExternalsConfig
): NodeWalker<N>Creates an iterator over external nodes (nodes without edges in the specified direction).
Details
External nodes have no outgoing edges (direction: "outgoing") or no
incoming edges (direction: "incoming"). These are useful for finding
sources, sinks, or isolated nodes.
Example (Iterating external nodes)
import { Graph } from "effect"
const graph = Graph.directed<string, number>((mutable) => {
const source = Graph.addNode(mutable, "source") // 0 - no incoming
const middle = Graph.addNode(mutable, "middle") // 1 - has both
const sink = Graph.addNode(mutable, "sink") // 2 - no outgoing
const isolated = Graph.addNode(mutable, "isolated") // 3 - no edges
Graph.addEdge(mutable, source, middle, 1)
Graph.addEdge(mutable, middle, sink, 2)
})
// Nodes with no outgoing edges (sinks + isolated)
const sinks = Array.from(
Graph.indices(Graph.externals(graph, { direction: "outgoing" }))
)
console.log(sinks) // [2, 3]
// Nodes with no incoming edges (sources + isolated)
const sources = Array.from(
Graph.indices(Graph.externals(graph, { direction: "incoming" }))
)
console.log(sources) // [0, 3]export const const externals: {
(config?: ExternalsConfig): <
N,
E,
T extends Kind = "directed"
>(
graph: Graph<N, E, T> | MutableGraph<N, E, T>
) => NodeWalker<N>
<N, E, T extends Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
config?: ExternalsConfig
): NodeWalker<N>
}
Creates an iterator over external nodes (nodes without edges in the specified direction).
Details
External nodes have no outgoing edges (direction: "outgoing") or no
incoming edges (direction: "incoming"). These are useful for finding
sources, sinks, or isolated nodes.
Example (Iterating external nodes)
import { Graph } from "effect"
const graph = Graph.directed<string, number>((mutable) => {
const source = Graph.addNode(mutable, "source") // 0 - no incoming
const middle = Graph.addNode(mutable, "middle") // 1 - has both
const sink = Graph.addNode(mutable, "sink") // 2 - no outgoing
const isolated = Graph.addNode(mutable, "isolated") // 3 - no edges
Graph.addEdge(mutable, source, middle, 1)
Graph.addEdge(mutable, middle, sink, 2)
})
// Nodes with no outgoing edges (sinks + isolated)
const sinks = Array.from(
Graph.indices(Graph.externals(graph, { direction: "outgoing" }))
)
console.log(sinks) // [2, 3]
// Nodes with no incoming edges (sources + isolated)
const sources = Array.from(
Graph.indices(Graph.externals(graph, { direction: "incoming" }))
)
console.log(sources) // [0, 3]
externals: {
(
config: ExternalsConfigconfig?: ExternalsConfig
): <function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>T extends type Kind = "directed" | "undirected"Graph type for distinguishing directed and undirected graphs.
When to use
Use when writing graph-polymorphic types or helpers that need to preserve
whether a graph is directed or undirected.
Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>graph: interface Graph<out N, out E, T extends Kind = "directed">Immutable graph interface.
When to use
Use as the immutable graph model for code that queries, traverses,
transforms, or analyzes graph structure without mutating it.
Graph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>T> | interface MutableGraph<out N, out E, T extends Kind = "directed">Mutable graph interface.
When to use
Use when adding, removing, or updating nodes and edges inside a graph
mutation scope.
MutableGraph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>T>) => type NodeWalker<N> = Walker<number, N>Type alias for node iteration using Walker.
NodeWalker is represented as Walker<NodeIndex, N>.
When to use
Use as the shared node walker type returned by graph traversal and node
listing APIs.
NodeWalker<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>N>
<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>T extends type Kind = "directed" | "undirected"Graph type for distinguishing directed and undirected graphs.
When to use
Use when writing graph-polymorphic types or helpers that need to preserve
whether a graph is directed or undirected.
Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>graph: interface Graph<out N, out E, T extends Kind = "directed">Immutable graph interface.
When to use
Use as the immutable graph model for code that queries, traverses,
transforms, or analyzes graph structure without mutating it.
Graph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>T> | interface MutableGraph<out N, out E, T extends Kind = "directed">Mutable graph interface.
When to use
Use when adding, removing, or updating nodes and edges inside a graph
mutation scope.
MutableGraph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>T>,
config: ExternalsConfigconfig?: ExternalsConfig
): type NodeWalker<N> = Walker<number, N>Type alias for node iteration using Walker.
NodeWalker is represented as Walker<NodeIndex, N>.
When to use
Use as the shared node walker type returned by graph traversal and node
listing APIs.
NodeWalker<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>N>
} = import dualdual((args: anyargs) => const isGraph: (
u: unknown
) => u is Graph<unknown, unknown>
Returns true if a value has the graph runtime type identifier, narrowing
it to a Graph.
When to use
Use to narrow an unknown value before treating it as a graph value.
Gotchas
This guard checks the shared graph runtime type identifier and does not
distinguish immutable graphs from mutable graphs.
isGraph(args: anyargs[0]), <function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>T extends type Kind = "directed" | "undirected"Graph type for distinguishing directed and undirected graphs.
When to use
Use when writing graph-polymorphic types or helpers that need to preserve
whether a graph is directed or undirected.
Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>graph: interface Graph<out N, out E, T extends Kind = "directed">Immutable graph interface.
When to use
Use as the immutable graph model for code that queries, traverses,
transforms, or analyzes graph structure without mutating it.
Graph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>T> | interface MutableGraph<out N, out E, T extends Kind = "directed">Mutable graph interface.
When to use
Use when adding, removing, or updating nodes and edges inside a graph
mutation scope.
MutableGraph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>T>,
config: ExternalsConfig(parameter) config: {
direction: Direction;
}
config: ExternalsConfig = {}
): type NodeWalker<N> = Walker<number, N>Type alias for node iteration using Walker.
NodeWalker is represented as Walker<NodeIndex, N>.
When to use
Use as the shared node walker type returned by graph traversal and node
listing APIs.
NodeWalker<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: ExternalsConfig): NodeWalker<N>N> => {
const const direction: Directiondirection = config: ExternalsConfig(parameter) config: {
direction: Direction;
}
config.ExternalsConfig.direction?: Directiondirection ?? "outgoing"
return new constructor Walker<number, N>(visit: <U>(f: (index: number, data: N) => U) => Iterable<U>): Walker<number, N>Represents an iterable wrapper used by graph traversal and listing APIs.
Details
A Walker yields [index, data] pairs lazily and can be viewed as just the
indices, just the values, or mapped entries with indices, values,
entries, and visit.
Example (Working with node walkers)
import { Graph } from "effect"
const graph = Graph.directed<string, number>((mutable) => {
const a = Graph.addNode(mutable, "A")
const b = Graph.addNode(mutable, "B")
Graph.addEdge(mutable, a, b, 1)
})
// Both traversal and element iterators return NodeWalker
const dfsNodes: Graph.NodeWalker<string> = Graph.dfs(graph, { start: [0] })
const allNodes: Graph.NodeWalker<string> = Graph.nodes(graph)
// Common interface for working with node iterables
function processNodes<N>(nodeIterable: Graph.NodeWalker<N>): Array<number> {
return Array.from(Graph.indices(nodeIterable))
}
// Access node data using values() or entries()
const nodeData = Array.from(Graph.values(dfsNodes)) // ["A", "B"]
const nodeEntries = Array.from(Graph.entries(allNodes)) // [[0, "A"], [1, "B"]]
Walker((f: (index: number, data: N) => Uf) => ({
[var Symbol: SymbolConstructorSymbol.SymbolConstructor.iterator: typeof Symbol.iteratorA method that returns the default iterator for an object. Called by the semantics of the
for-of statement.
iterator]: () => {
const const nodeMap: Map<number, N>nodeMap = graph: Graph<N, E, T> | MutableGraph<N, E, T>graph.Proto<out N, out E>.nodes: Map<NodeIndex, N>nodes
const const adjacencyMap: Map<number, number[]>adjacencyMap = const direction: Directiondirection === "incoming"
? graph: Graph<N, E, T> | MutableGraph<N, E, T>graph.Proto<out N, out E>.reverseAdjacency: Map<NodeIndex, Array<EdgeIndex>>reverseAdjacency
: graph: Graph<N, E, T> | MutableGraph<N, E, T>graph.Proto<out N, out E>.adjacency: Map<NodeIndex, Array<EdgeIndex>>adjacency
const const nodeIterator: MapIterator<
[number, N]
>
nodeIterator = const nodeMap: Map<number, N>nodeMap.Map<number, N>.entries(): MapIterator<[number, N]>Returns an iterable of key, value pairs for every entry in the map.
entries()
const const nextMapped: () =>
| {
done: boolean
value: U
}
| {
readonly done: true
readonly value: undefined
}
nextMapped = () => {
let let current: IteratorResult<
[number, N],
undefined
>
current = const nodeIterator: MapIterator<
[number, N]
>
nodeIterator.Iterator<[number, N], undefined, unknown>.next(...[value]: [] | [unknown]): IteratorResult<[number, N], undefined>next()
while (!let current: IteratorResult<
[number, N],
undefined
>
current.done?: boolean | undefineddone) {
const [const nodeIndex: numbernodeIndex, const nodeData: NnodeData] = let current: IteratorYieldResult<
[number, N]
>
current.IteratorYieldResult<[number, N]>.value: [number, N](property) IteratorYieldResult<[number, N]>.value: {
0: number;
1: N;
length: 2;
toString: () => string;
toLocaleString: { (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string };
pop: () => number | N | undefined;
push: (...items: Array<number | N>) => number;
concat: { (...items: Array<ConcatArray<number | N>>): Array<number | N>; (...items: Array<number | N | ConcatArray<number | N>>): Array<number | N> };
join: (separator?: string) => string;
reverse: () => Array<number | N>;
shift: () => number | N | undefined;
slice: (start?: number, end?: number) => Array<number | N>;
sort: (compareFn?: ((a: number | N, b: number | N) => number) | undefined) => [number, N];
splice: { (start: number, deleteCount?: number): Array<number | N>; (start: number, deleteCount: number, ...items: Array<number | N>): Array<number | N> };
unshift: (...items: Array<number | N>) => number;
indexOf: (searchElement: number | N, fromIndex?: number) => number;
lastIndexOf: (searchElement: number | N, fromIndex?: number) => number;
every: { (predicate: (value: number | N, index: number, array: Array<number | N>) => value is S, thisArg?: any): this is S[]; (predicate: (value: number | N, index: number, array: Array<number | N>) => unknown, thisArg?: any): boolean };
some: (predicate: (value: number | N, index: number, array: Array<number | N>) => unknown, thisArg?: any) => boolean;
forEach: (callbackfn: (value: number | N, index: number, array: Array<number | N>) => void, thisArg?: any) => void;
map: (callbackfn: (value: number | N, index: number, array: Array<number | N>) => U, thisArg?: any) => Array<U>;
filter: { (predicate: (value: number | N, index: number, array: Array<number | N>) => value is S, thisArg?: any): Array<S>; (predicate: (value: number | N, index: number, array: Array<number | N>) => unknown, thisArg?: any): Array<number | N> };
reduce: { (callbackfn: (previousValue: number | N, currentValue: number | N, currentIndex: number, array: Array<number | N>) => number | N): number | N; (callbackfn: (previousValue: number | N, currentValue: number | N, currentIndex: number, array…;
reduceRight: { (callbackfn: (previousValue: number | N, currentValue: number | N, currentIndex: number, array: Array<number | N>) => number | N): number | N; (callbackfn: (previousValue: number | N, currentValue: number | N, currentIndex: number, array…;
find: { (predicate: (value: number | N, index: number, obj: Array<number | N>) => value is S, thisArg?: any): S | undefined; (predicate: (value: number | N, index: number, obj: Array<number | N>) => unknown, thisArg?: any): number | N | undefine…;
findIndex: (predicate: (value: number | N, index: number, obj: Array<number | N>) => unknown, thisArg?: any) => number;
fill: (value: number | N, start?: number, end?: number) => [number, N];
copyWithin: (target: number, start: number, end?: number) => [number, N];
entries: () => ArrayIterator<[number, number | N]>;
keys: () => ArrayIterator<number>;
values: () => ArrayIterator<number | N>;
includes: (searchElement: number | N, fromIndex?: number) => boolean;
flatMap: (callback: (this: This, value: number | N, index: number, array: Array<number | N>) => U | ReadonlyArray<U>, thisArg?: This | undefined) => Array<U>;
flat: (this: A, depth?: D | undefined) => Array<FlatArray<A, D>>;
at: (index: number) => number | N | undefined;
findLast: { (predicate: (value: number | N, index: number, array: Array<number | N>) => value is S, thisArg?: any): S | undefined; (predicate: (value: number | N, index: number, array: Array<number | N>) => unknown, thisArg?: any): number | N | unde…;
findLastIndex: (predicate: (value: number | N, index: number, array: Array<number | N>) => unknown, thisArg?: any) => number;
toReversed: () => Array<number | N>;
toSorted: (compareFn?: ((a: number | N, b: number | N) => number) | undefined) => Array<number | N>;
toSpliced: { (start: number, deleteCount: number, ...items: Array<number | N>): Array<number | N>; (start: number, deleteCount?: number): Array<number | N> };
with: (index: number, value: number | N) => Array<number | N>;
}
value
const const adjacencyList: number[] | undefinedadjacencyList = const adjacencyMap: Map<number, number[]>adjacencyMap.Map<number, number[]>.get(key: number): number[] | undefinedReturns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.
get(const nodeIndex: numbernodeIndex)
// Node is external if it has no edges in the specified direction
if (const adjacencyList: number[] | undefinedadjacencyList === var undefinedundefined || const adjacencyList: number[]adjacencyList.Array<number>.length: numberGets or sets the length of the array. This is a number one higher than the highest index in the array.
length === 0) {
return { done: booleandone: false, value: Uvalue: f: (index: number, data: N) => Uf(const nodeIndex: numbernodeIndex, const nodeData: NnodeData) }
}
let current: IteratorResult<
[number, N],
undefined
>
current = const nodeIterator: MapIterator<
[number, N]
>
nodeIterator.Iterator<[number, N], undefined, unknown>.next(...[value]: [] | [unknown]): IteratorResult<[number, N], undefined>next()
}
return { done: truedone: true, value: undefinedvalue: var undefinedundefined } as type const = {
readonly done: true;
readonly value: undefined;
}
const
}
return { Iterator<U, any, any>.next(...[value]: [] | [any]): IteratorResult<U, any>next: const nextMapped: () =>
| {
done: boolean
value: U
}
| {
readonly done: true
readonly value: undefined
}
nextMapped }
}
}))
})