Stillat / blade-parser

A library that makes it simple to parse, analyze, and manipulate Blade templates. Designed with tool makers in mind ❤️
https://stillat.com/blade-parser
MIT License
125 stars 2 forks source link

Ability to traverse nodes #14

Closed khalyomede closed 1 year ago

khalyomede commented 1 year ago

Hi, I would like to know if there is a way to add a custom traverser?

My need is the following: I am building a translation parser (https://github.com/khalyomede/laravel-translate) and I have complex scenarios when x-components are nested with each others

I need to pull translations from different places:

  1. Blade Dynamic attributes (like <x-form :title="__('Enter your informations')"></x-form>
  2. Echo directives ({{ __('Enter your informations') }} and {!! __('Enter your informations') !!})
  3. Components literal values (<x-select><option>@lang("Hi")</option></x-select>)

For the 2. and 3., it is easy using Document::findDirectivesByName("lang") and Document::AllOfType(Echo::class), but for the first one since dynamic attributes could be in any level of nesting, and there is no way to find all dynamic attributes, I would need to make my own traverser and get those

Is there an easy way to do it?

khalyomede commented 1 year ago

Ok I think I got something working (need some more minutes to make it pass all tests)

$langs = $document->findDirectivesByName("lang");
$choices = $document->findDirectiveByName("choice");
$components = $document->allOfType(ComponentNode::class);
$echos = $document->allOfType(EchoNode::class);

I loop through components, get ComponentNode::getParameters() and it should be fine!

JohnathonKoster commented 1 year ago

To find all dynamic attributes, we can just go through each of the components in the template, and return all parameters that have the type DynamicVariable:

<?php

use Stillat\BladeParser\Document\Document;
use Stillat\BladeParser\Nodes\Components\ComponentNode;
use Stillat\BladeParser\Nodes\Components\ParameterNode;
use Stillat\BladeParser\Nodes\Components\ParameterType;

    $template = <<<'BLADE'
<x-form :title="__('Enter your informations')">
<x-form :title="__('Enter your informations2')">
    <x-form :title="__('Enter your informations3')">

    </x-form>
</x-form>
</x-form>
BLADE;

$doc = Document::fromText($template);

$dynamicAttributes = $doc->getComponents()->map(function (ComponentNode $node) {
    return $node->getParameters()->where(function (ParameterNode $param) {
        return $param->type == ParameterType::DynamicVariable;
    });
})->collapse();

$dynamicText = $dynamicAttributes->map(function (ParameterNode $param) {
    return $param->value;
})->all();
khalyomede commented 1 year ago

Yep I did something along the lines, thanks! I think I will not need a "custom traverser" in this case thank you :pray: