import 'node.dart'; /// Helper class to build nodes. class NodeBuilder { final String tagName; final Map attributes; final Iterable children; Node? _existing; NodeBuilder(this.tagName, {this.attributes = const {}, this.children = const []}); /// Creates a [NodeBuilder] that just spits out an already-existing [Node]. factory NodeBuilder.existing(Node existingNode) => NodeBuilder(existingNode.tagName).._existing = existingNode; factory NodeBuilder.from(Node node) => NodeBuilder(node.tagName, attributes: Map.from(node.attributes), children: List.from(node.children)); /// Builds the node. Node build({bool selfClosing = false}) => _existing ?? (selfClosing ? SelfClosingNode(tagName, attributes) : Node(tagName, attributes, children)); /// Produce a modified copy of this builder. NodeBuilder change( {String? tagName, Map? attributes, Iterable? children}) { return NodeBuilder(tagName ?? this.tagName, attributes: attributes ?? this.attributes, children: children ?? this.children); } NodeBuilder changeTagName(String tagName) => change(tagName: tagName); NodeBuilder changeAttributes(Map attributes) => change(attributes: attributes); NodeBuilder changeChildren(Iterable children) => change(children: children); NodeBuilder changeAttributesMapped( Map Function(Map) f) { var map = Map.from(attributes); return changeAttributes(f(map)); } NodeBuilder changeChildrenMapped(Iterable Function(List) f) { var list = List.from(children); return changeChildren(f(list)); } NodeBuilder mapChildren(Node Function(Node) f) => changeChildrenMapped((list) => list.map(f)); NodeBuilder mapAttributes( MapEntry Function(String, dynamic) f) => changeAttributesMapped((map) => map.map(f)); NodeBuilder setAttribute(String name, dynamic value) => changeAttributesMapped((map) => map..[name] = value); NodeBuilder addChild(Node child) => changeChildrenMapped((list) => list..add(child)); NodeBuilder removeChild(Node child) => changeChildrenMapped((list) => list..remove(child)); NodeBuilder removeAttribute(String name) => changeAttributesMapped((map) => map..remove(name)); NodeBuilder setId(String id) => setAttribute('id', id); NodeBuilder setClassName(String className) => setAttribute('class', className); NodeBuilder setClasses(Iterable classes) => setClassName(classes.join(' ')); NodeBuilder setClassesMapped(Iterable Function(List) f) { var clazz = attributes['class']; var classes = []; if (clazz is String) { classes.addAll(clazz.split(' ')); } else if (clazz is Iterable) { classes.addAll(clazz.map((s) => s.toString())); } return setClasses(f(classes)); } NodeBuilder addClass(String className) => setClassesMapped( (classes) => classes.contains(className) ? classes : classes ..add(className)); NodeBuilder removeClass(String className) => setClassesMapped((classes) => classes..remove(className)); NodeBuilder toggleClass(String className) => setClassesMapped((classes) => classes.contains(className) ? (classes..remove(className)) : (classes..add(className))); }