refactor: split TextReplacer into HtmlTokens and StoredForms (M1)

- HtmlTokens (static, with the S45 docblock): SPLIT, RAW_OPEN, tokenize(),
  structure(), closes(), unterminated() moved unchanged; new RAW_ELEMENTS list.
- StoredForms: of() (was TextReplacer::forms), mentions(), unicodeEscaped() –
  the DB prefilter forms; TextReplacer::mentions() delegates, the ability's
  candidate query uses StoredForms::of().
- TextReplacer keeps problems(), apply() and the splice/safe() verification;
  safe() still runs the tokenizer and HtmlContext as two independent scans, in
  the same order.
HtmlTokensTest asserts RAW_ELEMENTS === HtmlContext::RAW and that RAW_OPEN opens
exactly those elements. TextReplacerTest and HtmlContextTest unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
2026-09-26 18:14:49 +02:00
co-authored by Claude Opus 5.5
parent 570c1e6142
commit 3eeb7eee90
6 changed files with 239 additions and 161 deletions
@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Compose;
use LIT\MCP\Integrations\Divi\Compose\HtmlContext;
use LIT\MCP\Integrations\Divi\Compose\HtmlTokens;
use PHPUnit\Framework\TestCase;
/** Ruling S45: the tokenizer and the independent scan (HtmlContext) share one raw-text element list. */
final class HtmlTokensTest extends TestCase
{
public function testRawElementsAreHtmlContextsList(): void
{
self::assertSame(HtmlContext::RAW, HtmlTokens::RAW_ELEMENTS);
}
/** RAW_OPEN opens exactly the RAW_ELEMENTS: their body is "raw", other elements' body is text. */
public function testRawOpenMatchesTheList(): void
{
foreach (HtmlTokens::RAW_ELEMENTS as $element) {
$tokens = HtmlTokens::tokenize('<' . strtoupper($element) . ' a="1">x</' . $element . '>y');
// plaintext never ends: everything after it stays raw.
$after = $element === 'plaintext' ? 'raw' : 'text';
self::assertSame(['token', 'raw', 'token', $after], array_column((array) $tokens, 0), $element);
}
foreach (['div', 'scripts', 'styles', 'textarea', 'title'] as $element) {
$tokens = HtmlTokens::tokenize('<' . $element . '>x</' . $element . '>');
self::assertSame(['token', 'text', 'token'], array_column((array) $tokens, 0), $element);
}
}
}