297 lines
13 KiB
PHP
297 lines
13 KiB
PHP
<?php
|
|
|
|
/**
|
|
* AnnotationsBuilder module.
|
|
*
|
|
* This file is part of MadelineProto.
|
|
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU Affero General Public License for more details.
|
|
* You should have received a copy of the GNU General Public License along with MadelineProto.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* @author Daniil Gentili <daniil@daniil.it>
|
|
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
|
|
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
|
*
|
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
|
*/
|
|
|
|
namespace danog\MadelineProto;
|
|
|
|
use Amp\Promise;
|
|
use phpDocumentor\Reflection\DocBlockFactory;
|
|
|
|
class AnnotationsBuilder
|
|
{
|
|
use \danog\MadelineProto\TL\TL;
|
|
use Tools;
|
|
|
|
public function __construct($logger, $settings)
|
|
{
|
|
$this->logger = $logger;
|
|
$this->constructTL($settings['tl_schema']);
|
|
$this->settings = $settings;
|
|
}
|
|
|
|
public function mkAnnotations()
|
|
{
|
|
\danog\MadelineProto\Logger::log('Generating annotations...', \danog\MadelineProto\Logger::NOTICE);
|
|
$this->setProperties();
|
|
$this->createInternalClasses();
|
|
}
|
|
|
|
/**
|
|
* Open file of class APIFactory
|
|
* Insert properties
|
|
* save the file with new content.
|
|
*
|
|
* @return void
|
|
*/
|
|
private function setProperties()
|
|
{
|
|
\danog\MadelineProto\Logger::log('Generating properties...', \danog\MadelineProto\Logger::NOTICE);
|
|
$fixture = DocBlockFactory::createInstance();
|
|
$class = new \ReflectionClass(APIFactory::class);
|
|
$content = \file_get_contents($filename = $class->getFileName());
|
|
foreach ($class->getProperties() as $property) {
|
|
if ($raw_docblock = $property->getDocComment()) {
|
|
$docblock = $fixture->create($raw_docblock);
|
|
if ($docblock->hasTag('internal')) {
|
|
$content = \str_replace("\n ".$raw_docblock."\n public \$".$property->getName().';', '', $content);
|
|
}
|
|
}
|
|
}
|
|
foreach ($this->getMethodNamespaces() as $namespace) {
|
|
$content = \preg_replace('/(class( \\w+[,]?){0,}\\n{\\n)/', '${1}'." /**\n"." * @internal this is a internal property generated by build_docs.php, don't change manually\n"." *\n"." * @var {$namespace}\n"." */\n"." public \${$namespace};\n", $content);
|
|
}
|
|
\file_put_contents($filename, $content);
|
|
}
|
|
|
|
/**
|
|
* Create file InternalDoc with all interfaces.
|
|
*/
|
|
private function createInternalClasses()
|
|
{
|
|
\danog\MadelineProto\Logger::log('Creating internal classes...', \danog\MadelineProto\Logger::NOTICE);
|
|
$handle = \fopen(\dirname(__FILE__).'/InternalDoc.php', 'w');
|
|
\fwrite($handle, "<?php namespace danog\\MadelineProto; class InternalDoc extends APIFactory {}");
|
|
|
|
$class = new \ReflectionClass(API::class);
|
|
$methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC);
|
|
$ignoreMethods = [];
|
|
foreach ($methods as $method) {
|
|
$ignoreMethods[$method->getName()] = $method->getName();
|
|
}
|
|
\fclose($handle);
|
|
$handle = \fopen(\dirname(__FILE__).'/InternalDoc.php', 'w');
|
|
|
|
$internalDoc = [];
|
|
foreach ($this->methods->by_id as $id => $data) {
|
|
if (!\strpos($data['method'], '.')) {
|
|
continue;
|
|
}
|
|
list($namespace, $method) = \explode('.', $data['method']);
|
|
if (!\in_array($namespace, $this->getMethodNamespaces())) {
|
|
continue;
|
|
}
|
|
$internalDoc[$namespace][$method]['title'] = Lang::$current_lang["method_{$data['method']}"] ?? '';
|
|
|
|
$type = \str_ireplace(['vector<', '>'], ['_of_', '[]'], $data['type']);
|
|
foreach ($data['params'] as $param) {
|
|
if (\in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) {
|
|
continue;
|
|
}
|
|
if ($param['name'] === 'data' && $type === 'messages.SentEncryptedMessage') {
|
|
$param['name'] = 'message';
|
|
$param['type'] = 'DecryptedMessage';
|
|
}
|
|
if ($param['name'] === 'chat_id' && $data['method'] !== 'messages.discardEncryption') {
|
|
$param['type'] = 'InputPeer';
|
|
}
|
|
if ($param['name'] === 'hash' && $param['type'] === 'int') {
|
|
$param['pow'] = 'hi';
|
|
$param['type'] = 'Vector t';
|
|
$param['subtype'] = 'int';
|
|
}
|
|
|
|
$stype = 'type';
|
|
if (isset($param['subtype'])) {
|
|
$stype = 'subtype';
|
|
}
|
|
|
|
$ptype = \str_replace('.', '_', $param[$stype]);
|
|
switch ($ptype) {
|
|
case 'true':
|
|
case 'false':
|
|
$ptype = 'boolean';
|
|
}
|
|
$ptype = $stype === 'type' ? $ptype : "[$ptype]";
|
|
$opt = ($param['pow'] ?? false) ? 'Optional: ' : '';
|
|
$internalDoc[$namespace][$method]['attr'][$param['name']] = [
|
|
'type' => $ptype,
|
|
'description' => $opt.Lang::$current_lang["method_{$data['method']}_param_{$param['name']}_type_{$param['type']}"]
|
|
];
|
|
}
|
|
if ($type === 'Bool') {
|
|
$type = \strtolower($type);
|
|
}
|
|
$internalDoc[$namespace][$method]['return'] = $type;
|
|
}
|
|
|
|
$class = new \ReflectionClass(MTProto::class);
|
|
$methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC);
|
|
foreach ($methods as $key => $method) {
|
|
$name = $method->getName();
|
|
if ($method == 'methodCallAsyncRead') {
|
|
unset($methods[\array_search('methodCall', $methods)]);
|
|
} elseif (\strpos($name, '__') === 0) {
|
|
unset($methods[$key]);
|
|
} elseif (\stripos($name, 'async') !== false) {
|
|
if (\strpos($name, '_async') !== false) {
|
|
unset($methods[\array_search(\str_ireplace('_async', '', $method), $methods)]);
|
|
} else {
|
|
unset($methods[\array_search(\str_ireplace('async', '', $method), $methods)]);
|
|
}
|
|
}
|
|
}
|
|
foreach ($methods as $method) {
|
|
$name = $method->getName();
|
|
if (isset($ignoreMethods[$name])) {
|
|
continue;
|
|
}
|
|
|
|
if ($name == 'methodCallAsyncRead') {
|
|
$name = 'methodCall';
|
|
} elseif (\stripos($name, 'async') !== false) {
|
|
if (\strpos($name, '_async') !== false) {
|
|
$name = \str_ireplace('_async', '', $name);
|
|
} else {
|
|
$name = \str_ireplace('async', '', $name);
|
|
}
|
|
}
|
|
$name = Tools::fromSnakeCase($name);
|
|
$name = \str_ireplace(['mtproto', 'api'], ['MTProto', 'API'], $name);
|
|
|
|
$doc = 'public function ';
|
|
$doc .= $name;
|
|
|
|
$doc .= '(';
|
|
$paramList = '';
|
|
$hasVariadic = false;
|
|
foreach ($method->getParameters() as $param) {
|
|
if ($param->allowsNull()) {
|
|
//$doc .= '?';
|
|
}
|
|
if ($type = $param->getType()) {
|
|
if ($type->allowsNull()) {
|
|
$doc .= '?';
|
|
}
|
|
if (!$type->isBuiltin()) {
|
|
$doc .= '\\';
|
|
}
|
|
$doc .= $type->getName();
|
|
$doc .= ' ';
|
|
}
|
|
if ($param->isVariadic()) {
|
|
$doc .= '...';
|
|
}
|
|
if ($param->isPassedByReference()) {
|
|
$doc .= '&';
|
|
}
|
|
$doc .= '$';
|
|
$doc .= $param->getName();
|
|
if ($param->isOptional() && !$param->isVariadic()) {
|
|
$doc .= ' = ';
|
|
if ($param->isDefaultValueConstant()) {
|
|
$doc .= '\\'.\str_replace(['NULL', 'self'], ['null', 'danog\\MadelineProto\\MTProto'], $param->getDefaultValueConstantName());
|
|
} else {
|
|
$doc .= \str_replace('NULL', 'null', \var_export($param->getDefaultValue(), true));
|
|
}
|
|
}
|
|
$doc .= ', ';
|
|
|
|
|
|
if ($param->isVariadic()) {
|
|
$hasVariadic = true;
|
|
$paramList .= '...';
|
|
}
|
|
$paramList .= '$'.$param->getName().', ';
|
|
}
|
|
if (!$hasVariadic) {
|
|
$paramList .= '$extra, ';
|
|
$doc .= 'array $extra = []';
|
|
}
|
|
$doc = \rtrim($doc, ', ');
|
|
$paramList = \rtrim($paramList, ', ');
|
|
$doc .= ")";
|
|
if (($type = $method->getReturnType()) && !\in_array($type->getName(), [\Generator::class, Promise::class])) {
|
|
$doc .= ': ';
|
|
if ($type->allowsNull()) {
|
|
$doc .= '?';
|
|
}
|
|
$doc .= $type->getName();
|
|
}
|
|
$paramList = $hasVariadic ? "Tools::arr($paramList)" : "[$paramList]";
|
|
|
|
$doc .= "\n{\n";
|
|
$doc .= " return \$this->__call(__FUNCTION__, $paramList);\n";
|
|
$doc .= "}\n";
|
|
|
|
$internalDoc['InternalDoc'][$name]['method'] = $method->getDocComment() ?? '';
|
|
$internalDoc['InternalDoc'][$name]['method'] .= "\n ".\implode("\n ", \explode("\n", $doc));
|
|
}
|
|
|
|
\fwrite($handle, "<?php\n");
|
|
\fwrite($handle, "/**\n");
|
|
\fwrite($handle, " * This file is automatic generated by build_docs.php file\n");
|
|
\fwrite($handle, " * and is used only for autocomplete in multiple IDE\n");
|
|
\fwrite($handle, " * don't modify manually.\n");
|
|
\fwrite($handle, " */\n\n");
|
|
\fwrite($handle, "namespace danog\\MadelineProto;\n");
|
|
foreach ($internalDoc as $namespace => $methods) {
|
|
if ($namespace === 'InternalDoc') {
|
|
\fwrite($handle, "\nclass {$namespace} extends APIFactory\n{\n");
|
|
} else {
|
|
\fwrite($handle, "\ninterface {$namespace}\n{");
|
|
}
|
|
foreach ($methods as $method => $properties) {
|
|
if (isset($properties['method'])) {
|
|
\fwrite($handle, $properties['method']);
|
|
continue;
|
|
}
|
|
\fwrite($handle, "\n /**\n");
|
|
\fwrite($handle, " * {$properties['title']}\n");
|
|
\fwrite($handle, " *\n");
|
|
if (isset($properties['attr'])) {
|
|
\fwrite($handle, " * Parameters: \n");
|
|
$longest = [0, 0, 0];
|
|
foreach ($properties['attr'] as $name => $param) {
|
|
$longest[0] = \max($longest[0], \strlen($param['type']));
|
|
$longest[1] = \max($longest[1], \strlen($name));
|
|
$longest[2] = \max($longest[2], \strlen($param['description']));
|
|
}
|
|
foreach ($properties['attr'] as $name => $param) {
|
|
$param['type'] = \str_pad('`'.$param['type'].'`', $longest[0]+2);
|
|
$name = \str_pad('**'.$name.'**', $longest[1]+4);
|
|
$param['description'] = \str_pad($param['description'], $longest[2]);
|
|
\fwrite($handle, " * * {$param['type']} {$name} - {$param['description']}\n");
|
|
}
|
|
\fwrite($handle, " * \n");
|
|
\fwrite($handle, " * @param array \$params Parameters\n");
|
|
\fwrite($handle, " *\n");
|
|
}
|
|
\fwrite($handle, " * @return {$properties['return']}\n");
|
|
\fwrite($handle, " */\n");
|
|
\fwrite($handle, " public function {$method}(");
|
|
if (isset($properties['attr'])) {
|
|
\fwrite($handle, '$params');
|
|
}
|
|
\fwrite($handle, ");\n");
|
|
}
|
|
\fwrite($handle, "}\n");
|
|
}
|
|
\fclose($handle);
|
|
}
|
|
}
|