From 203d14a2f903807366cc59e9588ba4c88ddf0705 Mon Sep 17 00:00:00 2001 From: Jan-Niclas Loosen Date: Sat, 26 Sep 2026 18:07:56 +0200 Subject: [PATCH] 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) Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7 --- src/Integrations/Divi/Compose/AttrWriter.php | 3 +- .../Divi/Compose/DynamicContentRules.php | 8 +- .../Divi/Compose/Placeholders.php | 75 ++----------- src/Integrations/Divi/Compose/VariableRef.php | 8 +- src/Integrations/Divi/Design/DesignSystem.php | 102 +++++++++++++++--- .../Divi/Pages/DiviComposition.php | 29 +++-- tests/Support/ComposeFixture.php | 15 ++- .../Divi/Compose/PlaceholdersTest.php | 2 +- .../Divi/Design/DesignSystemTest.php | 50 +++++++-- .../Divi/Pages/DiviCompositionTest.php | 3 + .../Divi/Pages/DiviWriterTest.php | 2 +- .../Divi/Pages/DynamicContentMapTest.php | 5 +- 12 files changed, 184 insertions(+), 118 deletions(-) diff --git a/src/Integrations/Divi/Compose/AttrWriter.php b/src/Integrations/Divi/Compose/AttrWriter.php index 28c6a84..16a6ec5 100644 --- a/src/Integrations/Divi/Compose/AttrWriter.php +++ b/src/Integrations/Divi/Compose/AttrWriter.php @@ -58,6 +58,7 @@ final class AttrWriter public function __construct( private ModuleCatalog $catalog, private Placeholders $placeholders, + private VariableRef $references, private ValueSanitizer $sanitizer ) { } @@ -263,7 +264,7 @@ final class AttrWriter $kind ??= $routed; if (VariableRef::contains($value)) { // The only way a reference is stored: whole, straight from canonical(). - return $this->placeholders->references()->canonical($value, $this->sanitizer, $kind === 'url'); + return $this->references->canonical($value, $this->sanitizer, $kind === 'url'); } $clean = match ($kind) { diff --git a/src/Integrations/Divi/Compose/DynamicContentRules.php b/src/Integrations/Divi/Compose/DynamicContentRules.php index cdaffbc..d19149b 100644 --- a/src/Integrations/Divi/Compose/DynamicContentRules.php +++ b/src/Integrations/Divi/Compose/DynamicContentRules.php @@ -116,13 +116,7 @@ final class DynamicContentRules )); } - $design = array_values(DesignSystem::FONT_VARIABLES); - foreach ($this->design->variables() as $variable) { - if ($variable['type'] !== 'colors') { - $design[] = $variable['id']; - } - } - if (in_array($name, $design, true)) { + if (in_array($name, $this->design->contentVariableIds(), true)) { return self::DESIGN_SETTINGS; } diff --git a/src/Integrations/Divi/Compose/Placeholders.php b/src/Integrations/Divi/Compose/Placeholders.php index ac35da6..05a6c6a 100644 --- a/src/Integrations/Divi/Compose/Placeholders.php +++ b/src/Integrations/Divi/Compose/Placeholders.php @@ -12,7 +12,8 @@ use LIT\MCP\Integrations\Divi\Design\DesignSystem; * {{color:primary||gcid-…}}, {{var:|gvid-…}}, {{font:heading|body}}, * {{post:title|…}}, {{field:}}. A placeholder must be the whole value (D9); unknown * names fail with the list of existing ones, labels two entries share fail with their IDs - * (ruling S13a). The result is still checked by VariableRef wherever it is written. Pure PHP. + * (ruling S13a, DesignSystem::colorIdFor/variableFor). The result is still checked by VariableRef + * wherever it is written. Pure PHP. */ final class Placeholders { @@ -36,21 +37,8 @@ final class Placeholders private const PATTERN = '/^\{\{\s*(color|var|font|post|field)\s*:\s*([^{}]+?)\s*\}\}$/'; - private VariableRef $references; - - /** - * @param array>|null $dynamicContent Divi's dynamic content - * options for VariableRef (ruling S22); null = DynamicContentRules::DEFAULT_DYNAMIC_CONTENT. - */ - public function __construct(private DesignSystem $design, ?array $dynamicContent = null) + public function __construct(private DesignSystem $design) { - $this->references = new VariableRef($design, $dynamicContent); - } - - /** The strict checker of $variable(…)$ values against this design system (ruling S1). */ - public function references(): VariableRef - { - return $this->references; } /** @@ -102,18 +90,11 @@ final class Placeholders private function color(string $name): string { - $colors = $this->design->colors(); - $ids = array_column($colors, 'id'); - $alias = DesignSystem::COLOR_ALIASES[mb_strtolower($name)] ?? null; - $id = match (true) { - in_array($name, $ids, true) => $name, - $alias !== null && in_array($alias, $ids, true) => $alias, - default => self::byLabel($colors, $name, 'globale Farbe'), - }; - + $id = $this->design->colorIdFor($name); if ($id === null) { + $colors = $this->design->colors(); $known = array_merge( - array_keys(array_intersect(DesignSystem::COLOR_ALIASES, $ids)), + array_keys(array_intersect(DesignSystem::COLOR_ALIASES, array_column($colors, 'id'))), array_column($colors, 'label') ); throw new InvalidArgumentException(sprintf( @@ -128,12 +109,9 @@ final class Placeholders private function variable(string $name): string { - $variables = $this->design->variables(); - $id = in_array($name, array_column($variables, 'id'), true) - ? $name - : self::byLabel($variables, $name, 'globale Variable'); + $id = $this->design->variableFor($name); if ($id === null) { - $labels = array_column($variables, 'label'); + $labels = array_column($this->design->variables(), 'label'); throw new InvalidArgumentException(sprintf( 'Unbekannte globale Variable "%s". Vorhanden: %s.', $name, @@ -141,42 +119,7 @@ final class Placeholders )); } - $type = 'content'; - foreach ($variables as $variable) { - if ($variable['id'] === $id && $variable['type'] === 'colors') { - $type = 'color'; - } - } - - return VariableRef::serialize($type, $id, []); - } - - /** - * ID of the one entry labelled $name (case-insensitive); null when none is. - * - * @param list $entries - * @throws InvalidArgumentException When several entries share the label (ruling S13a). - */ - private static function byLabel(array $entries, string $name, string $what): ?string - { - $key = mb_strtolower($name); - $ids = []; - foreach ($entries as $entry) { - if (mb_strtolower($entry['label']) === $key) { - $ids[] = $entry['id']; - } - } - - if (count($ids) > 1) { - throw new InvalidArgumentException(sprintf( - 'Name der %s "%s" ist mehrdeutig; bitte die ID angeben: %s.', - $what, - $name, - implode(', ', $ids) - )); - } - - return $ids[0] ?? null; + return VariableRef::serialize($this->design->isColorVariable($id) ? 'color' : 'content', $id, []); } private function font(string $name): string diff --git a/src/Integrations/Divi/Compose/VariableRef.php b/src/Integrations/Divi/Compose/VariableRef.php index 5d7ab28..ac24806 100644 --- a/src/Integrations/Divi/Compose/VariableRef.php +++ b/src/Integrations/Divi/Compose/VariableRef.php @@ -204,13 +204,7 @@ final class VariableRef */ private function colorSettings(string $name, array $settings): array { - $names = array_column($this->design->colors(), 'id'); - foreach ($this->design->variables() as $variable) { - if ($variable['type'] === 'colors') { - $names[] = $variable['id']; - } - } - if (! in_array($name, $names, true)) { + if (! in_array($name, $this->design->colorReferenceIds(), true)) { throw self::unknownName($name, 'color'); } diff --git a/src/Integrations/Divi/Design/DesignSystem.php b/src/Integrations/Divi/Design/DesignSystem.php index a030b59..65cde67 100644 --- a/src/Integrations/Divi/Design/DesignSystem.php +++ b/src/Integrations/Divi/Design/DesignSystem.php @@ -137,31 +137,60 @@ final class DesignSystem return $this->sizes; } - /** gcid of an alias (primary …), an ID or a label (case-insensitive); null when unknown. */ - public function colorId(string $name): ?string + /** + * gcid for a placeholder name: an ID, an alias (primary …) of an existing customizer color, + * else the one color of that label (case-insensitive); null when unknown. + * + * @throws InvalidArgumentException When several colors share the label (ruling S13a). + */ + public function colorIdFor(string $name): ?string { - $key = mb_strtolower(trim($name)); - $alias = self::COLOR_ALIASES[$key] ?? null; - foreach ($this->colors as $color) { - if ($color['id'] === $alias || $color['id'] === trim($name) || mb_strtolower($color['label']) === $key) { - return $color['id']; - } - } + $ids = array_column($this->colors, 'id'); + $alias = self::COLOR_ALIASES[mb_strtolower($name)] ?? null; - return null; + return match (true) { + in_array($name, $ids, true) => $name, + $alias !== null && in_array($alias, $ids, true) => $alias, + default => self::byLabel($this->colors, $name, 'globale Farbe'), + }; } - /** @return array{id: string, type: string, label: string, value: string}|null By label or ID. */ - public function variable(string $name): ?array + /** + * gvid for a placeholder name: an ID, else the one variable of that label (case-insensitive); + * null when unknown. + * + * @throws InvalidArgumentException When several variables share the label (ruling S13a). + */ + public function variableFor(string $name): ?string { - $key = mb_strtolower(trim($name)); + return in_array($name, array_column($this->variables, 'id'), true) + ? $name + : self::byLabel($this->variables, $name, 'globale Variable'); + } + + /** Whether $id is a global variable of type "colors" (a color reference, not content). */ + public function isColorVariable(string $id): bool + { + return in_array($id, $this->colorVariableIds(), true); + } + + /** @return list Names a color reference may carry: global color IDs, then color variable IDs. */ + public function colorReferenceIds(): array + { + return array_merge(array_column($this->colors, 'id'), $this->colorVariableIds()); + } + + /** @return list Design names a content reference may carry: theme fonts, then non-color variable IDs. */ + public function contentVariableIds(): array + { + $ids = array_values(self::FONT_VARIABLES); foreach ($this->variables as $variable) { - if ($variable['id'] === trim($name) || mb_strtolower($variable['label']) === $key) { - return $variable; + if ($variable['type'] !== 'colors') { + $ids[] = $variable['id']; } } - return null; + return $ids; } /** @@ -232,6 +261,47 @@ final class DesignSystem return '{{color:' . ($alias !== false ? $alias : $label) . '}}'; } + /** @return list */ + private function colorVariableIds(): array + { + $ids = []; + foreach ($this->variables as $variable) { + if ($variable['type'] === 'colors') { + $ids[] = $variable['id']; + } + } + + return $ids; + } + + /** + * ID of the one entry labelled $name (case-insensitive); null when none is. + * + * @param list $entries + * @throws InvalidArgumentException When several entries share the label (ruling S13a). + */ + private static function byLabel(array $entries, string $name, string $what): ?string + { + $key = mb_strtolower($name); + $ids = []; + foreach ($entries as $entry) { + if (mb_strtolower($entry['label']) === $key) { + $ids[] = $entry['id']; + } + } + + if (count($ids) > 1) { + throw new InvalidArgumentException(sprintf( + 'Name der %s "%s" ist mehrdeutig; bitte die ID angeben: %s.', + $what, + $name, + implode(', ', $ids) + )); + } + + return $ids[0] ?? null; + } + private static function plain(mixed $value): mixed { if (is_object($value)) { diff --git a/src/Integrations/Divi/Pages/DiviComposition.php b/src/Integrations/Divi/Pages/DiviComposition.php index 46cfdd6..e1dc829 100644 --- a/src/Integrations/Divi/Pages/DiviComposition.php +++ b/src/Integrations/Divi/Pages/DiviComposition.php @@ -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 diff --git a/tests/Support/ComposeFixture.php b/tests/Support/ComposeFixture.php index 6a0439e..f40bdf1 100644 --- a/tests/Support/ComposeFixture.php +++ b/tests/Support/ComposeFixture.php @@ -11,6 +11,7 @@ use LIT\MCP\Integrations\Divi\Compose\Placeholders; use LIT\MCP\Integrations\Divi\Compose\ShortformWriter; use LIT\MCP\Integrations\Divi\Compose\StructureRules; use LIT\MCP\Integrations\Divi\Compose\ValueSanitizer; +use LIT\MCP\Integrations\Divi\Compose\VariableRef; use LIT\MCP\Integrations\Divi\Design\DesignSystem; /** @@ -131,9 +132,15 @@ final class ComposeFixture return new Placeholders(DiviFixtures::designSystem()); } + /** The strict $variable(…)$ checker for the sample design system and the default map. */ + public static function references(): VariableRef + { + return new VariableRef(DiviFixtures::designSystem()); + } + public static function attrWriter(bool $unfiltered = false): AttrWriter { - return new AttrWriter(DiviFixtures::catalog(), self::placeholders(), self::sanitizer($unfiltered)); + return new AttrWriter(DiviFixtures::catalog(), self::placeholders(), self::references(), self::sanitizer($unfiltered)); } /** @@ -151,14 +158,14 @@ final class ComposeFixture } /** - * Builder version 5.2.1. $design replaces the sample design system (one Placeholders instance - * shared by AttrWriter and ShortformWriter, like the live wiring – ruling S31). + * Builder version 5.2.1. $design replaces the sample design system (one Placeholders and one + * VariableRef instance shared by AttrWriter and ShortformWriter, like the live wiring – ruling S31). */ public static function composer(bool $unfiltered = false, ?DesignSystem $design = null): Composer { $design ??= DiviFixtures::designSystem(); $placeholders = new Placeholders($design); - $attrWriter = new AttrWriter(DiviFixtures::catalog(), $placeholders, self::sanitizer($unfiltered)); + $attrWriter = new AttrWriter(DiviFixtures::catalog(), $placeholders, new VariableRef($design), self::sanitizer($unfiltered)); return new Composer( DiviFixtures::catalog(), diff --git a/tests/Unit/Integrations/Divi/Compose/PlaceholdersTest.php b/tests/Unit/Integrations/Divi/Compose/PlaceholdersTest.php index c773112..c25688e 100644 --- a/tests/Unit/Integrations/Divi/Compose/PlaceholdersTest.php +++ b/tests/Unit/Integrations/Divi/Compose/PlaceholdersTest.php @@ -44,7 +44,7 @@ final class PlaceholdersTest extends TestCase self::assertSame($expected, $resolved); if ($expected !== $input) { // What placeholders produce passes the strict checker unchanged (ruling S1/S25). - self::assertSame($resolved, $placeholders->references()->canonical($resolved, ComposeFixture::sanitizer())); + self::assertSame($resolved, ComposeFixture::references()->canonical($resolved, ComposeFixture::sanitizer())); } } diff --git a/tests/Unit/Integrations/Divi/Design/DesignSystemTest.php b/tests/Unit/Integrations/Divi/Design/DesignSystemTest.php index 906d27d..e59e21f 100644 --- a/tests/Unit/Integrations/Divi/Design/DesignSystemTest.php +++ b/tests/Unit/Integrations/Divi/Design/DesignSystemTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace LIT\MCP\Tests\Unit\Integrations\Divi\Design; +use InvalidArgumentException; use LIT\MCP\Integrations\Divi\Design\DesignSystem; use LIT\MCP\Tests\Support\DiviFixtures; use PHPUnit\Framework\TestCase; @@ -34,16 +35,53 @@ final class DesignSystemTest extends TestCase self::assertSame(['p-1' => 'Standard', 'p-2' => 'CTA primär', 'g-1' => 'Fließtext groß'], $design->presetNames()); } + /** The name lists VariableRef/DynamicContentRules check references against (H3: one place). */ + public function testReferenceNameLists(): void + { + $design = new DesignSystem( + [['id' => 'gcid-a', 'label' => 'A', 'value' => '#000']], + [ + ['id' => 'gvid-c', 'type' => 'colors', 'label' => 'C', 'value' => '#fff'], + ['id' => 'gvid-t', 'type' => 'strings', 'label' => 'T', 'value' => 'x'], + ], + [], + ['heading' => '', 'body' => ''], + [] + ); + + self::assertSame(['gcid-a', 'gvid-c'], $design->colorReferenceIds()); + self::assertSame(['--et_global_heading_font', '--et_global_body_font', 'gvid-t'], $design->contentVariableIds()); + self::assertTrue($design->isColorVariable('gvid-c')); + self::assertFalse($design->isColorVariable('gvid-t')); + self::assertFalse($design->isColorVariable('gcid-a')); + } + + public function testLabelLookupsRefuseAmbiguousLabels(): void + { + $design = new DesignSystem( + [['id' => 'gcid-a', 'label' => 'Blau', 'value' => '#00f'], ['id' => 'gcid-b', 'label' => 'blau', 'value' => '#00e']], + [], + [], + ['heading' => '', 'body' => ''], + [] + ); + + self::assertSame('gcid-b', $design->colorIdFor('gcid-b')); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Name der globale Farbe "Blau" ist mehrdeutig; bitte die ID angeben: gcid-a, gcid-b.'); + $design->colorIdFor('Blau'); + } + public function testLooksUpByAliasLabelOrId(): void { $design = DiviFixtures::designSystem(); - self::assertSame('gcid-primary-color', $design->colorId('primary')); - self::assertSame('gcid-a1b2', $design->colorId('nachtblau')); - self::assertSame('gcid-a1b2', $design->colorId('gcid-a1b2')); - self::assertNull($design->colorId('secondary')); - self::assertNull($design->colorId('Alt')); - self::assertSame('gvid-s1', $design->variable('telefon')['id'] ?? null); + self::assertSame('gcid-primary-color', $design->colorIdFor('primary')); + self::assertSame('gcid-a1b2', $design->colorIdFor('nachtblau')); + self::assertSame('gcid-a1b2', $design->colorIdFor('gcid-a1b2')); + self::assertNull($design->colorIdFor('secondary')); + self::assertNull($design->colorIdFor('Alt')); + self::assertSame('gvid-s1', $design->variableFor('telefon')); self::assertSame('p-2', $design->modulePresetId('divi/button', 'cta PRIMÄR')); self::assertNull($design->modulePresetId('divi/text', 'Standard')); self::assertSame(['Standard', 'CTA primär'], $design->modulePresetNames('divi/button')); diff --git a/tests/Unit/Integrations/Divi/Pages/DiviCompositionTest.php b/tests/Unit/Integrations/Divi/Pages/DiviCompositionTest.php index 3e18367..a565513 100644 --- a/tests/Unit/Integrations/Divi/Pages/DiviCompositionTest.php +++ b/tests/Unit/Integrations/Divi/Pages/DiviCompositionTest.php @@ -71,6 +71,7 @@ final class DiviCompositionTest extends TestCase self::assertSame([7], $this->registryCalls, 'the registry is read once per post'); self::assertSame($composition->attrWriter(), $composition->attrWriter()); self::assertSame($composition->placeholders(), $composition->placeholders()); + self::assertSame($composition->references(), $composition->references()); } public function testWithoutAPostTheDefaultMapApplies(): void @@ -97,6 +98,8 @@ final class DiviCompositionTest extends TestCase self::assertNotSame($base, $seven); self::assertNotSame($seven->placeholders(), $eight->placeholders()); self::assertNotSame($base->placeholders(), $seven->placeholders()); + self::assertNotSame($seven->references(), $eight->references()); + self::assertNotSame($base->references(), $seven->references()); self::assertSame([7, 8], $this->registryCalls); } diff --git a/tests/Unit/Integrations/Divi/Pages/DiviWriterTest.php b/tests/Unit/Integrations/Divi/Pages/DiviWriterTest.php index 89ca407..ce0f3e7 100644 --- a/tests/Unit/Integrations/Divi/Pages/DiviWriterTest.php +++ b/tests/Unit/Integrations/Divi/Pages/DiviWriterTest.php @@ -91,7 +91,7 @@ final class DiviWriterTest extends TestCase $writer = $this->writer(Mockery::mock(DiviSaver::class), FakeChangeLog::forbidden()); $page = $writer->page(['post_id' => 7, 'tree_rev' => Rev::of($content)]); - $writer->composition($page)->placeholders(); + $writer->composition($page)->references(); self::assertSame([7], $this->registryCalls, 'the live dynamic content map of post 7 (ruling S22)'); } diff --git a/tests/Unit/Integrations/Divi/Pages/DynamicContentMapTest.php b/tests/Unit/Integrations/Divi/Pages/DynamicContentMapTest.php index a932439..3136006 100644 --- a/tests/Unit/Integrations/Divi/Pages/DynamicContentMapTest.php +++ b/tests/Unit/Integrations/Divi/Pages/DynamicContentMapTest.php @@ -61,12 +61,13 @@ final class DynamicContentMapTest extends TestCase self::assertSame('select', $map['post_date']['date_format']); self::assertSame('text', $map['post_excerpt']['words']); - $placeholders = new Placeholders(DiviFixtures::designSystem(), $map); + $placeholders = new Placeholders(DiviFixtures::designSystem()); + $references = new VariableRef(DiviFixtures::designSystem(), $map); foreach (array_keys(Placeholders::POST) as $key) { $reference = $placeholders->resolve('{{post:' . $key . '}}'); self::assertSame( $reference, - $placeholders->references()->canonical($reference, ComposeFixture::sanitizer()), + $references->canonical($reference, ComposeFixture::sanitizer()), $key ); }