PHPDOC
This commit is contained in:
parent
ac47a23639
commit
def6199437
@ -44,12 +44,12 @@
|
||||
"amphp/websocket-client": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"danog/class-finder": "dev-master",
|
||||
"phpdocumentor/reflection-docblock": "^5.2",
|
||||
"vlucas/phpdotenv": "^3",
|
||||
"ennexa/amp-update-cache": "dev-master",
|
||||
"phpunit/phpunit": "^8",
|
||||
"phpunit/phpunit": "^9",
|
||||
"amphp/php-cs-fixer-config": "dev-master",
|
||||
"haydenpierce/class-finder": "^0.4.2",
|
||||
"amphp/http-server": "dev-master",
|
||||
"amphp/http": "^1.6",
|
||||
"ext-ctype": "*",
|
||||
@ -57,8 +57,7 @@
|
||||
"danog/7to5": "^1",
|
||||
"vimeo/psalm": "dev-master",
|
||||
"phpstan/phpstan": "^0.12.14",
|
||||
"friendsofphp/php-cs-fixer": "^2.16",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
"friendsofphp/php-cs-fixer": "^2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libtgvoip": "Install the php-libtgvoip extension to make phone calls (https://github.com/danog/php-libtgvoip)"
|
||||
|
@ -122,7 +122,7 @@ final class APIWrapper
|
||||
}
|
||||
|
||||
/**
|
||||
* Property list
|
||||
* Property list.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@ -132,7 +132,7 @@ final class APIWrapper
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep function
|
||||
* Sleep function.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -55,7 +55,7 @@ class ContextConnector implements Connector
|
||||
$this->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING);
|
||||
return $result->getSocket();
|
||||
} catch (\Throwable $e) {
|
||||
if (defined('MADELINEPROTO_TEST') && \constant("MADELINEPROTO_TEST") === 'pony') {
|
||||
if (\defined('MADELINEPROTO_TEST') && \constant("MADELINEPROTO_TEST") === 'pony') {
|
||||
throw $e;
|
||||
}
|
||||
$this->logger->logger('Connection failed: '.$e, \danog\MadelineProto\Logger::ERROR);
|
||||
|
@ -281,7 +281,7 @@ final class Coroutine implements Promise, \ArrayAccess, JsonSerializable
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain
|
||||
* Obtain.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -146,6 +146,7 @@ class DataCenter
|
||||
/** @psalm-suppress UndefinedPropertyFetch */
|
||||
$array[$id]['permAuthKey']['authorized'] = $socket->authorized;
|
||||
}
|
||||
$array[$id] = [];
|
||||
}
|
||||
}
|
||||
$this->setDataCenterConnections($array);
|
||||
|
@ -208,10 +208,10 @@ class RedisArray extends SqlArray
|
||||
return call(function () {
|
||||
$iterator = $this->getIterator();
|
||||
$result = [];
|
||||
$len = strlen($this->rKey(''));
|
||||
$len = \strlen($this->rKey(''));
|
||||
while (yield $iterator->advance()) {
|
||||
[$key, $value] = $iterator->getCurrent();
|
||||
$key = substr($key, $len);
|
||||
$key = \substr($key, $len);
|
||||
$result[$key] = $value;
|
||||
}
|
||||
return $result;
|
||||
|
@ -53,7 +53,8 @@ class Wrapper extends ClientAbstract
|
||||
* @param mixed $data Payload data
|
||||
* @param SessionPaths $ipc IPC URI
|
||||
*
|
||||
* @return \Generator<int, Promise<ChannelledSocket>|Promise<mixed>, mixed, Wrapper>
|
||||
* @return \Generator
|
||||
* @psalm-return \Generator<int, Promise<ChannelledSocket>|Promise<mixed>, mixed, Wrapper>
|
||||
*/
|
||||
public static function create(&$data, SessionPaths $session, Logger $logger): \Generator
|
||||
{
|
||||
|
@ -862,9 +862,13 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
$this->rpcLoop = new PeriodicLoopInternal($this, [$this, 'rpcReport'], 'config', 60 * 1000);
|
||||
}
|
||||
if (!$this->ipcServer) {
|
||||
$this->ipcServer = new Server($this);
|
||||
$this->ipcServer->setSettings($this->settings->getIpc());
|
||||
$this->ipcServer->setIpcPath($this->wrapper->session);
|
||||
try {
|
||||
$this->ipcServer = new Server($this);
|
||||
$this->ipcServer->setSettings($this->settings->getIpc());
|
||||
$this->ipcServer->setIpcPath($this->wrapper->session);
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->logger("Error while starting IPC server: $e", Logger::FATAL_ERROR);
|
||||
}
|
||||
}
|
||||
$this->callCheckerLoop->start();
|
||||
$this->serializeLoop->start();
|
||||
@ -872,7 +876,11 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
$this->configLoop->start();
|
||||
$this->checkTosLoop->start();
|
||||
$this->rpcLoop->start();
|
||||
$this->ipcServer->start();
|
||||
try {
|
||||
$this->ipcServer->start();
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->logger("Error while starting IPC server: $e", Logger::FATAL_ERROR);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Stop all internal loops.
|
||||
@ -1167,6 +1175,9 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
*/
|
||||
public function unreference(): void
|
||||
{
|
||||
if (!isset($this->logger)) {
|
||||
$this->logger = new Logger(new \danog\MadelineProto\Settings\Logger);
|
||||
}
|
||||
$this->logger->logger("Will unreference instance");
|
||||
if (isset(self::$references[\spl_object_hash($this)])) {
|
||||
unset(self::$references[\spl_object_hash($this)]);
|
||||
@ -1175,21 +1186,25 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
if (isset($this->seqUpdater)) {
|
||||
$this->seqUpdater->signal(true);
|
||||
}
|
||||
$channelIds = [];
|
||||
foreach ($this->channels_state->get() as $state) {
|
||||
$channelIds[] = $state->getChannel();
|
||||
}
|
||||
\sort($channelIds);
|
||||
foreach ($channelIds as $channelId) {
|
||||
if (isset($this->feeders[$channelId])) {
|
||||
$this->feeders[$channelId]->signal(true);
|
||||
if (isset($this->channels_state)) {
|
||||
$channelIds = [];
|
||||
foreach ($this->channels_state->get() as $state) {
|
||||
$channelIds[] = $state->getChannel();
|
||||
}
|
||||
if (isset($this->updaters[$channelId])) {
|
||||
$this->updaters[$channelId]->signal(true);
|
||||
\sort($channelIds);
|
||||
foreach ($channelIds as $channelId) {
|
||||
if (isset($this->feeders[$channelId])) {
|
||||
$this->feeders[$channelId]->signal(true);
|
||||
}
|
||||
if (isset($this->updaters[$channelId])) {
|
||||
$this->updaters[$channelId]->signal(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($this->datacenter->getDataCenterConnections() as $datacenter) {
|
||||
$datacenter->disconnect();
|
||||
if (isset($this->datacenter)) {
|
||||
foreach ($this->datacenter->getDataCenterConnections() as $datacenter) {
|
||||
$datacenter->disconnect();
|
||||
}
|
||||
}
|
||||
$this->logger->logger("Unreferenced instance");
|
||||
}
|
||||
|
@ -24,22 +24,25 @@ class ClassDoc extends GenericDoc
|
||||
* @var array<string, MethodDoc>
|
||||
*/
|
||||
private array $methods = [];
|
||||
public function __construct(ReflectionClass $reflectionClass)
|
||||
public function __construct(PhpDocBuilder $builder, ReflectionClass $reflectionClass)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->name = $reflectionClass->getName();
|
||||
$doc = $reflectionClass->getDocComment();
|
||||
if (!$doc) {
|
||||
Logger::log($reflectionClass->getName()." has no PHPDOC");
|
||||
$this->ignore = true;
|
||||
return;
|
||||
}
|
||||
$doc = PhpDocBuilder::$factory->create($doc);
|
||||
$doc = $this->builder->getFactory()->create($doc);
|
||||
|
||||
parent::__construct($doc);
|
||||
parent::__construct($doc, $reflectionClass);
|
||||
|
||||
$tags = $doc->getTags();
|
||||
foreach ($tags as $tag) {
|
||||
if ($tag instanceof Property) {
|
||||
$this->properties[$tag->getVariableName()] = new PropertyDoc(
|
||||
$this->builder,
|
||||
$tag->getName(),
|
||||
$tag->getType(),
|
||||
$tag->getDescription()
|
||||
@ -52,6 +55,7 @@ class ClassDoc extends GenericDoc
|
||||
$type = \str_replace('@property ', '', $type);
|
||||
$description ??= '';
|
||||
$this->properties[$varName] = new PropertyDoc(
|
||||
$this->builder,
|
||||
$varName,
|
||||
$type,
|
||||
$description
|
||||
@ -66,8 +70,8 @@ class ClassDoc extends GenericDoc
|
||||
}
|
||||
$description = '';
|
||||
if ($refl->getDocComment()) {
|
||||
$docConst = PhpDocBuilder::$factory->create($refl->getDocComment());
|
||||
if (\in_array($refl->getDeclaringClass()->getName(), PhpDocBuilder::DISALLOW)) {
|
||||
$docConst = $this->builder->getFactory()->create($refl->getDocComment());
|
||||
if ($this->builder->shouldIgnore($refl->getDeclaringClass()->getName())) {
|
||||
continue;
|
||||
}
|
||||
$description .= $docConst->getSummary();
|
||||
@ -88,12 +92,40 @@ class ClassDoc extends GenericDoc
|
||||
|
||||
|
||||
foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
|
||||
if (str_starts_with($method->getName(), '__') && $method !== '__construct') continue;
|
||||
$this->methods[$method->getName()] = new MethodDoc($method);
|
||||
if (str_starts_with($method->getName(), '__') && $method !== '__construct') {
|
||||
continue;
|
||||
}
|
||||
$this->methods[$method->getName()] = new MethodDoc($this->builder, $method);
|
||||
}
|
||||
|
||||
$this->methods = \array_filter($this->methods, fn (MethodDoc $doc): bool => !$doc->shouldIgnore());
|
||||
//$this->properties = \array_filter($this->properties, fn (PropertyDoc $doc): bool => !$doc->shouldIgnore());
|
||||
}
|
||||
|
||||
public function format(): string
|
||||
{
|
||||
$init = parent::format();
|
||||
$methods = '';
|
||||
$properties = '';
|
||||
if ($this->methods) {
|
||||
$init .= "\n";
|
||||
foreach ($this->methods as $method) {
|
||||
$init .= "* ".$method->getSignature()."\n";
|
||||
}
|
||||
$init .= "\n";
|
||||
$init .= "## Methods:\n$methods\n";
|
||||
foreach ($this->methods as $method) {
|
||||
$init .= $method->format();
|
||||
$init .= "\n";
|
||||
}
|
||||
}
|
||||
if ($properties) {
|
||||
$init .= "## Properties:\n$properties\n";
|
||||
/*foreach ($this->properties as $property) {
|
||||
$init .= $property->format();
|
||||
$init .= "\n";
|
||||
}*/
|
||||
}
|
||||
return $init;
|
||||
}
|
||||
}
|
||||
|
25
src/danog/MadelineProto/PhpDoc/FunctionDoc.php
Normal file
25
src/danog/MadelineProto/PhpDoc/FunctionDoc.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace danog\MadelineProto\PhpDoc;
|
||||
|
||||
use danog\MadelineProto\Logger;
|
||||
use danog\MadelineProto\PhpDocBuilder;
|
||||
use ReflectionFunction;
|
||||
|
||||
class FunctionDoc extends MethodDoc
|
||||
{
|
||||
public function __construct(PhpDocBuilder $builder, ReflectionFunction $reflectionClass)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->nameGenericDoc = $reflectionClass->getName();
|
||||
$doc = $reflectionClass->getDocComment();
|
||||
if (!$doc) {
|
||||
Logger::log($reflectionClass->getName()." has no PHPDOC");
|
||||
$this->ignore = true;
|
||||
return;
|
||||
}
|
||||
$doc = $this->builder->getFactory()->create($doc);
|
||||
|
||||
parent::__construct($builder, $reflectionClass);
|
||||
}
|
||||
}
|
@ -2,39 +2,60 @@
|
||||
|
||||
namespace danog\MadelineProto\PhpDoc;
|
||||
|
||||
use danog\MadelineProto\PhpDocBuilder;
|
||||
use phpDocumentor\Reflection\DocBlock;
|
||||
use phpDocumentor\Reflection\DocBlock\Description;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Author;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Deprecated;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Fqsen;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Url;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\See;
|
||||
|
||||
abstract class GenericDoc
|
||||
{
|
||||
/**
|
||||
* Builder instance.
|
||||
*/
|
||||
protected PhpDocBuilder $builder;
|
||||
/**
|
||||
* Name.
|
||||
*/
|
||||
protected string $name;
|
||||
/**
|
||||
* Title.
|
||||
*/
|
||||
private string $title;
|
||||
protected string $title;
|
||||
/**
|
||||
* Description.
|
||||
*/
|
||||
private Description $description;
|
||||
protected Description $description;
|
||||
/**
|
||||
* See also array.
|
||||
*
|
||||
* @var array<string, string>
|
||||
* @var array<string, See>
|
||||
*/
|
||||
private array $seeAlso = [];
|
||||
protected array $seeAlso = [];
|
||||
/**
|
||||
* Author.
|
||||
*/
|
||||
private Author $author;
|
||||
protected Author $author;
|
||||
/**
|
||||
* Ignore this class.
|
||||
*/
|
||||
protected bool $ignore = false;
|
||||
public function __construct(DocBlock $doc)
|
||||
/**
|
||||
* Class name.
|
||||
*/
|
||||
protected string $className;
|
||||
/**
|
||||
* Class namespace.
|
||||
*/
|
||||
protected string $namespace;
|
||||
public function __construct(DocBlock $doc, $reflectionClass)
|
||||
{
|
||||
$this->className = $reflectionClass->getName();
|
||||
$this->namespace = \str_replace('/', '\\', \dirname(\str_replace('\\', '/', $this->className)));
|
||||
$this->title = $doc->getSummary();
|
||||
$this->description = $doc->getDescription();
|
||||
$tags = $doc->getTags();
|
||||
@ -53,14 +74,65 @@ abstract class GenericDoc
|
||||
break;
|
||||
}
|
||||
if ($tag instanceof See) {
|
||||
$this->seeAlso[$tag->getReference()->__toString()] = $tag->render();
|
||||
$this->seeAlso[$tag->getReference()->__toString()] = $tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function seeAlso(): string
|
||||
{
|
||||
$seeAlso = '';
|
||||
foreach ($this->seeAlso as $see) {
|
||||
$ref = $see->getReference();
|
||||
if ($ref instanceof Fqsen) {
|
||||
$ref = (string) $ref;
|
||||
$ref = $this->builder->resolveTypeAlias($this->className, $ref);
|
||||
$refExpl = \explode("\\", $ref);
|
||||
$name = \array_pop($refExpl);
|
||||
$namespace = \explode('/', $this->namespace);
|
||||
$count = \count($refExpl);
|
||||
foreach ($namespace as $k => $name) {
|
||||
if (isset($refExpl[$k]) && $refExpl[$k] === $name) {
|
||||
$count--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$ref = \str_repeat('../', $count)
|
||||
.\implode('/', \array_slice($refExpl, $count))
|
||||
."/$name.md";
|
||||
|
||||
$desc = $see->getDescription() ?: $ref;
|
||||
$seeAlso .= "* [$desc]($ref)\n";
|
||||
}
|
||||
if ($ref instanceof Url) {
|
||||
$desc = $see->getDescription() ?: $ref;
|
||||
$seeAlso .= "* [$desc]($ref)\n";
|
||||
}
|
||||
}
|
||||
if ($seeAlso) {
|
||||
$seeAlso = "\n#### See also: \n$seeAlso\n\n";
|
||||
}
|
||||
return $seeAlso;
|
||||
}
|
||||
public function format(): string
|
||||
{
|
||||
return '';
|
||||
$seeAlso = $this->seeAlso();
|
||||
return <<<EOF
|
||||
---
|
||||
title: $this->name: $this->title
|
||||
description: $this->description
|
||||
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
|
||||
---
|
||||
# `$this->name`: $this->title
|
||||
[Back to API index](index.md)
|
||||
|
||||
> Author: $this->author
|
||||
|
||||
$this->description
|
||||
$seeAlso
|
||||
EOF;
|
||||
}
|
||||
|
||||
public function shouldIgnore(): bool
|
||||
|
@ -8,27 +8,37 @@ use phpDocumentor\Reflection\DocBlock\Description;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Param;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
|
||||
use ReflectionFunctionAbstract;
|
||||
use ReflectionMethod;
|
||||
|
||||
class MethodDoc extends GenericDoc
|
||||
{
|
||||
private $return;
|
||||
private array $params = [];
|
||||
public function __construct(ReflectionMethod $method)
|
||||
public function __construct(PhpDocBuilder $phpDocBuilder, ReflectionFunctionAbstract $method)
|
||||
{
|
||||
$this->builder = $phpDocBuilder;
|
||||
$this->name = $method->getName();
|
||||
$doc = $method->getDocComment();
|
||||
if (!$doc) {
|
||||
$this->ignore = true;
|
||||
Logger::log($method->getDeclaringClass()->getName().'::'.$method->getName().' has no PHPDOC!');
|
||||
if ($method instanceof ReflectionMethod) {
|
||||
Logger::log($method->getDeclaringClass()->getName().'::'.$method->getName().' has no PHPDOC!');
|
||||
} else {
|
||||
Logger::log($method->getName().' has no PHPDOC!');
|
||||
}
|
||||
return;
|
||||
}
|
||||
$doc = PhpDocBuilder::$factory->create($doc);
|
||||
$doc = $this->builder->getFactory()->create($doc);
|
||||
|
||||
parent::__construct($doc);
|
||||
parent::__construct($doc, $method instanceof ReflectionMethod ? $method->getDeclaringClass() : $method);
|
||||
|
||||
foreach ($doc->getTags() as $tag) {
|
||||
if ($tag instanceof Param && !isset($this->params[$tag->getVariableName()])) {
|
||||
$this->params[$tag->getVariableName()] = $tag;
|
||||
$this->params[$tag->getVariableName()] = [
|
||||
$tag->getType(),
|
||||
$tag->getDescription()
|
||||
];
|
||||
} elseif ($tag instanceof Return_ && !$this->return) {
|
||||
$this->return = $tag;
|
||||
} elseif ($tag instanceof Generic && $tag->getName() === 'psalm-return') {
|
||||
@ -38,7 +48,7 @@ class MethodDoc extends GenericDoc
|
||||
$description .= ' ';
|
||||
[$varName, $description] = \explode(" ", $description, 2);
|
||||
if (!$description && isset($this->params[$varName])) {
|
||||
$description = $this->params[$varName]->getDescription();
|
||||
$description = (string) $this->params[$varName][1];
|
||||
} else {
|
||||
$description = new Description($description);
|
||||
}
|
||||
@ -50,8 +60,36 @@ class MethodDoc extends GenericDoc
|
||||
}
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
public function getSignature(): string
|
||||
{
|
||||
return '';
|
||||
$sig = $this->name;
|
||||
$sig .= "(";
|
||||
foreach ($this->params as $var => [$type, $description]) {
|
||||
$sig .= $type.' ';
|
||||
$sig .= "$".$var;
|
||||
$sig .= ', ';
|
||||
}
|
||||
$sig = \trim($sig, ', ');
|
||||
$sig .= ')';
|
||||
if ($this->return) {
|
||||
$sig .= ': ';
|
||||
$sig .= $this->return;
|
||||
}
|
||||
return $sig;
|
||||
}
|
||||
public function format(): string
|
||||
{
|
||||
$sig = '### '.$this->getSignature();
|
||||
$sig .= "\n\n";
|
||||
$sig .= $this->title;
|
||||
$sig .= "\n";
|
||||
$sig .= $this->description;
|
||||
$sig .= "\n";
|
||||
if ($this->return && $this->return->getDescription() && $this->return->getDescription()->render()) {
|
||||
$sig .= "\nReturn value: ".$this->return->getDescription()."\n";
|
||||
}
|
||||
$sig .= $this->seeAlso();
|
||||
$sig .= "\n";
|
||||
return $sig;
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
namespace danog\MadelineProto\PhpDoc;
|
||||
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Property;
|
||||
use danog\MadelineProto\PhpDocBuilder;
|
||||
|
||||
class PropertyDoc
|
||||
{
|
||||
public function __construct(string $name, $type, $description)
|
||||
public function __construct(PhpDocBuilder $phpDocBuilder, string $name, $type, $description)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -18,109 +18,159 @@
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
use danog\MadelineProto\Async\AsyncConstruct;
|
||||
use danog\MadelineProto\Db\DbPropertiesTrait;
|
||||
use danog\MadelineProto\Files\Server;
|
||||
use danog\MadelineProto\MTProtoTools\Crypt;
|
||||
use danog\MadelineProto\MTProtoTools\GarbageCollector;
|
||||
use danog\MadelineProto\MTProtoTools\MinDatabase;
|
||||
use danog\MadelineProto\MTProtoTools\PasswordCalculator;
|
||||
use danog\MadelineProto\MTProtoTools\ReferenceDatabase;
|
||||
use danog\MadelineProto\MTProtoTools\UpdatesState;
|
||||
use danog\ClassFinder\ClassFinder;
|
||||
use danog\MadelineProto\PhpDoc\ClassDoc;
|
||||
use danog\MadelineProto\TL\TL;
|
||||
use danog\MadelineProto\TL\TLCallback;
|
||||
use danog\MadelineProto\TL\TLConstructors;
|
||||
use danog\MadelineProto\TL\TLMethods;
|
||||
use danog\MadelineProto\TON\ADNLConnection;
|
||||
use danog\MadelineProto\TON\APIFactory as TAPIFactory;
|
||||
use danog\MadelineProto\TON\InternalDoc as TInternalDoc;
|
||||
use danog\MadelineProto\TON\Lite;
|
||||
use HaydenPierce\ClassFinder\ClassFinder;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Author;
|
||||
use danog\MadelineProto\PhpDoc\FunctionDoc;
|
||||
use phpDocumentor\Reflection\DocBlockFactory;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionFunction;
|
||||
|
||||
class PhpDocBuilder
|
||||
{
|
||||
const DISALLOW = [
|
||||
AnnotationsBuilder::class,
|
||||
APIFactory::class,
|
||||
APIWrapper::class,
|
||||
AbstractAPIFactory::class,
|
||||
Bug74586Exception::class,
|
||||
Connection::class,
|
||||
ContextConnector::class,
|
||||
DataCenter::class,
|
||||
DataCenterConnection::class,
|
||||
DoHConnector::class,
|
||||
DocsBuilder::class,
|
||||
InternalDoc::class,
|
||||
Lang::class,
|
||||
LightState::class,
|
||||
Magic::class,
|
||||
PhpDocBuilder::class,
|
||||
RSA::class,
|
||||
Serialization::class,
|
||||
SessionPaths::class,
|
||||
SettingsEmpty::class,
|
||||
SettingsAbstract::class,
|
||||
Snitch::class,
|
||||
AsyncConstruct::class,
|
||||
Server::class, // Remove when done
|
||||
VoIP::class,
|
||||
|
||||
Crypt::class,
|
||||
NothingInTheSocketException::class,
|
||||
|
||||
GarbageCollector::class,
|
||||
MinDatabase::class,
|
||||
PasswordCalculator::class,
|
||||
ReferenceDatabase::class,
|
||||
UpdatesState::class,
|
||||
|
||||
TL::class,
|
||||
TLConstructors::class,
|
||||
TLMethods::class,
|
||||
TLCallback::class,
|
||||
|
||||
ADNLConnection::class,
|
||||
TAPIFactory::class,
|
||||
TInternalDoc::class,
|
||||
Lite::class,
|
||||
|
||||
\ArrayIterator::class,
|
||||
];
|
||||
public static DocBlockFactory $factory;
|
||||
/**
|
||||
* Namespace.
|
||||
*/
|
||||
private string $namespace;
|
||||
/**
|
||||
* Scan mode.
|
||||
*/
|
||||
private int $mode;
|
||||
/**
|
||||
* Docblock factory.
|
||||
*/
|
||||
private DocBlockFactory $factory;
|
||||
/**
|
||||
* Classes/interfaces/traits to ignore.
|
||||
*
|
||||
* @var ?callable
|
||||
* @psalm-var null|callable(class-string)
|
||||
*/
|
||||
private $ignore;
|
||||
/**
|
||||
* Output directory.
|
||||
*/
|
||||
private string $output;
|
||||
public function __construct(string $output)
|
||||
/**
|
||||
* Use map.
|
||||
*
|
||||
* array<class-string, array<class-string, class-string>>
|
||||
*/
|
||||
private array $useMap = [];
|
||||
/**
|
||||
* Create docblock builder.
|
||||
*
|
||||
* @param string $namespace Namespace
|
||||
* @param int $mode Finder mode, an OR-selection of ClassFinder::ALLOW_*
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function fromNamespace(string $namespace, int $mode = ClassFinder::ALLOW_ALL): self
|
||||
{
|
||||
self::$factory = DocBlockFactory::createInstance();
|
||||
$this->output = $output;
|
||||
return new self($namespace, $mode);
|
||||
}
|
||||
public function run()
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $namespace
|
||||
* @param int $mode
|
||||
*/
|
||||
private function __construct(string $namespace, int $mode)
|
||||
{
|
||||
$classes = ClassFinder::getClassesInNamespace('danog\\MadelineProto', ClassFinder::RECURSIVE_MODE);
|
||||
$this->factory = DocBlockFactory::createInstance();
|
||||
$this->namespace = $namespace;
|
||||
$this->mode = $mode;
|
||||
}
|
||||
/**
|
||||
* Set filter to ignore certain classes.
|
||||
*
|
||||
* @param callable $ignore
|
||||
*
|
||||
* @psalm-param callable(class-string) $ignore
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setFilter(callable $ignore): self
|
||||
{
|
||||
$this->ignore = $ignore;
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Set output directory.
|
||||
*
|
||||
* @param string $output Output directory
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setOutput(string $output): self
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Run documentor.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function run(): self
|
||||
{
|
||||
$classes = ClassFinder::getClassesInNamespace($this->namespace, $this->mode | ClassFinder::RECURSIVE_MODE);
|
||||
foreach ($classes as $class) {
|
||||
if (\in_array($class, self::DISALLOW) || str_starts_with($class, 'danog\\MadelineProto\\Ipc')
|
||||
|| str_starts_with($class, 'danog\\MadelineProto\\Loop\\Update')
|
||||
|| str_starts_with($class, 'danog\\MadelineProto\\Loop\\Connection')
|
||||
|| str_starts_with($class, 'danog\\MadelineProto\\MTProto\\')
|
||||
|| str_starts_with($class, 'danog\\MadelineProto\\MTProtoSession\\')
|
||||
|| str_starts_with($class, 'danog\\MadelineProto\\PhpDoc\\')
|
||||
|| str_starts_with($class, 'danog\\MadelineProto\\Db\\NullCache')) {
|
||||
continue;
|
||||
}
|
||||
$class = new ReflectionClass($class);
|
||||
if ($class->isTrait()) {
|
||||
$this->addTypeAliases($class);
|
||||
}
|
||||
foreach ($classes as $class) {
|
||||
if ($this->ignore && ($this->ignore)($class)) {
|
||||
continue;
|
||||
}
|
||||
$class = \function_exists($class)
|
||||
? new ReflectionFunction($class)
|
||||
: new ReflectionClass($class);
|
||||
$this->generate($class);
|
||||
}
|
||||
$this->generate(new ReflectionClass(DbPropertiesTrait::class));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Resolve type alias.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $fromClass Class from where this function is called
|
||||
* @param string $name Name to resolve
|
||||
*
|
||||
* @psalm-param class-string $fromClass Class from where this function is called
|
||||
* @psalm-param class-string $name Name to resolve
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function resolveTypeAlias(string $fromClass, string $name): string
|
||||
{
|
||||
return $this->useMap[$fromClass][$name] ?? $name;
|
||||
}
|
||||
/**
|
||||
* Add type alias.
|
||||
*
|
||||
* @param string $class
|
||||
*
|
||||
* @psalm-param class-string $class
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addTypeAliases(string $class)
|
||||
{
|
||||
$reflectionClass = \function_exists($class)
|
||||
? new ReflectionFunction($class)
|
||||
: new ReflectionClass($class);
|
||||
$payload = \file_get_contents($reflectionClass->getFileName());
|
||||
\preg_match_all("/use *(function)? +(.*?)(?: +as +(.+))? *;/", $payload, $matches, PREG_SET_ORDER|PREG_UNMATCHED_AS_NULL);
|
||||
foreach ($matches as [, $function, $import, $alias]) {
|
||||
$import = "\\$import";
|
||||
$alias ??= \basename(\str_replace('\\', '/', $import));
|
||||
$this->useMap[$class][$alias] = $import;
|
||||
$this->useMap[$class]['\\'.$alias] = $import;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create directory recursively.
|
||||
*
|
||||
@ -137,25 +187,52 @@ class PhpDocBuilder
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function generate(ReflectionClass $class): void
|
||||
/**
|
||||
* Generate documentation for class.
|
||||
*
|
||||
* @param ReflectionClass|ReflectionFunction $class Class
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function generate($class): void
|
||||
{
|
||||
$name = $class->getName();
|
||||
$fName = $this->output;
|
||||
$fName .= \str_replace(['\\', 'danog\\MadelineProto'], ['/', ''], $name);
|
||||
$fName .= \str_replace('\\', DIRECTORY_SEPARATOR, $name);
|
||||
$fName .= '.md';
|
||||
|
||||
$class = $class instanceof ReflectionFunction
|
||||
? new FunctionDoc($this, $class)
|
||||
: new ClassDoc($this, $class);
|
||||
if ($class->shouldIgnore()) {
|
||||
return;
|
||||
}
|
||||
$class = $class->format();
|
||||
|
||||
$handle = \fopen(self::createDir($fName), 'w+');
|
||||
\fwrite($handle, $class);
|
||||
\fclose($handle);
|
||||
}
|
||||
|
||||
$class = new ClassDoc($class);
|
||||
/*
|
||||
\fwrite($handle, "---\n");
|
||||
\fwrite($handle, "title: $name: $title\n");
|
||||
\fwrite($handle, "description: $description\n");
|
||||
\fwrite($handle, "image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png\n");
|
||||
\fwrite($handle, "---\n");
|
||||
\fwrite($handle, "# $name: $title\n");
|
||||
\fwrite($handle, "[Back to API index](index.md)\n\n");
|
||||
/**
|
||||
* Get docblock factory.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @return DocBlockFactory
|
||||
*/
|
||||
public function getFactory(): DocBlockFactory
|
||||
{
|
||||
return $this->factory;
|
||||
}
|
||||
|
||||
\fwrite($handle, "> Author: $author \n");
|
||||
*/
|
||||
/**
|
||||
* Whether should ignore trait/class/interface.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldIgnore(string $class): bool
|
||||
{
|
||||
return ($this->ignore)($class);
|
||||
}
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
<?php
|
@ -170,7 +170,9 @@ class Logger extends SettingsAbstract
|
||||
public function setExtra($extra): self
|
||||
{
|
||||
if ($this->type === MadelineProtoLogger::CALLABLE_LOGGER && !\is_callable($extra)) {
|
||||
$this->setType(MadelineProtoLogger::NO_LOGGER);
|
||||
$this->setType((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg')
|
||||
? MadelineProtoLogger::ECHO_LOGGER
|
||||
: MadelineProtoLogger::FILE_LOGGER);
|
||||
return $this;
|
||||
}
|
||||
$this->extra = $extra;
|
||||
|
@ -8,7 +8,7 @@ use danog\MadelineProto\MTProto;
|
||||
use danog\MadelineProto\Tools;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
\define("MADELINEPROTO_TEST", "pony");
|
||||
\define('MADELINEPROTO_TEST', 'pony');
|
||||
|
||||
final class DataCenterTest extends TestCase
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user