diff --git a/src/PhpGenerator/Attribute.php b/src/PhpGenerator/Attribute.php index bd112c5e..ddea1df5 100644 --- a/src/PhpGenerator/Attribute.php +++ b/src/PhpGenerator/Attribute.php @@ -13,7 +13,7 @@ /** - * PHP Attribute. + * Definition of a PHP attribute. */ final class Attribute { diff --git a/src/PhpGenerator/ClassLike.php b/src/PhpGenerator/ClassLike.php index 6d9c1e8b..9e5469d4 100644 --- a/src/PhpGenerator/ClassLike.php +++ b/src/PhpGenerator/ClassLike.php @@ -13,7 +13,7 @@ /** - * Class/Interface/Trait/Enum description. + * Base definition of class, interface, trait or enum type. */ abstract class ClassLike { @@ -21,19 +21,17 @@ abstract class ClassLike use Traits\CommentAware; use Traits\AttributeAware; - public const - VisibilityPublic = 'public', - VisibilityProtected = 'protected', - VisibilityPrivate = 'private'; + /** @deprecated use Visibility::Public */ + public const VisibilityPublic = Visibility::Public, + VISIBILITY_PUBLIC = Visibility::Public; - /** @deprecated use ClassLike::VisibilityPublic */ - public const VISIBILITY_PUBLIC = self::VisibilityPublic; + /** @deprecated use Visibility::Protected */ + public const VisibilityProtected = Visibility::Protected, + VISIBILITY_PROTECTED = Visibility::Protected; - /** @deprecated use ClassLike::VisibilityProtected */ - public const VISIBILITY_PROTECTED = self::VisibilityProtected; - - /** @deprecated use ClassLike::VisibilityPrivate */ - public const VISIBILITY_PRIVATE = self::VisibilityPrivate; + /** @deprecated use Visibility::Private */ + public const VisibilityPrivate = Visibility::Private, + VISIBILITY_PRIVATE = Visibility::Private; private ?PhpNamespace $namespace; private ?string $name; diff --git a/src/PhpGenerator/ClassType.php b/src/PhpGenerator/ClassType.php index 1877d163..1982e22a 100644 --- a/src/PhpGenerator/ClassType.php +++ b/src/PhpGenerator/ClassType.php @@ -13,7 +13,7 @@ /** - * Class description. + * Definition of a class with properties, methods, constants, traits and PHP attributes. * * @property-deprecated Method[] $methods * @property-deprecated Property[] $properties diff --git a/src/PhpGenerator/Closure.php b/src/PhpGenerator/Closure.php index 398e1491..1bacb2eb 100644 --- a/src/PhpGenerator/Closure.php +++ b/src/PhpGenerator/Closure.php @@ -13,7 +13,7 @@ /** - * Closure. + * Definition of a closure. * * @property-deprecated string $body */ diff --git a/src/PhpGenerator/Constant.php b/src/PhpGenerator/Constant.php index 8097dba5..8fbf5c42 100644 --- a/src/PhpGenerator/Constant.php +++ b/src/PhpGenerator/Constant.php @@ -13,7 +13,7 @@ /** - * Class constant. + * Definition of a class constant. */ final class Constant { diff --git a/src/PhpGenerator/EnumCase.php b/src/PhpGenerator/EnumCase.php index 226fd090..a7886e2e 100644 --- a/src/PhpGenerator/EnumCase.php +++ b/src/PhpGenerator/EnumCase.php @@ -13,7 +13,7 @@ /** - * Enum case. + * Definition of an enum case. */ final class EnumCase { diff --git a/src/PhpGenerator/EnumType.php b/src/PhpGenerator/EnumType.php index 8122a2ad..7fc09a11 100644 --- a/src/PhpGenerator/EnumType.php +++ b/src/PhpGenerator/EnumType.php @@ -13,7 +13,7 @@ /** - * Enum description. + * Definition of an enum with cases, methods, constants and traits. */ final class EnumType extends ClassLike { diff --git a/src/PhpGenerator/Extractor.php b/src/PhpGenerator/Extractor.php index 7ec3b3b7..2bb32624 100644 --- a/src/PhpGenerator/Extractor.php +++ b/src/PhpGenerator/Extractor.php @@ -209,7 +209,11 @@ public function enterNode(Node $node) } }; - if ($this->statements) { + if ( + $this->statements + && !$this->statements[0] instanceof Node\Stmt\ClassLike + && !$this->statements[0] instanceof Node\Stmt\Function_ + ) { $this->addCommentAndAttributes($phpFile, $this->statements[0]); } @@ -424,9 +428,9 @@ private function formatValue(Node\Expr $value, int $level): Literal private function toVisibility(int $flags): ?string { return match (true) { - (bool) ($flags & Node\Stmt\Class_::MODIFIER_PUBLIC) => ClassType::VisibilityPublic, - (bool) ($flags & Node\Stmt\Class_::MODIFIER_PROTECTED) => ClassType::VisibilityProtected, - (bool) ($flags & Node\Stmt\Class_::MODIFIER_PRIVATE) => ClassType::VisibilityPrivate, + (bool) ($flags & Node\Stmt\Class_::MODIFIER_PUBLIC) => Visibility::Public, + (bool) ($flags & Node\Stmt\Class_::MODIFIER_PROTECTED) => Visibility::Protected, + (bool) ($flags & Node\Stmt\Class_::MODIFIER_PRIVATE) => Visibility::Private, default => null, }; } diff --git a/src/PhpGenerator/Factory.php b/src/PhpGenerator/Factory.php index 61b24dca..7a187767 100644 --- a/src/PhpGenerator/Factory.php +++ b/src/PhpGenerator/Factory.php @@ -37,8 +37,8 @@ public function fromClassReflection( if ($materializeTraits !== null) { trigger_error(__METHOD__ . '() parameter $materializeTraits has been removed (is always false).', E_USER_DEPRECATED); } - if ($withBodies && $from->isAnonymous()) { - throw new Nette\NotSupportedException('The $withBodies parameter cannot be used for anonymous functions.'); + if ($withBodies && ($from->isAnonymous() || $from->isInternal())) { + throw new Nette\NotSupportedException('The $withBodies parameter cannot be used for anonymous or internal classes.'); } $enumIface = null; @@ -183,8 +183,8 @@ public function fromFunctionReflection(\ReflectionFunction $from, bool $withBody $function->setReturnType((string) $from->getReturnType()); if ($withBody) { - if ($from->isClosure()) { - throw new Nette\NotSupportedException('The $withBody parameter cannot be used for closures.'); + if ($from->isClosure() || $from->isInternal()) { + throw new Nette\NotSupportedException('The $withBody parameter cannot be used for closures or internal functions.'); } $function->setBody($this->getExtractor($from)->extractFunctionBody($from->name)); @@ -310,8 +310,8 @@ private function getAttributes($from): array private function getVisibility($from): string { return $from->isPrivate() - ? ClassLike::VisibilityPrivate - : ($from->isProtected() ? ClassLike::VisibilityProtected : ClassLike::VisibilityPublic); + ? Visibility::Private + : ($from->isProtected() ? Visibility::Protected : Visibility::Public); } diff --git a/src/PhpGenerator/GlobalFunction.php b/src/PhpGenerator/GlobalFunction.php index ae1e4f88..09581c51 100644 --- a/src/PhpGenerator/GlobalFunction.php +++ b/src/PhpGenerator/GlobalFunction.php @@ -13,7 +13,7 @@ /** - * Global function. + * Definition of a global function. * * @property-deprecated string $body */ diff --git a/src/PhpGenerator/InterfaceType.php b/src/PhpGenerator/InterfaceType.php index 5a2d61d3..72f2b562 100644 --- a/src/PhpGenerator/InterfaceType.php +++ b/src/PhpGenerator/InterfaceType.php @@ -13,7 +13,7 @@ /** - * Interface description. + * Definition of an interface with methods and constants. * * @property-deprecated Method[] $methods */ diff --git a/src/PhpGenerator/Method.php b/src/PhpGenerator/Method.php index 0596658c..5dbd4c3e 100644 --- a/src/PhpGenerator/Method.php +++ b/src/PhpGenerator/Method.php @@ -13,7 +13,7 @@ /** - * Class method. + * Definition of a class method. * * @property-deprecated string|null $body */ @@ -99,7 +99,7 @@ public function addPromotedParameter(string $name, mixed $defaultValue = null): /** @throws Nette\InvalidStateException */ public function validate(): void { - if ($this->abstract && ($this->final || $this->visibility === ClassLike::VisibilityPrivate)) { + if ($this->abstract && ($this->final || $this->visibility === Visibility::Private)) { throw new Nette\InvalidStateException("Method $this->name() cannot be abstract and final or private at the same time."); } } diff --git a/src/PhpGenerator/Parameter.php b/src/PhpGenerator/Parameter.php index 975d0449..51f0beb6 100644 --- a/src/PhpGenerator/Parameter.php +++ b/src/PhpGenerator/Parameter.php @@ -14,7 +14,7 @@ /** - * Function/Method parameter description. + * Definition of a function/method parameter. * * @property-deprecated mixed $defaultValue */ diff --git a/src/PhpGenerator/PhpFile.php b/src/PhpGenerator/PhpFile.php index 34142f5a..79947c1e 100644 --- a/src/PhpGenerator/PhpFile.php +++ b/src/PhpGenerator/PhpFile.php @@ -13,7 +13,7 @@ /** - * Instance of PHP file. + * Definition of a PHP file. * * Generates: * - opening tag (dumper->format('...?:', $attr->getArguments()); $args = Helpers::simplifyTaggedNames($args, $this->namespace); - $items[] = $this->printType($attr->getName(), nullable: false) . ($args ? "($args)" : ''); + $items[] = $this->printType($attr->getName(), nullable: false) . ($args === '' ? '' : "($args)"); $inline = $inline && !str_contains($args, "\n"); } diff --git a/src/PhpGenerator/PromotedParameter.php b/src/PhpGenerator/PromotedParameter.php index f9ae4efe..701d0864 100644 --- a/src/PhpGenerator/PromotedParameter.php +++ b/src/PhpGenerator/PromotedParameter.php @@ -13,7 +13,7 @@ /** - * Promoted parameter in constructor. + * Definition of a promoted constructor parameter. */ final class PromotedParameter extends Parameter { diff --git a/src/PhpGenerator/Property.php b/src/PhpGenerator/Property.php index 01529a0e..38738e40 100644 --- a/src/PhpGenerator/Property.php +++ b/src/PhpGenerator/Property.php @@ -14,7 +14,7 @@ /** - * Class property description. + * Definition of a class property. * * @property-deprecated mixed $value */ diff --git a/src/PhpGenerator/TraitType.php b/src/PhpGenerator/TraitType.php index 57621ad4..ee3740e5 100644 --- a/src/PhpGenerator/TraitType.php +++ b/src/PhpGenerator/TraitType.php @@ -13,7 +13,7 @@ /** - * Trait description. + * Definition of a trait with properties, methods, constants and traits. * * @property-deprecated Method[] $methods * @property-deprecated Property[] $properties diff --git a/src/PhpGenerator/TraitUse.php b/src/PhpGenerator/TraitUse.php index 170b09ef..e1889cf3 100644 --- a/src/PhpGenerator/TraitUse.php +++ b/src/PhpGenerator/TraitUse.php @@ -13,7 +13,7 @@ /** - * use Trait + * Definition of a trait use statement. */ final class TraitUse { diff --git a/src/PhpGenerator/Traits/VisibilityAware.php b/src/PhpGenerator/Traits/VisibilityAware.php index 0b3230ed..0a3a383f 100644 --- a/src/PhpGenerator/Traits/VisibilityAware.php +++ b/src/PhpGenerator/Traits/VisibilityAware.php @@ -9,8 +9,7 @@ namespace Nette\PhpGenerator\Traits; -use Nette; -use Nette\PhpGenerator\ClassLike; +use Nette\PhpGenerator\Visibility; /** @@ -22,16 +21,10 @@ trait VisibilityAware private ?string $visibility = null; - /** - * @param string|null $val public|protected|private - */ - public function setVisibility(?string $val): static + /** @param 'public'|'protected'|'private'|null $value */ + public function setVisibility(?string $value): static { - if (!in_array($val, [ClassLike::VisibilityPublic, ClassLike::VisibilityProtected, ClassLike::VisibilityPrivate, null], true)) { - throw new Nette\InvalidArgumentException('Argument must be public|protected|private.'); - } - - $this->visibility = $val; + $this->visibility = $value === null ? $value : Visibility::from($value); return $this; } @@ -44,39 +37,39 @@ public function getVisibility(): ?string public function setPublic(): static { - $this->visibility = ClassLike::VisibilityPublic; + $this->visibility = Visibility::Public; return $this; } public function isPublic(): bool { - return $this->visibility === ClassLike::VisibilityPublic || $this->visibility === null; + return $this->visibility === Visibility::Public || $this->visibility === null; } public function setProtected(): static { - $this->visibility = ClassLike::VisibilityProtected; + $this->visibility = Visibility::Protected; return $this; } public function isProtected(): bool { - return $this->visibility === ClassLike::VisibilityProtected; + return $this->visibility === Visibility::Protected; } public function setPrivate(): static { - $this->visibility = ClassLike::VisibilityPrivate; + $this->visibility = Visibility::Private; return $this; } public function isPrivate(): bool { - return $this->visibility === ClassLike::VisibilityPrivate; + return $this->visibility === Visibility::Private; } } diff --git a/src/PhpGenerator/Visibility.php b/src/PhpGenerator/Visibility.php new file mode 100644 index 00000000..a31c75c8 --- /dev/null +++ b/src/PhpGenerator/Visibility.php @@ -0,0 +1,34 @@ +addMethod('getHandle') $method->addParameter('mode') ->addComment('comment') ->addAttribute('ExampleAttribute') - ->addAttribute('WithArguments', [123]); + ->addAttribute('WithArguments', [0]); sameFile(__DIR__ . '/expected/ClassType.attributes.expect', (string) $class); diff --git a/tests/PhpGenerator/ClassType.from.bodies.phpt b/tests/PhpGenerator/ClassType.from.bodies.phpt index a98a66f0..d0c667e8 100644 --- a/tests/PhpGenerator/ClassType.from.bodies.phpt +++ b/tests/PhpGenerator/ClassType.from.bodies.phpt @@ -11,8 +11,8 @@ require __DIR__ . '/fixtures/bodies.php'; Assert::exception( fn() => ClassType::from(PDO::class, withBodies: true), - Nette\InvalidStateException::class, - 'Source code of PDO not found.', + Nette\NotSupportedException::class, + 'The $withBodies parameter cannot be used for anonymous or internal classes.', ); @@ -23,7 +23,7 @@ Assert::exception( } }, withBodies: true), Nette\NotSupportedException::class, - 'The $withBodies parameter cannot be used for anonymous functions.', + 'The $withBodies parameter cannot be used for anonymous or internal classes.', ); diff --git a/tests/PhpGenerator/ClassType.phpt b/tests/PhpGenerator/ClassType.phpt index b012a42a..6bc845b1 100644 --- a/tests/PhpGenerator/ClassType.phpt +++ b/tests/PhpGenerator/ClassType.phpt @@ -175,8 +175,7 @@ Assert::same($parameters, $method->getParameters()); Assert::exception( fn() => (new ClassType)->addMethod('method')->setVisibility('unknown'), - Nette\InvalidArgumentException::class, - 'Argument must be public|protected|private.', + ValueError::class, ); diff --git a/tests/PhpGenerator/Extractor.extractAll.file.comments.phpt b/tests/PhpGenerator/Extractor.extractAll.file.comments.phpt new file mode 100644 index 00000000..03eafa44 --- /dev/null +++ b/tests/PhpGenerator/Extractor.extractAll.file.comments.phpt @@ -0,0 +1,43 @@ +extractAll(); + +Assert::null($file->getComment()); +Assert::same('doc comment', $file->getClasses()['Class1']->getComment()); + + +$file = (new Extractor(<<<'XX' + extractAll(); + +Assert::same('doc comment', $file->getComment()); + + +$file = (new Extractor(<<<'XX' + extractAll(); + +Assert::null($file->getComment()); diff --git a/tests/PhpGenerator/expected/ClassType.attributes.expect b/tests/PhpGenerator/expected/ClassType.attributes.expect index f9125620..434918ec 100644 --- a/tests/PhpGenerator/expected/ClassType.attributes.expect +++ b/tests/PhpGenerator/expected/ClassType.attributes.expect @@ -22,7 +22,7 @@ class Example #[ExampleAttribute] public function getHandle( /** comment */ - #[ExampleAttribute, WithArguments(123)] + #[ExampleAttribute, WithArguments(0)] $mode, ) { }