armature_graph 0.1.0
armature_graph: ^0.1.0 copied to clipboard
Directed-acyclic-graph resolver with topological ordering and visitor-based activation cascade. Pure Dart.
armature_graph #
Directed-acyclic-graph resolver with topological ordering and
visitor-based activation cascade. Pure Dart. Consumed by
armature to resolve feature
dependencies at container startup; usable standalone for any task that
needs cycle detection + topologically-ordered lifecycle hooks.
Concepts #
Graph<T>— a DAG of nodes where each node has aTpayload with its own declaredparents/optionalParents.GraphNodeStatus—.disabled/.pending/.active.GraphVisitor<T>— user-supplied hooks:shouldBeActive(node)— the node's own preference.onActivate(node)/onDeactivate(node)— called when the node enters / leaves.active.onStatusChanged(node, status)— fires for every settled transition.onError(node, error, st)— receives caught visitor throws.
Usage #
import 'package:armature_graph/armature_graph.dart';
class Node extends GraphNodeValue {
@override final String name;
@override final List<GraphNodeValue> parents;
@override final List<GraphNodeValue> optionalParents = const [];
Node(this.name, [this.parents = const []]);
}
class PrintVisitor implements GraphVisitor<Node> {
@override bool shouldBeActive(Node n) => true;
@override Future<void> onActivate(Node n) async => print('+ ${n.name}');
@override Future<void> onDeactivate(Node n) async => print('- ${n.name}');
@override void onStatusChanged(Node n, GraphNodeStatus s) {}
@override void onError(Node n, Object e, StackTrace st) {
print('! ${n.name}: $e');
}
}
Future<void> main() async {
final a = Node('a');
final b = Node('b', [a]);
final c = Node('c', [b]);
final graph = Graph(nodeValues: [a, b, c], visitor: PrintVisitor());
await graph.resolve();
// prints: + a, + b, + c — topological order
}
Cascade semantics #
resolve()walks the graph to a fixed point — each pass checks every node's preferred status (shouldBeActive) plus required-parent status, activates / deactivates as needed, and drains nested recomputes before returning.GraphFixedPointErrorsurfaces if the cascade fails to stabilise indrainIterationLimitpasses (default 100) — indicates a toggle loop in the user's visitor.GraphCycleError/GraphNodeNotFoundErrorcatch malformed inputs at construction.
Throttling #
Pass activationConcurrency: N to cap parallel onActivate calls via
an internal semaphore. null means unbounded.
Install #
dependencies:
armature_graph: ^0.1.0
Learn more #
armature— the feature framework that uses this graph for dependency resolution.- Monorepo README — full architecture and examples.
License #
MIT — see LICENSE.