feat: Divi composer – short/full form to blocks with structure rules, presets and labels
Labels, background_color and preset ids go through the choke point (S13); ambiguous preset names fail with their ids (S13a); fullwidth + rows is an error. Carry-ins: control characters stripped before the marker check (S32), kind override may only tighten, reference alt texts dropped, color check via VariableRef::typeOf (S33). 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:
@@ -375,4 +375,63 @@ final class AttrWriterTest extends TestCase
|
||||
$result['attrs']['module']['decoration']['background']['desktop']['value']['color']
|
||||
);
|
||||
}
|
||||
|
||||
/** Ruling S32: C0 controls (except tab, LF, CR) and DEL go at the choke point, before the marker check. */
|
||||
public function testControlCharactersAreStrippedBeforeTheMarkerCheck(): void
|
||||
{
|
||||
$writer = ComposeFixture::attrWriter();
|
||||
|
||||
self::assertSame("a\tb\n", $writer->cleanValue('divi/code', 'content.innerContent', "a\x00\t\x01b\x1f\n\x7f"));
|
||||
self::assertSame("<p>a\nb\r</p>", $writer->cleanValue('divi/text', 'content.innerContent', "<p>a\x0b\nb\r\x08</p>"));
|
||||
self::assertSame('Titel', $writer->cleanValue('divi/heading', 'title.innerContent', "Ti\x00tel\x7f"));
|
||||
|
||||
$tail = '({"type":"color","value":{"name":"gcid-a1b2","settings":{}}})$';
|
||||
$targets = [
|
||||
'text' => ['divi/heading', 'title.innerContent'],
|
||||
'html' => ['divi/text', 'content.innerContent'],
|
||||
'code' => ['divi/code', 'content.innerContent'],
|
||||
];
|
||||
foreach ([chr(0), chr(1), chr(8), chr(27), chr(127)] as $control) {
|
||||
$value = '$variable' . $control . $tail;
|
||||
// The fake keeps them like sanitize_text_field does: the production code must catch it.
|
||||
self::assertStringNotContainsString('$variable(', ComposeFixture::sanitizer()->text($value));
|
||||
foreach ($targets as $kind => [$module, $path]) {
|
||||
try {
|
||||
$writer->cleanValue($module, $path, $value);
|
||||
self::fail(sprintf('%s: control %d not caught', $kind, ord($control)));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
self::assertStringContainsString('allein im Wert', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Ruling S33a: a kind override may only tighten the routed kind (code < html < text; url is its own family). */
|
||||
public function testKindOverrideMayOnlyTighten(): void
|
||||
{
|
||||
$writer = ComposeFixture::attrWriter();
|
||||
|
||||
self::assertSame('x', $writer->cleanValue('divi/text', 'content.innerContent', '<p>x</p>', null, 'text'));
|
||||
self::assertSame('x', $writer->cleanValue('divi/code', 'content.innerContent', '<b>x</b>', null, 'text'));
|
||||
self::assertSame('<p>x</p>', $writer->cleanValue('divi/code', 'content.innerContent', '<p>x</p><script>y</script>', null, 'html'));
|
||||
self::assertSame('Los', $writer->cleanValue('divi/heading', 'title.innerContent', '<b>Los</b>', null, 'text'));
|
||||
self::assertSame('/a', $writer->cleanValue('divi/button', 'button.innerContent', '/a', 'linkUrl', 'url'));
|
||||
|
||||
$weaker = [
|
||||
'html over text' => ['divi/heading', 'title.innerContent', null, 'html'],
|
||||
'code over text' => ['divi/heading', 'title.innerContent', null, 'code'],
|
||||
'code over html' => ['divi/text', 'content.innerContent', null, 'code'],
|
||||
'url over text' => ['divi/heading', 'title.innerContent', null, 'url'],
|
||||
'text over url' => ['divi/button', 'button.innerContent', 'linkUrl', 'text'],
|
||||
'html over url' => ['divi/button', 'button.innerContent', 'linkUrl', 'html'],
|
||||
];
|
||||
foreach ($weaker as $name => [$module, $path, $sub, $kind]) {
|
||||
try {
|
||||
$writer->cleanValue($module, $path, 'x', $sub, $kind);
|
||||
self::fail($name . ' was accepted');
|
||||
} catch (InvalidArgumentException $e) {
|
||||
self::assertStringContainsString('Feldart', $e->getMessage(), $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user