refactor: ValueKind enum instead of kind string literals (L1)

enum ValueKind: string { Html, Code, Url, Text } with strictness() and
tightens(self $routed) (the S33a rule formerly AttrWriter/ValueCleaner::tightens
over STRICTNESS). ValueCleaner::clean() takes ?ValueKind, kindOf()/kind()/
unknownKind() return it, the sanitizer match is exhaustive over the four cases;
the "Feldart" message prints ->value, so its text is unchanged. ShortformWriter
drops the identity map CLEAN_KIND for ValueKind::tryFrom($spec['kind']) ??
ValueKind::Text; Composer and ShortformWriter pass ValueKind::Text/Url.
The installed PHPCompatibility sniffs do not know enums: two sniffs are disabled
in ValueKind.php only, with the reason.
Tests: ValueCleanerTest passes/asserts ValueKind cases instead of strings;
+ValueKindTest (full tightens matrix, case values).

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:13:23 +02:00
co-authored by Claude Opus 5.5
parent 62ce99e558
commit 570c1e6142
6 changed files with 143 additions and 81 deletions
@@ -26,9 +26,6 @@ final class ShortformWriter
private const COLOR_ERROR = 'Farbe erwartet, z. B. {{color:primary}} oder #1a1a1a';
/** Curated kind => sanitizer kind of ValueCleaner::clean(). */
private const CLEAN_KIND = ['html' => 'html', 'code' => 'code', 'url' => 'url', 'text' => 'text'];
/**
* @param array<string, array<string, array<string, mixed>>>|null $modules Short form per
* type (tests only); null = ShortformMap.
@@ -107,7 +104,7 @@ final class ShortformWriter
$value = trim($this->placeholders->resolve($value));
if (VariableRef::contains($value)) {
$reference = $this->cleaner->clean($module, $path, $value, $subKey, 'text');
$reference = $this->cleaner->clean($module, $path, $value, $subKey, ValueKind::Text);
if (! is_string($reference) || VariableRef::typeOf($reference) !== 'color') {
throw new InvalidArgumentException(self::COLOR_ERROR);
}
@@ -119,7 +116,7 @@ final class ShortformWriter
throw new InvalidArgumentException(self::COLOR_ERROR);
}
$clean = $this->cleaner->clean($module, $path, $value, $subKey, 'text');
$clean = $this->cleaner->clean($module, $path, $value, $subKey, ValueKind::Text);
if (! is_string($clean) || preg_match(self::COLOR, $clean) !== 1) {
throw new InvalidArgumentException(self::COLOR_ERROR);
}
@@ -175,7 +172,7 @@ final class ShortformWriter
[$urlKey, $idKey, $altKey] = $keys;
$base = $path . '.desktop.value.';
$url = $this->cleaner->clean($module, $path, $image['url'], $urlKey, 'url');
$url = $this->cleaner->clean($module, $path, $image['url'], $urlKey, ValueKind::Url);
if ($url === '') {
throw new InvalidArgumentException($notFound);
}
@@ -206,7 +203,7 @@ final class ShortformWriter
}
try {
$clean = $this->cleaner->clean($module, $path, $alt, $altKey, 'text');
$clean = $this->cleaner->clean($module, $path, $alt, $altKey, ValueKind::Text);
} catch (InvalidArgumentException) {
return '';
}
@@ -253,18 +250,19 @@ final class ShortformWriter
return $this->color($module, $path, $value, $sub);
}
$kind = self::CLEAN_KIND[$spec['kind']] ?? 'text';
// The curated kind as sanitizer kind; any other kind is text.
$kind = ValueKind::tryFrom((string) $spec['kind']) ?? ValueKind::Text;
if (! is_string($value) && ! is_int($value) && ! is_float($value)) {
throw new InvalidArgumentException('Text erwartet');
}
$value = (string) $value;
if ($kind !== 'code') {
if ($kind !== ValueKind::Code) {
$value = $this->placeholders->resolve($value);
}
$clean = $this->cleaner->clean($module, $path, $value, $sub, $kind);
if ($kind === 'url' && $clean === '' && trim($value) !== '') {
if ($kind === ValueKind::Url && $clean === '' && trim($value) !== '') {
throw new InvalidArgumentException('ungültige URL');
}