JsFileParser.php
- Pfad:
src/Infrastructure/CodeAnalysis/JsFileParser.php - Namespace: Infrastructure\CodeAnalysis
- Zeilen: 145 | Größe: 4,819 Bytes
- Geändert: 2025-12-23 21:03:51 | Gescannt: 2025-12-31 10:22:15
Code Hygiene Score: 100
- Dependencies: 100 (25%)
- LOC: 100 (20%)
- Methods: 100 (20%)
- Secrets: 100 (15%)
- Classes: 100 (10%)
- Magic Numbers: 100 (10%)
Keine Issues gefunden.
Klassen 1
-
JsFileParserclass Zeile 9
Funktionen 2
-
parse()public Zeile 26 -
extractNamespace()private Zeile 129
Verwendet von 2
- CodeScanner.php constructor
- InfrastructureServiceProvider.php use
Code
<?php
declare(strict_types=1);
namespace Infrastructure\CodeAnalysis;
// @responsibility: JavaScript-Dateianalyse via Regex (ES6 Modules)
final class JsFileParser
{
/**
* Parst eine JavaScript-Datei und extrahiert Metadaten.
*
* @return array{
* namespace: string|null,
* classes: array<array{name: string, type: string, line: int}>,
* functions: array<array{name: string, visibility: string|null, line: int}>,
* uses: array<string>,
* extends_class: string|null,
* implements_interfaces: array<string>,
* traits_used: array<string>,
* constructor_deps: array<string>,
* error: string|null
* }
*/
public function parse(string $filePath): array
{
$result = [
'namespace' => null,
'classes' => [],
'functions' => [],
'uses' => [],
'extends_class' => null,
'implements_interfaces' => [],
'traits_used' => [],
'constructor_deps' => [],
'error' => null,
];
if (!file_exists($filePath) || !is_readable($filePath)) {
$result['error'] = 'Datei nicht lesbar';
return $result;
}
$content = file_get_contents($filePath);
if ($content === false) {
$result['error'] = 'Datei konnte nicht gelesen werden';
return $result;
}
$lines = explode("\n", $content);
// Namespace aus Dateipfad
$result['namespace'] = $this->extractNamespace($filePath);
// ES6 Imports: import { X, Y } from 'module'
if (preg_match_all('/import\s+\{([^}]+)\}\s+from\s+[\'"]([^\'"]+)[\'"]/', $content, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$imports = array_map('trim', explode(',', $match[1]));
$module = $match[2];
foreach ($imports as $import) {
// Handle "X as Y" syntax
$name = preg_replace('/\s+as\s+\w+/', '', $import);
$result['uses'][] = $module . '.' . trim($name);
}
}
}
// ES6 Default Import: import X from 'module'
if (preg_match_all('/import\s+(\w+)\s+from\s+[\'"]([^\'"]+)[\'"]/', $content, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$result['uses'][] = $match[2] . '.' . $match[1];
}
}
// CommonJS: const X = require('module')
if (preg_match_all('/(?:const|let|var)\s+(\w+)\s*=\s*require\s*\(\s*[\'"]([^\'"]+)[\'"]\s*\)/', $content, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$result['uses'][] = $match[2];
}
}
// Klassen: class X extends Y
foreach ($lines as $lineNum => $line) {
if (preg_match('/^\s*(?:export\s+)?class\s+(\w+)(?:\s+extends\s+(\w+))?/', $line, $match)) {
$result['classes'][] = [
'name' => $match[1],
'type' => 'class',
'line' => $lineNum + 1,
];
if (isset($match[2]) && $result['extends_class'] === null) {
$result['extends_class'] = $match[2];
}
}
}
// Top-Level Funktionen
foreach ($lines as $lineNum => $line) {
// function name() oder export function name()
if (preg_match('/^(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/', $line, $match)) {
$result['functions'][] = [
'name' => $match[1],
'visibility' => null,
'line' => $lineNum + 1,
];
}
// const name = () => oder const name = function()
if (preg_match('/^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)\s*=>|function)/', $line, $match)) {
$result['functions'][] = [
'name' => $match[1],
'visibility' => null,
'line' => $lineNum + 1,
];
}
}
$result['uses'] = array_unique($result['uses']);
return $result;
}
/**
* Extrahiert einen pseudo-Namespace aus dem Dateipfad.
*/
private function extractNamespace(string $filePath): ?string
{
// /public/js/components/data-table.js -> js.components
if (preg_match('#/public/js/(.+)\.js$#', $filePath, $matches)) {
$subPath = dirname($matches[1]);
if ($subPath === '.') {
return 'js';
}
return 'js.' . str_replace('/', '.', $subPath);
}
return null;
}
}