Skip to content

Instantly share code, notes, and snippets.

@LionsAd
Created December 17, 2020 15:11
Show Gist options
  • Save LionsAd/ce4e375cbe0fd9435ba42b7b43125d03 to your computer and use it in GitHub Desktop.
Save LionsAd/ce4e375cbe0fd9435ba42b7b43125d03 to your computer and use it in GitHub Desktop.
Very WIP code for creating automatic compiled code for <x-alert> style components
<?php
function component($name, $functions) {
print_r([$name, $functions]);
if ($name == 'alert--0') {
$func = $functions['slot_title'];
$func();
}
}
?>
<?php component('alert--0', [function() { ?>
<?php }, 'slot_title' => function() { ?>
<h1 class="alert-{{ $type }}">Error occurred
<x-bar>
</x-bar>
</h1>
<?php }, function() { ?>
Lorem ipsum …
<x-heading-3 tabindex="-1" :heading-attributes="component.attributes">
<x-foo class="x-{{ $type }}" :tabindex="component.tabindex" index="{{ $i }}">
Some heading
</x-foo>
<x-foo class="x-{{ $type }}" :tabindex="component.tabindex" index="{{ $i }}">
Some heading 2
</x-foo>
</x-heading-3>
<x-example-content name="alert" alert-type="{{ $type }}" :alert-data="complex" :component-data="component.data" />
<?php }]); ?>
<?php component('list--0', [function() { ?>
<x-list-item class="item-1">
<x-list class="submenu-1">
<x-list-item class="subitem-1">Hi</x-list-item>
</x-list>
</x-list-item>
<?php }]); ?>
<?php component('list--0', [function() { ?>
<?php }]); ?>
<?php
function component($name, $slots=[]) {
print_r([$name, $slots]);
if ($name == 'alert--0') {
$func = $slots['slot_title'];
$func();
print_r(['==============']);
$func = $slots[1];
$func();
}
}
?>
<?php component('alert--0', [function() { ?>
<?php }, 'slot_title' => function() { ?>
<h1 class="alert-{{ $type }}">Error occurred
<?php component('bar--0', [function() { ?>
<?php }, 'slot_xyz_default' => function() { ?>Some data<?php }, function() { ?>
<?php }]); ?>
</h1>
<?php }, function() { ?>
Lorem ipsum …
<?php component('heading-3--0', [function() { ?>
<?php component('foo--0', [function() { ?>
Some heading
<?php }]); ?>
<?php component('foo--0', [function() { ?>
Some heading 2
<?php }]); ?>
<?php }]); ?>
<x-example-content name="alert" alert-type="{{ $type }}" :alert-data="complex" :component-data="component.data" />
<?php }]); ?>
<?php component('list--0', [function() { ?>
<?php component('list-item--0', [function() { ?>
<?php component('list--1', [function() { ?>
<?php component('list-item--1', [function() { ?>Hi<?php }]); ?>
<?php }]); ?>
<?php }]); ?>
<?php }]); ?>
<?php component('list--0', [function() { ?>
<?php }]); ?>
<?php
function compileRegularEchos($value)
{
$contentTags = ['{{', '}}'];
$pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $contentTags[0], $contentTags[1]);
$callback = function ($matches) {
$whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];
//$echoFormat = 'e(%s)';
$echoFormat = '(%s)';
$wrapped = sprintf($echoFormat, $matches[2]);
return $matches[1] ? substr($matches[0], 1) : "<?php echo {$wrapped}; ?>{$whitespace}";
};
return preg_replace_callback($pattern, $callback, $value);
}
function compileAttributeEchos($value) {
$value = compileRegularEchos($value);
// escapeSingleQuotesOutsideOfPhpBlocks
$tokens = token_get_all($value);
$data = [];
foreach ($tokens as $token) {
if (! is_array($token)) {
$data[] = $token;
continue;
}
$data[] = $token[0] === T_INLINE_HTML
? str_replace("'", "\\'", $token[1])
: $token[1];
}
$value = implode('', $data);
$value = str_replace('<?php echo ', '\'.', $value);
$value = str_replace('; ?>', '.\'', $value);
return $value;
return $value;
};
$value = '
<x-alert class="foo" type="{{ $type }}-foo" :complex-data="$complex">
<x-slot name="title">
<h1 class="alert-{{ $type }}">Error occurred
<x-bar>
<x-slot name="xyz_default">Some data</x-slot>
</x-bar>
</h1>
</x-slot>
Lorem ipsum …
<x-heading-3 tabindex="-1" :heading-attributes="$component->attributes">
<x-foo class="x-{{ $type }}" :tabindex="$component->tabindex" index="{{ $i }}">
Some heading
</x-foo>
<x-foo class="x-{{ $type }}" :tabindex="$component->tabindex" index="{{ $i }}">
Some heading 2
</x-foo>
</x-heading-3>
<x-example-content name="alert" alert-type="{{ $type }}" :alert-data="$complex" :component-data="$component->data" />
</x-alert>
<x-list class="menu-1">
<x-list-item class="item-1">
<x-list class="submenu-1">
<x-list-item class="subitem-1">Hi</x-list-item>
</x-list>
</x-list-item>
</x-list>
<x-list class="menu-2">
</x-list>
';
$value = preg_replace_callback('/<\s*x[\-\:]slot\s+(:?)name=(?<name>(\"[^\"]+\"|\\\'[^\\\']+\\\'|[^\s>]+))\s*>/', function ($matches) {
$name = $matches['name'];
/*if ($matches[1] !== ':') {
$name = "'{$name}'";
}*/
$name = str_replace('"', '', $name);
return "<?php }, 'slot_{$name}' => function(\$variables) { extract(\$variables); ?>";
//return "{% endverbatim %}{% endset %}{% set slot_$name %}{% verbatim %}";
}, $value);
// $value = preg_replace('/<\/\s*x[\-\:]slot[^>]*>/', '{% endverbatim %}{% endset %}{% set slot_default %}{{ slot_default }}{% verbatim %}', $value);
$value = preg_replace('/<\/\s*x[\-\:]slot[^>]*>/', '<?php }, function($variables) { extract($variables); ?>', $value);
$value = preg_replace_callback('/<\s*x[-\:]([\w\-\:\.]*).* \/>/x', function ($matches) {
return "<?php component('{$matches[1]}', \$variables); ?>";
}, $value);
$pattern = "/
<\/?
\s*
x[-\:]([\w\-\:\.]*)
(?<attributes>
(?:
\s+
(?:
(?:
\{\{\s*\\\$attributes(?:[^}]+?)?\s*\}\}
)
|
(?:
[\w\-:.@]+
(
=
(?:
\\\"[^\\\"]*\\\"
|
\'[^\']*\'
|
[^\'\\\"=<>]+
)
)?
)
)
)*
\s*
)
(?<![\/=\-])
>
/x";
print_r(['<pre>', $value]);
global $depth, $attributes, $x, $curr;
$depth = [];
$curr = '';
$x = preg_replace_callback($pattern, function (array $matches) {
global $depth, $x, $curr;
$name = $matches[1];
if (!isset($depth[$name])) {
$depth[$name] = 0;
}
if ($matches[0][1] == '/') {
$depth[$name]--;
$fullname = $name . '--' . $depth[$name];
}
else {
$fullname = $name . '--' . $depth[$name];
$depth[$name]++;
}
/*
if ($matches[0][1] == '/') {
if ($curr != $fullname) {
return $matches[0];
}
$curr = '';
}
else {
if (!empty($curr)) {
return $matches[0];
}
$curr = $fullname;
}
*/
print_r([$fullname, $matches, $depth, $curr]);
if ($matches[0][1] == '/') {
//return "{% endverbatim %}{% endset %}{% endapply %}";
return "<?php }]); ?>";
}
$attributeString = $matches['attributes'];
$pattern = "/
(?:^|\s+) # start of the string or whitespace between attributes
\{\{\s*(\\\$attributes(?:[^}]+?(?<!\s))?)\s*\}\} # exact match of attributes variable being echoed
/x";
$attributeString = preg_replace($pattern, ' :attributes="$1"', $attributeString);
$pattern = "/
(?:^|\s+) # start of the string or whitespace between attributes
: # attribute needs to start with a semicolon
([\w\-:.@]+) # match the actual attribute name
= # only match attributes that have a value
/xm";
$attributeString = preg_replace($pattern, ' bind:$1=', $attributeString);
$pattern = '/
(?<attribute>[\w\-:.@]+)
(
=
(?<value>
(
\"[^\"]+\"
|
\\\'[^\\\']+\\\'
|
[^\s>]+
)
)
)?
/x';
$attributes = [];
$boundAttributes = [];
if (preg_match_all($pattern, $attributeString, $matches, PREG_SET_ORDER)) {
print_r([$matches]);
foreach ($matches as $match) {
$attribute = $match['attribute'];
$value = $match['value'] ?? null;
if (is_null($value)) {
$value = 'true';
//$attribute = Str::start($attribute, 'bind:');
}
$value = trim($value, '"\'');
if (strpos($attribute, 'bind:') === 0) {
$attribute = substr($attribute, strlen('bind:'));
$boundAttributes[$attribute] = true;
} else {
$value = "'". compileAttributeEchos($value). "'";
}
$attributes[$attribute] = $value;
}
}
$data = [];
foreach ($attributes as $attribute => $value) {
$data[] = "'{$attribute}' => {$value}";
}
$attributePhp = '[' . implode(', ', $data) . ']';
//return "{% apply component({$fullname}, '{$matches['attributes']}') %}{% set slot_default %}{% verbatim %}";
//return "{% apply reverse %}{% set slot_default %}{% verbatim %}";
return "<?php component('{$name}', $attributePhp, \$variables, [function(\$variables) { extract(\$variables); ?>";
}, $value);
print_r([$x]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment