This commit is contained in:
team 1
2026-05-07 14:42:12 +02:00
parent 5237bb0c63
commit f136bec0d7
4 changed files with 193 additions and 129 deletions

View File

@@ -96,6 +96,7 @@ final readonly class GenreSourceOfTruthGuard
$coverageErrors = $this->validateConfigurationValueCoverage($configurationValues);
array_push($errors, ...$coverageErrors);
$nativeValueNodes = $this->countGenreNativeValueNodes($configurationValues);
$declaredSourcePaths = $this->collectSourcePaths($configurationValues);
$uniqueSourcePaths = [];
foreach ($declaredSourcePaths as $valuePath => $sourcePaths) {
@@ -157,6 +158,7 @@ final readonly class GenreSourceOfTruthGuard
$summary = $this->summarizeRows($rows);
$summary['configuration_value_groups'] = count($configurationValues);
$summary['genre_native_value_nodes'] = $nativeValueNodes;
$summary['source_path_value_nodes'] = count($declaredSourcePaths);
$summary['declared_source_paths'] = count($uniqueSourcePaths);
$summary['violations'] = count($errors);
@@ -190,10 +192,15 @@ final readonly class GenreSourceOfTruthGuard
{
$sourcePaths = $value['source_paths'] ?? null;
$hasSourcePaths = is_array($sourcePaths) && $sourcePaths !== [];
$hasGenreNativeOrigin = $this->hasGenreNativeOrigin($value);
if (array_key_exists('source_paths', $value) && !$hasSourcePaths && $path !== '') {
$errors[] = sprintf('genre.configuration_values.%s.source_paths must be a non-empty list when declared.', $path);
}
if (array_key_exists('origin', $value) && !$hasGenreNativeOrigin && $path !== '') {
$errors[] = sprintf('genre.configuration_values.%s.origin must be genre_native when declared.', $path);
}
if ($hasSourcePaths) {
$seen = [];
foreach ($sourcePaths as $sourcePath) {
@@ -209,13 +216,13 @@ final readonly class GenreSourceOfTruthGuard
}
}
$covered = $coveredBySourcePath || $hasSourcePaths;
$covered = $coveredBySourcePath || $hasSourcePaths || $hasGenreNativeOrigin;
if ($path !== '' && !$covered && $this->hasDirectPayload($value)) {
$errors[] = sprintf('genre.configuration_values.%s must declare source_paths or inherit them from a parent value node.', $path);
}
foreach ($value as $key => $child) {
if ($key === 'source_paths' || $key === 'description' || !is_string($key) || !is_array($child)) {
if ($this->isMetadataKey($key) || !is_string($key) || !is_array($child)) {
continue;
}
@@ -230,7 +237,7 @@ final readonly class GenreSourceOfTruthGuard
private function hasDirectPayload(array $value): bool
{
foreach ($value as $key => $child) {
if ($key === 'source_paths' || $key === 'description') {
if ($this->isMetadataKey($key)) {
continue;
}
if (!is_array($child)) {
@@ -241,6 +248,45 @@ final readonly class GenreSourceOfTruthGuard
return false;
}
/** @param array<int|string, mixed> $value */
private function hasGenreNativeOrigin(array $value): bool
{
$origin = $value['origin'] ?? null;
return is_string($origin) && trim($origin) === 'genre_native';
}
private function isMetadataKey(mixed $key): bool
{
return $key === 'source_paths' || $key === 'description' || $key === 'origin';
}
/**
* @param array<string, mixed> $configurationValues
*/
private function countGenreNativeValueNodes(array $configurationValues): int
{
return $this->countGenreNativeValueNodesRecursive($configurationValues, '');
}
/** @param array<int|string, mixed> $value */
private function countGenreNativeValueNodesRecursive(array $value, string $path): int
{
$count = $path !== '' && $this->hasGenreNativeOrigin($value) ? 1 : 0;
foreach ($value as $key => $child) {
if ($this->isMetadataKey($key) || !is_string($key) || !is_array($child)) {
continue;
}
$childPath = $path === '' ? $key : $path . '.' . $key;
$count += $this->countGenreNativeValueNodesRecursive($child, $childPath);
}
return $count;
}
/**
* @param array<string, mixed> $configurationValues
* @return array<string, string[]>
@@ -277,7 +323,7 @@ final readonly class GenreSourceOfTruthGuard
}
foreach ($value as $key => $child) {
if ($key === 'source_paths' || $key === 'description' || !is_string($key) || !is_array($child)) {
if ($this->isMetadataKey($key) || !is_string($key) || !is_array($child)) {
continue;
}
$childPath = $path === '' ? $key : $path . '.' . $key;
@@ -485,6 +531,7 @@ final readonly class GenreSourceOfTruthGuard
'configuration_value_groups' => 0,
'source_path_value_nodes' => 0,
'declared_source_paths' => 0,
'genre_native_value_nodes' => 0,
'legacy_fallback_empty' => 0,
'legacy_frozen_non_empty' => 0,
'legacy_non_empty_unregistered' => 0,