@@ -20,7 +20,8 @@ class TwigPreLexer
20
20
private int $ length ;
21
21
private int $ position = 0 ;
22
22
private int $ line ;
23
- /** @var string[] */
23
+ // each item has a "name" string key and a "hasDefaultBlock" bool key
24
+ /** @var array<string: name, bool: hasDefaultBlock> */
24
25
private array $ currentComponents = [];
25
26
26
27
public function __construct (int $ startingLine = 1 )
@@ -39,6 +40,13 @@ public function preLexComponents(string $input): string
39
40
$ componentName = $ this ->consumeComponentName ();
40
41
41
42
if ('block ' === $ componentName ) {
43
+ // if we're already inside the "default" block, let's close it
44
+ if (!empty ($ this ->currentComponents ) && $ this ->currentComponents [\count ($ this ->currentComponents ) - 1 ]['hasDefaultBlock ' ]) {
45
+ $ output .= '{% endblock %} ' ;
46
+
47
+ $ this ->currentComponents [\count ($ this ->currentComponents ) - 1 ]['hasDefaultBlock ' ] = false ;
48
+ }
49
+
42
50
$ output .= $ this ->consumeBlock ();
43
51
44
52
continue ;
@@ -48,7 +56,7 @@ public function preLexComponents(string $input): string
48
56
$ isSelfClosing = $ this ->consume ('/> ' );
49
57
if (!$ isSelfClosing ) {
50
58
$ this ->consume ('> ' );
51
- $ this ->currentComponents [] = $ componentName ;
59
+ $ this ->currentComponents [] = [ ' name ' => $ componentName, ' hasDefaultBlock ' => false ] ;
52
60
}
53
61
54
62
$ output .= "{% component {$ componentName }" .($ attributes ? " with { {$ attributes } } " : '' ).' %} ' ;
@@ -65,9 +73,16 @@ public function preLexComponents(string $input): string
65
73
$ this ->consume ('> ' );
66
74
67
75
$ lastComponent = array_pop ($ this ->currentComponents );
76
+ $ lastComponentName = $ lastComponent ['name ' ];
68
77
69
- if ($ closingComponentName !== $ lastComponent ) {
70
- throw new \RuntimeException ("Expected closing tag '</t: {$ lastComponent }>' but found '</t: {$ closingComponentName }>' at line {$ this ->line }" );
78
+ if ($ closingComponentName !== $ lastComponentName ) {
79
+ throw new \RuntimeException ("Expected closing tag '</t: {$ lastComponentName }>' but found '</t: {$ closingComponentName }>' at line {$ this ->line }" );
80
+ }
81
+
82
+ // we've reached the end of this component. If we're inside the
83
+ // default block, let's close it
84
+ if ($ lastComponent ['hasDefaultBlock ' ]) {
85
+ $ output .= '{% endblock %} ' ;
71
86
}
72
87
73
88
$ output .= '{% endcomponent %} ' ;
@@ -79,9 +94,24 @@ public function preLexComponents(string $input): string
79
94
if ("\n" === $ char ) {
80
95
++$ this ->line ;
81
96
}
97
+
98
+ // handle adding a default block if needed
99
+ if (!empty ($ this ->currentComponents )
100
+ && !$ this ->currentComponents [\count ($ this ->currentComponents ) - 1 ]['hasDefaultBlock ' ]
101
+ && preg_match ('/\S/ ' , $ char )
102
+ ) {
103
+ $ this ->currentComponents [\count ($ this ->currentComponents ) - 1 ]['hasDefaultBlock ' ] = true ;
104
+ $ output .= '{% block default %} ' ;
105
+ }
106
+
82
107
$ output .= $ char ;
83
108
}
84
109
110
+ if (!empty ($ this ->currentComponents )) {
111
+ $ lastComponent = array_pop ($ this ->currentComponents )['name ' ];
112
+ throw new \RuntimeException (sprintf ('Expected closing tag "</t:%s>" not found at line %d. ' , $ lastComponent , $ this ->line ));
113
+ }
114
+
85
115
return $ output ;
86
116
}
87
117
0 commit comments