Sort the design guard's findings by path, line and message

Different checks land violations for the same file in their own pass order
(colours before shadows before media queries, an application's CSS always
appended after its views) rather than the order a maintainer would read the
file in. DesignGuard::violations() now sorts everything it returns
deterministically before handing it back, and a fixture proves it crosses
both dimensions: a later-processed application-CSS file whose path sorts
first, and two different checks landing on the same line in the opposite
order from how they run.

Plan step 42 (Phase F), Part B.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-15 09:30:03 +02:00
co-authored by Claude Sonnet 5
parent 87004a9035
commit 9cfb24f419
2 changed files with 150 additions and 101 deletions
+24 -1
View File
@@ -403,7 +403,30 @@ class DesignGuard
}
}
return [...$violations, ...$this->applicationCssViolations()];
return $this->sortViolations([...$violations, ...$this->applicationCssViolations()]);
}
/**
* `$violations` ("path:line message", `relative()`'s shape) sorted by path, then line
* (numerically, so line 9 sits before line 10), then message — whichever check produced each
* one, so two checks that land on the same file read in one deterministic order instead of
* each check's own pass order (colours before shadows before media queries, line order inside
* `missingStylesheets()`'s own pass, and so on).
*
* @param list<string> $violations
* @return list<string>
*/
protected function sortViolations(array $violations): array
{
$parsed = array_map(function (string $violation): array {
preg_match('/^(.*):(\d+) (.*)$/s', $violation, $match);
return [$match[1] ?? $violation, isset($match[2]) ? (int) $match[2] : 0, $match[3] ?? '', $violation];
}, $violations);
usort($parsed, fn (array $a, array $b): int => $a[0] <=> $b[0] ?: $a[1] <=> $b[1] ?: $a[2] <=> $b[2]);
return array_column($parsed, 3);
}
/**