refactor: one VariableRef per composition, design lookups in DesignSystem (H3)

- DiviComposition::references() builds the one VariableRef with the entry's
  live map (S22/S31) and passes it to AttrWriter; Placeholders only needs the
  design system now, Placeholders::references() is gone (no reach-through).
- DesignSystem::colorIdFor()/variableFor() replace the dead colorId()/variable()
  and carry Placeholders' lookup incl. the S13a ambiguity check (byLabel moved,
  messages unchanged); isColorVariable() decides color vs content for {{var:}}.
- DesignSystem::colorReferenceIds() (VariableRef color names) and
  contentVariableIds() (DynamicContentRules design names) replace the two
  inline computations; same lists, same order.
Tests: fixtures/tests get the VariableRef from ComposeFixture::references() or
build it with the map; DesignSystemTest uses the new lookups (+2 tests).

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:07:56 +02:00
co-authored by Claude Opus 5.5
parent 874a92c6be
commit 203d14a2f9
12 changed files with 184 additions and 118 deletions
@@ -12,6 +12,7 @@ use LIT\MCP\Integrations\Divi\Compose\ShortformWriter;
use LIT\MCP\Integrations\Divi\Compose\StructureRules;
use LIT\MCP\Integrations\Divi\Compose\TreeEditor;
use LIT\MCP\Integrations\Divi\Compose\ValueSanitizer;
use LIT\MCP\Integrations\Divi\Compose\VariableRef;
use LIT\MCP\Integrations\Divi\Compose\Warnings;
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
@@ -19,8 +20,9 @@ use LIT\MCP\Integrations\Divi\Schema\DiviModules;
/**
* Wires the pure Compose classes with the live catalog, design system, Divi's dynamic content
* registry and the WordPress sanitizer/media lookup – once per request and entry. Ruling S31:
* ONE Placeholders instance (carrying the live dynamic content map of the entry, S22) is shared
* by AttrWriter and ShortformWriter, and the same AttrWriter serves ShortformWriter and Composer.
* ONE VariableRef (carrying the live dynamic content map of the entry, S22) and ONE Placeholders
* instance are shared by AttrWriter and ShortformWriter, and the same AttrWriter serves
* ShortformWriter and Composer.
*
* forPost() binds the composition to the entry being written (DiviWriter::composition() does it
* for the abilities); unbound, VariableRef's default map applies. Not final so abilities can be
@@ -29,6 +31,7 @@ use LIT\MCP\Integrations\Divi\Schema\DiviModules;
class DiviComposition
{
private ?int $postId = null;
private ?VariableRef $references = null;
private ?Placeholders $placeholders = null;
private ?AttrWriter $attrWriter = null;
private ?Composer $composer = null;
@@ -42,11 +45,12 @@ class DiviComposition
) {
}
/** A fresh composition for entry $postId (own Placeholders with that entry's live map). */
/** A fresh composition for entry $postId (own VariableRef with that entry's live map). */
public function forPost(int $postId): static
{
$bound = clone $this;
$bound->postId = $postId;
$bound->references = null;
$bound->placeholders = null;
$bound->attrWriter = null;
$bound->composer = null;
@@ -54,18 +58,29 @@ class DiviComposition
return $bound;
}
/** The one Placeholders instance of this composition (ruling S31). */
public function placeholders(): Placeholders
/** The one checker of $variable(…)$ values of this composition, with the entry's live map (S22, S31). */
public function references(): VariableRef
{
return $this->placeholders ??= new Placeholders(
return $this->references ??= new VariableRef(
$this->design->read(),
$this->postId === null ? null : $this->dynamicContent->forPost($this->postId)
);
}
/** The one Placeholders instance of this composition (ruling S31). */
public function placeholders(): Placeholders
{
return $this->placeholders ??= new Placeholders($this->design->read());
}
public function attrWriter(): AttrWriter
{
return $this->attrWriter ??= new AttrWriter($this->modules->catalog(), $this->placeholders(), $this->sanitizer);
return $this->attrWriter ??= new AttrWriter(
$this->modules->catalog(),
$this->placeholders(),
$this->references(),
$this->sanitizer
);
}
public function composer(): Composer