Scrawl.php

<?php

namespace Tlf;

class Scrawl {



    /** array for get/set */
    public array $stuff = [];

    public array $extensions = [
        'code'=>[],
    ];

    /** absolute path to your documentation dir */
    public ?string $dir_docs = null;

    /** absolute path to the root of your project */
    public ?string $dir_root = null;

    public array $template_dirs = [

    ];

    /** if true, append two spaces to every line so all new lines are parsed as new lines */
    public bool $markdown_preserveNewLines = true;

    /** if true, add an html comment to md docs saying not to edit directly */
    public bool $markdown_prependGenNotice = true;

    /**
     * @parma $options `key=>value` array to set properties
     */
    public function __construct(array $options=[]){
        $this->template_dirs[] = __DIR__.'/Template/';
        $this->options = $options;
        foreach ($this->options as $k=>$o){
            $k = str_replace('.','_',$k);
            $this->$k = $o;
        }

    }

    public function get_template(string $name, array $args){

        foreach ($this->template_dirs as $path){
            if (file_exists($file = $path.'/'.$name.'.md.php')){}
            else if (file_exists($file=$path.'/'.$name.'.php')){}
            else continue;
            $out = (function(array $args, string $file) {
                ob_start();
                require($file);
                $out = ob_get_clean();
                return $out;
            })($args, $file);
            return $out;
        }
        
        $this->warn("@template", $msg="Template '$name' does not exist.");
        return $msg;
    }

    /**
     * @param $string a string to parse ... template source or file source, idk
     * @param $file_ext a file extension like 'php' or 'md' (to indicate type)
     */
    public function process_str(string $string, string $file_ext){

        $extensions = $this->extensions['file'][$file_ext];

        foreach ($extensions as $ext){
            /**
             * I'm over designing
             * what am i over designing for?
             * i'm trying to make it so extensions are highly customizable
             * like i want to be able to make multiple extensions that handle php files
             * like maybe i want a php file extension that just ... finds all occurences of some particular string ...
             * So i think that's a reasonable goal
             * but then how do i integrate that all together?
             *
             * This one just needs to return an ast ...
             * so then maybe i need an additional extension that handles ASTs ...
             * or i could make the php extension do all the ast processing (getting docblock attributes)
             * which makes sense bc the php extension will produce different ast than any other language-based extension ... or even a diff php extension using a different lexer & ast generator
             *
             * so i probably should just make this do all the things (this being the php extension)
             * 
             * yeah, cuz right now i'm using onSourceFilesDone() to loop over ALL api outputs (which are ast outputs)
             * and generate some docs
             * which like ... yeah ... there's a point for that
             *
             * I think I could just have the extension do it's thing all at once
             * 
             * add a second function that takes in an ast and generates a file?
             *
             * Yeah ... bc that looping code doesn't have any more context
             *
             * I'm just looking for the simplest & most testable implementation
             *
             */
        }

    } 

    public function addExtension(object $ext){
        //something
    }

    public function get(string $group, string $key){
        if (!isset($this->stuff[$group])){
            $this->warn("Group not set", $group);
            return null;
        } else if (!isset($this->stuff[$group][$key])){
            $this->warn("Group.Key not set", "$group.$key");
            return null;
        }
        return $this->stuff[$group][$key];
    }
    public function get_group(string $group){
        if (!isset($this->stuff[$group])){
            $this->warn("Group not set", $group);
            return null;
        }
        return $this->stuff[$group];
    }


    public function set(string $group, string $key, $value){
        $this->stuff[$group][$key] = $value;
    }

    public function parse_str($str, $ext){
        $out = [];
        foreach ($this->extensions['code'][$ext] as $ext){
            $out = $ext->parse_str($str); 
        }
        return $out;
    }

    /**
     * save a file to disk in the documents directory
     */
    public function write_doc(string $rel_path, string $content){
        $content = $this->prepare_md_content($content);
        $rel_path = str_replace('../','/', $rel_path);
        $path = $this->dir_docs.'/'.$rel_path;
        $dir = dirname($path);
        if (!is_dir($dir))mkdir($dir,0755,true);
        if (is_file($path)){
            $this->warn('Overwrite',$rel_path);
        } else {
            $this->good('Write',$rel_path);
        }
        file_put_contents($path, $content);
    }

    /**
     * Read a file from disk, from the project root
     */
    public function read_file(string $rel_path){
        return file_get_contents($this->dir_root.'/'.$rel_path);
    }


    /**
     * Output a message to cli (may do logging later, idk)
     */
    public function report(string $msg){
        echo "\n$msg";
    }

    /**
     * Output a message to cli, header highlighted in red
     */
    public function warn($header, $message){
        echo "\033[0;31m$header:\033[0m $message\033[0;31m\033[0m\n";
    }

    /**
     * Output a message to cli, header highlighted in red
     */
    public function good($header, $message){
        echo "\033[0;32m$header:\033[0m $message\033[0;31m\033[0m\n";
    }

    /** apply small fixes to markdown */
    public function prepare_md_content(string $markdown){

        if ($this->markdown_preserveNewLines){
            $markdown  = str_replace("\n","  \n",$markdown);
        }

        if ($this->markdown_prependGenNotice){
            // @TODO give relative path to source file
            $markdown = "<!-- DO NOT EDIT. This file generated from template by Code Scrawl https://tluf.me/php/code-scrawl/ -->  \n".$markdown;
        }
        
        return $markdown;
    }
}