Last active
December 22, 2016 16:00
-
-
Save mpenick/75ca711a3085318ca93524d6c8495528 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| function startsWith($haystack, $needle) { | |
| $length = strlen($needle); | |
| return (substr($haystack, 0, $length) === $needle); | |
| } | |
| class DocComment { | |
| const UNINITIALIZE = 1; | |
| const INSIDE = 2; | |
| const DONE = 3; | |
| const DOC_COMMENT_START = "/*"; | |
| const DOC_COMMENT_END = "*/"; | |
| const DOC_COMMENT_INSIDE = "*"; | |
| private $comment; | |
| private $returnType; | |
| private $parameters = array(); | |
| public function __construct($docComment) { | |
| $this->clean($docComment); | |
| } | |
| public function clean($docComment) { | |
| $lines = preg_split('/\R/', $docComment); | |
| $state = self::UNINITIALIZE; | |
| $comment = array(); | |
| foreach ($lines as $line) { | |
| $line = ltrim($line); | |
| if (startsWith($line, self::DOC_COMMENT_START)) { | |
| if ($state != self::UNINITIALIZE) throw new Exception("Invalid comment"); | |
| $state = self::INSIDE; | |
| $line = ltrim(substr($line, strlen(self::DOC_COMMENT_START)), "*"); | |
| if ($line == "") continue; | |
| } else if (startsWith($line, self::DOC_COMMENT_END)) { | |
| if ($state !=self::INSIDE) throw new Exception("Invalid comment"); | |
| $state = self::DONE; | |
| continue; | |
| } else if (startsWith($line, self::DOC_COMMENT_INSIDE)) { | |
| if ($state != self::INSIDE) throw new Exception("Invalid comment"); | |
| $line = ltrim(substr($line, strlen(self::DOC_COMMENT_INSIDE)), "*"); | |
| } | |
| if (substr($line, 0, 1) == " ") { | |
| $line = substr($line, 1); | |
| } | |
| if (preg_match("/^@return\\s+([\\w_\\-\\\\|]+)\\s?(.*)/", ltrim($line), $matches)) { | |
| if (count($matches) > 1) { | |
| $returnType = $matches[1]; | |
| } | |
| if (count($matches) > 2) { | |
| $returnDocComment = $matches[2]; | |
| } | |
| $this->returnType = array($returnType, $returnDocComment); | |
| } else if (preg_match("/^@param\\s+([\\w_\\-\\\\|]+)\\s+\\$([\\w_\\-\\\\|]+)\\s*(.*)/", ltrim($line), $matches)) { | |
| if (count($matches) > 1) { | |
| $paramType = $matches[1]; | |
| } | |
| if (count($matches) > 2) { | |
| $paramName = $matches[2]; | |
| } | |
| if (count($matches) > 3) { | |
| $paramDocComment = $matches[3]; | |
| } | |
| $this->parameters[$paramName] = array($paramType, $paramDocComment); | |
| } else { | |
| $comment []= $line; | |
| } | |
| } | |
| if (count($comment) > 0 && $comment[count($comment) - 1] == "") { | |
| array_pop($comment); | |
| } | |
| $this->comment = implode(PHP_EOL, $comment); | |
| } | |
| public function getComment() { | |
| return $this->comment; | |
| } | |
| public function getReturnType() { | |
| return $this->returnType; | |
| } | |
| public function getParameter($name) { | |
| if (!isset($this->parameters[$name])) { | |
| return null; | |
| } | |
| return $this->parameters[$name]; | |
| } | |
| public function getParameters() { | |
| return $this->parameters; | |
| } | |
| } | |
| class ConstDocComments { | |
| private $docComments = array(); | |
| public function __construct($class) { | |
| $this->parse($class); | |
| } | |
| private function parse($class) { | |
| $content = file_get_contents($class->getFileName()); | |
| $tokens = token_get_all($content); | |
| $doc = null; | |
| $isConst = false; | |
| foreach($tokens as $token) { | |
| if (count($token) <= 1) { | |
| continue; | |
| } | |
| list($tokenType, $tokenValue) = $token; | |
| switch ($tokenType) { | |
| case T_WHITESPACE: | |
| case T_COMMENT: | |
| // ignored tokens | |
| break; | |
| case T_DOC_COMMENT: | |
| $doc = $tokenValue; | |
| break; | |
| case T_CONST: | |
| $isConst = true; | |
| break; | |
| case T_STRING: | |
| if ($isConst) { | |
| $docComment = new DocComment($doc); | |
| $this->docComments[$tokenValue] = $docComment->getComment(); | |
| } | |
| $doc = null; | |
| $isConst = false; | |
| break; | |
| // all other tokens reset the parser | |
| default: | |
| $doc = null; | |
| $isConst = false; | |
| break; | |
| } | |
| } | |
| } | |
| public function getDocComments() { | |
| return $this->docComments; | |
| } | |
| public function getDocComment($name) { | |
| if (!isset($this->docComments)) { | |
| return null; | |
| } | |
| return $this->docComments[$name]; | |
| } | |
| } | |
| if (count($argv) < 2) { | |
| die("Usage: {$argv[0]} <directory>" . PHP_EOL); | |
| } | |
| $dir = $argv[1]; | |
| function doesParentHaveMethod($class, $method) { | |
| $parent = $class->getParentClass(); | |
| if ($parent) { | |
| if ($parent->hasMethod($method->getName())) { | |
| return true; | |
| } | |
| return doesParentHaveMethod($parent, $method); | |
| } | |
| return false; | |
| } | |
| function writeDocYaml($yamlFileName, $overwrite, $class) { | |
| $classDoc = array(); | |
| $classDocComment = new DocComment($class->getDocComment()); | |
| $classDoc["comment"] = $classDocComment->getComment(); | |
| $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC); | |
| if ($methods) { | |
| $methodsDoc = array(); | |
| foreach($methods as $method) { | |
| if (doesParentHaveMethod($class, $method) && ($method->isStatic() || $method->isFinal())) { | |
| continue; | |
| } | |
| $methodDoc = array(); | |
| $docComment = new DocComment($method->getDocComment()); | |
| $methodDoc["comment"] = $docComment->getComment(); | |
| $parameters = $method->getParameters(); | |
| if ($parameters) { | |
| $paramsDoc = array(); | |
| foreach ($parameters as $parameter) { | |
| $paramDocComment = $docComment->getParameter($parameter->getName()); | |
| $paramDoc = array(); | |
| $paramDoc["comment"] = count($paramDocComment) > 1 ? $paramDocComment[1] : ""; | |
| $parameterType = $parameter->getType(); | |
| $parameterType = $parameterType ? $parameterType : $paramDocComment[0]; | |
| $paramDoc["type"] = $parameterType ? "$parameterType" : "mixed"; | |
| $paramsDoc[$parameter->getName()] = $paramDoc; | |
| } | |
| $methodDoc["params"] = $paramsDoc; | |
| } | |
| if (!$method->isConstructor() && !$method->isDestructor()) { | |
| $returnDocComment = $docComment->getReturnType(); | |
| $returnDoc = array(); | |
| $returnDoc["comment"] = count($returnDocComment) > 1 ? $returnDocComment[1] : ""; | |
| $returnType = $returnDocComment[0]; | |
| $returnDoc["type"] = $returnType ? "$returnType" : "mixed"; | |
| $methodDoc["return"] = $returnDoc; | |
| } | |
| $methodsDoc[$method->getShortName()] = $methodDoc; | |
| } | |
| $classDoc["methods"] = $methodsDoc; | |
| } | |
| $constants = $class->getConstants(); | |
| if ($constants) { | |
| $docComments = new ConstDocComments($class); | |
| $constantsDoc = array(); | |
| foreach($constants as $name => $notused) { | |
| $constantDoc = array(); | |
| $constantDoc["comment"] = $docComments->getDocComment($name); | |
| $constantsDoc[$name] = $constantDoc; | |
| } | |
| $classDoc["constants"] = $constantsDoc; | |
| } | |
| if (!$overwrite && file_exists($yamlFileName)) { | |
| logWarning("$yamlFileName already exists. Not overwriting."); | |
| return; | |
| } | |
| $className = preg_replace("/^\\Cassandra/", "Dse", $class->getName()); | |
| yaml_emit_file($yamlFileName, array($className => $classDoc)); | |
| } | |
| $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)); | |
| $regex = new RegexIterator($iterator, "/Cassandra.*\.php$/i", RecursiveRegexIterator::GET_MATCH); | |
| //$regex = array("./Cassandra/Type/Scalar.php" => null); | |
| foreach ($regex as $fileName => $notused) { | |
| $fullClassName = preg_replace("/(.+)\.php$/", "$1", $fileName); | |
| $path = dirname($fullClassName); | |
| $className = basename($fullClassName); | |
| $fullClassName = str_replace("/", "\\", ltrim($fullClassName, ".")); | |
| if ($fullClassName == "\Cassandra\Float") { | |
| $fullClassName = "\Cassandra\Float_"; | |
| } else if ($fullClassName == "\Cassandra\Function") { | |
| $fullClassName = "\Cassandra\Function_"; | |
| } | |
| $outputPath = "../src/" . trim(substr($path, strlen("./Cassandra/") - 1), "/"); | |
| print("Loading $fileName ($fullClassName --> $outputPath/$className.yaml)...\n"); | |
| require_once($fileName); | |
| $classDoc = array(); | |
| $class = new ReflectionClass($fullClassName); | |
| writeDocYaml("$outputPath/$className.yaml", true, $class); | |
| #foreach ($class->getMethods() as $method) { | |
| # $docComment = new DocComment($method->getDocComment()); | |
| # print_r($method); | |
| # printf("%s", $docComment->getComment()); | |
| # print_r($docComment->getReturnType()); | |
| # print_r($docComment->getParameters()); | |
| #} | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment