JsFileParser.php

Code Hygiene Score: 100

Keine Issues gefunden.

Klassen 1

Funktionen 2

Verwendet von 2

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;
    }
}
← Übersicht Graph