| 1 |  |  | <?php declare(strict_types=1); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | namespace Stratadox\PhpGenerics\Generator\Visitor; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | use PhpParser\Node; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | use PhpParser\Node\Name; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | use PhpParser\Node\Stmt\Namespace_; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | use PhpParser\Node\Stmt\Use_; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | use PhpParser\Node\Stmt\UseUse; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | use PhpParser\NodeTraverser; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | use PhpParser\NodeVisitorAbstract; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | use Stratadox\PhpGenerics\Annotation\Generic; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | use Stratadox\PhpGenerics\Generator\Type\TypeArguments; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  | use function in_array; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  | use function strpos; | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 16 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 17 |  |  | final class ImportsReplacement extends NodeVisitorAbstract | 
            
                                                                        
                            
            
                                    
            
            
                | 18 |  |  | { | 
            
                                                                        
                            
            
                                    
            
            
                | 19 |  |  |     /** @var string[] */ | 
            
                                                                        
                            
            
                                    
            
            
                | 20 |  |  |     private $newImports; | 
            
                                                                        
                            
            
                                    
            
            
                | 21 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 22 |  |  |     public function __construct( | 
            
                                                                        
                            
            
                                    
            
            
                | 23 |  |  |         string $genericBaseClass, | 
            
                                                                        
                            
            
                                    
            
            
                | 24 |  |  |         TypeArguments $typeArguments | 
            
                                                                        
                            
            
                                    
            
            
                | 25 |  |  |     ) { | 
            
                                                                        
                            
            
                                    
            
            
                | 26 |  |  |         $this->newImports = [$genericBaseClass]; | 
            
                                                                        
                            
            
                                    
            
            
                | 27 |  |  |         foreach ($typeArguments as $argument) { | 
            
                                                                        
                            
            
                                    
            
            
                | 28 |  |  |             if ( | 
            
                                                                        
                            
            
                                    
            
            
                | 29 |  |  |                 $argument->requiresImport() && | 
            
                                                                        
                            
            
                                    
            
            
                | 30 |  |  |                 !in_array($argument->fullName(), $this->newImports) | 
            
                                                                        
                            
            
                                    
            
            
                | 31 |  |  |             ) { | 
            
                                                                        
                            
            
                                    
            
            
                | 32 |  |  |                 $this->newImports[] = $argument->fullName(); | 
            
                                                                        
                            
            
                                    
            
            
                | 33 |  |  |             } | 
            
                                                                        
                            
            
                                    
            
            
                | 34 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 35 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 36 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |     public function leaveNode(Node $node) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |         if ($node instanceof Namespace_) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |             foreach ($this->newImports as $import) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |                 $this->addImportTo($node, $import); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |         } elseif ($node instanceof Use_) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |             if ($this->shouldRemoveImport($node->uses[0]->name->toString())) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |                 return NodeTraverser::REMOVE_NODE; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |         } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 48 |  |  |         return null; | 
            
                                                                        
                                                                
            
                                    
            
            
                | 49 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 50 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |     private function addImportTo(Node $namespace, string $import): void | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |         $position = 0; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |         foreach ($namespace->stmts as $stmt) { | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |             if ($stmt instanceof Use_ && $stmt->uses[0]->name->toString() < $import) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |                 $position++; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |         $namespace->stmts = array_merge( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |             array_slice($namespace->stmts, 0, $position), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |             [new Use_([new UseUse(new Name($import))])], | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 62 |  |  |             array_slice($namespace->stmts, $position) | 
            
                                                                        
                            
            
                                    
            
            
                | 63 |  |  |         ); | 
            
                                                                        
                            
            
                                    
            
            
                | 64 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 65 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |     private function shouldRemoveImport(string $use): bool | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |         return strpos($use, 'Stratadox\\PhpGenerics\\Generic\\') === 0 | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 69 |  |  |             || $use === Generic::class; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 71 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 72 |  |  |  |