Rewriting

Instrumentation

The Instrumentation pass injects tracking markers around nodes in the document. Create an Instrumentation instance using the static make method, then specify which node types to instrument:

<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Instrumentation;
$doc = Forte::parse('<div>Content</div><span>More</span>');
$result = $doc->apply(
Instrumentation::make()->elements()
)->render();

By default, instrumentation wraps matched nodes with HTML comments containing base64-encoded metadata:

<!-- forte:start eyJ0eXBlIjoiZWxlbWVudCIsIm5hbWUiOiJkaXYifQ== -->
<div>Content</div>
<!-- forte:end -->

#Targeting Node Types

You can instrument specific node types by calling the corresponding methods. Each accepts an optional array of name patterns to filter matches:

<?php
use Forte\Rewriting\Passes\Instrumentation;
// Instrument all elements
Instrumentation::make()->elements();
// Instrument only specific elements
Instrumentation::make()->elements(['div', 'section']);
// Instrument components
Instrumentation::make()->components(['x-*']);
// Instrument directives and directive blocks
Instrumentation::make()->directives(['include', 'yield']);
Instrumentation::make()->directiveBlocks(['if', 'foreach']);

You can chain multiple type methods together. When no type is specified, Instrumentation defaults to instrumenting all elements and components:

<?php
use Forte\Rewriting\Passes\Instrumentation;
// Elements + components + specific directives
Instrumentation::make()
->elements()
->components()
->directives(['include']);
// Default: all elements and components
Instrumentation::make();

#Customizing the Prefix

The default comment prefix is forte. Use the prefix method to change it:

<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Instrumentation;
$doc = Forte::parse('<div>Content</div>');
$result = $doc->apply(
Instrumentation::make()
->elements()
->prefix('debug')
)->render();

This produces <!-- debug:start ... --> and <!-- debug:end --> markers.

#Attribute-Based Instrumentation

Instead of HTML comments, you can inject metadata as a data attribute on element and component nodes. The asAttribute method uses base64 encoding, while asJsonAttribute uses readable JSON:

<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Instrumentation;
$doc = Forte::parse('<div>Content</div>');
$result = $doc->apply(
Instrumentation::make()
->elements()
->asAttribute()
)->render();

The result contains data-instrumentation="..." with base64-encoded metadata and no surrounding comments.

You can customize the attribute name:

<?php
use Forte\Rewriting\Passes\Instrumentation;
Instrumentation::make()->elements()->asAttribute('data-debug');
Instrumentation::make()->elements()->asJsonAttribute('data-source');

#Custom Marker Callbacks

For full control, pass a callback using the using method. The callback receives the metadata array and should return an array of [startComment, endComment] or [startComment, endComment, attributes]:

<?php
use Forte\Facades\Forte;
use Forte\Rewriting\Passes\Instrumentation;
$doc = Forte::parse('<div>Content</div>');
$result = $doc->apply(
Instrumentation::make()->elements()->using(fn ($meta) => [
"<!-- START:{$meta['name']} -->",
'<!-- END -->',
])
)->render();

The callback can also return a third element to set attributes on element nodes:

<?php
use Forte\Rewriting\Passes\Instrumentation;
Instrumentation::make()->elements()->using(fn ($meta) => [
'', // no start comment
'', // no end comment
['data-type' => $meta['type']], // attribute injection
]);

#Metadata Options

Include line numbers and extra metadata in the marker data:

<?php
use Forte\Rewriting\Passes\Instrumentation;
Instrumentation::make()
->elements()
->withLineNumbers()
->withMeta(['viewPath' => 'welcome.blade.php']);

The metadata object passed to callbacks includes type, name, and depth by default. Component nodes add componentName, componentType, and prefix. Directive nodes add arguments. Enabling withLineNumbers adds a line key.

#Decoding Markers

Use the static decode method to convert a marker string back to its metadata:

<?php
use Forte\Rewriting\Passes\Instrumentation;
$encoded = base64_encode(json_encode(['type' => 'element', 'name' => 'div']));
$meta = Instrumentation::decode($encoded);
$meta['type']; // "element"
$meta['name']; // "div"

The decode method also accepts a full comment string and extracts the encoded portion automatically. It returns null for invalid input.

#See also

  • Rewrite Passes: Built-in passes for element and directive transformations
  • Rewriters: The visitor pattern and NodePath API
  • Enclaves: Apply rewriters to isolated compilation environments
  • Documents: Parse templates and apply rewriters