|  | 
|  | 1 | +<?php | 
|  | 2 | + | 
|  | 3 | +namespace App\Services; | 
|  | 4 | + | 
|  | 5 | +use Illuminate\Filesystem\Filesystem; | 
|  | 6 | +use Illuminate\Support\Collection; | 
|  | 7 | + | 
|  | 8 | +class PresetManifest | 
|  | 9 | +{ | 
|  | 10 | +    /** @var ?array<string, string> */ | 
|  | 11 | +    protected ?array $manifest = null; | 
|  | 12 | + | 
|  | 13 | +    protected string $vendorPath; | 
|  | 14 | + | 
|  | 15 | +    public function __construct( | 
|  | 16 | +        protected Filesystem $files, | 
|  | 17 | +        protected string $basePath, | 
|  | 18 | +        protected string $manifestPath, | 
|  | 19 | +    ) { | 
|  | 20 | +        $this->vendorPath = $this->basePath.'/vendor'; | 
|  | 21 | +    } | 
|  | 22 | + | 
|  | 23 | +    /** | 
|  | 24 | +     * Get all available presets from packages. | 
|  | 25 | +     * | 
|  | 26 | +     * @return array<string, string> ['preset-name' => '/absolute/path/to/preset.php'] | 
|  | 27 | +     */ | 
|  | 28 | +    public function presets(): array | 
|  | 29 | +    { | 
|  | 30 | +        return $this->manifest ??= $this->getManifest(); | 
|  | 31 | +    } | 
|  | 32 | + | 
|  | 33 | +    /** | 
|  | 34 | +     * Check if a preset exists. | 
|  | 35 | +     */ | 
|  | 36 | +    public function has(string $preset): bool | 
|  | 37 | +    { | 
|  | 38 | +        return array_key_exists($preset, $this->presets()); | 
|  | 39 | +    } | 
|  | 40 | + | 
|  | 41 | +    /** | 
|  | 42 | +     * Get the path for a specific preset. | 
|  | 43 | +     */ | 
|  | 44 | +    public function path(string $preset): ?string | 
|  | 45 | +    { | 
|  | 46 | +        return $this->presets()[$preset] ?? null; | 
|  | 47 | +    } | 
|  | 48 | + | 
|  | 49 | +    /** | 
|  | 50 | +     * Get all preset names. | 
|  | 51 | +     * | 
|  | 52 | +     * @return list<string> | 
|  | 53 | +     */ | 
|  | 54 | +    public function names(): array | 
|  | 55 | +    { | 
|  | 56 | +        return array_keys($this->presets()); | 
|  | 57 | +    } | 
|  | 58 | + | 
|  | 59 | +    /** | 
|  | 60 | +     * Get the current preset manifest. | 
|  | 61 | +     * | 
|  | 62 | +     * @return array<string, string> | 
|  | 63 | +     */ | 
|  | 64 | +    protected function getManifest(): array | 
|  | 65 | +    { | 
|  | 66 | +        $path = $this->vendorPath.'/composer/installed.json'; | 
|  | 67 | + | 
|  | 68 | +        if ( | 
|  | 69 | +            ! $this->files->exists($this->manifestPath) || | 
|  | 70 | +            $this->files->lastModified($path) > $this->files->lastModified($this->manifestPath) | 
|  | 71 | +        ) { | 
|  | 72 | +            return $this->build(); | 
|  | 73 | +        } | 
|  | 74 | + | 
|  | 75 | +        return $this->files->getRequire($this->manifestPath); | 
|  | 76 | +    } | 
|  | 77 | + | 
|  | 78 | +    /** | 
|  | 79 | +     * Build the manifest and write it to disk. | 
|  | 80 | +     * | 
|  | 81 | +     * @return array<string, string> | 
|  | 82 | +     */ | 
|  | 83 | +    protected function build(): array | 
|  | 84 | +    { | 
|  | 85 | +        $packages = []; | 
|  | 86 | +        $installedPath = $this->vendorPath.'/composer/installed.json'; | 
|  | 87 | +        $composerPath = $this->basePath.'/composer.json'; | 
|  | 88 | + | 
|  | 89 | +        if ($this->files->exists($installedPath)) { | 
|  | 90 | +            $installed = json_decode($this->files->get($installedPath), true); | 
|  | 91 | +            $packages = $installed['packages'] ?? $installed; | 
|  | 92 | +        } | 
|  | 93 | + | 
|  | 94 | +        $presets = (new Collection($packages)) | 
|  | 95 | +            ->keyBy(fn ($package) => $this->vendorPath.'/'.$package['name']) | 
|  | 96 | +            ->when($this->files->exists($composerPath), function ($presets) use ($composerPath) { | 
|  | 97 | +                $composer = json_decode($this->files->get($composerPath), true); | 
|  | 98 | + | 
|  | 99 | +                return $presets->put($this->basePath, $composer); | 
|  | 100 | +            }) | 
|  | 101 | +            ->map(fn ($package) => $package['extra']['laravel-pint']['presets'] ?? []) | 
|  | 102 | +            ->map(function ($presets, $basePath) { | 
|  | 103 | +                foreach ($presets as $name => $relativePath) { | 
|  | 104 | +                    $absolutePath = $basePath.'/'.$relativePath; | 
|  | 105 | + | 
|  | 106 | +                    if ($this->files->exists($absolutePath)) { | 
|  | 107 | +                        $presets[$name] = $absolutePath; | 
|  | 108 | +                    } else { | 
|  | 109 | +                        unset($presets[$name]); | 
|  | 110 | +                    } | 
|  | 111 | +                } | 
|  | 112 | + | 
|  | 113 | +                return $presets; | 
|  | 114 | +            }) | 
|  | 115 | +            ->flatten() | 
|  | 116 | +            ->all(); | 
|  | 117 | + | 
|  | 118 | +        $this->write($presets); | 
|  | 119 | + | 
|  | 120 | +        return $presets; | 
|  | 121 | +    } | 
|  | 122 | + | 
|  | 123 | +    /** | 
|  | 124 | +     * Write the given manifest array to disk. | 
|  | 125 | +     * | 
|  | 126 | +     * @param  array<string, string>  $manifest | 
|  | 127 | +     */ | 
|  | 128 | +    protected function write(array $manifest): void | 
|  | 129 | +    { | 
|  | 130 | +        $this->files->ensureDirectoryExists(dirname($this->manifestPath), 0755, true); | 
|  | 131 | +        $this->files->replace($this->manifestPath, '<?php return '.var_export($manifest, true).';'); | 
|  | 132 | +    } | 
|  | 133 | +} | 
0 commit comments