2525 */
2626class ComponentLexer extends Lexer
2727{
28- public const ATTRIBUTES_REGEX = '(?<attributes>(?:\s+[\w\-:.@]+(=(?: \\\"[^ \\\"]* \\\"| \'[^ \']* \'|[^ \'\\\"=<>]+))?)*\s*) ' ;
29- public const OPEN_TAGS_REGEX = '/<\s*t:(?<name>([[\w\-\:\.]+))\s* ' .self ::ATTRIBUTES_REGEX .'(\s?)+>/ ' ;
30- public const CLOSE_TAGS_REGEX = '/<\/\s*t:([\w\-\:\.]+)\s*>/ ' ;
31- public const SELF_CLOSE_TAGS_REGEX = '/<\s*t:(?<name>([\w\-\:\.]+))\s* ' .self ::ATTRIBUTES_REGEX .'(\s?)+\/>/ ' ;
32- public const BLOCK_TAGS_OPEN = '/<\s*t:block\s+name=("| \')(?<name>([\w\-\:\.]+))("| \')\s*>/ ' ;
33- public const BLOCK_TAGS_CLOSE = '/<\s*\/\s*t:block\s*>/ ' ;
34- public const ATTRIBUTE_BAG_REGEX = '/(?:^|\s+)\{\{\s*(attributes(?:.+?(?<!\s))?)\s*\}\}/x ' ;
35- public const ATTRIBUTE_KEY_VALUE_REGEX = '/(?<attribute>[\w\-:.@]+)(=(?<value>(\"[^\"]+\"| \\\'[^ \\\']+ \\\'|[^\s>]+)))?/x ' ;
36-
3728 public function tokenize (Source $ source ): TokenStream
3829 {
39- $ preparsed = $ this ->preparsed ($ source ->getCode ());
30+ $ preLexer = new TwigPreLexer ();
31+ $ preparsed = $ preLexer ->preLexComponents ($ source ->getCode ());
4032
4133 return parent ::tokenize (
4234 new Source (
@@ -46,124 +38,4 @@ public function tokenize(Source $source): TokenStream
4638 )
4739 );
4840 }
49-
50- private function preparsed (string $ value )
51- {
52- $ value = $ this ->lexBlockTags ($ value );
53- $ value = $ this ->lexBlockTagsClose ($ value );
54- $ value = $ this ->lexSelfCloseTag ($ value );
55- $ value = $ this ->lexOpeningTags ($ value );
56- $ value = $ this ->lexClosingTag ($ value );
57-
58- return $ value ;
59- }
60-
61- private function lexOpeningTags (string $ value )
62- {
63- return preg_replace_callback (
64- self ::OPEN_TAGS_REGEX ,
65- function (array $ matches ) {
66- $ name = $ matches ['name ' ];
67- $ attributes = $ this ->getAttributesFromAttributeString ($ matches ['attributes ' ]);
68-
69- return '{% component ' .$ name .' with ' .$ attributes .'%} ' ;
70- },
71- $ value
72- );
73- }
74-
75- private function lexClosingTag (string $ value )
76- {
77- return preg_replace (self ::CLOSE_TAGS_REGEX , '{% endcomponent %} ' , $ value );
78- }
79-
80- private function lexSelfCloseTag (string $ value )
81- {
82- return preg_replace_callback (
83- self ::SELF_CLOSE_TAGS_REGEX ,
84- function (array $ matches ) {
85- $ name = $ matches ['name ' ];
86- $ attributes = $ this ->getAttributesFromAttributeString ($ matches ['attributes ' ]);
87-
88- return "{{ component(' " .$ name ."', " .$ attributes .') }} ' ;
89- },
90- $ value
91- );
92- }
93-
94- private function lexBlockTags (string $ value )
95- {
96- return preg_replace_callback (
97- self ::BLOCK_TAGS_OPEN ,
98- function (array $ matches ) {
99- $ name = $ matches ['name ' ];
100-
101- return '{% block ' .$ name .' %} ' ;
102- },
103- $ value
104- );
105- }
106-
107- private function lexBlockTagsClose (string $ value )
108- {
109- return preg_replace (
110- self ::BLOCK_TAGS_CLOSE ,
111- '{% endblock %} ' ,
112- $ value
113- );
114- }
115-
116- protected function getAttributesFromAttributeString (string $ attributeString )
117- {
118- $ attributeString = $ this ->parseAttributeBag ($ attributeString );
119-
120- if (!preg_match_all (self ::ATTRIBUTE_KEY_VALUE_REGEX , $ attributeString , $ matches , \PREG_SET_ORDER )) {
121- return '{} ' ;
122- }
123-
124- $ attributes = [];
125- foreach ($ matches as $ match ) {
126- $ attribute = $ match ['attribute ' ];
127- $ value = $ match ['value ' ] ?? null ;
128-
129- if (null === $ value ) {
130- $ value = 'true ' ;
131- }
132-
133- if (str_starts_with ($ attribute , ': ' )) {
134- $ attribute = str_replace (': ' , '' , $ attribute );
135- $ value = $ this ->stripQuotes ($ value );
136- }
137-
138- $ valueWithoutQuotes = $ this ->stripQuotes ($ value );
139-
140- if (str_starts_with ($ valueWithoutQuotes , '{{ ' ) && (strpos ($ valueWithoutQuotes , '}} ' ) === \strlen ($ valueWithoutQuotes ) - 2 )) {
141- $ value = substr ($ valueWithoutQuotes , 2 , -2 );
142- } else {
143- $ value = $ value ;
144- }
145-
146- $ attributes [$ attribute ] = $ value ;
147- }
148-
149- $ out = '{ ' ;
150- foreach ($ attributes as $ key => $ value ) {
151- $ key = "' $ key' " ;
152- $ out .= "$ key: $ value, " ;
153- }
154-
155- return rtrim ($ out , ', ' ).'} ' ;
156- }
157-
158- public function stripQuotes (string $ value )
159- {
160- return str_starts_with ($ value , '" ' ) || str_starts_with ($ value , '\'' )
161- ? substr ($ value , 1 , -1 )
162- : $ value ;
163- }
164-
165- protected function parseAttributeBag (string $ attributeString )
166- {
167- return preg_replace (self ::ATTRIBUTE_BAG_REGEX , ' :attributes="$1" ' , $ attributeString );
168- }
16941}
0 commit comments