import 'package:source_span/source_span.dart'; import 'ast_node.dart'; import 'attribute.dart'; import 'identifier.dart'; import 'token.dart'; abstract class ElementChild extends AstNode {} class TextNode extends ElementChild { final Token text; TextNode(this.text); @override FileSpan get span => text.span; } abstract class Element extends ElementChild { static const List<String> selfClosing = const [ 'include', 'base', 'basefont', 'frame', 'link', 'meta', 'area', 'br', 'col', 'hr', 'img', 'input', 'param', ]; Identifier get tagName; Iterable<Attribute> get attributes; Iterable<ElementChild> get children; } class SelfClosingElement extends Element { final Token lt, slash, gt; final Identifier tagName; final Iterable<Attribute> attributes; @override Iterable<ElementChild> get children => []; SelfClosingElement( this.lt, this.tagName, this.attributes, this.slash, this.gt); @override FileSpan get span { var start = attributes.fold<FileSpan>( lt.span.expand(tagName.span), (out, a) => out.expand(a.span)); return slash != null ? start.expand(slash.span).expand(gt.span) : start.expand(gt.span); } } class RegularElement extends Element { final Token lt, gt, lt2, slash, gt2; final Identifier tagName, tagName2; final Iterable<Attribute> attributes; final Iterable<ElementChild> children; RegularElement(this.lt, this.tagName, this.attributes, this.gt, this.children, this.lt2, this.slash, this.tagName2, this.gt2); @override FileSpan get span { var openingTag = attributes .fold<FileSpan>( lt.span.expand(tagName.span), (out, a) => out.expand(a.span)) .expand(gt.span); if (gt2 == null) return openingTag; return children .fold<FileSpan>(openingTag, (out, c) => out.expand(c.span)) .expand(lt2.span) .expand(slash.span) .expand(tagName2.span) .expand(gt2.span); } }