<?php
namespace Lia\Ext;
/**
* Generates documentation listing:
* - Packages
* - Addons
* - Routes
* - Views
* - Configurable Options (and maybe listing configs that have been set)
*/
class Scrawl extends \Tlf\Scrawl\DoNothingExtension implements \Tlf\Scrawl\Extension {
static public array $config_file_locations =
[
'config/liaison.json',
'.config/liaison.json',
'config/lia.json',
'.config/lia.json'
];
/**
* Actually generate the documentation and write it to the docs dir.
*
* @param $lia
* @param $out_dir the relative directory to write documentation to
* @param $base_dir the absolute path to the root of the software
*/
protected function generate_documentation(\Lia $lia, string $out_dir, string $base_dir){
$args = ['lia'=>$lia, 'base_dir'=>$base_dir, 'scrawl_ext' => $this];
$this->scrawl->write_doc($out_dir.'/README.md', $this->scrawl->get_template('Liaison-README', $args));
//$this->scrawl->write_doc($out_dir.'/Packages.md', $this->scrawl->get_template('Liaison-Packages', $args));
foreach ($lia->packages as $package){
$p_args = array_merge($args, ['package'=>$package]);
$this->scrawl->write_doc($out_dir.'/Package/'.$package->fqn.'.md',
$this->scrawl->prepare_md_content(
$this->scrawl->get_template('Liaison-Package',$p_args)
)
);
}
$this->scrawl->write_doc($out_dir.'/Views.md',
$this->scrawl->prepare_md_content(
$this->scrawl->get_template('Liaison-Views',$args)
)
);
$this->scrawl->write_doc($out_dir.'/Routes.md',
$this->scrawl->prepare_md_content(
$this->scrawl->get_template('Liaison-Routes',$args)
)
);
}
public function get_callable_details($c, $base_dir){
if ($c instanceof \Closure){
$refc = new \ReflectionFunction($c);
return "Anonymous Function defined in: `".$this->get_rel_path($refc->getFilename(), $base_dir)."` on line ".$refc->getStartLine();
// could use getDocComment() to provide further information, but I think this is fine for now.
} else if (is_string($c)) {
return "Function name: `$c(...)`";
} else if (is_array($c)) {
if (count($c)==2 && is_object($c[0]) && is_string($c[1])){
return "Object method: `".get_class($c[0]).'->'.$c[1]."(...)`";
} else {
return "(*details unavailable*)";
}
} else {
return "(*details unavailable*)";
}
}
public function get_rel_class_file(object $obj, string $base_dir): string{
$refClass = new \ReflectionClass($obj);
$class_abs_path = realpath($refClass->getFileName());
return $this->get_rel_path($class_abs_path, $base_dir);
}
public function get_rel_path(string $abs_path, string $base_dir): string{
$path = null;
if (substr($abs_path, 0, strlen($base_dir)) != $base_dir){
$path = '(error)';
} else {
$path = substr($abs_path, strlen($base_dir));
}
return $path;
}
/**
* Get absolute path to liaison config file, or null if it does not exist.
*/
static public function get_config_file(string $base_dir): ?string {
$config_file = null;
foreach (static::$config_file_locations as $file){
if (is_file($abs_file=$base_dir.'/'.$file)){
$config_file = $abs_file;
break;
}
}
return $config_file;
}
public function bootstrap(){
$template_dir = dirname(__DIR__,3).'/.doctemplate/';
if (!in_array($template_dir, $this->scrawl->template_dirs))$this->scrawl->template_dirs[] = $template_dir;
}
/**
* Called when all files are finished being processed
*
* @param $code_files array of all files that were scanned and processed
* @param $all_exports array of all exports found in the scanned files
*/
public function scan_filelist_processed(array $code_files, array $all_exports){
$this->scrawl->good("#### GENERATE LIA DOCS ####", "Begin generation of Liaison docs");
$base_dir = getcwd();
$config_file = static::get_config_file($base_dir);
if ($config_file===null){
$this->scrawl->warn("Config not found", "A liaison config file was not found. Create one of the following, relative to the current directory: ".implode(", ", static::$config_file_locations));
return;
}
$lia = null;
$configs = null;
try {
$configs = json_decode(file_get_contents($config_file), true);
$lia = $this->get_lia_instance($base_dir, $configs);
} catch (\Throwable $t){
}
if (!($lia instanceof \Lia)
|| $configs == null){
$this->scrawl->warn("Lia Docs", "Failed to load liaison instance based onf config file at: $config_file.");
return;
}
if (!isset($configs['liaison_docs_dir'])){
$this->scrawl->warn("Configuration missing", "You MUST set 'liaison_docs_dir' to a relative path inside your 'docs' dir. Set this config in: $config_file");
return;
}
$this->scrawl->report("Config and Liaison loaded\n");
$this->generate_documentation($lia, $configs['liaison_docs_dir'].'/', $base_dir);
$this->scrawl->good("#### FINISH LIA DOCS GENERATION ####", "End of generating lia docs");
}
protected function get_lia_instance(string $base_dir, array $configs): \Lia {
if (!isset($_SERVER['REQUEST_URI'])){
if (isset($configs['scrawl_route'])){
$_SERVER['REQUEST_URI'] = $configs['scrawl_route'];
} else {
$_SERVER['REQUEST_URI'] = '/';
}
$_SERVER['HTTP_HOST'] = null;
$_SERVER['REQUEST_METHOD'] = 'GET';
}
$get_output = function($__deliver_script, $__liaison_varname, &$__liaison_instance): string {
ob_start();
require($__deliver_script);
$__liaison_instance = $$__liaison_varname;
return ob_get_clean();
};
$deliver_script = $base_dir.'/'.$configs['deliver_script'];
$liaison_varname = $configs['liaison_variable_name'];
$lia = null;
$output = $get_output($deliver_script, $liaison_varname, $lia);
return $lia;
}
}