public function put($file, $content) { $dir_name = dirname($file); if ($dir_name != "." && !is_dir($this->ze->build_dir . '/' . $dir_name)) { mkdir($this->ze->build_dir . '/' . $dir_name, 0755, true); } FS::put($this->ze->build_dir . '/' . $file, $content); }
/** * Create project from Composer * @param string $path path to project root * @return Project */ public static function composer($path) { $path = realpath($path); chdir($path); $composer = json_decode(FS::get($path . "/composer.json"), true); require_once $path . '/vendor/autoload.php'; $project = new self($composer["name"]); $project->setRootDir($path); list($vendor, $name) = explode("/", $project->name); if ($vendor == $name) { $project->alias = ucfirst($name); $project->code = strtolower($name); } else { $project->alias = ucfirst($vendor) . ucfirst($name); $project->code = strtolower($vendor) . "_" . strtolower($name); } $project->description = $composer["description"]; if (isset($composer["config"]["koda"]["version"])) { $ver = $composer["config"]["koda"]["version"]; if (is_callable($ver)) { $project->version = call_user_func($ver); } else { $project->version = exec($ver); } } $paths = []; foreach ($composer["autoload"] as $loader) { $paths = array_merge($paths, array_values($loader)); } foreach ($composer["require"] as $require => $version) { if (strpos($require, "ext-") === 0) { $project->addDepends(substr($require, 4))->setRequired(); } } foreach ($composer["suggest"] as $suggest => $comment) { if (strpos($suggest, "ext-") === 0) { $project->addDepends(substr($suggest, 4))->setOptional(); } } foreach ($paths as $dir) { $dir = realpath($dir); if (is_file($dir)) { $project->files[$dir] = new EntityFile($dir, $project); } else { $iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)); foreach ($iter as $file) { /* @var \splFileInfo $file */ if ($file->isFile() && strtolower($file->getExtension()) == "php") { $project->files[$file->getRealPath()] = new EntityFile($file->getRealPath(), $project); } } } } return $project; }
public function process(Project $project) { if ($project->classes) { if (!file_exists("{$this->dir}/classes")) { if (!mkdir("{$this->dir}/classes", 0755, true)) { throw new \RuntimeException("Could not create directory {$this->dir}/classes for mdocs"); } } foreach ($project->classes as $class) { $doc = []; $doc["header"] = Flags::decode($class->flags & Flags::CLASS_TYPES) . " " . $class->name; $doc[] = str_pad("", strlen($doc["header"]), "="); $doc[] = ""; if ($class->parent) { $doc[] = "Parent: [" . $class->parent->name . "](#xxx)"; } if ($class->interfaces) { $doc[] = "Interfaces: " . implode(", ", array_keys($class->interfaces)); } if ($class->traits) { $doc[] = "Traits: " . implode(", ", array_keys($class->traits)); } $doc[] = $class->description; if ($class->constants) { $doc[] = ""; $doc[] = "## Constants"; foreach ($class->constants as $constant) { $doc[] = "**{$constant->short}** `{$constant->value}`"; } } if ($class->properties) { $doc[] = ""; $doc[] = "## Properties"; foreach ($class->properties as $property) { $doc[] = "**{$property->name}** `{$property->value}`"; } } if ($class->methods) { $doc[] = ""; $doc[] = "## Methods"; foreach ($class->methods as $method) { $doc[] = $method->dump() . " {$method->description}"; } } FS::put("{$this->dir}/classes/" . str_replace('\\', '-', $class->name) . '.md', implode("\n", $doc)); } } }
public function scan() { require_once $this->path; $ns = ""; $_ns = ""; $ns_bracket = false; $aliases = []; $tokens = new Tokenizer(FS::get($this->path)); while ($tokens->valid()) { if ($tokens->is(T_NAMESPACE)) { $ns = ""; $_ns = ""; $tokens->next(); if ($tokens->is(T_STRING)) { $ns = $this->_parseName($tokens); if ($tokens->is('{')) { $tokens->skip(); $ns_bracket = true; } else { $tokens->skipIf(';'); } $_ns = $ns . '\\'; } elseif ($tokens->is('{')) { $ns_bracket = true; $tokens->next(); } } elseif ($tokens->is(T_USE)) { do { $tokens->next(); $name = $this->_parseName($tokens); if ($tokens->is(T_AS)) { $aliases[$tokens->next()->get(T_STRING)] = $name; $tokens->next(); } else { if (strpos($name, '\\') === false) { $aliases[$name] = $name; } else { $aliases[ltrim('\\', strrchr($name, '\\'))] = $name; } } } while ($tokens->is(',')); $tokens->need(';')->next(); } elseif ($tokens->is(T_CONST)) { $name = $tokens->next()->get(T_STRING); $constant = new EntityConstant($_ns . $name); $constant->setValue(constant($_ns . $name)); $constant->setLine($this->line($tokens->getLine())); $this->constants[$_ns . $name] = $constant; $tokens->forwardTo(';')->next(); } elseif ($tokens->is(T_FUNCTION)) { $name = $tokens->next()->get(T_STRING); $function = new EntityFunction($_ns . $name); $function->setLine($this->line($tokens->getLine())); $function->setAliases($aliases); $this->parseCallable($function, new \ReflectionFunction($function->name)); $function->setBody($tokens->forwardTo('{')->getScope()); $tokens->next(); $this->functions[$function->name] = $function; } elseif ($tokens->is(T_FINAL, T_ABSTRACT, T_INTERFACE, T_TRAIT, T_CLASS)) { $tokens->forwardTo(T_STRING); $name = $tokens->current(); $class = new EntityClass($_ns . $name); $ref = new \ReflectionClass($class->name); $doc = $ref->getDocComment(); // if($name == "NamesInterface") { // drop($ref); // } if ($ref->isInterface()) { $class->addFlag(Flags::IS_INTERFACE); } elseif ($ref->isTrait()) { $class->addFlag(Flags::IS_TRAIT); } else { $class->addFlag(Flags::IS_CLASS); } if ($ref->isAbstract()) { $class->addFlag(Flags::IS_ABSTRACT); } elseif ($ref->isFinal()) { $class->addFlag(Flags::IS_FINAL); } if ($doc) { $info = ToolKit::parseDoc($doc); $class->setDescription($info['desc']); $class->addOptions($info['options']); } $class->setAliases($aliases); $class->setLine($this->line($tokens->getLine())); $tokens->next(); if ($tokens->is(T_EXTENDS)) { // process 'extends' keyword do { $tokens->next(); $root = $tokens->is(T_NS_SEPARATOR); $parent = $this->_parseName($tokens); if ($root) { // extends from root namespace $class->setParent($parent, $class->isInterface()); } elseif (isset($aliases[$parent])) { $class->setParent($aliases[$parent], $class->isInterface()); } else { $class->setParent($_ns . $parent, $class->isInterface()); } } while ($tokens->is(',')); } if ($tokens->is(T_IMPLEMENTS)) { // process 'implements' keyword do { $tokens->next(); $root = $tokens->is(T_NS_SEPARATOR); $parent = $this->_parseName($tokens); if ($root) { // extends from root namespace $class->addInterface($parent); } elseif (isset($aliases[$parent])) { $class->addInterface($aliases[$parent]); } else { $class->addInterface($_ns . $parent); } } while ($tokens->is(',')); } $tokens->forwardTo('{')->next(); while ($tokens->forwardTo(T_CONST, T_FUNCTION, '{', '}', T_VARIABLE) && $tokens->valid()) { switch ($tokens->key()) { case T_CONST: $constant = new EntityConstant($class->name . '::' . $tokens->next()->get(T_STRING)); $constant->setValue(constant($constant->name)); $constant->setLine(new Line($this, $tokens->getLine())); $class->addConstant($constant); break; case T_VARIABLE: $property = new EntityProperty(ltrim($tokens->getAndNext(), '$')); $ref = new \ReflectionProperty($class->name, $property->name); $doc = $ref->getDocComment(); if ($doc) { $property->setDescription(ToolKit::parseDoc($doc)['desc']); } if ($ref->isPrivate()) { $property->addFlag(Flags::IS_PRIVATE); } elseif ($ref->isProtected()) { $property->addFlag(Flags::IS_PROTECTED); } else { $property->addFlag(Flags::IS_PUBLIC); } if ($ref->isStatic()) { $property->addFlag(Flags::IS_STATIC); } if ($ref->isDefault()) { $property->setValue($ref->getDeclaringClass()->getDefaultProperties()[$property->name]); } $class->addProperty($property); break; case T_FUNCTION: $method = new EntityMethod($name . '::' . $tokens->next()->get(T_STRING)); $method->setLine($this->line($tokens->getLine())); $this->parseCallable($method, $ref = new \ReflectionMethod($class->name, $method->short)); if ($ref->isPrivate()) { $method->addFlag(Flags::IS_PRIVATE); } elseif ($ref->isProtected()) { $method->addFlag(Flags::IS_PROTECTED); } else { $method->addFlag(Flags::IS_PUBLIC); } if ($ref->isStatic()) { $method->addFlag(Flags::IS_STATIC); } if ($ref->isAbstract()) { $method->addFlag(Flags::IS_ABSTRACT); $method->addFlag(Flags::IS_ABSTRACT_IMPLICIT); } elseif ($ref->isFinal()) { $method->addFlag(Flags::IS_FINAL); } if (isset($method->options['deprecated'])) { $method->addFlag(Flags::IS_DEPRECATED); } $tokens->forwardTo(')')->next(); if ($tokens->is('{')) { $method_body = $tokens->getScope(); $method->setBody($method_body); } $tokens->next(); $class->addMethod($method); break; case '{': // use traits scope $tokens->forwardTo('}')->next(); break; case '}': // end of class $tokens->next(); $this->classes[$class->name] = $class; break 2; } } } elseif ($tokens->is('}') && $ns_bracket) { $tokens->next(); $ns_bracket = false; } else { drop($tokens->curr); if ($tokens->valid()) { throw new UnexpectedTokenException($tokens); } break; } } }