From 8c8b608c84300c7db06653aa4a6e0046cff12f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFck=20Piera?= Date: Fri, 15 Nov 2024 14:20:18 +0100 Subject: [PATCH] Add official support strings and var-dumper functions --- CHANGELOG.md | 1 + doc/reference.md | 13 +++++ src/Stub/StubsGenerator.php | 20 ++++++- .../fixtures/global-namespace/expected.php | 34 +++++++++++ .../Stub/fixtures/global-namespace/input1.php | 38 ++++++++++++ .../Stub/fixtures/global-namespace/input2.php | 58 +++++++++++++++++++ 6 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 tests/Stub/fixtures/global-namespace/expected.php create mode 100644 tests/Stub/fixtures/global-namespace/input1.php create mode 100644 tests/Stub/fixtures/global-namespace/input2.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e99d232a..27ceb35a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * Better rendering of run errors * Add `check()` function to ensure requirements are met * Add `ProblemException` to handle problems in a more structured way +* Add official support for symfony/string and symfony/var-dumper functions ### Internal diff --git a/doc/reference.md b/doc/reference.md index dac013a4..7f7c35f6 100644 --- a/doc/reference.md +++ b/doc/reference.md @@ -52,6 +52,19 @@ Castor provides the following built-in functions: - [`yaml_dump`](going-further/helpers/yaml.md) - [`yaml_parse`](going-further/helpers/yaml.md) +## Vendor helpers + +Some vendor helpers are also included natively in Castor: + +- Functions from symfony/string: + - [`u`](https://symfony.com/doc/current/string.html#method-reference) + - [`b`](https://symfony.com/doc/current/string.html#method-reference) + - [`s`](https://symfony.com/doc/current/string.html#method-reference) + +- Functions from symfony/var-dumper: + - [`dump`](https://symfony.com/doc/current/components/var_dumper.html#the-dump-function) + - [`dd`](https://symfony.com/doc/current/components/var_dumper.html#the-dump-function) + ## Attributes Castor provides the following attributes to register tasks, listener, etc: diff --git a/src/Stub/StubsGenerator.php b/src/Stub/StubsGenerator.php index 7488122a..2fe6c0d3 100644 --- a/src/Stub/StubsGenerator.php +++ b/src/Stub/StubsGenerator.php @@ -75,6 +75,12 @@ private function generateCastorStubs(string $dest): void \Symfony\Contracts\HttpClient\Exception\ExceptionInterface::class, \Symfony\Contracts\HttpClient\HttpClientInterface::class, \Symfony\Contracts\HttpClient\ResponseInterface::class, + \Symfony\Component\String\AbstractString::class, + \Symfony\Component\String\AbstractUnicodeString::class, + \Symfony\Component\String\ByteString::class, + \Symfony\Component\String\CodePointString::class, + \Symfony\Component\String\Exception\ExceptionInterface::class, + \Symfony\Component\String\UnicodeString::class, ]; foreach ($frequentlyUsedClasses as $class) { @@ -86,6 +92,10 @@ private function generateCastorStubs(string $dest): void $files[] = $file; } + // Expose some functions provided by vendors + $files[] = "{$basePath}/vendor/symfony/string/Resources/functions.php"; + $files[] = "{$basePath}/vendor/symfony/var-dumper/Resources/functions/dump.php"; + $stmts = $this->doGenerate($files); array_unshift($stmts, new Stmt\Nop([ @@ -127,9 +137,11 @@ private function doGenerate(array $files): array $phpDocNodeTraverser = new PhpDocNodeTraverser([new PhpDocNodeVisitor($nameResolver)]); + $nodeVisitor = new NodeVisitor($phpDocNodeTraverser, $lexer, $phpDocParser); + $traverser = new NodeTraverser(); $traverser->addVisitor($nameResolver); - $traverser->addVisitor(new NodeVisitor($phpDocNodeTraverser, $lexer, $phpDocParser)); + $traverser->addVisitor($nodeVisitor); // Parse all files one by one, traverse the related AST then merge all statements foreach ($files as $file) { @@ -137,6 +149,12 @@ private function doGenerate(array $files): array if (!$fileStmts) { continue; } + + $firstStmt = $fileStmts[0]; + if (!$firstStmt instanceof Stmt\Namespace_) { + $fileStmts = [new Stmt\Namespace_(null, $fileStmts)]; + } + $stmts = array_merge($stmts, $traverser->traverse($fileStmts)); } diff --git a/tests/Stub/fixtures/global-namespace/expected.php b/tests/Stub/fixtures/global-namespace/expected.php new file mode 100644 index 00000000..d6683ea2 --- /dev/null +++ b/tests/Stub/fixtures/global-namespace/expected.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String; + +if (!\function_exists(u::class)) { + function u(?string $string = ''): UnicodeString + { + return new UnicodeString($string ?? ''); + } +} + +if (!\function_exists(b::class)) { + function b(?string $string = ''): ByteString + { + return new ByteString($string ?? ''); + } +} + +if (!\function_exists(s::class)) { + /** + * @return UnicodeString|ByteString + */ + function s(?string $string = ''): AbstractString + { + $string ??= ''; + + return preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string); + } +} diff --git a/tests/Stub/fixtures/global-namespace/input2.php b/tests/Stub/fixtures/global-namespace/input2.php new file mode 100644 index 00000000..b3e3c784 --- /dev/null +++ b/tests/Stub/fixtures/global-namespace/input2.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Component\VarDumper\Caster\ScalarStub; +use Symfony\Component\VarDumper\VarDumper; + +if (!function_exists('dump')) { + function dump(mixed ...$vars): mixed + { + if (!$vars) { + VarDumper::dump(new ScalarStub('🐛')); + + return null; + } + + if (array_key_exists(0, $vars) && 1 === count($vars)) { + VarDumper::dump($vars[0]); + $k = 0; + } else { + foreach ($vars as $k => $v) { + VarDumper::dump($v, is_int($k) ? 1 + $k : $k); + } + } + + if (1 < count($vars)) { + return $vars; + } + + return $vars[$k]; + } +} + +if (!function_exists('dd')) { + function dd(mixed ...$vars): never + { + if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) && !headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + + if (array_key_exists(0, $vars) && 1 === count($vars)) { + VarDumper::dump($vars[0]); + } else { + foreach ($vars as $k => $v) { + VarDumper::dump($v, is_int($k) ? 1 + $k : $k); + } + } + + exit(1); + } +}