73 lines
2.5 KiB
PHP
Executable File
73 lines
2.5 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Modules\Stylist\Services;
|
|
|
|
use Illuminate\Filesystem\Filesystem;
|
|
use Modules\Stylist\Theme\Theme;
|
|
|
|
final class ThemeAccessibilityValidator
|
|
{
|
|
public function __construct(private readonly Filesystem $files) {}
|
|
|
|
/** @return array<int, array{severity:string,message:string,file:string}> */
|
|
public function validate(Theme $theme): array
|
|
{
|
|
$issues = [];
|
|
|
|
foreach ($this->files->allFiles($theme->path().'/views') as $file) {
|
|
$content = $file->getContents();
|
|
$relative = $file->getRelativePathname();
|
|
|
|
$missingAlt = 0;
|
|
if (preg_match_all('/<img\\b(?:(?:"[^"]*")|(?:\'[^\']*\')|[^\'">])*>/is', $content, $images)) {
|
|
foreach ($images[0] as $image) {
|
|
if (! preg_match('/\\balt\\s*=\\s*(?:"[^"]*"|\'[^\']*\')/is', $image)) {
|
|
$missingAlt++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($missingAlt > 0) {
|
|
$issues[] = [
|
|
'severity' => 'error',
|
|
'message' => $missingAlt.' image(s) missing alt text.',
|
|
'file' => $relative,
|
|
];
|
|
}
|
|
|
|
if (preg_match('/<html\\b(?![^>]*\\blang=)/i', $content)) {
|
|
$issues[] = [
|
|
'severity' => 'warning',
|
|
'message' => 'HTML element is missing a lang attribute.',
|
|
'file' => $relative,
|
|
];
|
|
}
|
|
|
|
$unnamedButtons = 0;
|
|
if (preg_match_all('/<button\\b((?:(?:"[^"]*")|(?:\'[^\']*\')|[^\'">])*)>(.*?)<\\/button>/is', $content, $buttons, PREG_SET_ORDER)) {
|
|
foreach ($buttons as $button) {
|
|
$attributes = $button[1];
|
|
$body = $button[2];
|
|
|
|
$hasAccessibleAttribute = preg_match('/\\b(?:aria-label|aria-labelledby|title)\\s*=\\s*(?:"[^"]+"|\'[^\']+\')/is', $attributes) === 1;
|
|
$visibleText = trim(html_entity_decode(strip_tags($body), ENT_QUOTES | ENT_HTML5));
|
|
|
|
if (! $hasAccessibleAttribute && $visibleText === '') {
|
|
$unnamedButtons++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($unnamedButtons > 0) {
|
|
$issues[] = [
|
|
'severity' => 'warning',
|
|
'message' => $unnamedButtons.' button(s) may lack an accessible name.',
|
|
'file' => $relative,
|
|
];
|
|
}
|
|
}
|
|
|
|
return $issues;
|
|
}
|
|
}
|