diff --git a/src/Tempest/Framework/Commands/MetaViewComponentCommand.php b/src/Tempest/Framework/Commands/MetaViewComponentCommand.php index ef9c5b0e14..b43d889a62 100644 --- a/src/Tempest/Framework/Commands/MetaViewComponentCommand.php +++ b/src/Tempest/Framework/Commands/MetaViewComponentCommand.php @@ -6,7 +6,6 @@ use Tempest\Console\ConsoleCommand; use Tempest\Console\HasConsole; use Tempest\Support\Arr\ImmutableArray; -use Tempest\Support\Str\ImmutableString; use Tempest\View\Slot; use Tempest\View\ViewComponent; use Tempest\View\ViewConfig; @@ -81,11 +80,17 @@ private function resolveSlots(ViewComponent $viewComponent): ImmutableArray private function resolveVariables(ViewComponent $viewComponent): ImmutableArray { return str($viewComponent->contents) - ->matchAll('/^\s*\*\s*@var.*$/m') - ->map(fn (array $matches) => str($matches[0])) - ->map(fn (ImmutableString $line) => $line->replaceRegex('/^\s*\*\s*@var\s*/', '')) - ->map(fn (ImmutableString $line) => $line->trim()) - ->map(fn (ImmutableString $line) => $line->explode(limit: 3)) + ->matchAll( + pattern: '/(?:^\s*\*|\/\*\*)[ \t]*@var[ \t]+(?[^\r\n]*?)[ \t]*(?:\*\/(?:\s*(?\$\w+)\s*=(?!=))?|\r?$)/m', + matches: ['declaration', 'assignee'], + ) + ->map(fn (array $matches) => [ + 'parts' => str($matches['declaration'])->explode(limit: 3), + 'assignee' => $matches['assignee'] ?? null, + ]) + // A one-line `@var` right before an assignment types a local variable, not an attribute. + ->filter(fn (array $match) => $match['assignee'] === null || $match['assignee'] !== ($match['parts'][1] ?? null)) + ->map(fn (array $match) => $match['parts']) ->mapWithKeys( fn (ImmutableArray $parts) => yield $parts[1] => [ 'type' => $parts[0], diff --git a/tests/Integration/Framework/Commands/MetaViewComponentCommandTest.php b/tests/Integration/Framework/Commands/MetaViewComponentCommandTest.php index 0b4621309b..b4b80f655d 100644 --- a/tests/Integration/Framework/Commands/MetaViewComponentCommandTest.php +++ b/tests/Integration/Framework/Commands/MetaViewComponentCommandTest.php @@ -61,4 +61,51 @@ public function show_meta_for_view_component(): void ], JSON); } + + #[Test] + public function show_variables_declared_in_one_line_docblock(): void + { + $this->console + ->call('meta:view-component x-with-variable') + ->assertSuccess() + ->assertSee(<<<'JSON' + "variables": [ + { + "type": "string", + "name": "$variable", + "attributeName": "variable", + "description": null + } + ] + JSON); + } + + #[Test] + public function show_description_of_one_line_docblock_variable(): void + { + $this->console + ->call('meta:view-component x-submit') + ->assertSuccess() + ->assertSee(<<<'JSON' + "variables": [ + { + "type": "null|string", + "name": "$label", + "attributeName": "label", + "description": "The submit button's label" + } + ] + JSON); + } + + #[Test] + public function ignore_one_line_docblock_typing_a_local_assignment(): void + { + $this->console + ->call('meta:view-component x-input') + ->assertSuccess() + ->assertSee('"name": "$default",') + ->assertNotSee('$formSession') + ->assertNotSee('$validator'); + } }