@@ -27,7 +27,7 @@ class TagEngine
2727 *
2828 * @var string
2929 */
30- protected string $ regex = ' /<%s-([\w-]+)\s*((?:"[^"]*"| \' [^ \' ]* \' |[^ \' ">])*)\/\s*>|<%s-([\w-]+)\s*((?:"[^"]*"| \' [^ \' ]* \' |[^ \' ">])*)>(.*?)<\/%s-\3>/s ' ;
30+ protected string $ regex ;
3131
3232 /**
3333 * Holds the data array which is passed to the custom tags
@@ -47,8 +47,7 @@ public function __construct(array $options = [])
4747 if ($ options ) {
4848 $ this ->options = array_merge ($ this ->options , $ options );
4949 }
50- $ prefix = $ this ->options ['component_prefix ' ] ?? 'c ' ;
51- $ this ->regex = sprintf ($ this ->regex , $ prefix , $ prefix , $ prefix );
50+ $ this ->setRegex ();
5251 $ this ->registerTags ();
5352
5453 if ($ this ->options ['enable_cache ' ]) {
@@ -61,6 +60,33 @@ public function __construct(array $options = [])
6160 }
6261 }
6362
63+ /**
64+ * The regex pattern is quite insane, so let's break it down
65+ *
66+ * @return void
67+ */
68+ protected function setRegex (): void
69+ {
70+ $ tagName = '([\w-]+) ' ; // Matches word characters and hyphens for tag names
71+ $ whitespace = '\s* ' ; // Optional whitespace
72+ $ quotedAttr = '(?:"[^"]*"| \'[^ \']* \') ' ; // Matches quoted attributes (e.g., "value" or 'value')
73+ $ unquotedAttr = '[^ \'">] ' ; // Matches unquoted attribute values (excluding quotes and >)
74+ $ attributes = "((?: $ quotedAttr| $ unquotedAttr)*) " ; // Zero or more attributes
75+ $ prefix = $ this ->options ['component_prefix ' ] ?? 'c ' ; // Placeholder for tag prefix (e.g., 'c' in c-tag)
76+
77+ // Self-closing tag pattern: <c-tag attributes/>
78+ $ selfClosingOpen = "< $ prefix- $ tagName$ whitespace$ attributes$ whitespace\/> " ;
79+
80+ // Tag with content pattern: <c-tag attributes>content</c-tag>
81+ $ contentOpen = "< $ prefix- $ tagName$ whitespace$ attributes> " ;
82+ $ contentInner = '(.*?) ' ; // Non-greedy content between tags
83+ $ contentClose = "<\/ $ prefix- \\3> " ; // Closing tag, referencing the tag name from group 3
84+ $ contentPattern = "$ contentOpen$ contentInner$ contentClose " ;
85+
86+ // Combine both patterns with alternation
87+ $ this ->regex = "/ $ selfClosingOpen| $ contentPattern/s " ;
88+ }
89+
6490 /**
6591 * Process Default Options and Parse to static variables
6692 *
0 commit comments