ai_upgrade_assistant-0.2.0-alpha2/src/Service/NodeVisitor/NamespaceVisitor.php

src/Service/NodeVisitor/NamespaceVisitor.php
<?php

namespace Drupal\ai_upgrade_assistant\Service\NodeVisitor;

use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;

/**
 * Node visitor that analyzes namespace usage and PSR-4 compliance.
 */
class NamespaceVisitor extends NodeVisitorAbstract {

  /**
   * List of findings.
   *
   * @var array
   */
  protected $findings = [];

  /**
   * The module name.
   *
   * @var string
   */
  protected $moduleName;

  /**
   * The module path.
   *
   * @var string
   */
  protected $modulePath;

  /**
   * Constructs a NamespaceVisitor.
   *
   * @param string $module_name
   *   The module name.
   * @param string $module_path
   *   The module path.
   */
  public function __construct($module_name, $module_path) {
    $this->moduleName = $module_name;
    $this->modulePath = $module_path;
  }

  /**
   * {@inheritdoc}
   */
  public function enterNode(Node $node) {
    if ($node instanceof Node\Stmt\Namespace_) {
      $namespace = $node->name->toString();
      $finding = [
        'type' => 'namespace',
        'name' => $namespace,
        'line' => $node->getLine(),
        'file' => $node->getAttribute('file'),
      ];

      // Check PSR-4 compliance
      $expected_namespace = $this->getExpectedNamespace($node->getAttribute('file'));
      if ($namespace !== $expected_namespace) {
        $finding['psr4_violation'] = true;
        $finding['expected_namespace'] = $expected_namespace;
      }

      // Check for use statements
      $use_statements = [];
      foreach ($node->stmts as $stmt) {
        if ($stmt instanceof Node\Stmt\Use_) {
          foreach ($stmt->uses as $use) {
            $use_name = $use->name->toString();
            $use_statements[] = [
              'name' => $use_name,
              'alias' => $use->alias ? $use->alias->name : null,
              'line' => $use->getLine(),
            ];

            // Check for deprecated namespaces
            if ($this->isDeprecatedNamespace($use_name)) {
              $finding['deprecated_uses'][] = [
                'name' => $use_name,
                'replacement' => $this->getNamespaceReplacement($use_name),
                'line' => $use->getLine(),
              ];
            }
          }
        }
      }
      $finding['use_statements'] = $use_statements;

      // Check for common namespace issues
      $this->checkNamespaceIssues($finding);

      $this->findings[] = $finding;
    }
  }

  /**
   * Gets the expected namespace based on file path.
   *
   * @param string $file_path
   *   The file path.
   *
   * @return string
   *   The expected namespace.
   */
  protected function getExpectedNamespace($file_path) {
    $relative_path = str_replace($this->modulePath . '/src/', '', $file_path);
    $relative_path = str_replace('.php', '', $relative_path);
    $parts = explode('/', $relative_path);
    return 'Drupal\\' . $this->moduleName . '\\' . implode('\\', $parts);
  }

  /**
   * Checks if a namespace is deprecated.
   *
   * @param string $namespace
   *   The namespace to check.
   *
   * @return bool
   *   TRUE if the namespace is deprecated.
   */
  protected function isDeprecatedNamespace($namespace) {
    $deprecated_namespaces = [
      'Drupal\Core\Entity\EntityNG',
      'Drupal\field\Plugin\Type',
      'Drupal\system\Plugin\views\field',
      'Drupal\views\Plugin\views\field',
    ];

    foreach ($deprecated_namespaces as $deprecated) {
      if (strpos($namespace, $deprecated) === 0) {
        return true;
      }
    }

    return false;
  }

  /**
   * Gets the replacement for a deprecated namespace.
   *
   * @param string $namespace
   *   The deprecated namespace.
   *
   * @return string
   *   The replacement namespace.
   */
  protected function getNamespaceReplacement($namespace) {
    $replacements = [
      'Drupal\Core\Entity\EntityNG' => 'Drupal\Core\Entity',
      'Drupal\field\Plugin\Type' => 'Drupal\Core\Field',
      'Drupal\system\Plugin\views\field' => 'Drupal\views\Plugin\views\field',
      'Drupal\views\Plugin\views\field' => 'Drupal\views\Plugin\views\field',
    ];

    foreach ($replacements as $old => $new) {
      if (strpos($namespace, $old) === 0) {
        return str_replace($old, $new, $namespace);
      }
    }

    return $namespace;
  }

  /**
   * Checks for common namespace issues.
   *
   * @param array &$finding
   *   The finding array to add issues to.
   */
  protected function checkNamespaceIssues(array &$finding) {
    $namespace = $finding['name'];

    // Check for common namespace mistakes
    if (strpos($namespace, '_') !== false) {
      $finding['issues'][] = 'Namespace contains underscores, should use CamelCase';
    }

    if (strpos($namespace, '\\\\') !== false) {
      $finding['issues'][] = 'Namespace contains double backslashes';
    }

    // Check for proper Drupal namespace prefix
    if (strpos($namespace, 'Drupal\\') !== 0) {
      $finding['issues'][] = 'Namespace should start with "Drupal\\"';
    }

    // Check for proper module namespace
    $expected_prefix = 'Drupal\\' . $this->moduleName;
    if (strpos($namespace, $expected_prefix) !== 0) {
      $finding['issues'][] = "Namespace should start with \"$expected_prefix\"";
    }

    // Check for test namespaces
    if (strpos($namespace, 'Drupal\Tests') === 0) {
      if (!preg_match('/^Drupal\\\\Tests\\\\' . $this->moduleName . '\\\\(Unit|Kernel|Functional|FunctionalJavascript)\\\\/', $namespace)) {
        $finding['issues'][] = 'Test namespace should include proper test type (Unit/Kernel/Functional/FunctionalJavascript)';
      }
    }
  }

  /**
   * Gets the findings.
   *
   * @return array
   *   Array of findings.
   */
  public function getFindings() {
    return $this->findings;
  }

  /**
   * Resets the findings.
   */
  public function reset() {
    $this->findings = [];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc