feat: GroupKeys und PresetAssignment – Preset-Stapel und Gruppen-Presets über eine Engstelle

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-18 16:45:29 +02:00
co-authored by Claude Sonnet 5.5
parent 6546e23e7f
commit fafa140546
6 changed files with 796 additions and 17 deletions
@@ -34,7 +34,7 @@ final class PresetComposerTest extends TestCase
};
}
private static function composer(bool $unfiltered = true): PresetComposer
private static function composer(bool $unfiltered = true, ?\Closure $groupsOf = null): PresetComposer
{
return new PresetComposer(
ComposeFixture::composer($unfiltered),
@@ -44,7 +44,7 @@ final class PresetComposerTest extends TestCase
ComposeFixture::sanitizer($unfiltered)
),
self::presetAttrs(),
static fn (string $module): array => [
$groupsOf ?? static fn (string $module): array => [
'module.decoration.spacing' => 'divi/spacing',
'button.decoration.font' => 'divi/font',
],
@@ -204,6 +204,39 @@ final class PresetComposerTest extends TestCase
self::assertStringContainsString('unbekanntes Gruppen-Preset', $result['errors']['items[0].group_presets.font']);
}
/** Ruling R3: GroupKeys replaces the first-match search – a name two groups share needs the path. */
public function testAmbiguousGroupNameIsAnErrorAndThePathResolvesIt(): void
{
$groupsOf = static fn (string $module): array => [
'button.decoration.font' => 'divi/font',
'title.decoration.font' => 'divi/font',
];
$book = self::book()->with(new PresetScope('group', 'divi/font'), [
'type' => 'group', 'id' => 'ffffffffff', 'name' => 'Schrift', 'groupName' => 'divi/font',
'groupId' => 'title.decoration.font', 'moduleName' => 'divi/button', 'attrs' => [],
]);
$composer = self::composer(true, $groupsOf);
$scope = new PresetScope('module', 'divi/button');
$ambiguous = $composer->compose($book, $scope, null, [
'name' => 'X', 'group_presets' => ['font' => 'Schrift'],
], 'items[0]', null);
self::assertSame(
'Gruppe "font" ist mehrdeutig; bitte den Attributpfad angeben: '
. 'button.decoration.font, title.decoration.font.',
$ambiguous['errors']['items[0].group_presets.font']
);
$byPath = $composer->compose($book, $scope, null, [
'name' => 'X', 'group_presets' => ['title.decoration.font' => 'Schrift'],
], 'items[0]', null);
self::assertSame([], $byPath['errors']);
self::assertSame(
['title.decoration.font' => ['presetId' => ['ffffffffff'], 'groupName' => 'divi/font']],
$byPath['item']['groupPresets']
);
}
public function testNewPresetNeedsAName(): void
{
$result = self::composer()->compose(self::book(), new PresetScope('module', 'divi/button'), null, [],