Remove unused Laravel IDE discovery files to clean up the vendor directory

This commit is contained in:
2026-03-16 19:46:52 -04:00
parent 91cdaf2a6b
commit 26d4f5d175
2 changed files with 0 additions and 790 deletions

View File

@@ -1,440 +0,0 @@
<?php
error_reporting(E_ERROR | E_PARSE);
define('LARAVEL_START', microtime(true));
require_once __DIR__ . '/../autoload.php';
class LaravelVsCode
{
public static function relativePath($path)
{
if (!str_contains($path, base_path())) {
return (string) $path;
}
return ltrim(str_replace(base_path(), '', realpath($path) ?: $path), DIRECTORY_SEPARATOR);
}
public static function isVendor($path)
{
return str_contains($path, base_path("vendor"));
}
public static function outputMarker($key)
{
return '__VSCODE_LARAVEL_' . $key . '__';
}
public static function startupError(\Throwable $e)
{
throw new Error(self::outputMarker('STARTUP_ERROR') . ': ' . $e->getMessage());
}
}
try {
$app = require_once __DIR__ . '/../../bootstrap/app.php';
} catch (\Throwable $e) {
LaravelVsCode::startupError($e);
exit(1);
}
$app->register(new class($app) extends \Illuminate\Support\ServiceProvider
{
public function boot()
{
config([
'logging.channels.null' => [
'driver' => 'monolog',
'handler' => \Monolog\Handler\NullHandler::class,
],
'logging.default' => 'null',
]);
}
});
try {
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$kernel->bootstrap();
} catch (\Throwable $e) {
LaravelVsCode::startupError($e);
exit(1);
}
echo LaravelVsCode::outputMarker('START_OUTPUT');
$components = new class {
protected $autoloaded = [];
protected $prefixes = [];
public function __construct()
{
$this->autoloaded = require base_path("vendor/composer/autoload_psr4.php");
}
public function all()
{
$components = collect(array_merge(
$this->getStandardClasses(),
$this->getStandardViews(),
$this->getNamespaced(),
$this->getAnonymousNamespaced(),
$this->getAnonymous(),
$this->getAliases(),
$this->getVendorComponents(),
))->groupBy('key')->pipe($this->setProps(...))->map(fn($items) => [
'isVendor' => $items->first()['isVendor'],
'paths' => $items->pluck('path')->unique()->values(),
'props' => $this->formatProps($items),
]);
return [
'components' => $components,
'prefixes' => $this->prefixes,
];
}
protected function formatProps($items)
{
$props = $items->pluck('props');
if ($codeBlock = $props->firstWhere(fn ($prop) => is_string($prop))) {
return $codeBlock;
}
return $props->values()->filter()->flatMap(fn($i) => $i);
}
protected function getStandardViews()
{
$path = resource_path('views/components');
return $this->findFiles($path, 'blade.php');
}
protected function findFiles($path, $extension, $keyCallback = null)
{
if (!is_dir($path)) {
return [];
}
$files = \Symfony\Component\Finder\Finder::create()
->files()
->name("*." . $extension)
->in($path);
$components = [];
$pathRealPath = realpath($path);
foreach ($files as $file) {
$realPath = $file->getRealPath();
$key = str($realPath)
->replace($pathRealPath, '')
->ltrim('/\\')
->replace('.' . $extension, '')
->replace(['/', '\\'], '.')
->pipe(fn($str) => $this->handleIndexComponents($str));
$components[] = [
"path" => LaravelVsCode::relativePath($realPath),
"isVendor" => LaravelVsCode::isVendor($realPath),
"key" => $keyCallback ? $keyCallback($key) : $key,
];
}
return $components;
}
protected function getStandardClasses()
{
$path = app_path('View/Components');
$appNamespace = collect($this->autoloaded)
->filter(fn($paths) => in_array(app_path(), $paths))
->keys()
->first() ?? '';
return collect($this->findFiles(
$path,
'php',
fn($key) => $key->explode('.')
->map(fn($p) => \Illuminate\Support\Str::kebab($p))
->implode('.'),
))->map(function ($item) use ($appNamespace) {
$class = str($item['path'])
->after('View/Components/')
->replace('.php', '')
->replace('/', '\\')
->prepend($appNamespace . 'View\\Components\\')
->toString();
if (!class_exists($class)) {
return $item;
}
$reflection = new \ReflectionClass($class);
$parameters = collect($reflection->getConstructor()?->getParameters() ?? [])
->filter(fn($p) => $p->isPromoted())
->flatMap(fn($p) => [$p->getName() => $p->isOptional() ? $p->getDefaultValue() : null])
->all();
$props = collect($reflection->getProperties())
->filter(fn($p) => $p->isPublic() && $p->getDeclaringClass()->getName() === $class)
->map(fn($p) => [
'name' => \Illuminate\Support\Str::kebab($p->getName()),
'type' => (string) ($p->getType() ?? 'mixed'),
'default' => $p->getDefaultValue() ?? $parameters[$p->getName()] ?? null,
]);
[$except, $props] = $props->partition(fn($p) => $p['name'] === 'except');
if ($except->isNotEmpty()) {
$except = $except->first()['default'];
$props = $props->reject(fn($p) => in_array($p['name'], $except));
}
return [
...$item,
'props' => $props,
];
})->all();
}
protected function getAliases()
{
$components = [];
foreach (\Illuminate\Support\Facades\Blade::getClassComponentAliases() as $key => $class) {
if (class_exists($class)) {
$reflection = new ReflectionClass($class);
$components[] = [
"path" => LaravelVsCode::relativePath($reflection->getFileName()),
"isVendor" => LaravelVsCode::isVendor($reflection->getFileName()),
"key" => $key,
];
}
}
return $components;
}
protected function getAnonymousNamespaced()
{
$components = [];
foreach (\Illuminate\Support\Facades\Blade::getAnonymousComponentNamespaces() as $key => $dir) {
$path = collect([$dir, resource_path('views/' . $dir)])->first(fn($p) => is_dir($p));
if (!$path) {
continue;
}
array_push(
$components,
...$this->findFiles(
$path,
'blade.php',
fn($k) => $k->kebab()->prepend($key . "::"),
)
);
}
return $components;
}
protected function getAnonymous()
{
$components = [];
foreach (\Illuminate\Support\Facades\Blade::getAnonymousComponentPaths() as $item) {
array_push(
$components,
...$this->findFiles(
$item['path'],
'blade.php',
function (\Illuminate\Support\Stringable $key) use ($item) {
$prefix = $item['prefix'] ? $item['prefix'] . '::' : '';
$key = $key->kebab();
$keys = [];
$keys[] = $key->prepend($prefix);
if ($item['prefix'] === 'flux') {
$keys[] = $key->prepend('flux:');
}
return $keys;
},
)
);
if (!in_array($item['prefix'], $this->prefixes)) {
$this->prefixes[] = $item['prefix'];
}
}
return $components;
}
protected function getVendorComponents(): array
{
$components = [];
/** @var \Illuminate\View\Factory $view */
$view = \Illuminate\Support\Facades\App::make('view');
/** @var \Illuminate\View\FileViewFinder $finder */
$finder = $view->getFinder();
/** @var array<string, array<int, string>> $views */
$views = $finder->getHints();
foreach ($views as $key => $paths) {
foreach ($paths as $path) {
$path .= '/components';
if (!is_dir($path)) {
continue;
}
array_push(
$components,
...$this->findFiles(
$path,
'blade.php',
fn (\Illuminate\Support\Stringable $k) => $k->kebab()->prepend($key.'::'),
)
);
}
}
return $components;
}
protected function handleIndexComponents($str)
{
if ($str->endsWith('.index')) {
return $str->replaceLast('.index', '');
}
if (!$str->contains('.')) {
return $str;
}
$parts = $str->explode('.');
if ($parts->slice(-2)->unique()->count() === 1) {
$parts->pop();
return str($parts->implode('.'));
}
return $str;
}
protected function getNamespaced()
{
$namespaced = \Illuminate\Support\Facades\Blade::getClassComponentNamespaces();
$components = [];
foreach ($namespaced as $key => $classNamespace) {
$path = $this->getNamespacePath($classNamespace);
if (!$path) {
continue;
}
array_push(
$components,
...$this->findFiles(
$path,
'php',
fn($k) => $k->kebab()->prepend($key . "::"),
)
);
}
return $components;
}
protected function getNamespacePath($classNamespace)
{
foreach ($this->autoloaded as $ns => $paths) {
if (!str_starts_with($classNamespace, $ns)) {
continue;
}
foreach ($paths as $p) {
$dir = str($classNamespace)
->replace($ns, '')
->replace('\\', '/')
->prepend($p . DIRECTORY_SEPARATOR)
->toString();
if (is_dir($dir)) {
return $dir;
}
}
return null;
}
return null;
}
protected function setProps($groups)
{
try {
$compiler = app('blade.compiler');
} catch (\Throwable $e) {
return $groups;
}
return $groups->map(function ($group) use ($compiler) {
return $group->transform(function ($component) use ($compiler) {
if (isset($component['props'])) {
return $component;
}
if (!str($component['path'])->endsWith('.blade.php')) {
return $component;
}
if (! $props = $this->parseProps($compiler, $component)) {
return $component;
}
return array_merge($component, ['props' => $props]);
});
});
}
protected function parseProps($compiler, array $component): ?string
{
$content = file_get_contents(base_path($component['path']));
$result = '';
$compiler->directive('props', function ($expression) use (&$result) {
return $result = $expression;
});
$compiler->compileString($content);
if (empty($result)) {
return null;
}
return '@props('.$result.')';
}
};
echo json_encode($components->all());
echo LaravelVsCode::outputMarker('END_OUTPUT');
exit(0);

View File

@@ -1,350 +0,0 @@
<?php
error_reporting(E_ERROR | E_PARSE);
define('LARAVEL_START', microtime(true));
require_once __DIR__ . '/../autoload.php';
class LaravelVsCode
{
public static function relativePath($path)
{
if (!str_contains($path, base_path())) {
return (string) $path;
}
return ltrim(str_replace(base_path(), '', realpath($path) ?: $path), DIRECTORY_SEPARATOR);
}
public static function isVendor($path)
{
return str_contains($path, base_path("vendor"));
}
public static function outputMarker($key)
{
return '__VSCODE_LARAVEL_' . $key . '__';
}
public static function startupError(\Throwable $e)
{
throw new Error(self::outputMarker('STARTUP_ERROR') . ': ' . $e->getMessage());
}
}
try {
$app = require_once __DIR__ . '/../../bootstrap/app.php';
} catch (\Throwable $e) {
LaravelVsCode::startupError($e);
exit(1);
}
$app->register(new class($app) extends \Illuminate\Support\ServiceProvider
{
public function boot()
{
config([
'logging.channels.null' => [
'driver' => 'monolog',
'handler' => \Monolog\Handler\NullHandler::class,
],
'logging.default' => 'null',
]);
}
});
try {
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$kernel->bootstrap();
} catch (\Throwable $e) {
LaravelVsCode::startupError($e);
exit(1);
}
echo LaravelVsCode::outputMarker('START_OUTPUT');
$livewire = new class {
protected $namespaces;
protected $paths;
protected $extensions = [".blade.php", ".php", ".js", ".global.css", ".css", ".test.php"];
public function __construct()
{
$this->namespaces = collect(
config("livewire.component_namespaces", [])
)->map(LaravelVsCode::relativePath(...));
$this->paths = collect($this->namespaces->values())
->merge(config("livewire.component_locations", []))
->unique()
->map(LaravelVsCode::relativePath(...));
}
public function parse(\Illuminate\Support\Collection $views)
{
return $this->isVersionFour()
? $this->parseLivewireFour($views)
: $this->parseLivewireThree($views);
}
protected function parseLivewireFour(\Illuminate\Support\Collection $views)
{
return $views
->map(function (array $view) {
if (!$this->pathExists($view["path"])) {
return $view;
}
if (is_null($component = $this->getComponent($key = $this->key($view)))) {
return $view;
}
$files = $this->files($view);
if (count($files) === 1 && !str($view['path'])->endsWith('.blade.php')) {
return null;
}
return array_merge($view, [
"key" => $key,
'livewire' => [
'props' => $this->getProps($component),
'files' => $files,
],
]);
})
->whereNotNull()
->unique('key')
->values();
}
protected function parseLivewireThree(\Illuminate\Support\Collection $views)
{
return $views->map(function (array $view) {
if (!str($view['key'])->startsWith('livewire.')) {
return $view;
}
$key = str($view['key'])->after('livewire.')->value();
if (is_null($component = $this->getComponent($key))) {
return $view;
}
return array_merge($view, [
'livewire' => [
'props' => $this->getProps($component),
'files' => [$view['path']],
],
]);
});
}
protected function isVersionFour(): bool
{
return property_exists(\Livewire\LivewireManager::class, "v4") &&
\Livewire\LivewireManager::$v4;
}
protected function pathExists(string $path): bool
{
return $this->paths->contains(fn (string $item) => str($path)->contains($item));
}
protected function getComponent(string $key)
{
try {
return app("livewire")->new($key);
} catch (\Throwable $e) {
return null;
}
}
protected function getProps($component): array
{
return array_map(function ($prop) use ($component) {
$reflection = new \ReflectionProperty($component, $prop);
return [
'name' => $prop,
'type' => (string) $reflection->getType() ?: 'mixed',
'hasDefaultValue' => $reflection->hasDefaultValue(),
'defaultValue' => $this->formatDefaultValue($reflection->getDefaultValue()),
];
}, array_keys($component->all()));
}
protected function formatDefaultValue(mixed $value)
{
return is_string($value) ? "'{$value}'": $value;
}
protected function key(array $view): string
{
return str($view["key"])
->replace("⚡", "")
->when($this->isMfc($view), fn ($key) => $key->beforeLast("."))
->value();
}
protected function files(array $view): array
{
if (! $this->isMfc($view)) {
return [$view['path']];
}
$filePathWithoutExtension = str($view["path"])->replace($this->extensions, "");
return collect($this->extensions)
->map(fn (string $extension) => $filePathWithoutExtension->append($extension))
->filter(fn (string $path) => \Illuminate\Support\Facades\File::exists($path))
->all();
}
protected function isMfc(array $view): bool
{
$directory = str($view["path"])
->replace("⚡", "")
->dirname()
->afterLast(DIRECTORY_SEPARATOR);
$file = str($view["path"])
->replace("⚡", "")
->basename()
->replace($this->extensions, "");
$class = str($view["path"])
->dirname()
->append(DIRECTORY_SEPARATOR . $file . ".php");
return $directory->is($file)
&& \Illuminate\Support\Facades\File::exists($class);
}
};
$blade = new class ($livewire) {
public function __construct(protected $livewire)
{
//
}
public function getAllViews()
{
$finder = app("view")->getFinder();
$paths = collect($finder->getPaths())->flatMap(fn($path) => $this->findViews($path));
$hints = collect($finder->getHints())
->filter(
fn ($_, $key) => ! (strlen($key) === 32 && ctype_xdigit($key))
)->flatMap(
fn($paths, $key) => collect($paths)->flatMap(
fn($path) => collect($this->findViews($path))->map(
fn($value) => array_merge($value, ["key" => "{$key}::{$value["key"]}"])
)
)
);
[$local, $vendor] = $paths
->merge($hints)
->values()
->partition(fn($v) => !$v["isVendor"]);
return $local
->sortBy("key", SORT_NATURAL)
->merge($vendor->sortBy("key", SORT_NATURAL))
->pipe($this->livewire->parse(...));
}
public function getAllComponents()
{
$namespaced = \Illuminate\Support\Facades\Blade::getClassComponentNamespaces();
$autoloaded = require base_path("vendor/composer/autoload_psr4.php");
$components = [];
foreach ($namespaced as $key => $ns) {
$path = null;
foreach ($autoloaded as $namespace => $paths) {
if (str_starts_with($ns, $namespace)) {
foreach ($paths as $p) {
$test = str($ns)->replace($namespace, '')->replace('\\', '/')->prepend($p . DIRECTORY_SEPARATOR)->toString();
if (is_dir($test)) {
$path = $test;
break;
}
}
break;
}
}
if (!$path) {
continue;
}
$files = \Symfony\Component\Finder\Finder::create()
->files()
->name("*.php")
->in($path);
foreach ($files as $file) {
$realPath = $file->getRealPath();
$components[] = [
"path" => LaravelVsCode::relativePath($realPath),
"isVendor" => str_contains($realPath, base_path("vendor")),
"key" => str($realPath)
->replace(realpath($path), "")
->replace(".php", "")
->ltrim(DIRECTORY_SEPARATOR)
->replace(DIRECTORY_SEPARATOR, ".")
->kebab()
->prepend($key . "::"),
];
}
}
return $components;
}
protected function findViews($path)
{
$paths = [];
if (!is_dir($path)) {
return $paths;
}
$finder = app("view")->getFinder();
$extensions = array_map(fn($extension) => ".{$extension}", $finder->getExtensions());
$files = \Symfony\Component\Finder\Finder::create()
->files()
->name(array_map(fn ($ext) => "*{$ext}", $extensions))
->in($path);
foreach ($files as $file) {
$paths[] = [
"path" => LaravelVsCode::relativePath($file->getRealPath()),
"isVendor" => str_contains($file->getRealPath(), base_path("vendor")),
"key" => str($file->getRealPath())
->replace(realpath($path), "")
->replace($extensions, "")
->ltrim(DIRECTORY_SEPARATOR)
->replace(DIRECTORY_SEPARATOR, "."),
];
}
return $paths;
}
};
echo json_encode($blade->getAllViews()->merge($blade->getAllComponents()));
echo LaravelVsCode::outputMarker('END_OUTPUT');
exit(0);