Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
80 lines
2.8 KiB
PHP
80 lines
2.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace LIT\MCP\Integrations\Divi\Release;
|
|
|
|
use Closure;
|
|
use LIT\MCP\Integrations\Divi\BlockTree\Block;
|
|
use LIT\MCP\Integrations\Divi\BlockTree\Parser;
|
|
use LIT\MCP\Integrations\Divi\BlockTree\Serializer;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
/**
|
|
* Spec §6.2 step 3: a builder-made Divi 5 page (reference-page.html, from the converted fixture) parses and
|
|
* serializes byte-identically, and WordPress' parse_blocks() sees the same block names and nesting as the plugin's
|
|
* parser. Nothing is written. Not final so CompatibilityCheck can be tested with a mock.
|
|
*/
|
|
class FormatCheck
|
|
{
|
|
public const REFERENCE = __DIR__ . '/reference-page.html';
|
|
|
|
/** @param (Closure(string): array<int, mixed>)|null $wpBlocks null = parse_blocks(). */
|
|
public function __construct(private ?string $file = null, private ?Closure $wpBlocks = null)
|
|
{
|
|
}
|
|
|
|
/** @return list<string> */
|
|
public function problems(): array
|
|
{
|
|
$file = $this->file ?? self::REFERENCE;
|
|
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- local plugin file.
|
|
$content = is_file($file) ? file_get_contents($file) : false;
|
|
if (! is_string($content) || $content === '') {
|
|
return ['Der Referenzinhalt der Prüfung fehlt im Plugin.'];
|
|
}
|
|
|
|
$document = (new Parser())->parse($content);
|
|
$problems = [];
|
|
if (Serializer::document($document) !== $content) {
|
|
$problems[] = 'Parser und Serializer geben den Referenzinhalt nicht byte-gleich zurück.';
|
|
}
|
|
$wordPress = ($this->wpBlocks ?? static fn (string $markup): array => parse_blocks($markup))($content);
|
|
if (self::structure($document->children()) !== self::wpStructure($wordPress)) {
|
|
$problems[] = 'WordPress liest eine andere Blockstruktur als LIT MCP.';
|
|
}
|
|
|
|
return $problems;
|
|
}
|
|
|
|
/**
|
|
* @param list<Block> $blocks
|
|
* @return list<array{0: string, 1: list<mixed>}>
|
|
*/
|
|
private static function structure(array $blocks): array
|
|
{
|
|
return array_map(
|
|
static fn (Block $block): array => [$block->name(), self::structure($block->children())],
|
|
$blocks
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param array<int, mixed> $blocks parse_blocks() result; freeform parts (blockName null) are left out.
|
|
* @return list<array{0: string, 1: list<mixed>}>
|
|
*/
|
|
private static function wpStructure(array $blocks): array
|
|
{
|
|
$structure = [];
|
|
foreach ($blocks as $block) {
|
|
if (is_array($block) && is_string($block['blockName'] ?? null)) {
|
|
$inner = is_array($block['innerBlocks'] ?? null) ? $block['innerBlocks'] : [];
|
|
$structure[] = [$block['blockName'], self::wpStructure($inner)];
|
|
}
|
|
}
|
|
|
|
return $structure;
|
|
}
|
|
}
|