veilletech.fr
3 sept. Feed du jour
#10 PHP Article

Réécrire du Blade sans expression régulière

Une regex devine la structure. Un AST la connaît.

Forte parse les templates Blade en un AST interrogeable en XPath et permet de les réécrire par structure plutôt que par expression régulière. Le paquet fortephp/forte (MIT, v1.1.0) vise les codemods reproductibles sur de grandes bases de vues.

3 min de lectureintermédiairevidéo 1:20
Partager
Sommaire6 sections
  1. Le problème
  2. Installation
  3. Lire
  4. Interroger
  5. Réécrire
  6. À retenir

Le problème

Renommer un composant, normaliser une directive, appliquer la même retouche à quatre cents vues : le réflexe est un sed, et il remplace toutes les occurrences — y compris celles qui vivent dans une chaîne, un commentaire ou un attribut qu'on ne voulait pas toucher. Blade n'est pas un langage régulier.

Forte, écrit par John Koster, analyse un .blade.php en arbre syntaxique typé, laisse interroger cet arbre, et rend un template réécrit. Le formateur prettier-plugin-blade v3, du même auteur, tourne dessus.

Installation

Terminal
composer require fortephp/forte

PHP 8.2, extension dom, Laravel 10 à 13. Le service provider s'enregistre seul, la façade Forte est disponible immédiatement.

Lire

PHP
use Forte\Facades\Forte;

$doc = Forte::parse('<div class="mt-4">Hello, {{ $name }}!</div>');
$doc = Forte::parseFile('resources/views/welcome.blade.php');

Deux propriétés font la différence à l'usage. D'abord le parseur est tolérant : sur une balise non fermée ou un @if sans @endif, il enregistre un diagnostic et rend un arbre partiel, qu'on peut interroger comme un autre — deux vues cassées dans une application de quatre cents en produisent deux, les 398 restantes s'analysent normalement. Ensuite, analyser puis rendre sans modification redonne les mêmes octets, espaces compris.

Interroger

Les méthodes de requête renvoient des lazy collections :

PHP
$forms = $doc->queryElements('form');
$conditionals = $doc->queryBlockDirectives(['if', 'unless']);
$components = $doc->queryComponents(['x-alert', 'livewire:*']);

Forte construit un DOMDocument et passe l'expression à DOMXPath — c'est ce que couvre l'exigence ext-dom. Les constructions Blade deviennent des éléments dans un espace de noms forte : un @if est un forte:if, un écho un forte:echo.

PHP
$divs = $doc->xpath('//div[@class]')->get();
$conditionals = $doc->xpath('//forte:if')->get();

Les résultats reviennent en nœuds Forte, pas en DOMElement, donc une requête se passe directement à une réécriture. Trouver tous les <a> sans href à l'intérieur d'un <nav> tient en une expression au lieu d'un parcours récursif.

Réécrire

apply(), rewrite() et rewriteWith() rendent chacun un nouveau Document et laissent l'original intact — les deux versions restent comparables.

PHP
use Forte\Rewriting\NodePath;

$newDoc = $doc->rewriteWith(function (NodePath $path) {
    if ($path->isTag('a') && str_starts_with($path->getAttribute('href') ?? '', 'http')) {
        $path->setAttribute('target', '_blank');
        $path->setAttribute('rel', 'noopener noreferrer');
    }
});
echo $newDoc->render();

Le rappel reçoit un NodePath, pas le nœud : parent, frères, ancêtres, profondeur, plus renameTag(), addClass(), replaceWith(), remove(), insertBefore(), insertAfter(), et skipChildren() / stopTraversal() pour sortir tôt. Les modifications sont mises en file puis appliquées d'un coup : une passe sur un gros template produit un document, pas un par retouche.

Pour plus long qu'une closure, on écrit un Visitor avec enter() — appelé avant les enfants — et leave(), utile quand la retouche dépend de ce qui est arrivé aux enfants. Un RewriteBuilder offre la variante déclarative : sélection XPath, puis mutations à appliquer.

À retenir

  1. Trois usages concrets : inventorier ce que contiennent les vues, appliquer une édition à des centaines de fichiers, ou faire échouer un build quand un template viole une convention d'équipe.
  2. La tolérance aux erreurs et le rendu à l'octet près sont ce qui rend un codemod utilisable sur une base réelle.
  3. Licence MIT, v1.1.0.

Source : Laravel News