diff --git a/src/ModifiedTypeInterface.php b/src/ModifiedTypeInterface.php new file mode 100644 index 0000000..f04ca23 --- /dev/null +++ b/src/ModifiedTypeInterface.php @@ -0,0 +1,16 @@ +modifiers === null) { + return false; + } + + foreach ($this->modifiers as $modifier) { + if ($modifier->kind === $targetModifier) { + return true; + } + } + + return false; + } + + /** + * Convenience method to check for the existence of the "public" modifier. + * Does not necessarily need to be defined for that type. + * + * @return bool + */ + public function isPublic(): bool { + return $this->hasModifier(TokenKind::PublicKeyword); + } + + /** + * Convenience method to check for the existence of the "static" modifier. + * Does not necessarily need to be defined for that type. + * + * @return bool + */ + public function isStatic(): bool { + return $this->hasModifier(TokenKind::StaticKeyword); + } +} diff --git a/src/Node/ClassConstDeclaration.php b/src/Node/ClassConstDeclaration.php index c724c5c..daf3158 100644 --- a/src/Node/ClassConstDeclaration.php +++ b/src/Node/ClassConstDeclaration.php @@ -6,13 +6,13 @@ namespace Microsoft\PhpParser\Node; +use Microsoft\PhpParser\ModifiedTypeInterface; +use Microsoft\PhpParser\ModifiedTypeTrait; use Microsoft\PhpParser\Node; use Microsoft\PhpParser\Token; -class ClassConstDeclaration extends Node { - - /** @var Token[] */ - public $modifiers; +class ClassConstDeclaration extends Node implements ModifiedTypeInterface { + use ModifiedTypeTrait; /** @var Token */ public $constKeyword; diff --git a/src/Node/MethodDeclaration.php b/src/Node/MethodDeclaration.php index cc24bac..5090b83 100644 --- a/src/Node/MethodDeclaration.php +++ b/src/Node/MethodDeclaration.php @@ -10,15 +10,14 @@ use Microsoft\PhpParser\Diagnostic; use Microsoft\PhpParser\DiagnosticKind; use Microsoft\PhpParser\DiagnosticsProvider; use Microsoft\PhpParser\FunctionLike; +use Microsoft\PhpParser\ModifiedTypeInterface; +use Microsoft\PhpParser\ModifiedTypeTrait; use Microsoft\PhpParser\Node; use Microsoft\PhpParser\Token; use Microsoft\PhpParser\TokenKind; -class MethodDeclaration extends Node implements FunctionLike { - /** @var Token[] */ - public $modifiers; - - use FunctionHeader, FunctionReturnType, FunctionBody; +class MethodDeclaration extends Node implements FunctionLike, ModifiedTypeInterface { + use FunctionHeader, FunctionReturnType, FunctionBody, ModifiedTypeTrait; const CHILD_NAMES = [ 'modifiers', @@ -41,23 +40,12 @@ class MethodDeclaration extends Node implements FunctionLike { 'compoundStatementOrSemicolon' ]; - public function hasModifier(int $targetModifier) : bool { - if ($this->modifiers === null) { - return false; - } - foreach ($this->modifiers as $modifier) { - if ($modifier->kind === $targetModifier) { - return true; - } - } - return false; - } - - public function isStatic() : bool { - return $this->hasModifier(TokenKind::StaticKeyword); - } - - public function getName() { + /** + * Returns the name of the method. + * + * @return string + */ + public function getName(): string { return $this->name->getText($this->getFileContents()); } @@ -79,4 +67,64 @@ class MethodDeclaration extends Node implements FunctionLike { } return null; } + + /** + * Returns the signature parts as an array. Use $this::getSignatureFormatted for a user-friendly string version. + * + * @return array + */ + private function getSignatureParts(): array { + $parts = []; + + foreach ($this->getChildNodesAndTokens() as $i => $child) { + if ($i === "compoundStatementOrSemicolon") { + return $parts; + } + + $parts[] = $child instanceof Token + ? $child->getText($this->getFileContents()) + : $child->getText(); + }; + + return $parts; + } + + /** + * Returns the signature of the method as a formatted string. + * + * @return string + */ + public function getSignatureFormatted(): string { + $signature = implode(" ", $this->getSignatureParts()); + return $signature; + } + + /** + * Returns the description part of the doc string. + * + * @return string + */ + public function getDescriptionFormatted(): string { + $comment = trim($this->getLeadingCommentAndWhitespaceText(), "\r\n"); + $commentParts = explode("\n", $comment); + + $description = []; + + foreach ($commentParts as $i => $part) { + $part = trim($part, "*\r\t /"); + + if (strlen($part) <= 0) { + continue; + } + + if ($part[0] === "@") { + break; + } + + $description[] = $part; + } + + $descriptionFormatted = implode(" ", $description); + return $descriptionFormatted; + } } diff --git a/src/Node/MissingMemberDeclaration.php b/src/Node/MissingMemberDeclaration.php index efc7bc6..6e38041 100644 --- a/src/Node/MissingMemberDeclaration.php +++ b/src/Node/MissingMemberDeclaration.php @@ -6,13 +6,13 @@ namespace Microsoft\PhpParser\Node; +use Microsoft\PhpParser\ModifiedTypeInterface; +use Microsoft\PhpParser\ModifiedTypeTrait; use Microsoft\PhpParser\Node; use Microsoft\PhpParser\Token; -class MissingMemberDeclaration extends Node { - - /** @var Token[] */ - public $modifiers; +class MissingMemberDeclaration extends Node implements ModifiedTypeInterface { + use ModifiedTypeTrait; /** @var Token|null needed along with typeDeclaration for what looked like typed property declarations but was missing VariableName */ public $questionToken; diff --git a/src/Node/PropertyDeclaration.php b/src/Node/PropertyDeclaration.php index 622df42..a698439 100644 --- a/src/Node/PropertyDeclaration.php +++ b/src/Node/PropertyDeclaration.php @@ -6,14 +6,13 @@ namespace Microsoft\PhpParser\Node; +use Microsoft\PhpParser\ModifiedTypeInterface; +use Microsoft\PhpParser\ModifiedTypeTrait; use Microsoft\PhpParser\Node; use Microsoft\PhpParser\Token; -use Microsoft\PhpParser\TokenKind; -class PropertyDeclaration extends Node { - - /** @var Token[] */ - public $modifiers; +class PropertyDeclaration extends Node implements ModifiedTypeInterface { + use ModifiedTypeTrait; /** @var Token|null question token for PHP 7.4 type declaration */ public $questionToken; @@ -41,16 +40,4 @@ class PropertyDeclaration extends Node { 'propertyElements', 'semicolon' ]; - - public function isStatic() : bool { - if ($this->modifiers === null) { - return false; - } - foreach ($this->modifiers as $modifier) { - if ($modifier->kind === TokenKind::StaticKeyword) { - return true; - } - } - return false; - } } diff --git a/src/Node/TraitSelectOrAliasClause.php b/src/Node/TraitSelectOrAliasClause.php index 0144716..e303812 100644 --- a/src/Node/TraitSelectOrAliasClause.php +++ b/src/Node/TraitSelectOrAliasClause.php @@ -6,19 +6,20 @@ namespace Microsoft\PhpParser\Node; +use Microsoft\PhpParser\ModifiedTypeInterface; +use Microsoft\PhpParser\ModifiedTypeTrait; use Microsoft\PhpParser\Node; use Microsoft\PhpParser\Token; -class TraitSelectOrAliasClause extends Node { +class TraitSelectOrAliasClause extends Node implements ModifiedTypeInterface { + use ModifiedTypeTrait; + /** @var QualifiedName|Node\Expression\ScopedPropertyAccessExpression */ public $name; /** @var Token */ public $asOrInsteadOfKeyword; - /** @var Token[] */ - public $modifiers; - /** @var QualifiedName|Node\Expression\ScopedPropertyAccessExpression */ public $targetName; diff --git a/tools/PrintApiDocumentation.php b/tools/PrintApiDocumentation.php index 8f4a482..012e8db 100644 --- a/tools/PrintApiDocumentation.php +++ b/tools/PrintApiDocumentation.php @@ -5,11 +5,8 @@ *--------------------------------------------------------------------------------------------*/ use Microsoft\PhpParser\Node\MethodDeclaration; -use Microsoft\PhpParser\Node\PropertyDeclaration; use Microsoft\PhpParser\Node\Statement\ClassDeclaration; use Microsoft\PhpParser\Parser; -use Microsoft\PhpParser\Token; -use Microsoft\PhpParser\TokenKind; require_once __DIR__ . "/../src/bootstrap.php"; @@ -32,6 +29,7 @@ echo "> Note: This documentation was auto-generated using this parser to help do foreach ($files as $file) { $ast = $parser->parseSourceFile(file_get_contents($file)); + foreach ($ast->getDescendantNodes() as $descendant) { if ($descendant instanceof ClassDeclaration) { $className = $descendant->name->getText($descendant->getFileContents()); @@ -39,34 +37,22 @@ foreach ($files as $file) { // TODO consider not having a separate classMemberDeclarations node foreach ($descendant->classMembers->classMemberDeclarations as $member) { + // TODO: Maybe ask a class directly for all its method declarations if ($member instanceof MethodDeclaration) { - // TODO this should be a helper function on any modified types - foreach ($member->modifiers as $modifier) { - if ($modifier->kind === TokenKind::PublicKeyword) { - $fileContents = $member->getFileContents(); - $signature = implode(" ", getSignatureParts($member)); - $comment = trim($member->getLeadingCommentAndWhitespaceText(), "\r\n"); - - $commentParts = explode("\n", $comment); - $description = []; - foreach ($commentParts as $i=>$part) { - $part = trim($part, "*\r\t /"); - if (isset($part[0])) { - if ($part[0] === "@") { - break; - } - $description[] = $part; - } - } - $comment = implode(" ", $description); - if (strlen(trim($comment, " \t")) === 0) { - $comment = "> TODO: add doc comment\n"; - } - echo "### " . $className . "::" . $member->name->getText($member->getFileContents()) . PHP_EOL; - echo $comment . PHP_EOL; - echo "```php\n$signature\n```" . PHP_EOL; - } + if (!$member->isPublic()) { + continue; } + + $signature = $member->getSignatureFormatted(); + + $description = $member->getDescriptionFormatted(); + if (strlen($description) <= 0) { + $description = "> TODO: add doc comment\n"; + } + + echo "### " . $className . "::" . $member->getName() . PHP_EOL; + echo $description . PHP_EOL; + echo "```php\n$signature\n```" . PHP_EOL; } } } @@ -76,17 +62,3 @@ foreach ($files as $file) { echo "## Node types > TODO: complete documentation - in addition to the helper methods on the Node base class, every Node object has properties specific to the Node type. Browse `src/Node/` to explore these properties."; - -function getSignatureParts(MethodDeclaration $methodDeclaration) : array { - // TODO - something like this in API? - $parts = []; - foreach ($methodDeclaration->getChildNodesAndTokens() as $i=>$child) { - if ($i === "compoundStatementOrSemicolon") { - return $parts; - } - $parts[] = $child instanceof Token - ? $child->getText($methodDeclaration->getFileContents()) - : $child->getText(); - }; - return $parts; -}