Skip to content

Commit c707f84

Browse files
committed
put doc generation into cli and part of core routes functionality
1 parent bb3f4a6 commit c707f84

2 files changed

Lines changed: 174 additions & 0 deletions

File tree

core/cli/Docs.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace OpenBroadcaster\CLI;
4+
5+
use OpenBroadcaster\Base\CLI;
6+
7+
class Docs extends CLI
8+
{
9+
protected array|string $help = [
10+
['<target_dir>', 'generate documentation and store in target directory'],
11+
];
12+
13+
public function run(array $args): bool
14+
{
15+
if (count($args) < 1) {
16+
(new OBCLI())->help();
17+
return false;
18+
}
19+
20+
$targetDir = $args[0];
21+
22+
if (! is_dir($targetDir)) {
23+
mkdir($targetDir, 0777, true);
24+
}
25+
26+
if (! is_writable($targetDir)) {
27+
echo "[E] Target directory isn't writable." . PHP_EOL;
28+
return false;
29+
}
30+
31+
if (count(scandir($targetDir)) > 2) {
32+
echo "[E] Target directory isn't empty. Script won't overwrite previous documentation automatically." . PHP_EOL;
33+
return false;
34+
}
35+
36+
$routes = new \OpenBroadcaster\Support\Routes();
37+
$result = $routes->genDocs($targetDir);
38+
39+
return $result;
40+
}
41+
}

core/support/Routes.php

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,139 @@ public function genRoutes(): bool
118118
return true;
119119
}
120120

121+
public function genDocs(string $targetDir): bool
122+
{
123+
foreach ($this->sourceDirs as $dir) {
124+
if (! is_readable($dir)) {
125+
echo "[E] Source directory isn't readable: " . $dir . "\n";
126+
return false;
127+
}
128+
}
129+
130+
/* Iterate over source directories and their files (don't do so recursively,
131+
the OpenBroadcaster framework doesn't support this for the core files anyway,
132+
so each directory with source code has to be added to the source directories
133+
array). Make sure all files are parsed before outputting any HTML, as we need
134+
to know about all the files to be able to output the navigation sidebar. */
135+
echo "Parsing PHP files and generating documentation structure.\n";
136+
$pages = [];
137+
$doc_files = [];
138+
foreach ($this->sourceDirs as $dir) {
139+
foreach (new \FilesystemIterator($dir) as $file) {
140+
if ($file->isDir()) {
141+
continue;
142+
}
143+
144+
if (! $file->isReadable()) {
145+
echo "[W] File '" . $file->getFilename() . "' isn't readable. Ignoring.\n";
146+
continue;
147+
}
148+
149+
/* Check if it's a HTML file, and if so, save it as one of the general
150+
documentation files to be inserted later. */
151+
if ($file->getExtension() == 'html') {
152+
$pages[$file->getFilename()] = file_get_contents($file->getPathname());
153+
154+
continue;
155+
}
156+
157+
/* Otherwise, we're assuming it's a PHP file with DocGen strings, and we use
158+
our custom parsing functions. */
159+
$content = $this->parse_clean(file_get_contents($file->getPathname()));
160+
$blocks = $this->parse_blocks($content);
161+
162+
$doc_files[] = $this->generate_tree($blocks, $file->getFilename(), basename($dir));
163+
}
164+
}
165+
166+
/* Generate routes as part of the documentation. */
167+
$routes = [];
168+
foreach ($doc_files as $file) {
169+
foreach ($file->getClass()->getMethods() as $method) {
170+
if (count($method->routes) > 0) {
171+
foreach ($method->routes as $route) {
172+
$routes[$route[0]][] = [$route[1], strtolower($file->getClass()->name), $method->name];
173+
}
174+
}
175+
}
176+
}
177+
178+
if ($this->routes_contain_duplicates($routes)) {
179+
echo "[E] Duplicate routes found. Quitting.\n";
180+
return false;
181+
}
182+
183+
echo "Generating navigation tree for HTML output.\n";
184+
$nav_tree = [];
185+
foreach ($pages as $index => $page) {
186+
$nav_tree['pages'][] = explode(".", $index)[0];
187+
}
188+
foreach ($doc_files as $doc_file) {
189+
$nav_tree[$doc_file->getClass()->package][] =
190+
($doc_file->getClass()->name != null) ? $doc_file->getClass()->name : $doc_file->name;
191+
}
192+
foreach ($nav_tree as &$tree) {
193+
sort($tree);
194+
}
195+
196+
echo "Outputting documentation as HTML.\n";
197+
foreach ($pages as $index => $page) {
198+
$doc_file_path = $targetDir . "/pages." . $index;
199+
file_put_contents($doc_file_path, $this->html_page($page, $nav_tree));
200+
}
201+
foreach ($doc_files as $doc_file) {
202+
$doc_file_path = $targetDir . "/" . $doc_file->getClass()->package . "."
203+
. (($doc_file->getClass()->name != null) ? $doc_file->getClass()->name : $doc_file->name)
204+
. ".html";
205+
file_put_contents($doc_file_path, $this->html_file($doc_file, $nav_tree));
206+
}
207+
208+
echo "Outputting route graph HTML.\n";
209+
file_put_contents($targetDir . "/routes.html", $this->html_routes($this->trim_toplevel_routes($this->routes_by_endpoint($routes)), $nav_tree));
210+
file_put_contents($targetDir . "/index.html", $this->html_index($nav_tree));
211+
echo "Successfully generated documentation HTML.\n\n";
212+
213+
/* Copy style files and other general data needed for the documentation
214+
to function. */
215+
echo "Copying style and script files over to target directory.\n";
216+
mkdir($targetDir . "/style");
217+
foreach (new \FilesystemIterator(OB_LOCAL . '/core/data/routes/style/') as $style) {
218+
if ($style->isDir()) {
219+
continue;
220+
}
221+
222+
if (! $style->isReadable()) {
223+
echo "[W] Stylesheet '" . $style->getFilename() . "' isn't readable. Ignoring.\n";
224+
continue;
225+
}
226+
227+
copy($style->getPathname(), $targetDir . "/style/" . $style->getFilename());
228+
}
229+
230+
mkdir($targetDir . "/js");
231+
foreach (new \FilesystemIterator(OB_LOCAL . '/core/data/routes/js/') as $script) {
232+
if ($script->isDir()) {
233+
continue;
234+
}
235+
236+
if (! $script->isReadable()) {
237+
echo "[W] Javascript file '" . $script->getFilename() . "' isn't readable. Ignoring.\n";
238+
continue;
239+
}
240+
241+
copy($script->getPathname(), $targetDir . "/js/" . $script->getFilename());
242+
}
243+
echo "Successfully copied style and script files.\n\n";
244+
245+
echo "Successfully generated documentation. Statistics:\n";
246+
echo "Packages:\t" . count($nav_tree) . "\n";
247+
echo "Classes:\t" . count($doc_files) . "\n";
248+
echo "CSS Files:\t" . (count(scandir($targetDir . "/style/")) - 2) . "\n";
249+
echo "JS Files:\t" . (count(scandir($targetDir . "/js/")) - 2) . "\n\n";
250+
251+
return true;
252+
}
253+
121254
/* Parsing functions. The first thing we need to do is clean the content we
122255
get from PHP files a bit. This includes removing empty lines (just in case there's
123256
gaps between DocBlocks and start of class/method definitions), trimming all the

0 commit comments

Comments
 (0)