ast.dart 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
  2. // for details. All rights reserved. Use of this source code is governed by a
  3. // BSD-style license that can be found in the LICENSE file.
  4. typedef Resolver = Node? Function(String name, [String? title]);
  5. /// Base class for any AST item.
  6. ///
  7. /// Roughly corresponds to Node in the DOM. Will be either an Element or Text.
  8. class Node {
  9. void accept(NodeVisitor visitor) {}
  10. bool isToplevel = false;
  11. String? get textContent {
  12. return null;
  13. }
  14. }
  15. /// A named tag that can contain other nodes.
  16. class Element extends Node {
  17. /// Instantiates a [tag] Element with [children].
  18. Element(this.tag, this.children) : attributes = <String, String>{};
  19. /// Instantiates an empty, self-closing [tag] Element.
  20. Element.empty(this.tag)
  21. : children = null,
  22. attributes = {};
  23. /// Instantiates a [tag] Element with no [children].
  24. Element.withTag(this.tag)
  25. : children = [],
  26. attributes = {};
  27. /// Instantiates a [tag] Element with a single Text child.
  28. Element.text(this.tag, String text)
  29. : children = [Text(text)],
  30. attributes = {};
  31. final String tag;
  32. final List<Node>? children;
  33. final Map<String, String> attributes;
  34. String? generatedId;
  35. /// Whether this element is self-closing.
  36. bool get isEmpty => children == null;
  37. @override
  38. void accept(NodeVisitor visitor) {
  39. if (visitor.visitElementBefore(this)) {
  40. if (children != null) {
  41. for (final child in children!) {
  42. child.accept(visitor);
  43. }
  44. }
  45. visitor.visitElementAfter(this);
  46. }
  47. }
  48. @override
  49. String get textContent => children == null
  50. ? ''
  51. : children!.map((child) => child.textContent).join();
  52. }
  53. /// A plain text element.
  54. class Text extends Node {
  55. Text(this.text);
  56. final String text;
  57. @override
  58. void accept(NodeVisitor visitor) => visitor.visitText(this);
  59. @override
  60. String get textContent => text;
  61. }
  62. /// Inline content that has not been parsed into inline nodes (strong, links,
  63. /// etc).
  64. ///
  65. /// These placeholder nodes should only remain in place while the block nodes
  66. /// of a document are still being parsed, in order to gather all reference link
  67. /// definitions.
  68. class UnparsedContent extends Node {
  69. UnparsedContent(this.textContent);
  70. @override
  71. final String textContent;
  72. @override
  73. void accept(NodeVisitor visitor);
  74. }
  75. /// Visitor pattern for the AST.
  76. ///
  77. /// Renderers or other AST transformers should implement this.
  78. abstract class NodeVisitor {
  79. /// Called when a Text node has been reached.
  80. void visitText(Text text);
  81. /// Called when an Element has been reached, before its children have been
  82. /// visited.
  83. ///
  84. /// Returns `false` to skip its children.
  85. bool visitElementBefore(Element element);
  86. /// Called when an Element has been reached, after its children have been
  87. /// visited.
  88. ///
  89. /// Will not be called if [visitElementBefore] returns `false`.
  90. void visitElementAfter(Element element);
  91. }