Skip to content

Commit 0c82021

Browse files
committed
Add attributes for renderers and reorganise codebase
1 parent 2879f11 commit 0c82021

File tree

3 files changed

+1519
-205
lines changed

3 files changed

+1519
-205
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
},
77
"autoload": {
88
"files": [
9-
"src/functions.php"
9+
"src/parser.php",
10+
"src/renderers.php"
1011
]
1112
},
1213
"extra": {

src/functions.php renamed to src/parser.php

Lines changed: 105 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,20 @@ function tokens($code) {
1919
$attributeStarted = null;
2020
$attributeEnded = null;
2121

22+
$expressionLevel = 0;
23+
$expressionStarted = null;
24+
$expressionEnded = null;
25+
26+
$nestedLevel = 0;
27+
$inQuote = false;
28+
2229
$carry = 0;
2330

2431
while ($cursor < $length) {
32+
if ($code[$cursor] === '"' || $code[$cursor] === "'" && $code[$cursor - 1] !== "\\") {
33+
$inQuote = !$inQuote;
34+
}
35+
2536
if ($code[$cursor] === "{" && $elementStarted !== null) {
2637
if ($attributeLevel === 0) {
2738
$attributeStarted = $cursor;
@@ -38,7 +49,7 @@ function tokens($code) {
3849
}
3950
}
4051

41-
if ($attributeStarted && $attributeEnded) {
52+
if ($attributeStarted !== null && $attributeEnded !== null) {
4253
$position = (string) count($attributes);
4354
$positionLength = strlen($position);
4455

@@ -62,10 +73,60 @@ function tokens($code) {
6273
continue;
6374
}
6475

76+
if ($code[$cursor] === "{" && $elementStarted === null && $nestedLevel > 0) {
77+
if ($expressionLevel === 0) {
78+
$expressionStarted = $cursor;
79+
}
80+
81+
$expressionLevel++;
82+
}
83+
84+
if ($code[$cursor] === "}" && $elementStarted === null && $nestedLevel > 0) {
85+
$expressionLevel--;
86+
87+
if ($expressionLevel === 0) {
88+
$expressionEnded = $cursor;
89+
}
90+
}
91+
92+
if ($expressionStarted !== null && $expressionEnded !== null) {
93+
$distance = $expressionEnded - $expressionStarted;
94+
95+
$carry += $cursor;
96+
97+
$before = trim(substr($code, 0, $expressionStarted));
98+
$expression = trim(substr($code, $expressionStarted + 1, $distance - 1));
99+
$after = trim(substr($code, $expressionEnded + 1));
100+
101+
$tokens[] = $before;
102+
$tokens[] = ["expression" => compile($expression), "started" => $carry];
103+
104+
$code = $after;
105+
$length = strlen($code);
106+
$cursor = 0;
107+
108+
$expressionStarted = null;
109+
$expressionEnded = null;
110+
111+
continue;
112+
}
113+
65114
preg_match("#^</?[a-zA-Z]#", substr($code, $cursor, 3), $matchesStart);
66115

67-
if (count($matchesStart) && $attributeLevel < 1) {
116+
if (
117+
count($matchesStart)
118+
&& $attributeLevel < 1
119+
&& $expressionLevel < 1
120+
&& !$inQuote
121+
) {
68122
$elementLevel++;
123+
124+
if ($matchesStart[0][1] !== "/") {
125+
$nestedLevel++;
126+
} else {
127+
$nestedLevel--;
128+
}
129+
69130
$elementStarted = $cursor;
70131
}
71132

@@ -77,6 +138,7 @@ function tokens($code) {
77138
&& !$matchesEqualBefore && !$matchesEqualAfter
78139
&& $attributeLevel < 1
79140
&& $elementStarted !== null
141+
&& $expressionStarted === null
80142
) {
81143
$elementLevel--;
82144
$elementEnded = $cursor;
@@ -101,9 +163,21 @@ function tokens($code) {
101163
$token["attributes"] = $attributes;
102164
}
103165

104-
$tokens[] = $before;
166+
if ($expressionStarted !== null) {
167+
$tokens[] = ["expression" => $before, "started" => $expressionStarted];
168+
} else {
169+
$tokens[] = $before;
170+
}
171+
105172
$tokens[] = $token;
106173

174+
if (preg_match("#/>$#", $tag)) {
175+
preg_match("#<([a-zA-Z]+)#", $tag, $matchesName);
176+
177+
$name = $matchesName[1];
178+
$tokens[] = ["tag" => "</{$name}>"];
179+
}
180+
107181
$attributes = [];
108182

109183
$code = $after;
@@ -234,7 +308,7 @@ function parse($nodes) {
234308
}
235309
}
236310

237-
preg_match_all("#([a-zA-Z]+)={([^}]+)}#", $node["tag"], $dynamic);
311+
preg_match_all("#([a-zA-Z][a-zA-Z-_]+)={([^}]+)}#", $node["tag"], $dynamic);
238312

239313
if (count($dynamic[0])) {
240314
foreach($dynamic[1] as $key => $value) {
@@ -253,30 +327,50 @@ function parse($nodes) {
253327
$children[] = parse([$child]);
254328
}
255329

330+
else if (isset($child["expression"])) {
331+
$children[] = $child["expression"];
332+
}
333+
256334
else {
257335
$children[] = "\"" . addslashes($child["text"]) . "\"";
258336
}
259337
}
260338

261339
$props["children"] = $children;
262340

263-
if (function_exists("Pre\\Phpx\\Renderer\\_" . $node["name"])) {
264-
$code .= "Pre\\Phpx\\Renderer\\_" . $node["name"] . "([" . PHP_EOL;
341+
if (function_exists("\\Pre\\Phpx\\Renderer\\__" . $node["name"])) {
342+
$code .= "\\Pre\\Phpx\\Renderer\\__" . $node["name"] . "([" . PHP_EOL;
265343
}
266344

267345
else {
268-
$code .= $node["name"] . "([" . PHP_EOL;
346+
$name = $node["name"];
347+
$code .= "(new {$name})->render([" . PHP_EOL;
269348
}
270349

271350
foreach ($props as $key => $value) {
272351
if ($key === "children") {
273-
$code .= "\"children\" => [" . PHP_EOL;
352+
$children = array_filter($children, function($child) {
353+
return trim($child, "\"'");
354+
});
355+
356+
$children = array_map("trim", $children);
357+
358+
$children = array_values($children);
274359

275-
foreach ($children as $child) {
276-
$code .= "{$child}," . PHP_EOL;
360+
if (count($children) === 1) {
361+
$code .= "\"children\" => " . $children[0] . "," . PHP_EOL;
362+
}
363+
364+
else {
365+
$code .= "\"children\" => [" . PHP_EOL;
366+
367+
foreach ($children as $child) {
368+
$code .= "{$child}," . PHP_EOL;
369+
}
370+
371+
$code .= "]," . PHP_EOL;
277372
}
278373

279-
$code .= "]," . PHP_EOL;
280374
}
281375

282376
else {
@@ -294,196 +388,3 @@ function parse($nodes) {
294388
function compile($code) {
295389
return parse(nodes(tokens($code)));
296390
}
297-
298-
namespace Pre\Phpx\Renderer;
299-
300-
use Closure;
301-
use Pre\Collections\Collection;
302-
303-
function element($name, $props, callable $attrs = null) {
304-
$code = "<{$name}";
305-
306-
$className = $props["className"] ?? null;
307-
308-
if (is_callable($className)) {
309-
$className = $className();
310-
}
311-
312-
if ($className instanceof Collection) {
313-
$className = $className->toArray();
314-
}
315-
316-
if (is_array($className)) {
317-
$combined = "";
318-
319-
foreach ($className as $key => $value) {
320-
if (is_string($key)) {
321-
$combined .= !!$value ? " {$key}" : "";
322-
}
323-
324-
else {
325-
$combined .= " {$value}";
326-
}
327-
}
328-
329-
$className = trim($combined);
330-
}
331-
332-
if ($className) {
333-
$code .= " class='{$className}'";
334-
}
335-
336-
$style = $props["style"] ?? null;
337-
338-
if (is_callable($style)) {
339-
$style = $style();
340-
}
341-
342-
if ($style instanceof Collection) {
343-
$style = $style->toArray();
344-
}
345-
346-
if (is_array($style)) {
347-
$styles = [];
348-
349-
foreach ($style as $key => $value) {
350-
$styles[] = "{$key}: {$value}";
351-
}
352-
353-
$style = join("; ", $styles);
354-
}
355-
356-
if ($style) {
357-
$code .= " style='{$style}'";
358-
}
359-
360-
$code .= ">";
361-
362-
foreach ($props["children"] as $child) {
363-
$code .= $child;
364-
}
365-
366-
$code .= "</{$name}>";
367-
368-
return $code;
369-
}
370-
371-
372-
define("ELEMENTS", [
373-
"a",
374-
"abbr",
375-
"address",
376-
"area",
377-
"article",
378-
"aside",
379-
"audio",
380-
"b",
381-
"base",
382-
"bdi",
383-
"bdo",
384-
"blockquote",
385-
"body",
386-
"br",
387-
"button",
388-
"canvas",
389-
"caption",
390-
"cite",
391-
"code",
392-
"col",
393-
"colgroup",
394-
"data",
395-
"datalist",
396-
"dd",
397-
"del",
398-
"details",
399-
"dfn",
400-
"div",
401-
"dl",
402-
"dt",
403-
"em",
404-
"embed",
405-
"fieldset",
406-
"figcaption",
407-
"figure",
408-
"footer",
409-
"form",
410-
"h1",
411-
"h2",
412-
"h3",
413-
"h4",
414-
"h5",
415-
"h6",
416-
"head",
417-
"header",
418-
"hr",
419-
"html",
420-
"i",
421-
"iframe",
422-
"img",
423-
"input",
424-
"ins",
425-
"kbd",
426-
"label",
427-
"legend",
428-
"li",
429-
"link",
430-
"main",
431-
"map",
432-
"mark",
433-
"meta",
434-
"meter",
435-
"nav",
436-
"noframes",
437-
"noscript",
438-
"object",
439-
"ol",
440-
"optgroup",
441-
"option",
442-
"output",
443-
"p",
444-
"param",
445-
"pre",
446-
"progress",
447-
"q",
448-
"rp",
449-
"rt",
450-
"rtc",
451-
"ruby",
452-
"s",
453-
"samp",
454-
"script",
455-
"section",
456-
"select",
457-
"slot",
458-
"small",
459-
"source",
460-
"span",
461-
"strong",
462-
"style",
463-
"sub",
464-
"summary",
465-
"sup",
466-
"table",
467-
"tbody",
468-
"td",
469-
"template",
470-
"textarea",
471-
"tfoot",
472-
"th",
473-
"thead",
474-
"time",
475-
"title",
476-
"tr",
477-
"track",
478-
"u",
479-
"ul",
480-
"var",
481-
"video",
482-
"wbr",
483-
]);
484-
485-
foreach (ELEMENTS as $element) {
486-
eval("namespace Pre\Phpx\Renderer { function _{$element}(\$props) {
487-
return element('{$element}', \$props);
488-
} }");
489-
}

0 commit comments

Comments
 (0)