Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ contact_links:
about: Ask questions and discuss with other community members
- name: Documentation
url: https://github.com/livewire/blaze#readme
about: Check the README for usage instructions
about: Check the README for usage instructions
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ What you want to happen.
Any alternative solutions or features you've considered.

**Additional context**
Add any code examples or use cases here.
Add any code examples or use cases here.
2 changes: 1 addition & 1 deletion .github/workflows/benchmark-comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
echo "heading=$(sed -n '2p' benchmark-result.md)" >> "$GITHUB_OUTPUT"
tail -n +2 benchmark-result.md > benchmark-comment.md
echo "" >> benchmark-comment.md
echo "<sub>To run a specific benchmark, comment <code>/benchmark &lt;name&gt;</code> where name is one of: <code>attributes</code>, <code>aware</code>, <code>class</code>, <code>default</code>, <code>forwarding</code>, <code>merge</code>, <code>named-slots</code>, <code>no-attributes</code>, <code>slot</code></sub>" >> benchmark-comment.md
echo "<sub>To run a specific benchmark, comment <code>/benchmark &lt;name&gt;</code><br><code>attributes</code>, <code>aware</code>, <code>class</code>, <code>default</code>, <code>forwarding</code>, <code>merge</code>, <code>named-slots</code>, <code>no-attributes</code>, <code>slot</code>, <code>compilation</code></sub>" >> benchmark-comment.md

- name: Find existing comment
uses: peter-evans/find-comment@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/benchmark-on-demand.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
COMMENT: ${{ github.event.comment.body }}
run: |
BENCHMARK=$(echo "$COMMENT" | awk '{print $2}')
VALID="attributes aware class default forwarding merge named-slots no-attributes slot"
VALID="attributes aware class compilation default forwarding merge named-slots no-attributes slot"
if ! echo "$VALID" | grep -qw "$BENCHMARK"; then
echo "::error::Unknown benchmark '$BENCHMARK'. Valid options: $VALID"
exit 1
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
composer.lock
phpunit.xml.dist
.env
.env.testing
.env.testing
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.
2 changes: 1 addition & 1 deletion UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ Blaze::optimize()
->in(resource_path('views/components/icons'), memo: true);
```

Only use these strategies if you understand their limitations. To learn more, read the [Optimization strategies](README.md#optimization-strategies) section in the README.
Only use these strategies if you understand their limitations. To learn more, read the [Optimization strategies](README.md#optimization-strategies) section in the README.
28 changes: 0 additions & 28 deletions src/BladeService.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ class BladeService
{
protected ComponentTagCompiler $tagCompiler;

protected ?array $customConditions = null;

public function __construct(
public BladeCompiler $compiler,
protected Factory $view,
Expand Down Expand Up @@ -124,17 +122,6 @@ public function compileComments(string $input): string
return $compileComments->invoke($this->compiler, $input);
}

/**
* Invoke the Blade compiler's hasEvenNumberOfParentheses via reflection.
*/
public function hasEvenNumberOfParentheses(string $expression): bool
{
$reflection = new ReflectionClass($this->compiler);
$method = $reflection->getMethod('hasEvenNumberOfParentheses');

return $method->invoke($this->compiler, $expression);
}

/**
* Preprocess a component attribute string using Laravel's ComponentTagCompiler.
*
Expand Down Expand Up @@ -172,21 +159,6 @@ public function compileUseStatements(string $input): string
})->compile($input);
}

/**
* Get the custom conditional directives registered with the Blade compiler.
*/
public function customConditions(): array
{
if ($this->customConditions !== null) {
return $this->customConditions;
}

$reflection = new ReflectionClass($this->compiler);
$conditions = $reflection->getProperty('conditions')->getValue($this->compiler);

return $this->customConditions = collect($conditions)->keys()->all();
}

/**
* Compile an attribute to a PHP array entry string (e.g. "'propName' => value").
*/
Expand Down
2 changes: 1 addition & 1 deletion src/BlazeManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function __construct(
protected BladeService $blade,
) {
$this->renderer = new BladeRenderer($bladeCompiler, app('view'), $this->runtime, $this);
$this->parser = new Parser(new Tokenizer($this->blade), new AttributeParser($this->blade));
$this->parser = new Parser(new Tokenizer, new AttributeParser($this->blade));
$this->walker = new Walker;
$this->compiler = new Compiler($config, $this->blade, $this);
$this->folder = new Folder($config, $this->blade, $this->renderer, $this);
Expand Down
54 changes: 38 additions & 16 deletions src/Compiler/SlotCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,24 @@ public function __construct(
public function compile(string $slotsVariableName, array $children): string
{
$output = '';
$hasExplicitDefault = $this->hasExplicitDefaultSlot($children);

if (! $hasExplicitDefault) {
$output .= '<' . '?php ob_start(); ?>';
// Compile implicit default slot from loose content (non-SlotNode children)
if (! $this->hasExplicitDefaultSlot($children)) {
$output .= $this->compileSlot('slot', $this->renderLooseContent($children), '[]', $slotsVariableName) . "\n";
}

// Compile each named slot
foreach ($children as $child) {
if ($child instanceof SlotNode) {
$output .= ' ' . $this->compileSlot(
$output .= $this->compileSlot(
$this->resolveSlotName($child),
$this->renderChildren($child->children),
$this->compileSlotAttributes($child),
$slotsVariableName,
);
} else {
$output .= $child->render();
) . "\n";
}
}

if (! $hasExplicitDefault) {
$contentHandler = $this->manager->isFolding()
? '$__blaze->processPassthroughContent(\'trim\', trim(ob_get_clean()))'
: 'trim(ob_get_clean())';

$output .= '<' . '?php ' . $slotsVariableName . '[\'slot\'] = new \Illuminate\View\ComponentSlot(' . $contentHandler . ', []); ?>' . "\n";
}

return $output;
}

Expand All @@ -72,13 +63,44 @@ protected function hasExplicitDefaultSlot(array $children): bool
return false;
}

/**
* Render non-SlotNode children as the default slot content.
*
* @param array<Node> $children
*/
protected function renderLooseContent(array $children): string
{
$content = '';
$previousWasSlot = false;

foreach ($children as $child) {
if ($child instanceof SlotNode) {
$previousWasSlot = true;
continue;
}

$rendered = $child->render();

// Laravel's slot compilation consumes the newline after </x-slot> and adds a leading space.
// We match this by prepending a space and stripping any leading newline.
if ($previousWasSlot) {
$rendered = ' ' . preg_replace('/^\n/', '', $rendered);
}

$content .= $rendered;
$previousWasSlot = false;
}

return $content;
}

/**
* Compile a slot into ob_start/ob_get_clean code.
*/
protected function compileSlot(string $name, string $content, string $attributes, string $slotsVariableName): string
{
$contentHandler = $this->manager->isFolding() ? '$__blaze->processPassthroughContent(\'trim\', trim(ob_get_clean()))' : 'trim(ob_get_clean())';

return '<' . '?php ob_start(); ?>'
. $content
. '<' . '?php ' . $slotsVariableName . '[\'' . $name . '\'] = new \Illuminate\View\ComponentSlot(' . $contentHandler . ', ' . $attributes . '); ?>';
Expand Down
2 changes: 1 addition & 1 deletion src/Events/ComponentFolded.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ public function __construct(
public string $path,
public int $filemtime
) {}
}
}
2 changes: 1 addition & 1 deletion src/Exceptions/LeftoverPlaceholdersException.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ public function getRenderedSnippet(): ?string
{
return $this->renderedSnippet;
}
}
}
26 changes: 0 additions & 26 deletions src/Folder/Folder.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
use Livewire\Blaze\BlazeManager;
use Illuminate\Support\Arr;
use Livewire\Blaze\Config;
use Livewire\Blaze\Parser\Nodes\DirectiveNode;
use Livewire\Blaze\Support\DirectiveStack;
use Throwable;

/**
Expand Down Expand Up @@ -99,10 +97,6 @@ protected function shouldFold(ComponentSource $source): bool
*/
protected function isSafeToFold(ComponentSource $source, ComponentNode $node): bool
{
if ($this->slotsAreWrappedInDirective($node)) {
return false;
}

$dynamicAttributes = array_filter($node->attributes, fn ($attribute) => ! $attribute->isStaticValue());

foreach ($source->directives->aware() as $prop) {
Expand Down Expand Up @@ -177,26 +171,6 @@ protected function isSafeToFold(ComponentSource $source, ComponentNode $node): b
return true;
}

/**
* Check if a slot is wrapped in a directive.
*/
protected function slotsAreWrappedInDirective(ComponentNode $node): bool
{
$stack = DirectiveStack::make($this->blade->customConditions());

foreach ($node->children as $child) {
if ($child instanceof DirectiveNode) {
$stack->add($child->name);
}

if ($child instanceof SlotNode && $stack->open()) {
return true;
}
}

return false;
}

/**
* Check if a slot has any dynamically-bound attributes.
*/
Expand Down
18 changes: 0 additions & 18 deletions src/Parser/Nodes/DirectiveNode.php

This file was deleted.

2 changes: 1 addition & 1 deletion src/Parser/Nodes/Node.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ abstract class Node
* Render this node to its string output.
*/
abstract public function render(): string;
}
}
2 changes: 1 addition & 1 deletion src/Parser/Nodes/TextNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ public function render(): string
{
return $this->content;
}
}
}
4 changes: 2 additions & 2 deletions src/Parser/ParseStack.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function addToRoot(Node $node): void
if ($current instanceof ComponentNode || $current instanceof SlotNode) {
$current->children[] = $node;
} else {
$this->ast[] = $node;
$this->ast[] = $node;
}
}
}
Expand Down Expand Up @@ -86,4 +86,4 @@ public function depth(): int
{
return count($this->stack);
}
}
}
14 changes: 0 additions & 14 deletions src/Parser/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

use Livewire\Blaze\BladeService;
use Livewire\Blaze\Parser\Nodes\ComponentNode;
use Livewire\Blaze\Parser\Nodes\DirectiveNode;
use Livewire\Blaze\Parser\Nodes\SlotNode;
use Livewire\Blaze\Parser\Nodes\TextNode;
use Livewire\Blaze\Parser\Tokenizer;
use Livewire\Blaze\Parser\Tokens\DirectiveToken;
use Livewire\Blaze\Parser\Tokens\SlotCloseToken;
use Livewire\Blaze\Parser\Tokens\SlotOpenToken;
use Livewire\Blaze\Parser\Tokens\TagCloseToken;
Expand Down Expand Up @@ -44,7 +42,6 @@ public function parse(string $content): array
TagCloseToken::class => $this->handleTagClose($token, $stack),
SlotOpenToken::class => $this->handleSlotOpen($token, $stack),
SlotCloseToken::class => $this->handleSlotClose($token, $stack),
DirectiveToken::class => $this->handleDirective($token, $stack),
TextToken::class => $this->handleText($token, $stack),
default => throw new \RuntimeException('Unknown token type: ' . get_class($token))
};
Expand Down Expand Up @@ -133,17 +130,6 @@ protected function handleSlotClose(SlotCloseToken $token, ParseStack $stack): vo
}
}

protected function handleDirective(DirectiveToken $token, ParseStack $stack): void
{
$node = new DirectiveNode(
name: $token->name,
original: $token->original,
arguments: $token->arguments,
);

$stack->addToRoot($node);
}

/**
* Handle a text content token.
*/
Expand Down
Loading
Loading