diff --git a/.rubocop.yml b/.rubocop.yml index 0672d768a..62881c7cf 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -116,6 +116,7 @@ Metrics/BlockLength: Metrics/ParameterLists: Exclude: + - lib/herb/ast/node.rb - lib/herb/ast/nodes.rb - lib/herb/errors.rb - lib/herb/engine/validators/security_validator.rb @@ -178,3 +179,7 @@ Security/MarshalLoad: Lint/UnderscorePrefixedVariableName: Exclude: - test/engine/secure_compiler_test.rb + +Lint/UnusedMethodArgument: + Exclude: + - lib/herb/errors.rb diff --git a/lib/herb/ast/node.rb b/lib/herb/ast/node.rb index e1e5e4270..e1b5768c6 100644 --- a/lib/herb/ast/node.rb +++ b/lib/herb/ast/node.rb @@ -46,8 +46,15 @@ def inspect_errors(prefix: " ") "├── errors: #{inspect_array(errors, item_name: "error", prefix: prefix)}" end - #: (Array[Herb::AST::Node|Herb::Errors::Error], ?item_name: String, ?prefix: String) -> String - def inspect_array(array, item_name: "item", prefix: " ") + #: ( + #| Array[Herb::AST::Node|Herb::Errors::Error], + #| ?item_name: String, + #| ?prefix: String, + #| ?indent: Integer, + #| ?depth: Integer, + #| ?depth_limit: Integer + #| ) -> String + def inspect_array(array, item_name: "item", prefix: " ", indent: 0, depth: 0, depth_limit: 25) output = +"" if array.any? @@ -55,10 +62,12 @@ def inspect_array(array, item_name: "item", prefix: " ") output += "\n" items = array.map { |item| + kwargs = { indent: indent, depth: depth, depth_limit: depth_limit } + if array.last == item - "└── #{item.tree_inspect.gsub(/^/, " ").lstrip}" + "└── #{item.tree_inspect(**kwargs).gsub(/^/, " ").lstrip}" else - "├── #{item.tree_inspect.gsub(/^/, "│ ")}".gsub("├── │ ", "├──") + "├── #{item.tree_inspect(**kwargs).gsub(/^/, "│ ")}".gsub("├── │ ", "├──") end } @@ -71,8 +80,8 @@ def inspect_array(array, item_name: "item", prefix: " ") output end - #: (?Integer) -> String - def tree_inspect(_indent = 0) + #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect(indent: 0, depth: 0, depth_limit: 25) raise NotImplementedError end diff --git a/sig/herb/ast/node.rbs b/sig/herb/ast/node.rbs index c89780470..7d52e7498 100644 --- a/sig/herb/ast/node.rbs +++ b/sig/herb/ast/node.rbs @@ -27,11 +27,18 @@ module Herb # : (?prefix: String) -> String def inspect_errors: (?prefix: String) -> String - # : (Array[Herb::AST::Node|Herb::Errors::Error], ?item_name: String, ?prefix: String) -> String - def inspect_array: (Array[Herb::AST::Node | Herb::Errors::Error], ?item_name: String, ?prefix: String) -> String - - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : ( + # | Array[Herb::AST::Node|Herb::Errors::Error], + # | ?item_name: String, + # | ?prefix: String, + # | ?indent: Integer, + # | ?depth: Integer, + # | ?depth_limit: Integer + # | ) -> String + def inspect_array: (untyped array, ?item_name: untyped, ?prefix: untyped, ?indent: untyped, ?depth: untyped, ?depth_limit: untyped) -> untyped + + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String # : (Visitor) -> void def accept: (Visitor) -> void diff --git a/sig/herb/ast/nodes.rbs b/sig/herb/ast/nodes.rbs index 47ad6767b..a79e16e1f 100644 --- a/sig/herb/ast/nodes.rbs +++ b/sig/herb/ast/nodes.rbs @@ -25,8 +25,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class LiteralNode < Node @@ -52,8 +52,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class HTMLOpenTagNode < Node @@ -87,8 +87,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class HTMLCloseTagNode < Node @@ -120,8 +120,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class HTMLElementNode < Node @@ -157,8 +157,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class HTMLAttributeValueNode < Node @@ -190,8 +190,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class HTMLAttributeNameNode < Node @@ -217,8 +217,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class HTMLAttributeNode < Node @@ -248,8 +248,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class HTMLTextNode < Node @@ -275,8 +275,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class HTMLCommentNode < Node @@ -306,8 +306,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class HTMLDoctypeNode < Node @@ -337,8 +337,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class XMLDeclarationNode < Node @@ -368,8 +368,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class CDATANode < Node @@ -399,8 +399,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class WhitespaceNode < Node @@ -426,8 +426,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBContentNode < Node @@ -463,8 +463,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBEndNode < Node @@ -494,8 +494,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBElseNode < Node @@ -527,8 +527,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBIfNode < Node @@ -564,8 +564,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBBlockNode < Node @@ -599,8 +599,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBWhenNode < Node @@ -632,8 +632,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBCaseNode < Node @@ -671,8 +671,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBCaseMatchNode < Node @@ -710,8 +710,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBWhileNode < Node @@ -745,8 +745,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBUntilNode < Node @@ -780,8 +780,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBForNode < Node @@ -815,8 +815,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBRescueNode < Node @@ -850,8 +850,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBEnsureNode < Node @@ -883,8 +883,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBBeginNode < Node @@ -924,8 +924,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBUnlessNode < Node @@ -961,8 +961,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBYieldNode < Node @@ -992,8 +992,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBInNode < Node @@ -1025,8 +1025,8 @@ module Herb # : () -> String def inspect: () -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end end end diff --git a/sig/herb/errors.rbs b/sig/herb/errors.rbs index 28ba337a5..92d7f4d00 100644 --- a/sig/herb/errors.rbs +++ b/sig/herb/errors.rbs @@ -24,8 +24,8 @@ module Herb # : (?untyped) -> String def to_json: (?untyped) -> String - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class UnexpectedError < Error @@ -46,8 +46,8 @@ module Herb # : () -> serialized_unexpected_error def to_hash: () -> serialized_unexpected_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class UnexpectedTokenError < Error @@ -66,8 +66,8 @@ module Herb # : () -> serialized_unexpected_token_error def to_hash: () -> serialized_unexpected_token_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class MissingOpeningTagError < Error @@ -84,8 +84,8 @@ module Herb # : () -> serialized_missing_opening_tag_error def to_hash: () -> serialized_missing_opening_tag_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class MissingClosingTagError < Error @@ -102,8 +102,8 @@ module Herb # : () -> serialized_missing_closing_tag_error def to_hash: () -> serialized_missing_closing_tag_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class TagNamesMismatchError < Error @@ -122,8 +122,8 @@ module Herb # : () -> serialized_tag_names_mismatch_error def to_hash: () -> serialized_tag_names_mismatch_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class QuotesMismatchError < Error @@ -142,8 +142,8 @@ module Herb # : () -> serialized_quotes_mismatch_error def to_hash: () -> serialized_quotes_mismatch_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class VoidElementClosingTagError < Error @@ -164,8 +164,8 @@ module Herb # : () -> serialized_void_element_closing_tag_error def to_hash: () -> serialized_void_element_closing_tag_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class UnclosedElementError < Error @@ -182,8 +182,8 @@ module Herb # : () -> serialized_unclosed_element_error def to_hash: () -> serialized_unclosed_element_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class RubyParseError < Error @@ -204,8 +204,8 @@ module Herb # : () -> serialized_ruby_parse_error def to_hash: () -> serialized_ruby_parse_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class ERBControlFlowScopeError < Error @@ -222,8 +222,8 @@ module Herb # : () -> serialized_erb_control_flow_scope_error def to_hash: () -> serialized_erb_control_flow_scope_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end class MissingERBEndTagError < Error @@ -240,8 +240,8 @@ module Herb # : () -> serialized_missingerb_end_tag_error def to_hash: () -> serialized_missingerb_end_tag_error - # : (?Integer) -> String - def tree_inspect: (?Integer) -> String + # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String end end end diff --git a/templates/lib/herb/ast/nodes.rb.erb b/templates/lib/herb/ast/nodes.rb.erb index f02c14ea1..3fa363070 100644 --- a/templates/lib/herb/ast/nodes.rb.erb +++ b/templates/lib/herb/ast/nodes.rb.erb @@ -57,13 +57,19 @@ module Herb tree_inspect.rstrip.gsub(/\s+$/, "") end - #: (?Integer) -> String - def tree_inspect(indent = 0) + #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect(indent: 0, depth: 0, depth_limit: 10) output = +"" output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}") output += "\n" + if depth >= depth_limit + output += dimmed("└── [depth limit reached ...]\n\n") + + return output.gsub(/^/, " " * indent) + end + output += inspect_errors(prefix: "<%= node.fields.any? ? "│ " : " " %>") <%- node.fields.each do |field| -%> @@ -95,7 +101,7 @@ module Herb <%- else -%> output += "│ └── " <%- end -%> - output += <%= field.name %>.tree_inspect(indent).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "<%= prefix %>").delete_prefix("<%= prefix %>") + output += <%= field.name %>.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "<%= prefix %>").delete_prefix("<%= prefix %>") <%- if false -%> <%- unless node.fields.last == field -%> output += "\n" @@ -107,7 +113,7 @@ module Herb end <%- when Herb::Template::ArrayField -%> output += white("<%= symbol %> <%= field.name %>: ") - output += inspect_array(<%= field.name %>, prefix: "<%= (node.fields.last == field) ? " " : "│ " %>") + output += inspect_array(<%= field.name %>, prefix: "<%= (node.fields.last == field) ? " " : "│ " %>", indent: indent, depth: depth + 1, depth_limit: depth_limit) <%- else -%> <%- raise "Unhandled type: #{field.class}" -%> <%- end -%> diff --git a/templates/lib/herb/errors.rb.erb b/templates/lib/herb/errors.rb.erb index 8fe497990..da4a8474a 100644 --- a/templates/lib/herb/errors.rb.erb +++ b/templates/lib/herb/errors.rb.erb @@ -37,8 +37,8 @@ module Herb to_hash.to_json(state) end - #: (?Integer) -> String - def tree_inspect(_indent = 0) + #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect(indent: 0, depth: 0, depth_limit: 25) raise NotImplementedError end end @@ -74,8 +74,8 @@ module Herb }) #: Herb::serialized_<%= error.human %> end - #: (?Integer) -> String - def tree_inspect(indent = 0) + #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String + def tree_inspect(indent: 0, depth: 0, depth_limit: 25) output = +"" output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}") diff --git a/test/ast/tree_inspect_test.rb b/test/ast/tree_inspect_test.rb new file mode 100644 index 000000000..1a8b3e36f --- /dev/null +++ b/test/ast/tree_inspect_test.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +module AST + class TreeInspectTest < Minitest::Spec + include SnapshotUtils + + test "deeply nested document" do + assert_parsed_snapshot(<<~ERB) +
+
+
+
+
+
+
+
+
+
+
+
+

Very deep nesting

+
+
+
+
+
+
+
+
+
+
+
+
+ ERB + end + + test "deeply nested with attributes" do + assert_parsed_snapshot(<<~ERB) +
+
+
+
+
+
+
+
+
+

Deep with attributes

+
+
+
+
+
+
+
+
+
+ ERB + end + end +end diff --git a/test/snapshots/ast/tree_inspect_test/test_0001_deeply_nested_document_4593d80d72ab12fb3c2b889b019dd0cb.txt b/test/snapshots/ast/tree_inspect_test/test_0001_deeply_nested_document_4593d80d72ab12fb3c2b889b019dd0cb.txt new file mode 100644 index 000000000..1b5a82dc2 --- /dev/null +++ b/test/snapshots/ast/tree_inspect_test/test_0001_deeply_nested_document_4593d80d72ab12fb3c2b889b019dd0cb.txt @@ -0,0 +1,272 @@ +--- +source: "AST::TreeInspectTest#test_0001_deeply nested document" +input: |2- +
+
+
+
+
+
+
+
+
+
+
+
+

Very deep nesting

+
+
+
+
+
+
+
+
+
+
+
+
+--- +@ DocumentNode (location: (1:0)-(26:0)) +└── children: (2 items) + ├── @ HTMLElementNode (location: (1:0)-(25:6)) + │ ├── open_tag: + │ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:5)) + │ │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ │ ├── tag_closing: ">" (location: (1:4)-(1:5)) + │ │ ├── children: [] + │ │ └── is_void: false + │ │ + │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ ├── body: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:5)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (2:2)-(24:8)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (2:2)-(2:7)) + │ │ │ │ ├── tag_opening: "<" (location: (2:2)-(2:3)) + │ │ │ │ ├── tag_name: "div" (location: (2:3)-(2:6)) + │ │ │ │ ├── tag_closing: ">" (location: (2:6)-(2:7)) + │ │ │ │ ├── children: [] + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "div" (location: (2:3)-(2:6)) + │ │ │ ├── body: (3 items) + │ │ │ │ ├── @ HTMLTextNode (location: (2:7)-(3:4)) + │ │ │ │ │ └── content: "\n " + │ │ │ │ │ + │ │ │ │ ├── @ HTMLElementNode (location: (3:4)-(23:10)) + │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (3:4)-(3:9)) + │ │ │ │ │ │ ├── tag_opening: "<" (location: (3:4)-(3:5)) + │ │ │ │ │ │ ├── tag_name: "div" (location: (3:5)-(3:8)) + │ │ │ │ │ │ ├── tag_closing: ">" (location: (3:8)-(3:9)) + │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ + │ │ │ │ │ ├── tag_name: "div" (location: (3:5)-(3:8)) + │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ ├── @ HTMLTextNode (location: (3:9)-(4:6)) + │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ + │ │ │ │ │ │ ├── @ HTMLElementNode (location: (4:6)-(22:12)) + │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (4:6)-(4:11)) + │ │ │ │ │ │ │ │ ├── tag_opening: "<" (location: (4:6)-(4:7)) + │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (4:7)-(4:10)) + │ │ │ │ │ │ │ │ ├── tag_closing: ">" (location: (4:10)-(4:11)) + │ │ │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ ├── tag_name: "div" (location: (4:7)-(4:10)) + │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (4:11)-(5:8)) + │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (5:8)-(21:14)) + │ │ │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (5:8)-(5:13)) + │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "<" (location: (5:8)-(5:9)) + │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (5:9)-(5:12)) + │ │ │ │ │ │ │ │ │ │ ├── tag_closing: ">" (location: (5:12)-(5:13)) + │ │ │ │ │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (5:9)-(5:12)) + │ │ │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (5:13)-(6:10)) + │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (6:10)-(20:16)) + │ │ │ │ │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (6:10)-(6:15)) + │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "<" (location: (6:10)-(6:11)) + │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (6:11)-(6:14)) + │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_closing: ">" (location: (6:14)-(6:15)) + │ │ │ │ │ │ │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (6:11)-(6:14)) + │ │ │ │ │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (6:15)-(7:12)) + │ │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (7:12)-(19:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (7:12)-(7:17)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "<" (location: (7:12)-(7:13)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (7:13)-(7:16)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_closing: ">" (location: (7:16)-(7:17)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (7:13)-(7:16)) + │ │ │ │ │ │ │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (7:17)-(8:14)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (8:14)-(18:20)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (8:14)-(8:19)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "<" (location: (8:14)-(8:15)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (8:15)-(8:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_closing: ">" (location: (8:18)-(8:19)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (8:15)-(8:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (8:19)-(9:16)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (9:16)-(17:22)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (9:16)-(9:21)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── [depth limit reached ...] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (9:17)-(9:20)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (9:21)-(10:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── [depth limit reached ...] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (10:18)-(16:24)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── [depth limit reached ...] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (16:24)-(17:16)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── [depth limit reached ...] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (17:16)-(17:22)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── [depth limit reached ...] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (17:22)-(18:14)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (18:14)-(18:20)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "" (location: (18:19)-(18:20)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (18:20)-(19:12)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (19:12)-(19:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "" (location: (19:17)-(19:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (19:18)-(20:10)) + │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (20:10)-(20:16)) + │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "" (location: (20:15)-(20:16)) + │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (20:16)-(21:8)) + │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (21:8)-(21:14)) + │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "" (location: (21:13)-(21:14)) + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (21:14)-(22:6)) + │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (22:6)-(22:12)) + │ │ │ │ │ │ │ │ ├── tag_opening: "" (location: (22:11)-(22:12)) + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ + │ │ │ │ │ │ └── @ HTMLTextNode (location: (22:12)-(23:4)) + │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ + │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (23:4)-(23:10)) + │ │ │ │ │ │ ├── tag_opening: "" (location: (23:9)-(23:10)) + │ │ │ │ │ │ + │ │ │ │ │ ├── is_void: false + │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ + │ │ │ │ └── @ HTMLTextNode (location: (23:10)-(24:2)) + │ │ │ │ └── content: "\n " + │ │ │ │ + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (24:2)-(24:8)) + │ │ │ │ ├── tag_opening: "" (location: (24:7)-(24:8)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (24:8)-(25:0)) + │ │ └── content: "\n" + │ │ + │ ├── close_tag: + │ │ └── @ HTMLCloseTagNode (location: (25:0)-(25:6)) + │ │ ├── tag_opening: "" (location: (25:5)-(25:6)) + │ │ + │ ├── is_void: false + │ └── source: "HTML" + │ + └── @ HTMLTextNode (location: (25:6)-(26:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/ast/tree_inspect_test/test_0002_deeply_nested_with_attributes_f06a9fd72ce823160a92ff8ec5433c9e.txt b/test/snapshots/ast/tree_inspect_test/test_0002_deeply_nested_with_attributes_f06a9fd72ce823160a92ff8ec5433c9e.txt new file mode 100644 index 000000000..57ff62007 --- /dev/null +++ b/test/snapshots/ast/tree_inspect_test/test_0002_deeply_nested_with_attributes_f06a9fd72ce823160a92ff8ec5433c9e.txt @@ -0,0 +1,266 @@ +--- +source: "AST::TreeInspectTest#test_0002_deeply nested with attributes" +input: |2- +
+
+
+
+
+
+
+
+
+

Deep with attributes

+
+
+
+
+
+
+
+
+
+--- +@ DocumentNode (location: (1:0)-(20:0)) +└── children: (2 items) + ├── @ HTMLElementNode (location: (1:0)-(19:6)) + │ ├── open_tag: + │ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:5)) + │ │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ │ ├── tag_closing: ">" (location: (1:4)-(1:5)) + │ │ ├── children: [] + │ │ └── is_void: false + │ │ + │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ ├── body: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:5)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (2:2)-(18:8)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (2:2)-(2:7)) + │ │ │ │ ├── tag_opening: "<" (location: (2:2)-(2:3)) + │ │ │ │ ├── tag_name: "div" (location: (2:3)-(2:6)) + │ │ │ │ ├── tag_closing: ">" (location: (2:6)-(2:7)) + │ │ │ │ ├── children: [] + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "div" (location: (2:3)-(2:6)) + │ │ │ ├── body: (3 items) + │ │ │ │ ├── @ HTMLTextNode (location: (2:7)-(3:4)) + │ │ │ │ │ └── content: "\n " + │ │ │ │ │ + │ │ │ │ ├── @ HTMLElementNode (location: (3:4)-(17:10)) + │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (3:4)-(3:9)) + │ │ │ │ │ │ ├── tag_opening: "<" (location: (3:4)-(3:5)) + │ │ │ │ │ │ ├── tag_name: "div" (location: (3:5)-(3:8)) + │ │ │ │ │ │ ├── tag_closing: ">" (location: (3:8)-(3:9)) + │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ + │ │ │ │ │ ├── tag_name: "div" (location: (3:5)-(3:8)) + │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ ├── @ HTMLTextNode (location: (3:9)-(4:6)) + │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ + │ │ │ │ │ │ ├── @ HTMLElementNode (location: (4:6)-(16:12)) + │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (4:6)-(4:11)) + │ │ │ │ │ │ │ │ ├── tag_opening: "<" (location: (4:6)-(4:7)) + │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (4:7)-(4:10)) + │ │ │ │ │ │ │ │ ├── tag_closing: ">" (location: (4:10)-(4:11)) + │ │ │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ ├── tag_name: "div" (location: (4:7)-(4:10)) + │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (4:11)-(5:8)) + │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (5:8)-(15:14)) + │ │ │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (5:8)-(5:13)) + │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "<" (location: (5:8)-(5:9)) + │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (5:9)-(5:12)) + │ │ │ │ │ │ │ │ │ │ ├── tag_closing: ">" (location: (5:12)-(5:13)) + │ │ │ │ │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (5:9)-(5:12)) + │ │ │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (5:13)-(6:10)) + │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (6:10)-(14:16)) + │ │ │ │ │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (6:10)-(6:15)) + │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "<" (location: (6:10)-(6:11)) + │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (6:11)-(6:14)) + │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_closing: ">" (location: (6:14)-(6:15)) + │ │ │ │ │ │ │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (6:11)-(6:14)) + │ │ │ │ │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (6:15)-(7:12)) + │ │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (7:12)-(13:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (7:12)-(7:17)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "<" (location: (7:12)-(7:13)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (7:13)-(7:16)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_closing: ">" (location: (7:16)-(7:17)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (7:13)-(7:16)) + │ │ │ │ │ │ │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (7:17)-(8:14)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (8:14)-(12:20)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (8:14)-(8:19)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "<" (location: (8:14)-(8:15)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (8:15)-(8:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_closing: ">" (location: (8:18)-(8:19)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── children: [] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (8:15)-(8:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (8:19)-(9:16)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (9:16)-(11:22)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (9:16)-(9:72)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── [depth limit reached ...] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_name: "div" (location: (9:17)-(9:20)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── body: (3 items) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLTextNode (location: (9:72)-(10:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── [depth limit reached ...] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── @ HTMLElementNode (location: (10:18)-(10:45)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── [depth limit reached ...] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (10:45)-(11:16)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── [depth limit reached ...] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (11:16)-(11:22)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── [depth limit reached ...] + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (11:22)-(12:14)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (12:14)-(12:20)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "" (location: (12:19)-(12:20)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (12:20)-(13:12)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (13:12)-(13:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "" (location: (13:17)-(13:18)) + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (13:18)-(14:10)) + │ │ │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (14:10)-(14:16)) + │ │ │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "" (location: (14:15)-(14:16)) + │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (14:16)-(15:8)) + │ │ │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (15:8)-(15:14)) + │ │ │ │ │ │ │ │ │ │ ├── tag_opening: "" (location: (15:13)-(15:14)) + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ └── @ HTMLTextNode (location: (15:14)-(16:6)) + │ │ │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (16:6)-(16:12)) + │ │ │ │ │ │ │ │ ├── tag_opening: "" (location: (16:11)-(16:12)) + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ ├── is_void: false + │ │ │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ │ │ + │ │ │ │ │ │ └── @ HTMLTextNode (location: (16:12)-(17:4)) + │ │ │ │ │ │ └── content: "\n " + │ │ │ │ │ │ + │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (17:4)-(17:10)) + │ │ │ │ │ │ ├── tag_opening: "" (location: (17:9)-(17:10)) + │ │ │ │ │ │ + │ │ │ │ │ ├── is_void: false + │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ + │ │ │ │ └── @ HTMLTextNode (location: (17:10)-(18:2)) + │ │ │ │ └── content: "\n " + │ │ │ │ + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (18:2)-(18:8)) + │ │ │ │ ├── tag_opening: "" (location: (18:7)-(18:8)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (18:8)-(19:0)) + │ │ └── content: "\n" + │ │ + │ ├── close_tag: + │ │ └── @ HTMLCloseTagNode (location: (19:0)-(19:6)) + │ │ ├── tag_opening: "" (location: (19:5)-(19:6)) + │ │ + │ ├── is_void: false + │ └── source: "HTML" + │ + └── @ HTMLTextNode (location: (19:6)-(20:0)) + └── content: "\n" \ No newline at end of file