$files * @param array $externalImportStubFiles */ public function generate(array $files, array $externalImportStubFiles): string { /** @var array> $namespaces */ $namespaces = []; foreach ($files as $file) { $realFile = realpath($file); if ($realFile === false || isset($externalImportStubFiles[$realFile])) { continue; } if (pathinfo($realFile, PATHINFO_EXTENSION) !== 'php') { continue; } $code = file_get_contents($realFile); if ($code === false) { throw new \RuntimeException('Can not read file: ' . $realFile); } $ast = $this->parser->parse($code) ?? []; $traverser = new NodeTraverser(); $traverser->addVisitor(new NameResolver()); $ast = $traverser->traverse($ast); foreach ($ast as $stmt) { if ($stmt instanceof Node\Stmt\Namespace_) { $namespace = $stmt->name?->toString() ?? ''; $this->appendDeclarations($namespaces, $namespace, $stmt->stmts); continue; } $this->appendDeclarations($namespaces, '', [$stmt]); } } $namespaceNodes = []; foreach ($namespaces as $namespace => $stmts) { if ($stmts === []) { continue; } $namespaceNodes[] = new Node\Stmt\Namespace_( $namespace === '' ? null : new Node\Name($namespace), $stmts, ); } $code = "printer->prettyPrint($namespaceNodes) . "\n"; } return $code; } /** * @param array> $namespaces * @param array $stmts */ private function appendDeclarations(array &$namespaces, string $namespace, array $stmts): void { foreach ($stmts as $stmt) { if ($namespace === '' && $stmt instanceof Node\Stmt\Function_ && strtolower($stmt->name->toString()) === 'main') { continue; } $declaration = $this->makeImportDeclaration($stmt); if ($declaration !== null) { $namespaces[$namespace][] = $declaration; } } } private function makeImportDeclaration(Node\Stmt $stmt): ?Node\Stmt { $comments = array_filter( $stmt->getComments(), static fn(\PhpParser\Comment $comment): bool => preg_match( '/@import-library\b/', $comment->getText(), ) !== 1, ); $stmt->setAttribute('comments', array_values($comments)); if ($stmt instanceof Node\Stmt\Function_) { $stmt->stmts = []; return $stmt; } if ($stmt instanceof Node\Stmt\ClassLike) { $members = []; foreach ($stmt->stmts as $member) { if ($member instanceof Node\Stmt\ClassMethod) { if (!($member->flags & Modifiers::ABSTRACT) && !($stmt instanceof Node\Stmt\Interface_)) { $member->stmts = []; } $members[] = $member; continue; } if ($member instanceof Node\Stmt\Property) { foreach ($member->hooks as $hook) { if ($hook->body !== null) { $hook->body = []; } } $members[] = $member; continue; } if ($member instanceof Node\Stmt\ClassConst || $member instanceof Node\Stmt\TraitUse || $member instanceof Node\Stmt\EnumCase) { $members[] = $member; } } $stmt->stmts = $members; return $stmt; } return null; } }