Backup #1114
| ID | 1114 |
| Dateipfad | /var/www/dev.campus.systemische-tools.de/src/Infrastructure/CodeAnalysis/PythonFileParser.php |
| Version | 1 |
| Typ |
modified |
| Größe | 4.7 KB |
| Hash | 73e1e090e4fe45fdd5b3493bb39f80648307ddcab012f933d8f8649f8aa6db63 |
| Datum | 2025-12-25 09:23:49 |
| Geändert von | claude-code-hook |
| Grund | Claude Code Pre-Hook Backup vor Edit-Operation |
| Datei existiert |
Ja
|
Dateiinhalt
<?php
declare(strict_types=1);
namespace Infrastructure\CodeAnalysis;
// @responsibility: Python-Dateianalyse via AST-basiertem Python-Script
final class PythonFileParser
{
private const SCRIPT_PATH = __DIR__ . '/scripts/python_parser.py';
/**
* Parst eine Python-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;
}
// Python-Script ausführen
$command = sprintf(
'python3 %s %s 2>&1',
escapeshellarg(self::SCRIPT_PATH),
escapeshellarg($filePath)
);
$output = shell_exec($command);
if ($output === null) {
$result['error'] = 'Python-Parser konnte nicht ausgeführt werden';
return $result;
}
$parsed = json_decode($output, true);
if ($parsed === null) {
$result['error'] = 'JSON-Parsing fehlgeschlagen: ' . $output;
return $result;
}
if (isset($parsed['error']) && $parsed['error'] !== null) {
$result['error'] = $parsed['error'];
return $result;
}
// Namespace aus Verzeichnisstruktur ableiten
$result['namespace'] = $this->extractNamespace($filePath);
// Klassen konvertieren
foreach ($parsed['classes'] ?? [] as $class) {
$result['classes'][] = [
'name' => $class['name'],
'type' => 'class',
'line' => $class['line'],
];
// Erste Basisklasse als extends_class
if (!empty($class['bases']) && $result['extends_class'] === null) {
$result['extends_class'] = $class['bases'][0];
}
// Weitere Basisklassen als "Mixins" (ähnlich Traits)
if (count($class['bases'] ?? []) > 1) {
$result['traits_used'] = array_merge(
$result['traits_used'],
array_slice($class['bases'], 1)
);
}
}
// Funktionen konvertieren
foreach ($parsed['functions'] ?? [] as $func) {
$result['functions'][] = [
'name' => $func['name'],
'visibility' => null,
'line' => $func['line'],
];
}
// Imports als uses
foreach ($parsed['imports'] ?? [] as $import) {
if ($import['type'] === 'import') {
$result['uses'][] = $import['module'];
} else {
// from X import Y -> X.Y
$result['uses'][] = $import['full'] ?? $import['module'];
}
}
$result['uses'] = array_unique($result['uses']);
return $result;
}
/**
* Extrahiert einen pseudo-Namespace aus dem Dateipfad.
*/
private function extractNamespace(string $filePath): ?string
{
// /opt/mcp-servers/mcp-db/tools/select_tool.py -> mcp-db.tools
if (preg_match('#/opt/mcp-servers/([^/]+)/(.+)\.py$#', $filePath, $matches)) {
$server = $matches[1];
$subPath = dirname($matches[2]);
if ($subPath === '.') {
return $server;
}
return $server . '.' . str_replace('/', '.', $subPath);
}
// /var/www/scripts/pipeline/detect.py -> pipeline
if (preg_match('#/var/www/scripts/([^/]+)#', $filePath, $matches)) {
return $matches[1];
}
// /var/www/tools/ki-protokoll/claude-hook/quality/pre_rules.py -> claude-hook.quality
if (preg_match('#/claude-hook/(.+)\.py$#', $filePath, $matches)) {
$subPath = dirname($matches[1]);
if ($subPath === '.') {
return 'claude-hook';
}
return 'claude-hook.' . str_replace('/', '.', $subPath);
}
return null;
}
}
Vollständig herunterladen
Aktionen
← Zurück zur Übersicht