feat(proxmox): add statistics redirect component and route

Introduced a new Livewire component for statistics redirection and added a corresponding route to enhance navigation within the Proxmox extension. This update lays the groundwork for future statistics-related features.
This commit is contained in:
2026-03-28 15:48:17 -04:00
parent 5b61b75729
commit 9e33470134
5179 changed files with 35525 additions and 88560 deletions

11
vendor/_laravel_ide/_auth.php vendored Normal file
View File

@@ -0,0 +1,11 @@
<?php
namespace Illuminate\Contracts\Auth;
interface Guard
{
/**
* @return \App\Models\User|null
*/
public function user();
}

41
vendor/_laravel_ide/_facade.php vendored Normal file
View File

@@ -0,0 +1,41 @@
<?php
namespace Illuminate\Support\Facades;
interface Auth
{
/**
* @return \App\Models\User|false
*/
public static function loginUsingId(mixed $id, bool $remember = false);
/**
* @return \App\Models\User|false
*/
public static function onceUsingId(mixed $id);
/**
* @return \App\Models\User|null
*/
public static function getUser();
/**
* @return \App\Models\User
*/
public static function authenticate();
/**
* @return \App\Models\User|null
*/
public static function user();
/**
* @return \App\Models\User|null
*/
public static function logoutOtherDevices(string $password);
/**
* @return \App\Models\User
*/
public static function getLastAttempted();
}

View File

@@ -0,0 +1 @@
<?php

11
vendor/_laravel_ide/_request.php vendored Normal file
View File

@@ -0,0 +1,11 @@
<?php
namespace Illuminate\Http;
interface Request
{
/**
* @return \App\Models\User|null
*/
public function user($guard = null);
}

View File

@@ -0,0 +1,361 @@
<?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');
if (class_exists('\phpDocumentor\Reflection\DocBlockFactory')) {
$factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
} else {
$factory = null;
}
$docblocks = new class($factory) {
public function __construct(protected $factory) {}
public function forMethod($method)
{
if ($this->factory !== null) {
$docblock = $this->factory->create($method->getDocComment());
$params = collect($docblock->getTagsByName("param"))->map(fn($p) => (string) $p)->all();
$return = (string) $docblock->getTagsByName("return")[0] ?? null;
return [$params, $return];
}
$params = collect($method->getParameters())
->map(function (\ReflectionParameter $param) {
$types = match ($param?->getType()) {
null => [],
default => method_exists($param->getType(), "getTypes")
? $param->getType()->getTypes()
: [$param->getType()]
};
$types = collect($types)
->filter()
->values()
->map(fn($t) => $t->getName());
return trim($types->join("|") . " $" . $param->getName());
})
->all();
$return = $method->getReturnType()?->getName();
return [$params, $return];
}
};
$models = new class($factory) {
protected $output;
public function __construct(protected $factory)
{
$this->output = new \Symfony\Component\Console\Output\BufferedOutput();
}
public function all()
{
if (\Illuminate\Support\Facades\File::isDirectory(base_path('app/Models'))) {
collect(\Illuminate\Support\Facades\File::allFiles(base_path('app/Models')))
->filter(fn(\Symfony\Component\Finder\SplFileInfo $file) => $file->getExtension() === 'php')
->each(fn($file) => include_once($file));
}
return collect(get_declared_classes())
->filter(fn($class) => is_subclass_of($class, \Illuminate\Database\Eloquent\Model::class))
->filter(fn($class) => !in_array($class, [\Illuminate\Database\Eloquent\Relations\Pivot::class, \Illuminate\Foundation\Auth\User::class]))
->values()
->flatMap(fn(string $className) => $this->getInfo($className))
->filter();
}
protected function getCastReturnType($className)
{
if ($className === null) {
return null;
}
try {
$method = (new \ReflectionClass($className))->getMethod('get');
if ($method->hasReturnType()) {
return $method->getReturnType()->getName();
}
return $className;
} catch (\Exception | \Throwable $e) {
return $className;
}
}
protected function fromArtisan($className)
{
try {
\Illuminate\Support\Facades\Artisan::call(
"model:show",
[
"model" => $className,
"--json" => true,
],
$this->output
);
} catch (\Exception | \Throwable $e) {
return null;
}
return json_decode($this->output->fetch(), true);
}
protected function collectExistingProperties($reflection)
{
if ($this->factory === null) {
return collect();
}
if ($comment = $reflection->getDocComment()) {
$docblock = $this->factory->create($comment);
$existingProperties = collect($docblock->getTagsByName("property"))->map(fn($p) => $p->getVariableName());
$existingReadProperties = collect($docblock->getTagsByName("property-read"))->map(fn($p) => $p->getVariableName());
return $existingProperties->merge($existingReadProperties);
}
return collect();
}
protected function getParentClass(\ReflectionClass $reflection)
{
if (!$reflection->getParentClass()) {
return null;
}
$parent = $reflection->getParentClass()->getName();
if ($parent === \Illuminate\Database\Eloquent\Model::class) {
return null;
}
return \Illuminate\Support\Str::start($parent, '\\');
}
protected function getInfo($className)
{
if (($data = $this->fromArtisan($className)) === null) {
return null;
}
$reflection = new \ReflectionClass($className);
$data["extends"] = $this->getParentClass($reflection);
$existingProperties = $this->collectExistingProperties($reflection);
$data['attributes'] = collect($data['attributes'])
->map(fn($attrs) => array_merge($attrs, [
'title_case' => str($attrs['name'])->title()->replace('_', '')->toString(),
'documented' => $existingProperties->contains($attrs['name']),
'cast' => $this->getCastReturnType($attrs['cast'])
]))
->toArray();
$data['scopes'] = collect($reflection->getMethods())
->filter(fn(\ReflectionMethod $method) => !$method->isStatic() && ($method->getAttributes(\Illuminate\Database\Eloquent\Attributes\Scope::class) || ($method->isPublic() && str_starts_with($method->name, 'scope'))))
->map(fn(\ReflectionMethod $method) => [
"name" => str($method->name)->replace('scope', '')->lcfirst()->toString(),
"method" => $method->name,
"parameters" => collect($method->getParameters())->map($this->getScopeParameterInfo(...)),
])
->values()
->toArray();
$data['relations'] = collect($data['relations'])
->map(fn($relation) => array_merge($relation, [
'snake_case' => \Illuminate\Support\Str::snake($relation['name']),
]))
->toArray();
$data['uri'] = $reflection->getFileName();
return [
$className => $data,
];
}
protected function getScopeParameterInfo(\ReflectionParameter $parameter): array
{
$result = [
"name" => $parameter->getName(),
"type" => $this->typeToString($parameter->getType()),
"hasDefault" => $parameter->isDefaultValueAvailable(),
"isVariadic" => $parameter->isVariadic(),
"isPassedByReference" => $parameter->isPassedByReference(),
];
if ($parameter->isDefaultValueAvailable()) {
$result['default'] = $this->defaultValueToString($parameter);
}
return $result;
}
protected function typeToString(?\ReflectionType $type): string
{
return match (true) {
$type instanceof \ReflectionNamedType => $this->namedTypeToString($type),
$type instanceof \ReflectionUnionType => $this->unionTypeToString($type),
$type instanceof \ReflectionIntersectionType => $this->intersectionTypeToString($type),
default => 'mixed',
};
}
protected function namedTypeToString(\ReflectionNamedType $type): string
{
$name = $type->getName();
if (! $type->isBuiltin() && ! in_array($name, ['self', 'parent', 'static'])) {
$name = '\\'.$name;
}
if ($type->allowsNull() && ! in_array($name, ['null', 'mixed', 'void'])) {
$name = '?'.$name;
}
return $name;
}
protected function unionTypeToString(\ReflectionUnionType $type): string
{
return implode('|', array_map(function (\ReflectionType $type) {
$result = $this->typeToString($type);
if ($type instanceof \ReflectionIntersectionType) {
return "({$result})";
}
return $result;
}, $type->getTypes()));
}
protected function intersectionTypeToString(\ReflectionIntersectionType $type): string
{
return implode('&', array_map($this->typeToString(...), $type->getTypes()));
}
protected function defaultValueToString(\ReflectionParameter $param): string
{
if ($param->isDefaultValueConstant()) {
return '\\'.$param->getDefaultValueConstantName();
}
$value = $param->getDefaultValue();
return match (true) {
is_null($value) => 'null',
is_numeric($value) => $value,
is_bool($value) => $value ? 'true' : 'false',
is_array($value) => '[]',
is_object($value) => 'new \\'.get_class($value),
default => "'{$value}'",
};
}
};
$builder = new class($docblocks) {
public function __construct(protected $docblocks) {}
public function methods()
{
$reflection = new \ReflectionClass(\Illuminate\Database\Query\Builder::class);
return collect($reflection->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED))
->filter(fn(ReflectionMethod $method) => !str_starts_with($method->getName(), "__") || (!$method->isPublic() && empty($method->getAttributes(\Illuminate\Database\Eloquent\Attributes\Scope::class))))
->map(fn(\ReflectionMethod $method) => $this->getMethodInfo($method))
->filter()
->values();
}
protected function getMethodInfo($method)
{
[$params, $return] = $this->docblocks->forMethod($method);
return [
"name" => $method->getName(),
"parameters" => $params,
"return" => $return,
];
}
};
echo json_encode([
'builderMethods' => $builder->methods(),
'models' => $models->all(),
]);
echo LaravelVsCode::outputMarker('END_OUTPUT');
exit(0);

View File

@@ -0,0 +1,175 @@
<?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');
$routes = new class {
public function all()
{
return collect(app('router')->getRoutes()->getRoutes())
->map(fn(\Illuminate\Routing\Route $route) => $this->getRoute($route))
->merge($this->getFolioRoutes());
}
protected function getFolioRoutes()
{
try {
$output = new \Symfony\Component\Console\Output\BufferedOutput();
\Illuminate\Support\Facades\Artisan::call("folio:list", ["--json" => true], $output);
$mountPaths = collect(app(\Laravel\Folio\FolioManager::class)->mountPaths());
return collect(json_decode($output->fetch(), true))->map(fn($route) => $this->getFolioRoute($route, $mountPaths));
} catch (\Exception | \Throwable $e) {
return [];
}
}
protected function getFolioRoute($route, $mountPaths)
{
if ($mountPaths->count() === 1) {
$mountPath = $mountPaths[0];
} else {
$mountPath = $mountPaths->first(fn($mp) => file_exists($mp->path . DIRECTORY_SEPARATOR . $route['view']));
}
$path = $route['view'];
if ($mountPath) {
$path = $mountPath->path . DIRECTORY_SEPARATOR . $path;
}
return [
'method' => $route['method'],
'uri' => $route['uri'],
'name' => $route['name'],
'action' => null,
'parameters' => [],
'filename' => LaravelVsCode::relativePath($path),
'line' => 0,
];
}
protected function getRoute(\Illuminate\Routing\Route $route)
{
try {
$reflection = $this->getRouteReflection($route);
} catch (\Throwable $e) {
$reflection = null;
}
return [
'method' => collect($route->methods())
->filter(fn($method) => $method !== 'HEAD')
->implode('|'),
'uri' => $route->uri(),
'name' => $route->getName(),
'action' => $route->getActionName(),
'parameters' => $route->parameterNames(),
'filename' => $reflection ? LaravelVsCode::relativePath($reflection->getFileName()) : null,
'line' => $reflection ? $reflection->getStartLine() : null,
'livewire' => $this->getLivewireView($route),
];
}
protected function getLivewireView(\Illuminate\Routing\Route $route): ?string
{
if ($route->getActionName() !== 'Livewire\Features\SupportRouting\LivewirePageController') {
return null;
}
return $route->defaults['_livewire_component'] ?? null;
}
protected function getRouteReflection(\Illuminate\Routing\Route $route)
{
if ($route->getActionName() === 'Closure') {
return new \ReflectionFunction($route->getAction()['uses']);
}
if (!str_contains($route->getActionName(), '@')) {
return new \ReflectionClass($route->getActionName());
}
try {
return new \ReflectionMethod($route->getControllerClass(), $route->getActionMethod());
} catch (\Throwable $e) {
$namespace = app(\Illuminate\Routing\UrlGenerator::class)->getRootControllerNamespace()
?? (app()->getNamespace() . 'Http\Controllers');
return new \ReflectionMethod(
$namespace . '\\' . ltrim($route->getControllerClass(), '\\'),
$route->getActionMethod(),
);
}
}
};
echo $routes->all()->toJson();
echo LaravelVsCode::outputMarker('END_OUTPUT');
exit(0);

View File

@@ -0,0 +1,451 @@
<?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() ? $this->normalizeDefault($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' => $this->normalizeDefault($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 normalizeDefault($value)
{
if ($value instanceof \UnitEnum) {
return $value instanceof \BackedEnum
? $value->value
: $value::class.'::'.$value->name;
}
return $value;
}
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

@@ -0,0 +1,89 @@
<?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');
$pageExtensions = config(
'inertia.pages.extensions',
config('inertia.page_extensions', config('inertia.testing.page_extensions', [])),
);
$pagePaths = config(
'inertia.pages.paths',
config('inertia.page_paths', config('inertia.testing.page_paths', [])),
);
echo json_encode([
'page_extensions' => $pageExtensions,
'page_paths' => collect($pagePaths)->flatMap(function($path) {
$relativePath = LaravelVsCode::relativePath($path);
return [$relativePath, mb_strtolower($relativePath)];
})->unique()->values(),
]);
echo LaravelVsCode::outputMarker('END_OUTPUT');
exit(0);