Git Komut Rehberi & Terminal Asistanı
Sıfırdan Yeni Bir Depo Başlatın:
Mevcut Bir Git Deposu veya Klasörü Gönderin:
Hataları Geri Alma, İptal & Temizlik:
Son commit'i geri al (yapılan değişiklikleri korur):
git reset --soft HEAD~1
Yapılan yerel değişiklikleri iptal et (çalışma ağacını temizler):
git restore .
Takip edilmeyen gereksiz dosyaları sil:
git clean -fd
Değişiklikleri geçici sakla ve geri getir (stash):
git stash git stash pop
Dal (Branch) ve Sürüm Etiketleri:
Yeni dal aç ve geçiş yap:
git checkout -b yeni-ozellik git push -u origin yeni-ozellik
Sürüm etiketi (tag) oluştur ve gönder:
git tag -a v1.0.0 -m "Sürüm 1.0.0" git push origin --tags
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75171c6f96 | ||
|
|
1ea2579d20 |
@@ -0,0 +1,4 @@
|
|||||||
|
parameters:
|
||||||
|
level: 9
|
||||||
|
paths:
|
||||||
|
- src
|
||||||
@@ -30,8 +30,16 @@ class FixCommand extends Command
|
|||||||
{
|
{
|
||||||
$io = new SymfonyStyle($input, $output);
|
$io = new SymfonyStyle($input, $output);
|
||||||
$target = $input->getArgument('target');
|
$target = $input->getArgument('target');
|
||||||
$projectPath = $input->getOption('project-path') ?? getcwd();
|
if (!is_string($target)) {
|
||||||
$dryRun = $input->getOption('dry-run');
|
$io->error("Target must be a string URL or file path.");
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
$projectPathOption = $input->getOption('project-path');
|
||||||
|
$projectPath = is_string($projectPathOption) ? $projectPathOption : getcwd();
|
||||||
|
if ($projectPath === false) {
|
||||||
|
$projectPath = '.';
|
||||||
|
}
|
||||||
|
$dryRun = (bool)$input->getOption('dry-run');
|
||||||
|
|
||||||
$config = new Config();
|
$config = new Config();
|
||||||
$apiKey = $config->getGeminiApiKey();
|
$apiKey = $config->getGeminiApiKey();
|
||||||
@@ -45,7 +53,7 @@ class FixCommand extends Command
|
|||||||
|
|
||||||
// 1. Fetch HTML
|
// 1. Fetch HTML
|
||||||
$html = @file_get_contents($target);
|
$html = @file_get_contents($target);
|
||||||
if (!$html) {
|
if ($html === false || $html === '') {
|
||||||
$io->error("Could not read target: $target");
|
$io->error("Could not read target: $target");
|
||||||
return Command::FAILURE;
|
return Command::FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use YakNet\AccessibilityConsole\Source\SourceLocator;
|
|||||||
|
|
||||||
class ScanCommand extends Command
|
class ScanCommand extends Command
|
||||||
{
|
{
|
||||||
protected static $defaultName = 'scan';
|
protected static ?string $defaultName = 'scan';
|
||||||
|
|
||||||
protected function configure(): void
|
protected function configure(): void
|
||||||
{
|
{
|
||||||
@@ -33,14 +33,22 @@ class ScanCommand extends Command
|
|||||||
{
|
{
|
||||||
$io = new SymfonyStyle($input, $output);
|
$io = new SymfonyStyle($input, $output);
|
||||||
$target = $input->getArgument('target');
|
$target = $input->getArgument('target');
|
||||||
$enableAi = $input->getOption('ai');
|
if (!is_string($target)) {
|
||||||
$projectPath = $input->getOption('project-path') ?? getcwd();
|
$io->error("Target must be a string URL or file path.");
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
$enableAi = (bool)$input->getOption('ai');
|
||||||
|
$projectPathOption = $input->getOption('project-path');
|
||||||
|
$projectPath = is_string($projectPathOption) ? $projectPathOption : getcwd();
|
||||||
|
if ($projectPath === false) {
|
||||||
|
$projectPath = '.';
|
||||||
|
}
|
||||||
|
|
||||||
$io->title("Accessibility Console - Scanning: $target");
|
$io->title("Accessibility Console - Scanning: $target");
|
||||||
|
|
||||||
// 1. Fetch HTML
|
// 1. Fetch HTML
|
||||||
$html = @file_get_contents($target);
|
$html = @file_get_contents($target);
|
||||||
if (!$html) {
|
if ($html === false || $html === '') {
|
||||||
$io->error("Could not read target: $target");
|
$io->error("Could not read target: $target");
|
||||||
return Command::FAILURE;
|
return Command::FAILURE;
|
||||||
}
|
}
|
||||||
@@ -97,7 +105,7 @@ class ScanCommand extends Command
|
|||||||
|
|
||||||
// Export Report
|
// Export Report
|
||||||
$reportPath = $input->getOption('report');
|
$reportPath = $input->getOption('report');
|
||||||
if ($reportPath) {
|
if (is_string($reportPath) && $reportPath !== '') {
|
||||||
$extension = pathinfo($reportPath, PATHINFO_EXTENSION);
|
$extension = pathinfo($reportPath, PATHINFO_EXTENSION);
|
||||||
if ($extension === 'json') {
|
if ($extension === 'json') {
|
||||||
$data = array_map(fn($v) => $v->toArray(), $violations);
|
$data = array_map(fn($v) => $v->toArray(), $violations);
|
||||||
|
|||||||
@@ -21,12 +21,21 @@ abstract class AbstractRule
|
|||||||
|
|
||||||
protected function createViolation(string $message, \DOMElement $element): Violation
|
protected function createViolation(string $message, \DOMElement $element): Violation
|
||||||
{
|
{
|
||||||
|
$doc = $element->ownerDocument;
|
||||||
|
$html = '';
|
||||||
|
if ($doc !== null) {
|
||||||
|
$htmlVal = $doc->saveHTML($element);
|
||||||
|
if (is_string($htmlVal)) {
|
||||||
|
$html = $htmlVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new Violation(
|
return new Violation(
|
||||||
ruleId: (new \ReflectionClass($this))->getShortName(),
|
ruleId: (new \ReflectionClass($this))->getShortName(),
|
||||||
message: $message,
|
message: $message,
|
||||||
severity: $this->getSeverity(),
|
severity: $this->getSeverity(),
|
||||||
standard: $this->getStandard(),
|
standard: $this->getStandard(),
|
||||||
htmlSnippet: $element->ownerDocument->saveHTML($element)
|
htmlSnippet: $html
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,8 +4,12 @@ namespace YakNet\AccessibilityConsole\Core;
|
|||||||
|
|
||||||
class Config
|
class Config
|
||||||
{
|
{
|
||||||
|
/** @var array<string, mixed> */
|
||||||
private array $settings = [];
|
private array $settings = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $settings
|
||||||
|
*/
|
||||||
public function __construct(array $settings = [])
|
public function __construct(array $settings = [])
|
||||||
{
|
{
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
|
|||||||
+15
-19
@@ -4,7 +4,7 @@ namespace YakNet\AccessibilityConsole\Core;
|
|||||||
|
|
||||||
class RuleEngine
|
class RuleEngine
|
||||||
{
|
{
|
||||||
/** @var array */
|
/** @var array<int, mixed> */
|
||||||
private array $rules = [];
|
private array $rules = [];
|
||||||
|
|
||||||
public function addRule(mixed $rule): void
|
public function addRule(mixed $rule): void
|
||||||
@@ -19,25 +19,21 @@ class RuleEngine
|
|||||||
{
|
{
|
||||||
$allViolations = [];
|
$allViolations = [];
|
||||||
foreach ($this->rules as $rule) {
|
foreach ($this->rules as $rule) {
|
||||||
if (method_exists($rule, 'check')) {
|
if ($rule instanceof AbstractRule) {
|
||||||
// Determine if it's a document-level rule or element-level rule
|
// Document-level rule (Core\AbstractRule style)
|
||||||
$reflection = new \ReflectionMethod($rule, 'check');
|
$violations = $rule->check($doc);
|
||||||
$params = $reflection->getParameters();
|
$allViolations = array_merge($allViolations, $violations);
|
||||||
|
} elseif ($rule instanceof \YakNet\AccessibilityConsole\Rules\RuleInterface) {
|
||||||
$type = $params[0]->getType();
|
// Element-level rule (Rules\RuleInterface style)
|
||||||
if (isset($params[0]) && $type instanceof \ReflectionNamedType && $type->getName() === 'DOMDocument') {
|
$xpath = new \DOMXPath($doc);
|
||||||
// Document-level rule (Core\AbstractRule style)
|
$elements = $xpath->query('//*');
|
||||||
$violations = $rule->check($doc);
|
if ($elements !== false) {
|
||||||
$allViolations = array_merge($allViolations, $violations);
|
|
||||||
} else {
|
|
||||||
// Element-level rule (Rules\RuleInterface style)
|
|
||||||
// We need to iterate over all elements
|
|
||||||
$xpath = new \DOMXPath($doc);
|
|
||||||
$elements = $xpath->query('//*');
|
|
||||||
foreach ($elements as $element) {
|
foreach ($elements as $element) {
|
||||||
$violation = $rule->check($element);
|
if ($element instanceof \DOMElement) {
|
||||||
if ($violation) {
|
$violation = $rule->check($element);
|
||||||
$allViolations[] = $violation;
|
if ($violation) {
|
||||||
|
$allViolations[] = $violation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ namespace YakNet\AccessibilityConsole\Core;
|
|||||||
|
|
||||||
class Scanner
|
class Scanner
|
||||||
{
|
{
|
||||||
public function __construct(private ?RuleEngine $engine = null)
|
private RuleEngine $engine;
|
||||||
|
|
||||||
|
public function __construct(?RuleEngine $engine = null)
|
||||||
{
|
{
|
||||||
if ($this->engine === null) {
|
$this->engine = $engine ?? new RuleEngine();
|
||||||
$this->engine = new RuleEngine();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addRule(mixed $rule): void
|
public function addRule(mixed $rule): void
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ namespace YakNet\AccessibilityConsole\Core;
|
|||||||
|
|
||||||
class Violation
|
class Violation
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @param array{file: string, line: int}|null $location
|
||||||
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $ruleId,
|
public string $ruleId,
|
||||||
public string $message,
|
public string $message,
|
||||||
@@ -14,6 +17,9 @@ class Violation
|
|||||||
public ?string $fixSuggestion = null
|
public ?string $fixSuggestion = null
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{ruleId: string, message: string, severity: string, standard: string, htmlSnippet: string, location: array{file: string, line: int}|null, fixSuggestion: string|null}
|
||||||
|
*/
|
||||||
public function toArray(): array
|
public function toArray(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -16,12 +16,21 @@ abstract class AbstractRule implements RuleInterface
|
|||||||
|
|
||||||
protected function createViolation(DOMElement $element, string $message, ?string $suggestion = null): Violation
|
protected function createViolation(DOMElement $element, string $message, ?string $suggestion = null): Violation
|
||||||
{
|
{
|
||||||
|
$doc = $element->ownerDocument;
|
||||||
|
$html = '';
|
||||||
|
if ($doc !== null) {
|
||||||
|
$htmlVal = $doc->saveHTML($element);
|
||||||
|
if (is_string($htmlVal)) {
|
||||||
|
$html = $htmlVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new Violation(
|
return new Violation(
|
||||||
ruleId: $this->getId(),
|
ruleId: $this->getId(),
|
||||||
message: $message,
|
message: $message,
|
||||||
severity: $this->getSeverity(),
|
severity: $this->getSeverity(),
|
||||||
standard: $this->getStandard(),
|
standard: $this->getStandard(),
|
||||||
htmlSnippet: $element->ownerDocument->saveHTML($element),
|
htmlSnippet: $html,
|
||||||
fixSuggestion: $suggestion
|
fixSuggestion: $suggestion
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-31
@@ -8,6 +8,7 @@ use YakNet\AccessibilityConsole\Core\WCAGStandard;
|
|||||||
|
|
||||||
class AriaRole extends AbstractRule
|
class AriaRole extends AbstractRule
|
||||||
{
|
{
|
||||||
|
/** @var array<int, string> */
|
||||||
private static array $validRoles = [
|
private static array $validRoles = [
|
||||||
'alert', 'alertdialog', 'application', 'article', 'banner', 'button', 'cell', 'checkbox',
|
'alert', 'alertdialog', 'application', 'article', 'banner', 'button', 'cell', 'checkbox',
|
||||||
'columnheader', 'combobox', 'complementary', 'contentinfo', 'definition', 'dialog', 'directory',
|
'columnheader', 'combobox', 'complementary', 'contentinfo', 'definition', 'dialog', 'directory',
|
||||||
@@ -27,43 +28,47 @@ class AriaRole extends AbstractRule
|
|||||||
|
|
||||||
// 1. Check WAI-ARIA Role Validity
|
// 1. Check WAI-ARIA Role Validity
|
||||||
$roleElements = $xpath->query('//*[@role]');
|
$roleElements = $xpath->query('//*[@role]');
|
||||||
foreach ($roleElements as $el) {
|
if ($roleElements !== false) {
|
||||||
if (!$el instanceof \DOMElement) {
|
foreach ($roleElements as $el) {
|
||||||
continue;
|
if (!$el instanceof \DOMElement) {
|
||||||
}
|
continue;
|
||||||
$role = trim($el->getAttribute('role'));
|
}
|
||||||
if ($role === '') {
|
$role = trim($el->getAttribute('role'));
|
||||||
continue;
|
if ($role === '') {
|
||||||
}
|
continue;
|
||||||
$roles = array_filter(explode(' ', $role));
|
}
|
||||||
foreach ($roles as $r) {
|
$roles = array_filter(explode(' ', $role));
|
||||||
if (!in_array(strtolower($r), self::$validRoles, true)) {
|
foreach ($roles as $r) {
|
||||||
$violations[] = $this->createViolation(
|
if (!in_array(strtolower($r), self::$validRoles, true)) {
|
||||||
"Invalid ARIA role \"{$r}\" declared on element. Must use standard WAI-ARIA roles.",
|
$violations[] = $this->createViolation(
|
||||||
$el
|
"Invalid ARIA role \"{$r}\" declared on element. Must use standard WAI-ARIA roles.",
|
||||||
);
|
$el
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Check aria-controls Targets Existence
|
// 2. Check aria-controls Targets Existence
|
||||||
$controlsElements = $xpath->query('//*[@aria-controls]');
|
$controlsElements = $xpath->query('//*[@aria-controls]');
|
||||||
foreach ($controlsElements as $el) {
|
if ($controlsElements !== false) {
|
||||||
if (!$el instanceof \DOMElement) {
|
foreach ($controlsElements as $el) {
|
||||||
continue;
|
if (!$el instanceof \DOMElement) {
|
||||||
}
|
continue;
|
||||||
$targetsStr = trim($el->getAttribute('aria-controls'));
|
}
|
||||||
if ($targetsStr === '') {
|
$targetsStr = trim($el->getAttribute('aria-controls'));
|
||||||
continue;
|
if ($targetsStr === '') {
|
||||||
}
|
continue;
|
||||||
$targets = array_filter(explode(' ', $targetsStr));
|
}
|
||||||
foreach ($targets as $targetId) {
|
$targets = array_filter(explode(' ', $targetsStr));
|
||||||
$targetQuery = $xpath->query('//*[@id="' . $targetId . '"]');
|
foreach ($targets as $targetId) {
|
||||||
if ($targetQuery->length === 0) {
|
$targetQuery = $xpath->query('//*[@id="' . $targetId . '"]');
|
||||||
$violations[] = $this->createViolation(
|
if ($targetQuery !== false && $targetQuery->length === 0) {
|
||||||
"Attribute aria-controls=\"{$targetId}\" targets an element that does not exist in the document.",
|
$violations[] = $this->createViolation(
|
||||||
$el
|
"Attribute aria-controls=\"{$targetId}\" targets an element that does not exist in the document.",
|
||||||
);
|
$el
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,18 +92,21 @@ class ColorContrast extends AbstractRule
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{0: int, 1: int, 2: int}|null
|
||||||
|
*/
|
||||||
private function hexToRgb(string $hex): ?array
|
private function hexToRgb(string $hex): ?array
|
||||||
{
|
{
|
||||||
$hex = ltrim($hex, '#');
|
$hex = ltrim($hex, '#');
|
||||||
if (strlen($hex) === 3) {
|
if (strlen($hex) === 3) {
|
||||||
$r = hexdec(substr($hex, 0, 1) . substr($hex, 0, 1));
|
$r = (int)hexdec(substr($hex, 0, 1) . substr($hex, 0, 1));
|
||||||
$g = hexdec(substr($hex, 1, 1) . substr($hex, 1, 1));
|
$g = (int)hexdec(substr($hex, 1, 1) . substr($hex, 1, 1));
|
||||||
$b = hexdec(substr($hex, 2, 1) . substr($hex, 2, 1));
|
$b = (int)hexdec(substr($hex, 2, 1) . substr($hex, 2, 1));
|
||||||
return [$r, $g, $b];
|
return [$r, $g, $b];
|
||||||
} elseif (strlen($hex) === 6) {
|
} elseif (strlen($hex) === 6) {
|
||||||
$r = hexdec(substr($hex, 0, 2));
|
$r = (int)hexdec(substr($hex, 0, 2));
|
||||||
$g = hexdec(substr($hex, 2, 2));
|
$g = (int)hexdec(substr($hex, 2, 2));
|
||||||
$b = hexdec(substr($hex, 4, 2));
|
$b = (int)hexdec(substr($hex, 4, 2));
|
||||||
return [$r, $g, $b];
|
return [$r, $g, $b];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ class DuplicateId extends AbstractRule
|
|||||||
$violations = [];
|
$violations = [];
|
||||||
$xpath = new \DOMXPath($doc);
|
$xpath = new \DOMXPath($doc);
|
||||||
$elements = $xpath->query('//*[@id]');
|
$elements = $xpath->query('//*[@id]');
|
||||||
|
if ($elements === false) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
$ids = [];
|
$ids = [];
|
||||||
foreach ($elements as $el) {
|
foreach ($elements as $el) {
|
||||||
|
|||||||
@@ -29,10 +29,13 @@ class FormLabel extends AbstractRule
|
|||||||
|
|
||||||
if ($element->hasAttribute('id')) {
|
if ($element->hasAttribute('id')) {
|
||||||
$id = $element->getAttribute('id');
|
$id = $element->getAttribute('id');
|
||||||
$xpath = new \DOMXPath($element->ownerDocument);
|
$doc = $element->ownerDocument;
|
||||||
$labels = $xpath->query("//label[@for='$id']");
|
if ($doc !== null) {
|
||||||
if ($labels->length > 0) {
|
$xpath = new \DOMXPath($doc);
|
||||||
return null;
|
$labels = $xpath->query("//label[@for='$id']");
|
||||||
|
if ($labels !== false && $labels->length > 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ class HeadingOrderRule extends AbstractRule
|
|||||||
$violations = [];
|
$violations = [];
|
||||||
$xpath = new \DOMXPath($doc);
|
$xpath = new \DOMXPath($doc);
|
||||||
$headings = $xpath->query('//h1|//h2|//h3|//h4|//h5|//h6');
|
$headings = $xpath->query('//h1|//h2|//h3|//h4|//h5|//h6');
|
||||||
|
if ($headings === false) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
$lastLevel = 0;
|
$lastLevel = 0;
|
||||||
foreach ($headings as $h) {
|
foreach ($headings as $h) {
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ class StandardRuleSet
|
|||||||
*/
|
*/
|
||||||
public static function all(): array
|
public static function all(): array
|
||||||
{
|
{
|
||||||
return [
|
/** @var RuleInterface[] $rules */
|
||||||
|
$rules = [
|
||||||
new HtmlHasLang(),
|
new HtmlHasLang(),
|
||||||
new ImgAltText(),
|
new ImgAltText(),
|
||||||
new EmptyLink(),
|
new EmptyLink(),
|
||||||
@@ -24,5 +25,6 @@ class StandardRuleSet
|
|||||||
new AriaRole(),
|
new AriaRole(),
|
||||||
new IframeTitle(),
|
new IframeTitle(),
|
||||||
];
|
];
|
||||||
|
return $rules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,19 +8,24 @@ use SplFileInfo;
|
|||||||
|
|
||||||
class SourceLocator
|
class SourceLocator
|
||||||
{
|
{
|
||||||
|
/** @var array<int, string> */
|
||||||
private array $extensions = ['php', 'html', 'twig', 'blade.php'];
|
private array $extensions = ['php', 'html', 'twig', 'blade.php'];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly string $searchPath
|
private readonly string $searchPath
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{file: string, line: int}|null
|
||||||
|
*/
|
||||||
public function locate(string $snippet): ?array
|
public function locate(string $snippet): ?array
|
||||||
{
|
{
|
||||||
if (!is_dir($this->searchPath) || !is_readable($this->searchPath)) {
|
if (!is_dir($this->searchPath) || !is_readable($this->searchPath)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$cleanSnippet = trim(preg_replace('/\s+/', ' ', $snippet));
|
$replaced = preg_replace('/\s+/', ' ', $snippet);
|
||||||
|
$cleanSnippet = is_string($replaced) ? trim($replaced) : '';
|
||||||
if ($cleanSnippet === '') {
|
if ($cleanSnippet === '') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -76,6 +81,9 @@ class SourceLocator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{type: 'exact', location: array{file: string, line: int}}|array{type: 'fuzzy', score: float, location: array{file: string, line: int}}|array{type: 'none'}
|
||||||
|
*/
|
||||||
private function searchInFile(string $filepath, string $searchSnippet, string $fullSnippet): array
|
private function searchInFile(string $filepath, string $searchSnippet, string $fullSnippet): array
|
||||||
{
|
{
|
||||||
$content = file_get_contents($filepath);
|
$content = file_get_contents($filepath);
|
||||||
@@ -91,7 +99,8 @@ class SourceLocator
|
|||||||
|
|
||||||
foreach ($lines as $index => $line) {
|
foreach ($lines as $index => $line) {
|
||||||
$lineNumber = $index + 1;
|
$lineNumber = $index + 1;
|
||||||
$cleanLine = trim(preg_replace('/\s+/', ' ', $line));
|
$replacedLine = preg_replace('/\s+/', ' ', $line);
|
||||||
|
$cleanLine = is_string($replacedLine) ? trim($replacedLine) : '';
|
||||||
|
|
||||||
if (str_contains($cleanLine, $searchSnippet)) {
|
if (str_contains($cleanLine, $searchSnippet)) {
|
||||||
return [
|
return [
|
||||||
@@ -118,6 +127,9 @@ class SourceLocator
|
|||||||
return ['type' => 'none'];
|
return ['type' => 'none'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{tag: string|null, attributes: array<string, string>}
|
||||||
|
*/
|
||||||
private function parseSnippet(string $snippet): array
|
private function parseSnippet(string $snippet): array
|
||||||
{
|
{
|
||||||
preg_match('/<([a-zA-Z0-9]+)/', $snippet, $matches);
|
preg_match('/<([a-zA-Z0-9]+)/', $snippet, $matches);
|
||||||
@@ -133,6 +145,9 @@ class SourceLocator
|
|||||||
return ['tag' => $tagName, 'attributes' => $attributes];
|
return ['tag' => $tagName, 'attributes' => $attributes];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array{tag: string|null, attributes: array<string, string>} $parsed
|
||||||
|
*/
|
||||||
private function calculateFuzzyScore(string $line, array $parsed): float
|
private function calculateFuzzyScore(string $line, array $parsed): float
|
||||||
{
|
{
|
||||||
if (!$parsed['tag'] || !str_contains(strtolower($line), '<' . strtolower($parsed['tag']))) {
|
if (!$parsed['tag'] || !str_contains(strtolower($line), '<' . strtolower($parsed['tag']))) {
|
||||||
|
|||||||
Reference in New Issue
Block a user