- 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
141 lines
5.9 KiB
PHP
141 lines
5.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Compose;
|
|
|
|
use InvalidArgumentException;
|
|
use LIT\MCP\Integrations\Divi\Compose\Placeholders;
|
|
use LIT\MCP\Integrations\Divi\Design\DesignSystem;
|
|
use LIT\MCP\Tests\Support\ComposeFixture;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class PlaceholdersTest extends TestCase
|
|
{
|
|
/** @return array<string, array{string, string}> */
|
|
public static function placeholders(): array
|
|
{
|
|
return [
|
|
'color alias' => ['{{color:primary}}', '$variable({"type":"color","value":{"name":"gcid-primary-color","settings":{}}})$'],
|
|
'color label' => ['{{ color : Nachtblau }}', '$variable({"type":"color","value":{"name":"gcid-a1b2","settings":{}}})$'],
|
|
'color id' => ['{{color:gcid-a1b2}}', '$variable({"type":"color","value":{"name":"gcid-a1b2","settings":{}}})$'],
|
|
'variable' => ['{{var:Telefon}}', '$variable({"type":"content","value":{"name":"gvid-s1","settings":{}}})$'],
|
|
'variable id' => ['{{var:gvid-s1}}', '$variable({"type":"content","value":{"name":"gvid-s1","settings":{}}})$'],
|
|
'font' => ['{{font:heading}}', '$variable({"type":"content","value":{"name":"--et_global_heading_font","settings":{}}})$'],
|
|
'post title' => [
|
|
'{{post:title}}',
|
|
'$variable({"type":"content","value":{"name":"post_title","settings":{"before":"","after":""}}})$',
|
|
],
|
|
'featured image' => ['{{post:featured_image}}', '$variable({"type":"content","value":{"name":"post_featured_image","settings":{}}})$'],
|
|
'custom field' => [
|
|
'{{field:telefon_mobil}}',
|
|
'$variable({"type":"content","value":{"name":"custom_meta_telefon_mobil","settings":{"before":"","after":""}}})$',
|
|
],
|
|
'plain text' => ['Hallo Welt', 'Hallo Welt'],
|
|
];
|
|
}
|
|
|
|
/** @dataProvider placeholders */
|
|
public function testResolvesToDiviVariables(string $input, string $expected): void
|
|
{
|
|
$placeholders = ComposeFixture::placeholders();
|
|
$resolved = $placeholders->resolve($input);
|
|
|
|
self::assertSame($expected, $resolved);
|
|
if ($expected !== $input) {
|
|
// What placeholders produce passes the strict checker unchanged (ruling S1/S25).
|
|
self::assertSame($resolved, ComposeFixture::references()->canonical($resolved, ComposeFixture::sanitizer()));
|
|
}
|
|
}
|
|
|
|
/** @return array<string, array{string, string}> */
|
|
public static function invalid(): array
|
|
{
|
|
return [
|
|
'unknown color' => ['{{color:Lila}}', 'Vorhanden: primary, body, Primärfarbe, Fließtextfarbe, Nachtblau.'],
|
|
'unknown color id' => ['{{color:gcid-nope}}', 'Unbekannte globale Farbe'],
|
|
'unknown variable' => ['{{var:Fax}}', 'Vorhanden: Radius, Telefon'],
|
|
'unknown font' => ['{{font:mono}}', 'heading, body'],
|
|
'unknown post value' => ['{{post:views}}', 'title, excerpt'],
|
|
'bad field key' => ['{{field:a b}}', 'Ungültiger Feldschlüssel'],
|
|
'protected field key' => ['{{field:_edit_lock}}', 'Ungültiger Feldschlüssel'],
|
|
'embedded' => ['Seite: {{post:title}}', 'allein im Wert'],
|
|
];
|
|
}
|
|
|
|
/** @dataProvider invalid */
|
|
public function testRejectsUnknownNamesWithTheExistingOnes(string $input, string $message): void
|
|
{
|
|
$this->expectException(InvalidArgumentException::class);
|
|
$this->expectExceptionMessage($message);
|
|
|
|
ComposeFixture::placeholders()->resolve($input);
|
|
}
|
|
|
|
/** @return array<string, array{string, string}> */
|
|
public static function ambiguous(): array
|
|
{
|
|
return [
|
|
'color label' => ['{{color:blau}}', 'gcid-b1, gcid-b2'],
|
|
'variable label' => ['{{var:Info}}', 'gvid-i1, gvid-i2'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Ruling S13a: a label two entries share never silently picks the first one; IDs work directly.
|
|
*
|
|
* @dataProvider ambiguous
|
|
*/
|
|
public function testAmbiguousLabelsFailWithTheIds(string $input, string $ids): void
|
|
{
|
|
$placeholders = new Placeholders(new DesignSystem(
|
|
[
|
|
['id' => 'gcid-b1', 'label' => 'Blau', 'value' => '#00f'],
|
|
['id' => 'gcid-b2', 'label' => 'blau', 'value' => '#00a'],
|
|
],
|
|
[
|
|
['id' => 'gvid-i1', 'type' => 'strings', 'label' => 'Info', 'value' => 'a'],
|
|
['id' => 'gvid-i2', 'type' => 'strings', 'label' => 'Info', 'value' => 'b'],
|
|
],
|
|
[],
|
|
['heading' => '', 'body' => ''],
|
|
[]
|
|
));
|
|
|
|
try {
|
|
$placeholders->resolve($input);
|
|
self::fail('Ambiguous label accepted.');
|
|
} catch (InvalidArgumentException $e) {
|
|
self::assertStringContainsString('mehrdeutig', $e->getMessage());
|
|
self::assertStringContainsString($ids, $e->getMessage());
|
|
}
|
|
|
|
self::assertStringContainsString('"gcid-b2"', $placeholders->resolve('{{color:gcid-b2}}'));
|
|
self::assertStringContainsString('"gvid-i2"', $placeholders->resolve('{{var:gvid-i2}}'));
|
|
}
|
|
|
|
public function testColorTypeVariablesBecomeColorReferences(): void
|
|
{
|
|
$placeholders = new Placeholders(new DesignSystem(
|
|
[],
|
|
[['id' => 'gvid-c1', 'type' => 'colors', 'label' => 'Akzent', 'value' => '#f00']],
|
|
[],
|
|
['heading' => '', 'body' => ''],
|
|
[]
|
|
));
|
|
|
|
self::assertSame(
|
|
'$variable({"type":"color","value":{"name":"gvid-c1","settings":{}}})$',
|
|
$placeholders->resolve('{{var:Akzent}}')
|
|
);
|
|
}
|
|
|
|
public function testResolvesDeepValues(): void
|
|
{
|
|
self::assertSame(
|
|
['color' => '$variable({"type":"color","value":{"name":"gcid-primary-color","settings":{}}})$', 'size' => '20px'],
|
|
ComposeFixture::placeholders()->resolveDeep(['color' => '{{color:primary}}', 'size' => '20px'])
|
|
);
|
|
}
|
|
}
|