1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-12-11 16:39:36 +01:00
MadelineProto/tools/build_docs.php

346 lines
13 KiB
PHP
Raw Normal View History

#!/usr/bin/env php
<?php
2019-10-28 22:39:23 +01:00
/**
2020-02-17 14:13:46 +01:00
* Copyright 2016-2020 Daniil Gentili
2019-10-28 22:39:23 +01:00
* (https://daniil.it)
* 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/>.
*/
2023-07-14 16:34:52 +02:00
use danog\ClassFinder\ClassFinder;
2019-12-14 16:47:04 +01:00
use danog\MadelineProto\API;
2023-07-14 16:34:52 +02:00
use danog\MadelineProto\EventHandler\Message\ServiceMessage;
use danog\MadelineProto\EventHandler\Update;
use danog\MadelineProto\Lang;
2020-06-16 17:52:55 +02:00
use danog\MadelineProto\Logger;
use danog\MadelineProto\Magic;
2019-12-14 16:47:04 +01:00
use danog\MadelineProto\MTProto;
2020-09-24 20:49:34 +02:00
use danog\MadelineProto\Settings\Logger as SettingsLogger;
2023-07-14 16:34:52 +02:00
use danog\MadelineProto\Settings\TLSchema;
use danog\MadelineProto\TL\TL;
2021-12-21 14:44:39 +01:00
use danog\MadelineProto\Tools;
2023-07-14 16:34:52 +02:00
use danog\PhpDoc\PhpDoc;
use danog\PhpDoc\PhpDoc\MethodDoc;
2024-04-06 19:21:12 +02:00
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
2023-07-14 16:34:52 +02:00
use function Amp\File\read;
2019-12-14 16:47:04 +01:00
2022-12-08 20:16:40 +01:00
chdir($d=__DIR__.'/..');
2019-10-29 22:00:21 +01:00
2023-08-13 16:57:42 +02:00
`git checkout src/InternalDoc.php`;
require 'vendor/autoload.php';
2019-10-28 22:39:23 +01:00
2023-06-24 19:08:30 +02:00
require 'tools/translator.php';
2023-05-27 18:35:31 +02:00
copy('https://rpc.madelineproto.xyz/v3.json', 'src/v3.json');
2023-01-25 16:32:48 +01:00
Magic::start(light: false);
2020-09-24 20:49:34 +02:00
Logger::constructorFromSettings(new SettingsLogger);
2020-06-16 17:52:55 +02:00
$logger = Logger::$default;
2022-12-08 20:16:40 +01:00
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
2020-06-16 17:52:55 +02:00
$logger->logger('Merging constructor localization...', Logger::NOTICE);
mergeExtracted();
2020-06-16 17:52:55 +02:00
$logger->logger('Loading schemas...', Logger::NOTICE);
$schemas = loadSchemas();
$logger->logger('Upgrading layer...', Logger::NOTICE);
$layer = maxLayer($schemas);
layerUpgrade($layer);
2020-03-06 13:09:52 +01:00
2020-10-01 18:02:54 +02:00
$logger->logger("Initing docs (layer $layer)...", Logger::NOTICE);
$docs = [
[
2023-08-13 16:21:59 +02:00
'TL' => (new TLSchema)->setMTProtoSchema('')->setAPISchema("$d/schemas/TL_telegram_v$layer.tl")->setSecretSchema("$d/schemas/TL_secret.tl"),
2020-03-06 13:09:52 +01:00
'title' => "MadelineProto API documentation (layer $layer)",
'description' => "MadelineProto API documentation (layer $layer)",
2019-10-29 22:00:21 +01:00
'output_dir' => "$d/docs/docs/API_docs",
2020-06-16 17:52:55 +02:00
'template' => "$d/docs/template",
2017-01-07 12:40:51 +01:00
'readme' => false,
],
];
2020-06-16 17:52:55 +02:00
$logger->logger('Creating annotations...', Logger::NOTICE);
2019-12-14 16:47:04 +01:00
$doc = new \danog\MadelineProto\AnnotationsBuilder(
$logger,
2022-05-01 20:17:16 +02:00
$docs[0],
2019-12-14 16:47:04 +01:00
[
'API' => API::class,
2023-11-11 16:55:29 +01:00
'MTProto' => MTProto::class,
2019-12-14 16:47:04 +01:00
],
'danog\\MadelineProto'
);
2019-10-29 22:00:21 +01:00
$doc->mkAnnotations();
2020-06-16 17:52:55 +02:00
$logger->logger('Creating docs...', Logger::NOTICE);
foreach ($docs as $settings) {
2018-04-19 19:56:52 +02:00
$doc = new \danog\MadelineProto\DocsBuilder($logger, $settings);
2019-10-29 22:00:21 +01:00
$doc->mkDocs();
}
2019-03-08 15:16:58 +01:00
2022-12-08 20:16:40 +01:00
chdir(__DIR__.'/..');
2019-03-08 15:16:58 +01:00
2020-06-16 17:52:55 +02:00
$logger->logger('Fixing readme...', Logger::NOTICE);
2019-03-08 15:16:58 +01:00
$orderedfiles = [];
$order = [
'CREATING_A_CLIENT',
'LOGIN',
'FEATURES',
'REQUIREMENTS',
2023-05-31 12:23:26 +02:00
'DOCKER',
2019-03-08 15:16:58 +01:00
'INSTALLATION',
2023-05-26 17:54:42 +02:00
'BROADCAST',
2019-03-08 15:16:58 +01:00
'UPDATES',
2023-07-14 16:34:52 +02:00
'FILTERS',
'PLUGINS',
2021-09-05 19:33:22 +02:00
'DATABASE',
2019-03-08 15:16:58 +01:00
'SETTINGS',
'SELF',
'EXCEPTIONS',
'FLOOD_WAIT',
'LOGGING',
'CALLS',
'FILES',
'CHAT_INFO',
'DIALOGS',
'INLINE_BUTTONS',
'SECRET_CHATS',
'PROXY',
2019-12-30 20:41:06 +01:00
'ASYNC',
2023-06-25 16:59:56 +02:00
'FAQ',
2023-08-20 19:22:51 +02:00
'UPGRADING',
2019-03-08 15:16:58 +01:00
'USING_METHODS',
'CONTRIB',
2019-06-04 14:55:58 +02:00
'TEMPLATES',
2019-03-08 15:16:58 +01:00
];
$index = '';
2022-12-08 20:16:40 +01:00
$files = glob('docs/docs/docs/*md');
2019-03-08 15:16:58 +01:00
foreach ($files as $file) {
2022-12-08 20:16:40 +01:00
$base = basename($file, '.md');
2019-10-28 19:48:59 +01:00
if ($base === 'UPDATES_INTERNAL') {
continue;
}
2023-11-11 16:55:29 +01:00
$key = array_search($base, $order, true);
2019-03-08 15:16:58 +01:00
if ($key !== false) {
$orderedfiles[$key] = $file;
}
}
2022-12-08 20:16:40 +01:00
ksort($orderedfiles);
2023-07-14 16:34:52 +02:00
2024-04-06 19:21:12 +02:00
/** @internal */
function getSummary(string $phpdoc): string
{
$lexer = new Lexer();
$constExprParser = new ConstExprParser();
$typeParser = new TypeParser($constExprParser);
$parser = new PhpDocParser(
$typeParser,
$constExprParser,
textBetweenTagsBelongsToDescription: true
);
foreach ($parser->parse(new TokenIterator($lexer->tokenize($phpdoc)))->children as $t) {
if ($t instanceof PhpDocTextNode) {
return explode("\n", $t->text)[0];
}
}
return '';
}
2023-07-14 16:34:52 +02:00
/** @internal */
function printTypes(array $types, string $type): string
{
$phpdoc = PhpDoc::fromNamespace();
$data = '';
foreach ($types as $class) {
2023-07-14 18:29:20 +02:00
if ($type === 'concretefilters' && $class === Update::class) {
continue;
}
2023-07-14 16:34:52 +02:00
$refl = new ReflectionClass($class);
$link = "https://docs.madelineproto.xyz/PHP/".str_replace('\\', '/', $class).'.html';
2023-08-31 18:02:11 +02:00
if (!$refl->getDocComment()) {
throw new AssertionError("No documentation for $class!");
}
2024-04-06 19:21:12 +02:00
$f = getSummary($refl->getDocComment());
2023-07-14 16:34:52 +02:00
if ($refl->hasMethod('__construct')) {
$c = $refl->getMethod('__construct');
if ($c->getParameters() && $type === 'attributefilters') {
$c = new MethodDoc($phpdoc, $c);
$c = $c->getSignature();
$class .= str_replace(['__construct', '\danog\MadelineProto\EventHandler\Filter\\'], '', $c);
}
}
$data .= "* [$class &raquo;]($link) - $f\n";
if ($type !== 'concretefilters') {
continue;
}
$data .= " * [Full property list &raquo;]($link#properties)\n";
2023-07-14 18:29:20 +02:00
$data .= " * [Full bound method list &raquo;]($link#method-list)\n";
2023-07-14 16:34:52 +02:00
}
return $data;
}
2019-03-08 15:16:58 +01:00
foreach ($orderedfiles as $key => $filename) {
2023-07-14 16:34:52 +02:00
$lines = file_get_contents($filename);
2023-11-11 16:55:29 +01:00
$lines = preg_replace_callback('/\<\!--\s+cut_here\s+(\S+)\s+-->.*\<\!--\s+cut_here_end\s+\1\s+--\>/sim', static function ($matches) {
2023-07-14 16:34:52 +02:00
[, $match] = $matches;
if ($match === "concretefilters") {
$result = ClassFinder::getClassesInNamespace(
\danog\MadelineProto::class,
2023-07-14 16:34:52 +02:00
ClassFinder::RECURSIVE_MODE | ClassFinder::ALLOW_ALL
);
$result []= ServiceMessage::class;
$result = array_filter(
$result,
2023-11-11 16:55:29 +01:00
static fn ($class) => is_subclass_of($class, Update::class)
);
sort($result);
2023-07-14 16:34:52 +02:00
$data = printTypes($result, $match);
} elseif ($match === "simplefilters") {
$result = ClassFinder::getClassesInNamespace(
\danog\MadelineProto\EventHandler\SimpleFilter::class,
ClassFinder::RECURSIVE_MODE | ClassFinder::ALLOW_ALL
);
$data = printTypes($result, $match);
} elseif ($match === "attributefilters") {
$result = ClassFinder::getClassesInNamespace(
\danog\MadelineProto\EventHandler\Filter::class,
ClassFinder::RECURSIVE_MODE | ClassFinder::ALLOW_ALL
);
2023-11-11 16:55:29 +01:00
$result = array_filter($result, static fn (string $class) => (new ReflectionClass($class))->getAttributes());
2023-07-14 16:34:52 +02:00
$data = printTypes($result, $match);
2023-10-26 19:39:23 +02:00
} elseif ($match === "plugins") {
$result = ClassFinder::getClassesInNamespace(
\danog\MadelineProto\EventHandler\Plugin::class,
ClassFinder::RECURSIVE_MODE | ClassFinder::ALLOW_ALL
);
$data = printTypes($result, $match);
2023-07-14 16:34:52 +02:00
} elseif ($match === "mtprotofilters") {
2023-07-14 18:29:20 +02:00
$data = " * onUpdateCustomEvent: Receives messages sent to the event handler from an API instance using the [`sendCustomEvent` &raquo;](https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#sendcustomevent-mixed-payload-void) method.\n";
$data .= " * onAny: Catch-all filter, if defined catches all updates that aren't catched by any other filter.\n";
$data .= " * [onUpdateBroadcastProgress &raquo;](https://docs.madelineproto.xyz/docs/BROADCAST.html#get-progress): Used to receive updates to an in-progress [message broadcast &raquo;](https://docs.madelineproto.xyz/docs/BROADCAST.html)";
2023-07-14 16:34:52 +02:00
$TL = new TL(null);
$TL->init(new TLSchema);
foreach ($TL->getConstructors()->by_id as $cons) {
if ($cons['type'] !== 'Update') {
continue;
}
$predicate = 'on'.ucfirst($cons['predicate']);
$predicateRaw = $cons['predicate'];
$desc = explode("\n", Lang::$lang['en']["object_$predicateRaw"])[0];
$desc = str_replace(['](../', '.md'], ['](https://docs.madelineproto.xyz/API_docs/', '.html'], $desc);
$data .= "* [$predicate &raquo;](https://docs.madelineproto.xyz/API_docs/constructors/$predicateRaw.html) - $desc\n";
}
} else {
$data = read($match);
$data = "```php\n{$data}\n```";
}
return "<!-- cut_here $match -->\n\n$data\n\n<!-- cut_here_end $match -->";
}, $lines);
$lines = explode("\n", $lines);
2022-12-08 20:16:40 +01:00
while (end($lines) === '' || strpos(end($lines), 'Next')) {
unset($lines[count($lines) - 1]);
2019-03-08 15:16:58 +01:00
}
if ($lines[0] === '---') {
2022-12-08 20:16:40 +01:00
array_shift($lines);
2019-03-08 15:16:58 +01:00
while ($lines[0] !== '---') {
2022-12-08 20:16:40 +01:00
array_shift($lines);
2019-03-08 15:16:58 +01:00
}
2022-12-08 20:16:40 +01:00
array_shift($lines);
2019-03-08 15:16:58 +01:00
}
2022-12-08 20:16:40 +01:00
preg_match('|^# (.*)|', $lines[0], $matches);
2019-03-08 15:16:58 +01:00
$title = $matches[1];
2022-12-08 20:16:40 +01:00
$description = str_replace('"', "'", Tools::toString($lines[2]));
2019-03-08 15:16:58 +01:00
2022-12-08 20:16:40 +01:00
array_unshift(
2022-05-01 20:17:16 +02:00
$lines,
'---',
'title: "'.$title.'"',
'description: "'.$description.'"',
'nav_order: '.($key+4),
'image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png',
'---'
);
2019-03-08 15:16:58 +01:00
if (isset($orderedfiles[$key + 1])) {
2022-12-08 20:16:40 +01:00
$nextfile = 'https://docs.madelineproto.xyz/docs/'.basename($orderedfiles[$key + 1], '.md').'.html';
$lines[count($lines)] = "\n<a href=\"$nextfile\">Next section</a>";
2019-03-08 15:16:58 +01:00
} else {
2022-12-08 20:16:40 +01:00
$lines[count($lines)] = "\n<a href=\"https://docs.madelineproto.xyz/#very-complex-and-complete-examples\">Next section</a>";
2019-03-08 15:16:58 +01:00
}
2022-12-08 20:16:40 +01:00
file_put_contents($filename, implode("\n", $lines));
2019-03-08 15:16:58 +01:00
2022-12-08 20:16:40 +01:00
$file = file_get_contents($filename);
2019-03-08 15:16:58 +01:00
2022-12-08 20:16:40 +01:00
preg_match_all('|( *)\* \[(.*)\]\((.*)\)|', $file, $matches);
$file = 'https://docs.madelineproto.xyz/docs/'.basename($filename, '.md').'.html';
2023-08-13 13:35:46 +02:00
$index .= "* [$title]($file) - $description\n";
2022-12-08 20:16:40 +01:00
if (basename($filename) !== 'FEATURES.md') {
2019-03-08 15:16:58 +01:00
foreach ($matches[1] as $key => $match) {
$spaces = " $match";
$name = $matches[2][$key];
2021-09-05 20:51:29 +02:00
if ($matches[3][$key][0] === '#') {
$url = $file.$matches[3][$key];
2022-12-08 20:16:40 +01:00
} elseif (substr($matches[3][$key], 0, 3) === '../') {
$url = 'https://docs.madelineproto.xyz/'.str_replace('.md', '.html', substr($matches[3][$key], 3));
2023-07-14 16:34:52 +02:00
if (basename($filename) === 'FILTERS.md') {
continue;
}
2021-09-05 20:51:29 +02:00
} else {
$url = $matches[3][$key];
2023-07-14 16:34:52 +02:00
if (basename($filename) === 'FILTERS.md') {
continue;
}
2021-09-05 20:51:29 +02:00
}
2023-07-14 18:29:20 +02:00
if (basename($filename) === 'UPDATES.md' && str_starts_with($url, 'https://docs.madelineproto.xyz/PHP/danog/MadelineProto/EventHandler')) {
continue;
}
2019-03-08 15:16:58 +01:00
$index .= "$spaces* [$name]($url)\n";
if ($name === 'FULL API Documentation with descriptions') {
2019-06-04 14:55:58 +02:00
$spaces .= ' ';
2022-12-08 20:16:40 +01:00
preg_match_all('|\* (.*)|', file_get_contents('docs/docs/API_docs/methods/index.md'), $smatches);
2019-03-08 15:16:58 +01:00
foreach ($smatches[1] as $key => $match) {
2022-12-08 20:16:40 +01:00
if (str_contains($match, 'You cannot use this method directly')) {
2022-05-01 20:17:16 +02:00
continue;
}
2023-06-13 21:30:02 +02:00
if (!str_contains($match, 'href="https://docs.madelineproto.xyz')) {
$match = str_replace('href="', 'href="https://docs.madelineproto.xyz/API_docs/methods/', $match);
}
2019-03-08 15:16:58 +01:00
$index .= "$spaces* ".$match."\n";
}
}
}
}
}
2020-06-16 17:52:55 +02:00
$logger->logger('Fixing readme...', Logger::NOTICE);
2022-12-08 20:16:40 +01:00
$readme = explode('## ', file_get_contents('README.md'));
2019-03-08 15:16:58 +01:00
foreach ($readme as &$section) {
2022-12-08 20:16:40 +01:00
if (explode("\n", $section)[0] === 'Documentation') {
2019-03-08 15:16:58 +01:00
$section = "Documentation\n\n".$index."\n";
}
}
2022-12-08 20:16:40 +01:00
$readme = implode('## ', $readme);
2019-03-08 15:16:58 +01:00
2022-12-08 20:16:40 +01:00
file_put_contents('README.md', $readme);
file_put_contents('docs/docs/index.md', '---
2022-05-01 19:59:07 +02:00
title: MadelineProto
2019-03-08 15:16:58 +01:00
description: PHP client/server for the telegram MTProto protocol (a better tg-cli)
2022-05-01 20:17:16 +02:00
nav_order: 1
2019-03-08 15:16:58 +01:00
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
---
'.$readme);
2022-05-01 20:17:16 +02:00
2023-05-26 17:54:42 +02:00
include 'phpdoc.php';