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:

1<?php
2
3use Forte\Facades\Forte;
4use Forte\Rewriting\Passes\Instrumentation;
5
6$doc = Forte::parse('<div>Content</div><span>More</span>');
7
8$result = $doc->apply(
9 Instrumentation::make()->elements()
10)->render();

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

1<!-- forte:start eyJ0eXBlIjoiZWxlbWVudCIsIm5hbWUiOiJkaXYifQ== -->
2<div>Content</div>
3<!-- 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:

1<?php
2
3use Forte\Rewriting\Passes\Instrumentation;
4
5// Instrument all elements
6Instrumentation::make()->elements();
7
8// Instrument only specific elements
9Instrumentation::make()->elements(['div', 'section']);
10
11// Instrument components
12Instrumentation::make()->components(['x-*']);
13
14// Instrument directives and directive blocks
15Instrumentation::make()->directives(['include', 'yield']);
16Instrumentation::make()->directiveBlocks(['if', 'foreach']);

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

1<?php
2
3use Forte\Rewriting\Passes\Instrumentation;
4
5// Elements + components + specific directives
6Instrumentation::make()
7 ->elements()
8 ->components()
9 ->directives(['include']);
10
11// Default: all elements and components
12Instrumentation::make();

#Customizing the Prefix

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

1<?php
2
3use Forte\Facades\Forte;
4use Forte\Rewriting\Passes\Instrumentation;
5
6$doc = Forte::parse('<div>Content</div>');
7
8$result = $doc->apply(
9 Instrumentation::make()
10 ->elements()
11 ->prefix('debug')
12)->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:

1<?php
2
3use Forte\Facades\Forte;
4use Forte\Rewriting\Passes\Instrumentation;
5
6$doc = Forte::parse('<div>Content</div>');
7
8$result = $doc->apply(
9 Instrumentation::make()
10 ->elements()
11 ->asAttribute()
12)->render();

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

You can customize the attribute name:

1<?php
2
3use Forte\Rewriting\Passes\Instrumentation;
4
5Instrumentation::make()->elements()->asAttribute('data-debug');
6Instrumentation::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]:

1<?php
2
3use Forte\Facades\Forte;
4use Forte\Rewriting\Passes\Instrumentation;
5
6$doc = Forte::parse('<div>Content</div>');
7
8$result = $doc->apply(
9 Instrumentation::make()->elements()->using(fn ($meta) => [
10 "<!-- START:{$meta['name']} -->",
11 '<!-- END -->',
12 ])
13)->render();

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

1<?php
2
3use Forte\Rewriting\Passes\Instrumentation;
4
5Instrumentation::make()->elements()->using(fn ($meta) => [
6 '', // no start comment
7 '', // no end comment
8 ['data-type' => $meta['type']], // attribute injection
9]);

#Metadata Options

Include line numbers and extra metadata in the marker data:

1<?php
2
3use Forte\Rewriting\Passes\Instrumentation;
4
5Instrumentation::make()
6 ->elements()
7 ->withLineNumbers()
8 ->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:

1<?php
2
3use Forte\Rewriting\Passes\Instrumentation;
4
5$encoded = base64_encode(json_encode(['type' => 'element', 'name' => 'div']));
6$meta = Instrumentation::decode($encoded);
7
8$meta['type']; // "element"
9$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