diff --git a/.gitignore b/.gitignore index d4375311..57294617 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ /vendor composer.lock .phpunit.result.cache +/node_sandbox/package-lock.json +/node_sandbox/node_modules +/node_sandbox/version diff --git a/app/Actions/FixCode.php b/app/Actions/FixCode.php index 263b509f..bb931abf 100644 --- a/app/Actions/FixCode.php +++ b/app/Actions/FixCode.php @@ -3,7 +3,6 @@ namespace App\Actions; use App\Factories\ConfigurationResolverFactory; -use LaravelZero\Framework\Exceptions\ConsoleException; use PhpCsFixer\Runner\Runner; class FixCode @@ -35,11 +34,7 @@ public function __construct( */ public function execute() { - try { - [$resolver, $totalFiles] = ConfigurationResolverFactory::fromIO($this->input, $this->output); - } catch (ConsoleException $exception) { - return [$exception->getCode(), []]; - } + [$resolver, $totalFiles] = ConfigurationResolverFactory::fromIO($this->input, $this->output); if (is_null($this->input->getOption('format'))) { $this->progress->subscribe(); diff --git a/app/BladeFormatter.php b/app/BladeFormatter.php new file mode 100644 index 00000000..346467ae --- /dev/null +++ b/app/BladeFormatter.php @@ -0,0 +1,49 @@ + $processors + * @return void + */ + public function __construct( + protected $prettier, + protected $processors, + ) { + // + } + + /** + * Format the given content. + * + * @param string $path + * @param string $content + * @return string + */ + public function format($path, $content) + { + foreach ($this->processors as $processor) { + if ($processor instanceof PreProcessor) { + $content = $processor->preProcess($content); + } + } + + $content = $this->prettier->format($path, $content); + + foreach ($this->processors as $processor) { + if ($processor instanceof PostProcessor) { + $content = $processor->postProcess($content); + } + } + + return $content; + } +} diff --git a/app/Commands/DefaultCommand.php b/app/Commands/DefaultCommand.php index 5c6e1002..69350d98 100644 --- a/app/Commands/DefaultCommand.php +++ b/app/Commands/DefaultCommand.php @@ -35,6 +35,7 @@ protected function configure() ->setDefinition( [ new InputArgument('path', InputArgument::IS_ARRAY, 'The path to fix', [(string) getcwd()]), + new InputOption('blade', '', InputOption::VALUE_NONE, 'Fixes blade files (experimental)'), new InputOption('config', '', InputOption::VALUE_REQUIRED, 'The configuration that should be used'), new InputOption('no-config', '', InputOption::VALUE_NONE, 'Disable loading any configuration file'), new InputOption('preset', '', InputOption::VALUE_REQUIRED, 'The preset that should be used'), diff --git a/app/Contracts/PostProcessor.php b/app/Contracts/PostProcessor.php new file mode 100644 index 00000000..8f4c12ef --- /dev/null +++ b/app/Contracts/PostProcessor.php @@ -0,0 +1,14 @@ +setFinder(self::finder()) ->setRules(array_merge($rules, resolve(ConfigurationJsonRepository::class)->rules())) ->setRiskyAllowed(true) - ->setUsingCache(true); + ->setUsingCache(true) + ->registerCustomFixers([ + new Fixer(resolve(BladeFormatter::class)), + ]); } /** @@ -57,6 +62,10 @@ public static function finder() { $localConfiguration = resolve(ConfigurationJsonRepository::class); + if (resolve(InputInterface::class)->getOption('blade') === false) { + $notName = array_merge(static::$notName, ['*.blade.php']); + } + $finder = Finder::create() ->notName(static::$notName) ->exclude(static::$exclude) diff --git a/app/Factories/ConfigurationResolverFactory.php b/app/Factories/ConfigurationResolverFactory.php index 37b140bb..da4f0049 100644 --- a/app/Factories/ConfigurationResolverFactory.php +++ b/app/Factories/ConfigurationResolverFactory.php @@ -2,6 +2,7 @@ namespace App\Factories; +use App\NodeSandbox; use App\Project; use App\Repositories\ConfigurationJsonRepository; use ArrayIterator; @@ -43,6 +44,10 @@ public static function fromIO($input, $output) abort(1, 'Preset not found.'); } + if ($input->getOption('blade') && $preset !== 'laravel') { + abort(1, 'The blade option is only available for the laravel preset.'); + } + $resolver = new ConfigurationResolver( new Config('default'), [ @@ -61,7 +66,7 @@ public static function fromIO($input, $output) realpath(sys_get_temp_dir()), md5( app()->isProduction() - ? implode('|', $path) + ? (implode('|', $path) . '||' . NodeSandbox::VERSION) : (string) microtime() ), ]), diff --git a/app/Fixers/LaravelBlade/Fixer.php b/app/Fixers/LaravelBlade/Fixer.php new file mode 100644 index 00000000..d3eaa13a --- /dev/null +++ b/app/Fixers/LaravelBlade/Fixer.php @@ -0,0 +1,90 @@ + + */ + protected static $ignorables = [ + Ignorables\Envoy::class, + Ignorables\MarkdownMail::class, + ]; + + /** + * {@inheritdoc} + */ + public function __construct(protected $formatter) + { + } + + /** + * {@inheritdoc} + */ + public function getName(): string + { + return 'Laravel/blade'; + } + + /** + * {@inheritdoc} + */ + public function isCandidate(Tokens $tokens): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getDefinition(): FixerDefinitionInterface + { + return new FixerDefinition('Fixes Laravel Blade files.', []); + } + + /** + * {@inheritdoc} + */ + public function getPriority(): int + { + return -2; + } + + /** + * {@inheritdoc} + * + * @throws \App\Exceptions\PrettierException + */ + protected function applyFix(SplFileInfo $file, Tokens $tokens): void + { + $path = $file->getRealPath(); + + if (! str_ends_with($path, '.blade.php')) { + return; + } + + $content = $tokens->generateCode(); + + foreach (static::$ignorables as $ignorable) { + if (app()->call($ignorable, [ + 'path' => $path, + 'content' => $content, + ])) { + return; + } + } + + $content = $this->formatter->format($path, $content); + + $tokens->setCode($content); + } +} diff --git a/app/Fixers/LaravelBlade/Ignorables/Envoy.php b/app/Fixers/LaravelBlade/Ignorables/Envoy.php new file mode 100644 index 00000000..4fbb3e15 --- /dev/null +++ b/app/Fixers/LaravelBlade/Ignorables/Envoy.php @@ -0,0 +1,20 @@ + + */ + protected $placeholders = []; + + /** + * {@inheritDoc} + */ + public function preProcess($content) + { + $content = $this->ignoreMinifiedCss($content); + // $content = $this->ignoreText($content); + + return $content; + } + + /** + * {@inheritDoc} + */ + public function postProcess($content) + { + foreach (array_reverse($this->placeholders) as $placeholder => $value) { + $content = str_replace($placeholder, $value, $content); + } + + $this->placeholders = []; + + return $content; + } + + /** + * Ignore minified CSS. + * + * @param string $content + * @return string + */ + protected function ignoreMinifiedCss($content) + { + return preg_replace_callback('/(.*?)<\/style>/s', function ($matches) { + if (! Str::of($matches[2])->replace([' ', "\n", "\r", "\t"], '')->startsWith(['/*!', '/* !'])) { + return $matches[0]; + } + + $placeholder = sprintf('::%s::', uniqid('ignore-minified-css')); + + $ident = str_repeat(' ', Str::of(Str::of($matches[0])->explode("\n")->last())->before('')->length()); + + $this->placeholders[$placeholder] = trim($matches[2]); + + return ''."\n$ident ".$placeholder."\n$ident"; + }, $content); + } + + protected function ignoreText($content) + { + $dom = new \DOMDocument(); + + $useInternalErrors = libxml_use_internal_errors(true); + + try { + $dom->loadHTML($content); + } catch (ErrorException $e) { + return $content; + } finally { + libxml_use_internal_errors($useInternalErrors); + } + + $elements = $dom->getElementsByTagName('*'); + + foreach ($elements as $element) { + $content = $this->foreachElement($element, function ($element, $content) use ($dom) { + + $textContent = $element->firstChild?->textContent; + + if (! is_null($textContent) && $this->isText($textContent) && $element->childNodes->length > 1) { + try { + $html = $dom->saveHTML($element); + } catch (DOMException) { + return $content; + } + + foreach (Str::of($html)->after('>')->beforeLast('<')->explode("\n") as $key => $line) { + $placeholder = sprintf('::%s::', uniqid('ignore-text')); + $this->placeholders[$placeholder] = $html; + + $content = str_replace($html, $placeholder, $content); + } + } + + return $content; + }, $content); + } + + return $content; + } + + /** + * Runs the given callback for each element. + * + * @param DOMElement $element + * @param callable $callback + * @param string $content + * @return string + */ + protected function foreachElement($element, $callback, $content) + { + $content = $callback($element, $content); + + foreach ($element->childNodes as $child) { + if (! $child instanceof DOMElement) { + continue; + } + + $content = $this->foreachElement($child, $callback, $content); + } + + return $content; + } + + /** + * Check if the given text is not empty. + * + * @param string $text + * @return bool + */ + protected function isText($text) + { + $text = str_replace([' ', "\n", "\r", "\t"], '', $text); + + return $text !== '' && ! Str::startsWith($text, '@'); + } +} diff --git a/app/Fixers/LaravelBlade/Processors/OneLinerSvg.php b/app/Fixers/LaravelBlade/Processors/OneLinerSvg.php new file mode 100644 index 00000000..93eb0493 --- /dev/null +++ b/app/Fixers/LaravelBlade/Processors/OneLinerSvg.php @@ -0,0 +1,34 @@ +(.*?)<\/svg>/s', function ($matches) { + $multiline = Str::of($matches[2])->startsWith("\n"); + $ident = $multiline ? (Str::of($matches[2])->before('<')->length() - 5) : 0; + + $tags = Str::of($matches[2]) + ->explode("\n") + ->map(fn ($line) => trim($line)) + ->filter() + ->values() + ->map(fn ($line) => Str::of($line)->startsWith(['<', '>']) ? $line : (' '.$line)) + ->when(Str::startsWith($matches[2], "\n"), fn ($lines) => $lines->prepend("\n".str_repeat(' ', $ident + 4))) + ->when(Str::startsWith($matches[2], "\n"), function ($lines) use ($ident) { + return $lines->push("\n".str_repeat(' ', $ident)); + }) + ->implode(''); + + return ''.$tags.''; + }, $content); + } +} diff --git a/app/NodeSandbox.php b/app/NodeSandbox.php new file mode 100644 index 00000000..a4ff6049 --- /dev/null +++ b/app/NodeSandbox.php @@ -0,0 +1,121 @@ +path = $path; + } + + /** + * Ensures the sandbox is initialized. + * + * @return void + */ + public function ensureInitialized() + { + if ($this->initialized) { + return; + } + + if (! File::exists($this->path.'/version') || File::get($this->path.'/version') !== static::VERSION) { + File::deleteDirectory($this->path.'/node_modules'); + File::delete($this->path.'/package-lock.json'); + + $this->ensureNodeIsInstalled(); + $this->ensureNpmIsInstalled(); + + $this->installNodeDependencies(); + + File::put($this->path.'/version', static::VERSION); + } + } + + /** + * The sandbox path. + * + * @return string + */ + public function path() + { + return $this->path; + } + + /** + * Ensure node is installed. + * + * @return void + */ + private function ensureNodeIsInstalled() + { + if (Process::run('node -v')->failed()) { + abort(1, 'Pint requires node to be installed on your machine.'); + } + } + + /** + * Ensure NPM is installed. + * + * @return void + */ + private function ensureNpmIsInstalled() + { + if (Process::run('npm -v')->failed()) { + abort(1, 'Pint requires npm to be installed on your machine.'); + } + } + + /** + * Install the node dependencies. + * + * @return void + */ + private function installNodeDependencies() + { + $commands = [ + 'npm install', + ]; + + $result = Process::command(implode(' && ', $commands)) + ->path($this->path) + ->run(); + + if ($result->failed()) { + $reason = $result->output(); + + abort(1, sprintf('Pint was unable to install its node dependencies. Reason: %s', $reason)); + } + } +} diff --git a/app/Prettier.php b/app/Prettier.php new file mode 100644 index 00000000..6bb21907 --- /dev/null +++ b/app/Prettier.php @@ -0,0 +1,142 @@ +sandbox = $sandbox; + } + + /** + * Formats the given file. + * + * @param string $path + * @param string $content + * @return string + * + * @throws \App\Exceptions\PrettierException + */ + public function format($path, $content) + { + $this->sandbox->ensureInitialized(); + + $this->ensureStarted(); + + $this->inputStream->write(json_encode([ + 'path' => $path, + 'content' => $content, + ])); + + $this->process->clearOutput(); + $this->process->clearErrorOutput(); + + $error = ''; + + while (true) { + $formatted = $this->process->getIncrementalOutput(); + + if (Str::endsWith($formatted, '[PINT_BLADE_PRETTIER_WORKER_END]')) { + break; + } + + if ($error = $this->process->getIncrementalErrorOutput()) { + break; + } + } + + $this->process->clearOutput(); + $this->process->clearErrorOutput(); + + if ($error !== '') { + throw new PrettierException($error); + } + + foreach ([ + '[PINT_BLADE_PRETTIER_WORKER_START]', + '[PINT_BLADE_PRETTIER_WORKER_END]', + ] as $delimiter) { + if (! Str::contains($formatted, $delimiter)) { + throw new PrettierException('Laravel Pint\'s Prettier worker did not return a valid response.'); + } + } + + return Str::of($formatted) + ->after('[PINT_BLADE_PRETTIER_WORKER_START]') + ->before('[PINT_BLADE_PRETTIER_WORKER_END]') + ->value(); + } + + /** + * Ensures the process is started. + * + * @return void + */ + public function ensureStarted() + { + if ($this->process) { + return; + } + + $this->process = new Process( + ['node', $this->sandbox->path().'/prettier-worker.js'], + $this->sandbox->path(), + ); + + $this->process->setTty(false); + + $this->process->setInput( + $this->inputStream = new InputStream(), + ); + + $this->process->start(); + } + + /** + * Ensures the process is terminated. + * + * @return void + */ + public function ensureTerminated() + { + if ($this->process) { + $this->process->stop(); + + $this->inputStream = null; + $this->process = null; + } + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 4aec48cc..13f28377 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,7 +2,13 @@ namespace App\Providers; +use App\BladeFormatter; +use App\Fixers\LaravelBlade\Processors\IgnoreCode; +use App\Fixers\LaravelBlade\Processors\OneLinerSvg; +use App\NodeSandbox; +use App\Prettier; use Illuminate\Support\ServiceProvider; +use Phar; use PhpCsFixer\Error\ErrorsManager; use Symfony\Component\EventDispatcher\EventDispatcher; @@ -32,5 +38,31 @@ public function register() $this->app->singleton(EventDispatcher::class, function () { return new EventDispatcher(); }); + + $this->app->singleton(NodeSandbox::class, function () { + return new NodeSandbox( + Phar::running() + ? (dirname(Phar::running(false), 2).'/node_sandbox') + : base_path('node_sandbox'), + ); + }); + + $this->app->singleton(Prettier::class, function ($app) { + return new Prettier($app->make(NodeSandbox::class)); + }); + + $this->app->terminating(function () { + $this->app->make(Prettier::class)->ensureTerminated(); + }); + + $this->app->bind(BladeFormatter::class, function ($app) { + return new BladeFormatter( + $app->make(Prettier::class), + collect([ + OneLinerSvg::class, + IgnoreCode::class, + ])->map(fn ($processor) => $app->make($processor))->all(), + ); + }); } } diff --git a/builds/pint b/builds/pint index c7fb3dd0..bbe0cfff 100755 Binary files a/builds/pint and b/builds/pint differ diff --git a/composer.json b/composer.json index c4dc18f3..406142dc 100644 --- a/composer.json +++ b/composer.json @@ -17,19 +17,19 @@ ], "require": { "php": "^8.1.0", + "ext-dom": "*", "ext-json": "*", "ext-mbstring": "*", - "ext-tokenizer": "*", - "ext-xml": "*" + "ext-tokenizer": "*" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.52.1", - "illuminate/view": "^10.48.4", - "larastan/larastan": "^2.9.2", + "friendsofphp/php-cs-fixer": "^3.53.0", + "illuminate/view": "^10.48.7", + "larastan/larastan": "^2.9.4", "laravel-zero/framework": "^10.3.0", "mockery/mockery": "^1.6.11", "nunomaduro/termwind": "^1.15.1", - "pestphp/pest": "^2.34.5" + "pestphp/pest": "^2.34.7" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 6569587d..95651d38 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b6a1b1eb8c6d09a12be943467228fd61", + "content-hash": "c7adcdc906b46d1dd8d669567346cbaf", "packages": [], "packages-dev": [ { @@ -777,16 +777,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.52.1", + "version": "v3.53.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "6e77207f0d851862ceeb6da63e6e22c01b1587bc" + "reference": "69a19093a9ded8d1baac62ed6c009b8bc148d008" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/6e77207f0d851862ceeb6da63e6e22c01b1587bc", - "reference": "6e77207f0d851862ceeb6da63e6e22c01b1587bc", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/69a19093a9ded8d1baac62ed6c009b8bc148d008", + "reference": "69a19093a9ded8d1baac62ed6c009b8bc148d008", "shasum": "" }, "require": { @@ -810,6 +810,7 @@ }, "require-dev": { "facile-it/paraunit": "^1.3 || ^2.0", + "infection/infection": "^0.27.11", "justinrainbow/json-schema": "^5.2", "keradus/cli-executor": "^2.1", "mikey179/vfsstream": "^1.6.11", @@ -857,7 +858,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.52.1" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.53.0" }, "funding": [ { @@ -865,7 +866,7 @@ "type": "github" } ], - "time": "2024-03-19T21:02:43+00:00" + "time": "2024-04-08T15:03:00+00:00" }, { "name": "fruitcake/php-cors", @@ -1139,7 +1140,7 @@ }, { "name": "illuminate/bus", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/bus.git", @@ -1192,7 +1193,7 @@ }, { "name": "illuminate/cache", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/cache.git", @@ -1254,7 +1255,7 @@ }, { "name": "illuminate/collections", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", @@ -1309,7 +1310,7 @@ }, { "name": "illuminate/conditionable", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", @@ -1355,7 +1356,7 @@ }, { "name": "illuminate/config", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/config.git", @@ -1403,16 +1404,16 @@ }, { "name": "illuminate/console", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/console.git", - "reference": "f6f9b944ef0f59dd331350bdd1e720c850946bb1" + "reference": "d001036218ea5fbb382ee5c845292b067ea8b46f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/console/zipball/f6f9b944ef0f59dd331350bdd1e720c850946bb1", - "reference": "f6f9b944ef0f59dd331350bdd1e720c850946bb1", + "url": "https://api.github.com/repos/illuminate/console/zipball/d001036218ea5fbb382ee5c845292b067ea8b46f", + "reference": "d001036218ea5fbb382ee5c845292b067ea8b46f", "shasum": "" }, "require": { @@ -1464,11 +1465,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-03-11T21:46:09+00:00" + "time": "2024-03-21T13:10:17+00:00" }, { "name": "illuminate/container", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/container.git", @@ -1519,7 +1520,7 @@ }, { "name": "illuminate/contracts", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -1636,7 +1637,7 @@ }, { "name": "illuminate/events", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/events.git", @@ -1691,7 +1692,7 @@ }, { "name": "illuminate/filesystem", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/filesystem.git", @@ -1758,7 +1759,7 @@ }, { "name": "illuminate/http", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/http.git", @@ -1818,7 +1819,7 @@ }, { "name": "illuminate/macroable", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -1864,7 +1865,7 @@ }, { "name": "illuminate/pipeline", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/pipeline.git", @@ -1912,7 +1913,7 @@ }, { "name": "illuminate/process", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/process.git", @@ -1963,7 +1964,7 @@ }, { "name": "illuminate/session", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/session.git", @@ -2020,16 +2021,16 @@ }, { "name": "illuminate/support", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "980d80017e859c8b1720892d952516e8c0b6708f" + "reference": "ee3a1aaed36d916654ce0ae09dfbd38644a4f582" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/980d80017e859c8b1720892d952516e8c0b6708f", - "reference": "980d80017e859c8b1720892d952516e8c0b6708f", + "url": "https://api.github.com/repos/illuminate/support/zipball/ee3a1aaed36d916654ce0ae09dfbd38644a4f582", + "reference": "ee3a1aaed36d916654ce0ae09dfbd38644a4f582", "shasum": "" }, "require": { @@ -2087,11 +2088,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-03-11T21:46:45+00:00" + "time": "2024-04-07T17:47:33+00:00" }, { "name": "illuminate/testing", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/testing.git", @@ -2150,7 +2151,7 @@ }, { "name": "illuminate/view", - "version": "v10.48.4", + "version": "v10.48.7", "source": { "type": "git", "url": "https://github.com/illuminate/view.git", @@ -2376,16 +2377,16 @@ }, { "name": "larastan/larastan", - "version": "v2.9.2", + "version": "v2.9.4", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "a79b46b96060504b400890674b83f66aa7f5db6d" + "reference": "3e7b1217c0021c29727a6df078830d4ef908f3bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/a79b46b96060504b400890674b83f66aa7f5db6d", - "reference": "a79b46b96060504b400890674b83f66aa7f5db6d", + "url": "https://api.github.com/repos/larastan/larastan/zipball/3e7b1217c0021c29727a6df078830d4ef908f3bf", + "reference": "3e7b1217c0021c29727a6df078830d4ef908f3bf", "shasum": "" }, "require": { @@ -2398,15 +2399,15 @@ "illuminate/pipeline": "^9.52.16 || ^10.28.0 || ^11.0", "illuminate/support": "^9.52.16 || ^10.28.0 || ^11.0", "php": "^8.0.2", - "phpmyadmin/sql-parser": "^5.8.2", - "phpstan/phpstan": "^1.10.50" + "phpmyadmin/sql-parser": "^5.9.0", + "phpstan/phpstan": "^1.10.66" }, "require-dev": { "doctrine/coding-standard": "^12.0", - "nikic/php-parser": "^4.17.1", - "orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.0", - "orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.0", - "phpunit/phpunit": "^9.6.13 || ^10.5" + "nikic/php-parser": "^4.19.1", + "orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.2", + "orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.3", + "phpunit/phpunit": "^9.6.13 || ^10.5.16" }, "suggest": { "orchestra/testbench": "Using Larastan for analysing a package needs Testbench" @@ -2454,7 +2455,7 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v2.9.2" + "source": "https://github.com/larastan/larastan/tree/v2.9.4" }, "funding": [ { @@ -2474,7 +2475,7 @@ "type": "patreon" } ], - "time": "2024-02-27T03:16:03+00:00" + "time": "2024-04-14T14:47:58+00:00" }, { "name": "laravel-zero/foundation", @@ -2630,16 +2631,16 @@ }, { "name": "laravel/prompts", - "version": "v0.1.17", + "version": "v0.1.18", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5" + "reference": "3b5e6b03f1f1175574b5a32331d99c9819da9848" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5", - "reference": "8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5", + "url": "https://api.github.com/repos/laravel/prompts/zipball/3b5e6b03f1f1175574b5a32331d99c9819da9848", + "reference": "3b5e6b03f1f1175574b5a32331d99c9819da9848", "shasum": "" }, "require": { @@ -2681,22 +2682,22 @@ ], "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.1.17" + "source": "https://github.com/laravel/prompts/tree/v0.1.18" }, - "time": "2024-03-13T16:05:43+00:00" + "time": "2024-04-04T17:41:50+00:00" }, { "name": "league/flysystem", - "version": "3.26.0", + "version": "3.27.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "072735c56cc0da00e10716dd90d5a7f7b40b36be" + "reference": "4729745b1ab737908c7d055148c9a6b3e959832f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/072735c56cc0da00e10716dd90d5a7f7b40b36be", - "reference": "072735c56cc0da00e10716dd90d5a7f7b40b36be", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4729745b1ab737908c7d055148c9a6b3e959832f", + "reference": "4729745b1ab737908c7d055148c9a6b3e959832f", "shasum": "" }, "require": { @@ -2761,7 +2762,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.26.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.27.0" }, "funding": [ { @@ -2773,7 +2774,7 @@ "type": "github" } ], - "time": "2024-03-25T11:49:53+00:00" + "time": "2024-04-07T19:17:50+00:00" }, { "name": "league/flysystem-local", @@ -3295,16 +3296,16 @@ }, { "name": "nunomaduro/laravel-console-summary", - "version": "v1.11.0", + "version": "v1.11.1", "source": { "type": "git", "url": "https://github.com/nunomaduro/laravel-console-summary.git", - "reference": "14834db07c9900f8228098d7c345dece45c4c3d9" + "reference": "2e3cf7b261697eed3fdf87a66be4470d32b405bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/laravel-console-summary/zipball/14834db07c9900f8228098d7c345dece45c4c3d9", - "reference": "14834db07c9900f8228098d7c345dece45c4c3d9", + "url": "https://api.github.com/repos/nunomaduro/laravel-console-summary/zipball/2e3cf7b261697eed3fdf87a66be4470d32b405bd", + "reference": "2e3cf7b261697eed3fdf87a66be4470d32b405bd", "shasum": "" }, "require": { @@ -3353,29 +3354,29 @@ "issues": "https://github.com/nunomaduro/laravel-console-summary/issues", "source": "https://github.com/nunomaduro/laravel-console-summary" }, - "time": "2024-03-05T09:24:48+00:00" + "time": "2024-04-09T08:41:54+00:00" }, { "name": "nunomaduro/laravel-console-task", - "version": "v1.8.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/laravel-console-task.git", - "reference": "e49e7be261a7b7329c4538777489b355fb234bde" + "reference": "02b2a550318fda3355e45763885e30b4e650bc1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/laravel-console-task/zipball/e49e7be261a7b7329c4538777489b355fb234bde", - "reference": "e49e7be261a7b7329c4538777489b355fb234bde", + "url": "https://api.github.com/repos/nunomaduro/laravel-console-task/zipball/02b2a550318fda3355e45763885e30b4e650bc1b", + "reference": "02b2a550318fda3355e45763885e30b4e650bc1b", "shasum": "" }, "require": { - "illuminate/console": "^9.0|^10.0", - "illuminate/support": "^9.0|^10.0", + "illuminate/console": "^10.0|^11.0", + "illuminate/support": "^10.0|^11.0", "php": "^8.1" }, "require-dev": { - "pestphp/pest": "^1.22.3" + "pestphp/pest": "^2.34" }, "type": "library", "extra": { @@ -3415,20 +3416,20 @@ "issues": "https://github.com/nunomaduro/laravel-console-task/issues", "source": "https://github.com/nunomaduro/laravel-console-task" }, - "time": "2023-01-11T15:16:19+00:00" + "time": "2024-04-11T07:51:10+00:00" }, { "name": "nunomaduro/laravel-desktop-notifier", - "version": "v2.8.0", + "version": "v2.8.1", "source": { "type": "git", "url": "https://github.com/nunomaduro/laravel-desktop-notifier.git", - "reference": "d9935c73670f368032d84092a554417d71ee2233" + "reference": "9937f1f8898077ad6d058c03ecee39d6eae7eb39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/laravel-desktop-notifier/zipball/d9935c73670f368032d84092a554417d71ee2233", - "reference": "d9935c73670f368032d84092a554417d71ee2233", + "url": "https://api.github.com/repos/nunomaduro/laravel-desktop-notifier/zipball/9937f1f8898077ad6d058c03ecee39d6eae7eb39", + "reference": "9937f1f8898077ad6d058c03ecee39d6eae7eb39", "shasum": "" }, "require": { @@ -3483,9 +3484,9 @@ ], "support": { "issues": "https://github.com/nunomaduro/laravel-desktop-notifier/issues", - "source": "https://github.com/nunomaduro/laravel-desktop-notifier/tree/v2.8.0" + "source": "https://github.com/nunomaduro/laravel-desktop-notifier/tree/v2.8.1" }, - "time": "2024-03-05T13:34:36+00:00" + "time": "2024-04-06T06:39:11+00:00" }, { "name": "nunomaduro/termwind", @@ -3575,16 +3576,16 @@ }, { "name": "pestphp/pest", - "version": "v2.34.6", + "version": "v2.34.7", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "680111fb1e7175a5010b73c115edef58ceef303e" + "reference": "a7a3e4240e341d0fee1c54814ce18adc26ce5a76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/680111fb1e7175a5010b73c115edef58ceef303e", - "reference": "680111fb1e7175a5010b73c115edef58ceef303e", + "url": "https://api.github.com/repos/pestphp/pest/zipball/a7a3e4240e341d0fee1c54814ce18adc26ce5a76", + "reference": "a7a3e4240e341d0fee1c54814ce18adc26ce5a76", "shasum": "" }, "require": { @@ -3594,10 +3595,10 @@ "pestphp/pest-plugin": "^2.1.1", "pestphp/pest-plugin-arch": "^2.7.0", "php": "^8.1.0", - "phpunit/phpunit": "^10.5.16" + "phpunit/phpunit": "^10.5.17" }, "conflict": { - "phpunit/phpunit": ">10.5.16", + "phpunit/phpunit": ">10.5.17", "sebastian/exporter": "<5.1.0", "webmozart/assert": "<1.11.0" }, @@ -3667,7 +3668,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v2.34.6" + "source": "https://github.com/pestphp/pest/tree/v2.34.7" }, "funding": [ { @@ -3679,7 +3680,7 @@ "type": "github" } ], - "time": "2024-03-28T11:36:46+00:00" + "time": "2024-04-05T07:44:17+00:00" }, { "name": "pestphp/pest-plugin", @@ -3995,28 +3996,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", + "version": "5.4.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + "reference": "298d2febfe79d03fe714eb871d5538da55205b1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/298d2febfe79d03fe714eb871d5538da55205b1a", + "reference": "298d2febfe79d03fe714eb871d5538da55205b1a", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.1", "ext-filter": "*", - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7", "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" + "mockery/mockery": "~1.3.5", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.13" }, "type": "library", "extra": { @@ -4040,15 +4048,15 @@ }, { "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" + "email": "opensource@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.0" }, - "time": "2021-10-19T17:43:47+00:00" + "time": "2024-04-09T21:13:58+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -4273,16 +4281,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.27.0", + "version": "1.28.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "86e4d5a4b036f8f0be1464522f4c6b584c452757" + "reference": "cd06d6b1a1b3c75b0b83f97577869fd85a3cd4fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/86e4d5a4b036f8f0be1464522f4c6b584c452757", - "reference": "86e4d5a4b036f8f0be1464522f4c6b584c452757", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/cd06d6b1a1b3c75b0b83f97577869fd85a3cd4fb", + "reference": "cd06d6b1a1b3c75b0b83f97577869fd85a3cd4fb", "shasum": "" }, "require": { @@ -4314,9 +4322,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.27.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.28.0" }, - "time": "2024-03-21T13:14:53+00:00" + "time": "2024-04-03T18:51:33+00:00" }, { "name": "phpstan/phpstan", @@ -4703,16 +4711,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.16", + "version": "10.5.17", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "18f8d4a5f52b61fdd9370aaae3167daa0eeb69cd" + "reference": "c1f736a473d21957ead7e94fcc029f571895abf5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/18f8d4a5f52b61fdd9370aaae3167daa0eeb69cd", - "reference": "18f8d4a5f52b61fdd9370aaae3167daa0eeb69cd", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c1f736a473d21957ead7e94fcc029f571895abf5", + "reference": "c1f736a473d21957ead7e94fcc029f571895abf5", "shasum": "" }, "require": { @@ -4784,7 +4792,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.16" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.17" }, "funding": [ { @@ -4800,7 +4808,7 @@ "type": "tidelift" } ], - "time": "2024-03-28T10:08:10+00:00" + "time": "2024-04-05T04:39:01+00:00" }, { "name": "psr/clock", @@ -6153,16 +6161,16 @@ }, { "name": "symfony/console", - "version": "v6.4.4", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0d9e4eb5ad413075624378f474c4167ea202de78" + "reference": "a2708a5da5c87d1d0d52937bdeac625df659e11f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0d9e4eb5ad413075624378f474c4167ea202de78", - "reference": "0d9e4eb5ad413075624378f474c4167ea202de78", + "url": "https://api.github.com/repos/symfony/console/zipball/a2708a5da5c87d1d0d52937bdeac625df659e11f", + "reference": "a2708a5da5c87d1d0d52937bdeac625df659e11f", "shasum": "" }, "require": { @@ -6227,7 +6235,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.4" + "source": "https://github.com/symfony/console/tree/v6.4.6" }, "funding": [ { @@ -6243,7 +6251,7 @@ "type": "tidelift" } ], - "time": "2024-02-22T20:27:10+00:00" + "time": "2024-03-29T19:07:53+00:00" }, { "name": "symfony/deprecation-contracts", @@ -6314,16 +6322,16 @@ }, { "name": "symfony/error-handler", - "version": "v6.4.4", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "c725219bdf2afc59423c32793d5019d2a904e13a" + "reference": "64db1c1802e3a4557e37ba33031ac39f452ac5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/c725219bdf2afc59423c32793d5019d2a904e13a", - "reference": "c725219bdf2afc59423c32793d5019d2a904e13a", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/64db1c1802e3a4557e37ba33031ac39f452ac5d4", + "reference": "64db1c1802e3a4557e37ba33031ac39f452ac5d4", "shasum": "" }, "require": { @@ -6369,7 +6377,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.4.4" + "source": "https://github.com/symfony/error-handler/tree/v6.4.6" }, "funding": [ { @@ -6385,7 +6393,7 @@ "type": "tidelift" } ], - "time": "2024-02-22T20:27:10+00:00" + "time": "2024-03-19T11:56:30+00:00" }, { "name": "symfony/event-dispatcher", @@ -6469,16 +6477,16 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.4.0", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" + "reference": "4e64b49bf370ade88e567de29465762e316e4224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", - "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/4e64b49bf370ade88e567de29465762e316e4224", + "reference": "4e64b49bf370ade88e567de29465762e316e4224", "shasum": "" }, "require": { @@ -6525,7 +6533,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.2" }, "funding": [ { @@ -6541,20 +6549,20 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-01-23T14:51:35+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.3", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb" + "reference": "9919b5509ada52cc7f66f9a35c86a4a29955c9d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb", - "reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/9919b5509ada52cc7f66f9a35c86a4a29955c9d3", + "reference": "9919b5509ada52cc7f66f9a35c86a4a29955c9d3", "shasum": "" }, "require": { @@ -6588,7 +6596,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.3" + "source": "https://github.com/symfony/filesystem/tree/v6.4.6" }, "funding": [ { @@ -6604,7 +6612,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-03-21T19:36:20+00:00" }, { "name": "symfony/finder", @@ -6749,16 +6757,16 @@ }, { "name": "symfony/http-kernel", - "version": "v6.4.5", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "f6947cb939d8efee137797382cb4db1af653ef75" + "reference": "060038863743fd0cd982be06acecccf246d35653" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f6947cb939d8efee137797382cb4db1af653ef75", - "reference": "f6947cb939d8efee137797382cb4db1af653ef75", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/060038863743fd0cd982be06acecccf246d35653", + "reference": "060038863743fd0cd982be06acecccf246d35653", "shasum": "" }, "require": { @@ -6842,7 +6850,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.5" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.6" }, "funding": [ { @@ -6858,20 +6866,20 @@ "type": "tidelift" } ], - "time": "2024-03-04T21:00:47+00:00" + "time": "2024-04-03T06:09:15+00:00" }, { "name": "symfony/mime", - "version": "v6.4.3", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "5017e0a9398c77090b7694be46f20eb796262a34" + "reference": "14762b86918823cb42e3558cdcca62e58b5227fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/5017e0a9398c77090b7694be46f20eb796262a34", - "reference": "5017e0a9398c77090b7694be46f20eb796262a34", + "url": "https://api.github.com/repos/symfony/mime/zipball/14762b86918823cb42e3558cdcca62e58b5227fe", + "reference": "14762b86918823cb42e3558cdcca62e58b5227fe", "shasum": "" }, "require": { @@ -6892,6 +6900,7 @@ "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.4|^7.0", "symfony/property-access": "^5.4|^6.0|^7.0", "symfony/property-info": "^5.4|^6.0|^7.0", "symfony/serializer": "^6.3.2|^7.0" @@ -6926,7 +6935,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.3" + "source": "https://github.com/symfony/mime/tree/v6.4.6" }, "funding": [ { @@ -6942,7 +6951,7 @@ "type": "tidelift" } ], - "time": "2024-01-30T08:32:12+00:00" + "time": "2024-03-21T19:36:20+00:00" }, { "name": "symfony/options-resolver", @@ -7782,16 +7791,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.4.1", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" + "reference": "11bbf19a0fb7b36345861e85c5768844c552906e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/11bbf19a0fb7b36345861e85c5768844c552906e", + "reference": "11bbf19a0fb7b36345861e85c5768844c552906e", "shasum": "" }, "require": { @@ -7844,7 +7853,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.4.2" }, "funding": [ { @@ -7860,7 +7869,7 @@ "type": "tidelift" } ], - "time": "2023-12-26T14:02:43+00:00" + "time": "2023-12-19T21:51:00+00:00" }, { "name": "symfony/stopwatch", @@ -8107,16 +8116,16 @@ }, { "name": "symfony/translation-contracts", - "version": "v3.4.1", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "06450585bf65e978026bda220cdebca3f867fde7" + "reference": "43810bdb2ddb5400e5c5e778e27b210a0ca83b6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/06450585bf65e978026bda220cdebca3f867fde7", - "reference": "06450585bf65e978026bda220cdebca3f867fde7", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/43810bdb2ddb5400e5c5e778e27b210a0ca83b6b", + "reference": "43810bdb2ddb5400e5c5e778e27b210a0ca83b6b", "shasum": "" }, "require": { @@ -8165,7 +8174,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.4.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.4.2" }, "funding": [ { @@ -8181,20 +8190,20 @@ "type": "tidelift" } ], - "time": "2023-12-26T14:02:43+00:00" + "time": "2024-01-23T14:51:35+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.4", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "b439823f04c98b84d4366c79507e9da6230944b1" + "reference": "95bd2706a97fb875185b51ecaa6112ec184233d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b439823f04c98b84d4366c79507e9da6230944b1", - "reference": "b439823f04c98b84d4366c79507e9da6230944b1", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/95bd2706a97fb875185b51ecaa6112ec184233d4", + "reference": "95bd2706a97fb875185b51ecaa6112ec184233d4", "shasum": "" }, "require": { @@ -8250,7 +8259,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.4" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.6" }, "funding": [ { @@ -8266,7 +8275,7 @@ "type": "tidelift" } ], - "time": "2024-02-15T11:23:52+00:00" + "time": "2024-03-19T11:56:30+00:00" }, { "name": "ta-tikoma/phpunit-architecture-test", @@ -8601,10 +8610,10 @@ "prefer-lowest": false, "platform": { "php": "^8.1.0", + "ext-dom": "*", "ext-json": "*", "ext-mbstring": "*", - "ext-tokenizer": "*", - "ext-xml": "*" + "ext-tokenizer": "*" }, "platform-dev": [], "platform-overrides": { diff --git a/node_sandbox/.blade.format.json b/node_sandbox/.blade.format.json new file mode 100644 index 00000000..55c97dda --- /dev/null +++ b/node_sandbox/.blade.format.json @@ -0,0 +1,8 @@ +{ + "useLaravelPint": true, + "pintCommand": "../builds/pint {file}", + "forceMultilineAttributesToNewLine": true, + "minAttributeWrapping": 1, + "indentRootHtml": false, + "respectHtmlWhitespaceSensitivity": true +} diff --git a/node_sandbox/package.json b/node_sandbox/package.json new file mode 100644 index 00000000..a78ddbc2 --- /dev/null +++ b/node_sandbox/package.json @@ -0,0 +1,7 @@ +{ + "devDependencies": { + "prettier": "^3.2.5", + "prettier-plugin-blade-debug": "^2.1.14", + "prettier-plugin-tailwindcss": "^0.5.13" + } +} diff --git a/node_sandbox/prettier-worker.js b/node_sandbox/prettier-worker.js new file mode 100644 index 00000000..5a42da0c --- /dev/null +++ b/node_sandbox/prettier-worker.js @@ -0,0 +1,18 @@ +const prettier = require("prettier"); +const fs = require("fs").promises; +const options = require(__dirname + '/prettierrc.json'); +process.stdin.setEncoding('utf-8'); + +process.stdin.on('data', async function (input) { + try { + const { path, content } = JSON.parse(input); + + const formatted = await prettier.format(content, { ...options, filepath: path.trim() }); + + process.stdout.write( + `[PINT_BLADE_PRETTIER_WORKER_START]${formatted}[PINT_BLADE_PRETTIER_WORKER_END]` + ); + } catch (error) { + process.stderr.write(`${error.message}`); + } +}); diff --git a/node_sandbox/prettierrc.json b/node_sandbox/prettierrc.json new file mode 100644 index 00000000..58915bf4 --- /dev/null +++ b/node_sandbox/prettierrc.json @@ -0,0 +1,23 @@ +{ + "semi": false, + "singleQuote": true, + "singleAttributePerLine": true, + "htmlWhitespaceSensitivity": "css", + "printWidth": 150, + "plugins": [ + "prettier-plugin-blade-debug", + "prettier-plugin-tailwindcss" + ], + "overrides": [ + { + "files": [ + "*.blade.php" + ], + "options": { + "singleQuote": true, + "parser": "blade", + "tabWidth": 4 + } + } + ] +} diff --git a/resources/presets/laravel.php b/resources/presets/laravel.php index f724ca32..df44c62c 100644 --- a/resources/presets/laravel.php +++ b/resources/presets/laravel.php @@ -1,6 +1,7 @@ true, @@ -211,4 +212,8 @@ 'identical' => false, 'less_and_greater' => false, ], + + // Pint Specific Rules + + 'Laravel/blade' => resolve(InputInterface::class)->getOption('blade'), ]); diff --git a/resources/views/issue/show.blade.php b/resources/views/issue/show.blade.php index a657d7ab..f2f38822 100644 --- a/resources/views/issue/show.blade.php +++ b/resources/views/issue/show.blade.php @@ -1,4 +1,4 @@ -
+
{{ $issue->symbol() }} @@ -7,7 +7,7 @@ {{ $issue->file() }} - + {{ $issue->description($testing) }}
diff --git a/resources/views/summary.blade.php b/resources/views/summary.blade.php index 71e94498..5a1982b9 100644 --- a/resources/views/summary.blade.php +++ b/resources/views/summary.blade.php @@ -1,8 +1,6 @@ -
+
- - - + {{ $preset }} @@ -12,46 +10,44 @@
- @php $fixableErrors = $issues->filter->fixable(); $nonFixableErrors = $issues->reject->fixable(); @endphp - @if($issues->count() == 0) - - PASS - - @elseif($nonFixableErrors->count() == 0 && ! $testing) - - FIXED - + @if ($issues->count() == 0) + PASS + @elseif ($nonFixableErrors->count() == 0 && ! $testing) + FIXED @else - - FAIL - + FAIL @endif - + - {{ $totalFiles }} {{ str('file')->plural($totalFiles) }} + {{ $totalFiles }} + {{ str('file')->plural($totalFiles) }} @if ($nonFixableErrors->isNotEmpty()) - - , {{ $nonFixableErrors->count() }} {{ str('error')->plural($nonFixableErrors) }} - + + , {{ $nonFixableErrors->count() }} + {{ str('error')->plural($nonFixableErrors) }} + @endif @if ($fixableErrors->isNotEmpty()) - - @if ($testing) - , {{ $fixableErrors->count() }} style {{ str('issue')->plural($fixableErrors) }} - @else - , {{ $fixableErrors->count() }} style {{ str('issue')->plural($fixableErrors) }} fixed - @endif - + + @if ($testing) + , {{ $fixableErrors->count() }} style + {{ str('issue')->plural($fixableErrors) }} + @else + , {{ $fixableErrors->count() }} style + {{ str('issue')->plural($fixableErrors) }} + fixed + @endif + @endif
diff --git a/tests/Fixtures/fake.blade.php b/tests/Fixtures/fake.blade.php new file mode 100644 index 00000000..e69de29b diff --git a/tests/Pest.php b/tests/Pest.php index ba5ead48..ca51ef8e 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -18,7 +18,7 @@ use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; -uses(Tests\TestCase::class)->in('Feature'); +uses(Tests\TestCase::class)->in('Feature', 'Unit'); /* |-------------------------------------------------------------------------- diff --git a/tests/Unit/Fixers/Processors/IgnoreCodeTest.php b/tests/Unit/Fixers/Processors/IgnoreCodeTest.php new file mode 100644 index 00000000..1b696669 --- /dev/null +++ b/tests/Unit/Fixers/Processors/IgnoreCodeTest.php @@ -0,0 +1,569 @@ +format( + __DIR__.'../../../Fixtures/fake.blade.php', + $before, + ); + + expect($formatted)->toBe($after); +})->with([ + [ + <<<'HTML' + + + + + HTML, + <<<'HTML' + + + + + HTML, + ], + [ + <<<'HTML' + + + + + HTML, + <<<'HTML' + + + + + HTML, + ], + [ + <<<'HTML' + + + + + HTML, + <<<'HTML' + + + + + HTML, + ], + [ + <<<'HTML' + + + + + HTML, + <<<'HTML' + + + + + HTML, + ], +]); + +test('text', function ($before, $after) { + if (! str_contains($before, '')) { + expect(true)->toBeTrue(); + + return; + } + + $formatted = resolve(BladeFormatter::class)->format( + __DIR__.'../../../Fixtures/fake.blade.php', + $before, + ); + + expect($formatted)->toBe($after); +})->with([ + [ + <<<'HTML' + +

foo

+ + + HTML, + <<<'HTML' + +

foo

+ + + HTML, + ], + [ + <<<'HTML' + +

foo barbarbarbarbarbarbar

+ + + HTML, + <<<'HTML' + +

foo barbarbarbarbarbarbar

+ + + HTML, + <<<'HTML' + +

barbarbarbarbarbarbarbarbarbarbarbarbarbar

+ + + HTML, + <<<'HTML' + +

barbarbarbarbarbarbarbarbarbarbarbarbarbar

+ + + HTML, + <<<'HTML' + +

+ foo baz

bar

barbarbarbarbarbarbarbarbarbarbarbarbarfoo. +

+ + + HTML, + <<<'HTML' + +

+ foo baz

bar

barbarbarbarbarbarbarbarbarbarbarbarbarfoo. +

+ + + HTML, + ], + [ + << + + + + + + Laravel + + + + + + + + + + + + + + HTML, + << + + + + + + Laravel + + + + + + + + + + + + + + HTML, + ], +])->only(); diff --git a/tests/Unit/Fixers/Processors/OneLinerSvgTest.php b/tests/Unit/Fixers/Processors/OneLinerSvgTest.php new file mode 100644 index 00000000..f43e1ca6 --- /dev/null +++ b/tests/Unit/Fixers/Processors/OneLinerSvgTest.php @@ -0,0 +1,164 @@ +format( + __DIR__.'../../../Fixtures/fake.blade.php', + $before, + ); + + expect($formatted)->toBe($after); +})->with([ + [ + <<<'SVG' +
+ +
+
+ +
+ + SVG, + <<<'SVG' +
+ +
+
+ +
+ + SVG, + ], + [ + <<<'SVG' + + + + + + + + SVG, + <<<'SVG' + + + + + + + + SVG, + ], + [ + <<<'SVG' + + + + + + + + + + SVG, + <<<'SVG' + + + + + + + + SVG, + ], + [ + <<<'SVG' + + + + + + + + + SVG, + <<<'SVG' + + + + + SVG, + ], + [ + <<<'SVG' + + + + + + SVG, + <<<'SVG' + + + + + SVG, + ], + [ + <<<'SVG' +
+ +
+ + SVG, + <<<'SVG' +
+ +
+ + SVG, + ], +]);