Repository: tatuylonen/wikitextprocessor

Issue:
Weird parsing of broken templates
```python
    def test_hdr_bad(self):
        tree = self.parse(
            "test",
            """==Türkçe==
===Köken===
:Foo.
===Bar===
* Baz
===Fee===
# Foo
====Fie====
Fum
* Almanca: {{==Türkçe==

===Oof===
:Rab.
===Zab===
* Lorem ipsum}}
""",
        )
        print_tree(tree)
        self.assertEqual(True, False)
```

Gives

```
ROOT [['test']]
  LEVEL2 [['Türkçe'], ['\n', <LEVEL3(['Köken']){} '\n', <LIST(:){} <LIST_ITEM(:){} 'Foo.\n'>>>, <LEVEL3(['Bar']){} '\n', <LIST(*){} <LIST_ITEM(*){} ' Baz\n'>>>, <LEVEL3(['Fee']){} '\n', <LIST(#){} <LIST_ITEM(#){} ' Foo\n'>>, <LEVEL4(['Fie']){} '\nFum\n', <LIST(*){} <LIST_ITEM(*){} ' Almanca: ', <TEMPLATE(['==Türkçe']){} >>>>>]]
    '\n\n'
    LEVEL3 [['Oof']]
      '\n:Rab.\n'
    LEVEL3 [['Zab']]
      '\n* Lorem ipsum'
  '\n'
```

Removing the `}}` after `Lorem ipsum` gives

```
ROOT [['test']]
  LEVEL2 [['Türkçe']]
    '\n'
    LEVEL3 [['Köken']]
      '\n'
      LIST :
        LIST_ITEM :
          'Foo.\n'
    LEVEL3 [['Bar']]
      '\n'
      LIST *
        LIST_ITEM *
          ' Baz\n'
    LEVEL3 [['Fee']]
      '\n'
      LIST #
        LIST_ITEM #
          ' Foo\n'
      LEVEL4 [['Fie']]
        '\nFum\n'
        LIST *
          LIST_ITEM *
            ' Almanca: {{==Türkçe==\n'
        '\n'
    LEVEL3 [['Oof']]
      '\n'
      LIST :
        LIST_ITEM :
          'Rab.\n'
    LEVEL3 [['Zab']]
      '\n'
      LIST *
        LIST_ITEM *
          ' Lorem ipsum\n'
```

We would prefer the latter, where the broken template is output as text.

Discussion:

Solution patch:
diff --git a/src/wikitextprocessor/parser.py b/src/wikitextprocessor/parser.py
index 6cc5735..bff0653 100644
--- a/src/wikitextprocessor/parser.py
+++ b/src/wikitextprocessor/parser.py
@@ -1076,7 +1076,7 @@ def subtitle_end_fn(ctx: "Wtp", token: str) -> None:
     pop_count = 0
     find_start_node = False
     for parent_node in reversed(ctx.parser_stack):
-        if parent_node.kind == kind:
+        if parent_node.kind == kind and parent_node.loc == ctx.linenum:
             for _ in range(pop_count):
                 _parser_pop(ctx, True)
             find_start_node = True


Test patch:
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 3e55955..2bbe0de 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -3190,6 +3190,23 @@ text
         self.assertEqual(root.children[0].kind, NodeKind.TEMPLATE)
         self.assertEqual(self.ctx.node_to_html(root), "textaaa")
 
+    def test_deformed_level_nodes(self):
+        # the section end "==" token in "{{==Türkçe==" shouldn't close the
+        # first level 2 node and move all the nodes in between to `.largs`
+        root = self.parse(
+            "deist",
+            """==Türkçe==
+====Çeviriler====
+* Almanca: {{==Türkçe==
+
+===Kaynakça===
+* {{Kaynak-TDK}}}}
+""",
+        )
+        level_2 = root.children[0]
+        self.assertEqual(level_2.kind, NodeKind.LEVEL2)
+        self.assertEqual(level_2.children[1].kind, NodeKind.LEVEL4)
+
 
 # XXX implement <nowiki/> marking for links, templates
 #  - https://en.wikipedia.org/wiki/Help:Wikitext#Nowiki