feat: Divi path IDs, attribute paths and outline
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:
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
|
||||
/**
|
||||
* The page tree as rows and as compact text (lit-divi-outline, spec §5.3/§5.7; also the
|
||||
* "outline" of write results). Preset IDs are shown with their names when known.
|
||||
*/
|
||||
final class Outline
|
||||
{
|
||||
/** @param array<string, string> $presetNames Preset ID => name. */
|
||||
public function __construct(private array $presetNames = [])
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{id: string, type: string, label: string, excerpt: string, info: string,
|
||||
* presets: list<string>, children: int, editable: bool, depth: int}>
|
||||
*/
|
||||
public function rows(NodeIndex $index, ?string $rootId = null, ?int $maxDepth = null): array
|
||||
{
|
||||
$rows = [];
|
||||
$baseDepth = null;
|
||||
foreach ($index->entries() as $entry) {
|
||||
$id = $entry['id'];
|
||||
if ($rootId !== null && $id !== $rootId && ! str_starts_with($id, $rootId . '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$baseDepth ??= $entry['depth'];
|
||||
$depth = $entry['depth'] - $baseDepth;
|
||||
if ($maxDepth !== null && $depth > $maxDepth) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rows[] = $this->row($entry['block'], $id, $depth);
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/** @param list<array<string, mixed>> $rows Output of rows(). */
|
||||
public function text(array $rows): string
|
||||
{
|
||||
$lines = [];
|
||||
foreach ($rows as $row) {
|
||||
$line = str_repeat(' ', (int) $row['depth']) . $row['id'] . ' ' . $row['type'];
|
||||
$line .= $row['label'] !== '' ? ' "' . $row['label'] . '"' : '';
|
||||
$line .= $row['info'] !== '' ? ' [' . $row['info'] . ']' : '';
|
||||
$line .= $row['presets'] !== [] ? ' {Preset: ' . implode(', ', $row['presets']) . '}' : '';
|
||||
$line .= $row['excerpt'] !== '' ? ' – ' . $row['excerpt'] : '';
|
||||
$line .= $row['editable'] ? '' : ' (nur lesbar)';
|
||||
$lines[] = $line;
|
||||
}
|
||||
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{id: string, type: string, label: string, excerpt: string, info: string,
|
||||
* presets: list<string>, children: int, editable: bool, depth: int}
|
||||
*/
|
||||
private function row(Block $block, string $id, int $depth): array
|
||||
{
|
||||
$editable = $block->isDivi() && ! $block->isOpaque();
|
||||
|
||||
return [
|
||||
'id' => $id,
|
||||
'type' => $block->isDivi() ? $block->shortName() : $block->name(),
|
||||
'label' => NodeSummary::label($block),
|
||||
'excerpt' => NodeSummary::excerpt($block),
|
||||
'info' => $editable ? NodeSummary::info($block) : '',
|
||||
'presets' => array_map(
|
||||
fn (string $presetId): string => $this->presetNames[$presetId] ?? $presetId,
|
||||
NodeSummary::presetIds($block)
|
||||
),
|
||||
'children' => $editable ? count($block->children()) : 0,
|
||||
'editable' => $editable,
|
||||
'depth' => $depth,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user