AST
Elements
Elements represent HTML tags in the Forte AST. Forte tracks opening tags, closing tags, attributes, and children for each element. Forte also considers element scopes when pairing directives, and vice versa.
#Working with Elements
ElementNode is the primary node type for HTML elements. You can retrieve the tag name with tagNameText or check it against a pattern using is:
1<?php
2
3use Forte\Ast\Elements\ElementNode;
4use Forte\Facades\Forte;
5
6$doc = Forte::parse('<div class="container">Hello</div>');
7
8$element = $doc->findElementByName('div');
9
10$element->tagNameText(); // "div"
11$element->is('div'); // true
12$element->is('d*'); // true
For access to the full tag name node, use tagName:
1<?php
2
3$element->tagName(); // ElementNameNode
To get the rendered content between the opening and closing tags:
1<?php
2
3$element->innerContent(); // "Hello"
You can access the closing tag node directly, which returns null for self-closing or void elements:
1<?php
2
3$element->closingTag(); // ?ElementNameNode
#Element Types
Elements can take several structural forms. These type-check methods are useful when building rewriters or validators that need to handle each form differently.
Use isPaired to check for elements with both an opening and closing tag:
1<?php
2
3// <div>...</div>
4$element->isPaired(); // true
HTML void elements (which cannot have children) are identified with isVoid:
1<?php
2
3// <br>, <img>, <input>, <hr>, <meta>, <link>
4$element->isVoid(); // true
For self-closing syntax (<div />):
1<?php
2
3// <div />
4$element->isSelfClosing(); // true
When the parser inserts a closing tag that was not present in the source, hasSyntheticClosing returns true:
1<?php
2
3$element->hasSyntheticClosing(); // bool
To check whether the element is a Blade component (i.e., its tag name matches a registered component prefix):
1<?php
2
3$element->isComponent(); // bool
#Generic Type Arguments
Forte parses TSX-style generic type arguments on any element, including Blade components. Use genericTypeArguments to retrieve the type parameter string, or null when no generics are present:
1<?php
2
3use Forte\Facades\Forte;
4
5$doc = Forte::parse('<List<Item> />');
6
7$element = $doc->findElementByName('List');
8
9$element->genericTypeArguments(); // "<Item>"
10$element->isComponent(); // false
When no generic type is present, the method returns null:
1<?php
2
3use Forte\Facades\Forte;
4
5$doc = Forte::parse('<div class="container">Hello</div>');
6
7$element = $doc->findElementByName('div');
8
9$element->genericTypeArguments(); // null
#Attributes
Attributes let you inspect the properties passed to an element. Use hasAttribute to check for an attribute by name, and getAttribute to retrieve its value:
1<?php
2
3$doc = Forte::parse('<div id="main" class="container" hidden>Hello</div>');
4
5$element = $doc->findElementByName('div');
6
7$element->hasAttribute('class'); // true
8$element->getAttribute('class'); // "container"
9$element->getAttribute('id'); // "main"
Shorthand accessors are available for the most common attributes:
1<?php
2
3$element->getClass(); // "container"
4$element->getId(); // "main"
For full access to all attributes, use attributes (returns an Attributes collection) or getAttributes (returns an array):
1<?php
2
3$attrs = $element->attributes(); // Attributes collection
4$array = $element->getAttributes(); // array<Attribute>
#The Attributes Collection
The Attributes collection extends Laravel's Collection with typed filtering methods, making it easy to work with different kinds of Blade and HTML attributes.
#By Attribute Type
Filter attributes by their syntactic form. These methods help distinguish standard HTML attributes from Blade-specific ones:
1<?php
2
3$attrs = $element->attributes();
4
5$attrs->static(); // standard HTML attributes (name="value")
6$attrs->bound(); // Blade bound attributes (:name="expr")
7$attrs->escaped(); // Blade escaped attributes (::name="expr")
8$attrs->boolean(); // boolean attributes with no value (e.g. disabled)
9$attrs->complex(); // attributes with interpolated names or values
10$attrs->simple(); // non-Blade, non-complex attributes
#Blade Constructs
Blade constructs like directives and echoes can appear within an element's attribute list. These methods help you isolate them:
1<?php
2
3$attrs->bladeConstructs(); // all embedded Blade constructs
4$attrs->directives(); // standalone directives (@csrf, @class, etc.)
5$attrs->blockDirectives(); // block directives (@if...@endif, etc.)
6$attrs->echoes(); // echo interpolations ({{ }}, {!! !!})
7$attrs->phpTags(); // PHP tags (<?php ?>, <?= ?>)
You can also check for the presence of these without filtering:
1<?php
2
3$attrs->hasBladeConstruct(); // bool
4$attrs->hasExpression(); // bool
#By Name
Filter or find attributes by their name, using exact match, regex, or allow/deny lists:
1<?php
2
3$attrs->whereNameIs('class'); // attributes named "class"
4$attrs->whereNameMatches('/^data-/'); // attributes matching a regex
5$attrs->onlyNames(['class', 'id']); // include only specific names
6$attrs->exceptNames(['class', 'id']); // exclude specific names
To retrieve a single attribute by name (case-insensitive):
1<?php
2
3$classAttr = $attrs->find('class'); // ?Attribute
#Individual Attributes
Each Attribute instance provides methods for inspecting its name, value, and type.
You can inspect the name with nameText (without prefix) or rawName (including any : or :: prefix):
1<?php
2
3use Forte\Ast\Elements\Attribute;
4
5foreach ($element->getAttributes() as $attr) {
6 $attr->nameText(); // string (e.g. "class")
7 $attr->rawName(); // string (e.g. ":class" for bound attributes)
8}
For the attribute value, valueText returns null for boolean attributes, while valueOrDefault lets you provide a fallback:
1<?php
2
3$attr->valueText(); // ?string
4$attr->valueOrDefault(''); // string (uses default if null)
#Type Checks
Each attribute can be identified by its syntactic form. These type checks help distinguish standard HTML from Blade-specific syntax:
1<?php
2
3$attr->isStatic(); // true for standard name="value" attributes
4$attr->isBound(); // true for :name="expr" attributes
5$attr->isEscaped(); // true for ::name="expr" attributes
6$attr->isBoolean(); // true for value-less attributes (e.g. disabled)
7$attr->isVariableShorthand(); // true for :$variable shorthand
8$attr->isExpression(); // true for JSX-style {expression} attributes
9$attr->isBladeConstruct(); // true for embedded Blade constructs
To check whether the name or value contains interpolation:
1<?php
2
3$attr->hasComplexName(); // bool
4$attr->hasComplexValue(); // bool
You can also inspect the quoting style used for the value:
1<?php
2
3$attr->quote(); // ?string
When an attribute is a Blade construct, you can retrieve the underlying AST node for deeper inspection:
1<?php
2
3if ($attr->isBladeConstruct()) {
4 $node = $attr->getBladeConstruct(); // ?Node (DirectiveNode, EchoNode, etc.)
5}
#Rendering Parts of an Element
You can render an element's opening tag, closing tag, or the full element with custom child content. These methods preserve the original source faithfully, including whitespace and attribute formatting.
Use renderOpeningTag to get just the opening tag with its attributes:
1<?php
2
3use Forte\Facades\Forte;
4
5$doc = Forte::parse('<div class="container" id="main">Hello</div>');
6
7$element = $doc->findElementByName('div');
8
9$element->renderOpeningTag(); // '<div class="container" id="main">'
Use renderClosingTag to get just the closing tag. Self-closing and void elements return an empty string:
1<?php
2
3use Forte\Facades\Forte;
4
5$doc = Forte::parse('<div class="container">Hello</div>');
6
7$div = $doc->findElementByName('div');
8$div->renderClosingTag(); // "</div>"
1<?php
2
3use Forte\Facades\Forte;
4
5$doc = Forte::parse('<input type="text">');
6
7$input = $doc->findElementByName('input');
8$input->renderClosingTag(); // ""
Use renderWithChildren to render the full element but substitute the children with custom content. Self-closing and void elements return render() unchanged:
1<?php
2
3use Forte\Facades\Forte;
4
5$doc = Forte::parse('<div class="card"><p>Old content</p></div>');
6
7$element = $doc->findElementByName('div');
8
9// '<div class="card"><span>New content</span></div>'
10$element->renderWithChildren('<span>New content</span>');
#Finding Elements
You can locate elements by tag name using dedicated finder methods. The singular variant returns the first match, while the plural variant returns a LazyCollection:
1<?php
2
3$doc->findElementByName('div'); // ?ElementNode
4$doc->findElementsByName('div'); // LazyCollection<ElementNode>
To traverse all elements in the document tree:
1<?php
2
3$doc->elements; // LazyCollection of all ElementNode instances
You may filter, count, and map the collection:
1<?php
2
3// Find all divs with a specific class
4$containers = $doc->elements->filter(
5 fn($el) => $el->is('div') && $el->hasAttribute('class')
6);
7
8// Get all tag names
9$tagNames = $doc->elements->map(
10 fn($el) => $el->tagNameText()
11)->unique()->all();
#Special Element Types
The following node types represent non-standard or structural HTML constructs.
#Conditional Comments
Internet Explorer conditional comments are captured as ConditionalCommentNode. You can inspect the condition expression and content:
1<?php
2
3use Forte\Ast\Elements\ConditionalCommentNode;
4
5$node->condition(); // string (e.g. "lt IE 9")
6$node->content(); // string (content between markers)
7$node->isDownlevelHidden(); // bool
8$node->isDownlevelRevealed(); // bool
9$node->hasClose(); // bool
#Bogus Comments
Malformed HTML comments are parsed as BogusCommentNode:
1<?php
2
3use Forte\Ast\Elements\BogusCommentNode;
4
5$node->content(); // string
6$node->hasClose(); // bool
7$node->isEmpty(); // bool
#CDATA Sections
CDATA sections (<![CDATA[...]]>) are captured as CdataNode:
1<?php
2
3use Forte\Ast\Elements\CdataNode;
4
5$node->content(); // string
6$node->hasClose(); // bool
7$node->isEmpty(); // bool
#Stray Closing Tags
Unmatched closing tags (no corresponding opening tag) are captured as StrayClosingTagNode:
1<?php
2
3use Forte\Ast\Elements\StrayClosingTagNode;
4
5$node->tagNameText(); // string (e.g. "div")
#See also
- Basic Nodes: Common node API shared by all node types
- Components and Slots: Blade component elements and slot access
- Traversal: Navigate and query the document tree
- Rewriters: Transform elements using the visitor pattern