deployphp/deployer

View on GitHub
src/Documentation/DocRecipe.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

declare(strict_types=1);

/* (c) Anton Medvedev <anton@medv.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Deployer\Documentation;

class DocRecipe
{
    /**
     * @var string
     */
    public $recipeName;
    /**
     * @var string
     */
    public $recipePath;
    /**
     * @var string
     */
    public $comment;
    /**
     * @var string[]
     */
    public $require = [];
    /**
     * @var DocConfig[]
     */
    public $config = [];
    /**
     * @var DocTask[]
     */
    public $tasks = [];

    public function __construct(string $recipeName, string $recipePath)
    {
        $this->recipeName = $recipeName;
        $this->recipePath = $recipePath;
    }

    /**
     * @return bool|int
     */
    public function parse(string $content)
    {
        $comment = '';
        $desc = '';
        $currentTask = null;

        $content = str_replace("\r\n", "\n", $content);

        $state = 'root';
        $lines = explode("\n", $content);

        for ($i = 0; $i < count($lines); $i++) {
            $line = $lines[$i];

            if (empty($line)) {
                continue; // Skip empty lines
            }

            $m = [];
            $match = function ($regexp) use ($line, &$m) {
                return preg_match("#$regexp#", $line, $m);
            };
            switch ($state) {
                case 'root':
                    if ($match('^/\*\*?')) {
                        $state = 'comment';
                        $comment .= trim_comment($line) . "\n";
                        break;
                    }
                    if ($match('^//')) {
                        $comment .= trim_comment($line) . "\n";
                        break;
                    }
                    if ($match('^require.+?[\'"](?<recipe>.+?)[\'"]')) {
                        $this->require[] = dirname($this->recipePath) . $m['recipe'];
                        break;
                    }
                    if ($match('^set\([\'"](?<config_name>[\w_:\-/]+?)[\'"]')) {
                        $set = new DocConfig();
                        $set->name = $m['config_name'];
                        $set->comment = trim($comment);
                        $comment = '';
                        $set->recipePath = $this->recipePath;
                        $set->lineNumber = $i + 1;
                        if (preg_match('#^set\(.+?,\s(?<value>.+?)\);$#', $line, $m)) {
                            $set->defaultValue = $m['value'];
                        }
                        if (preg_match('#^set\(.+?,\s\[$#', $line, $m)) {
                            $multiLineArray = "[\n";
                            $line = $lines[++$i];
                            while (!preg_match('/^]/', $line)) {
                                $multiLineArray .= $line . "\n";
                                $line = $lines[++$i];
                            }
                            $multiLineArray .= "]";
                            $set->defaultValue = $multiLineArray;
                        }
                        if (preg_match('/^set\(.+?, function/', $line, $m)) {
                            $body = [];
                            $line = $lines[++$i];
                            while (!preg_match('/^}\);$/', $line)) {
                                $body[] = trim($line);
                                $line = $lines[++$i];
                            }
                            if (count($body) === 1 && preg_match('/throw new/', $body[0])) {
                                $set->comment .= "\n:::info Required\nThrows exception if not set.\n:::\n";
                            } elseif (count($body) <= 4) {
                                $set->defaultValue = implode("\n", $body);
                            } else {
                                $set->comment .= "\n:::info Autogenerated\nThe value of this configuration is autogenerated on access.\n:::\n";
                            }
                        }
                        $this->config[$set->name] = $set;
                        break;
                    }
                    if ($match('^desc\([\'"](?<desc>.+?)[\'"]\);$')) {
                        $desc = $m['desc'];
                        break;
                    }
                    if ($match('^task\([\'"](?<task_name>[\w_:-]+?)[\'"],\s\[$')) {
                        $task = new DocTask();
                        $task->name = $m['task_name'];
                        $task->desc = $desc;
                        $task->comment = trim($comment);
                        $comment = '';
                        $task->group = [];
                        $task->recipePath = $this->recipePath;
                        $task->lineNumber = $i + 1;
                        $this->tasks[$task->name] = $task;
                        $state = 'group_task';
                        $currentTask = $task;
                        break;
                    }
                    if ($match('^task\([\'"](?<task_name>[\w_:-]+?)[\'"],')) {
                        $task = new DocTask();
                        $task->name = $m['task_name'];
                        $task->desc = $desc;
                        $task->comment = trim($comment);
                        $comment = '';
                        $task->recipePath = $this->recipePath;
                        $task->lineNumber = $i + 1;
                        $this->tasks[$task->name] = $task;
                        break;
                    }
                    if ($match('^<\?php')) {
                        break;
                    }
                    if ($match('^namespace Deployer;$')) {
                        $this->comment = $comment;
                        break;
                    }

                    $desc = '';
                    $comment = '';
                    break;

                case 'comment':
                    if ($match('\*/\s*$')) {
                        $state = 'root';
                        break;
                    }
                    $comment .= trim_comment($line) . "\n";
                    break;

                case 'group_task':
                    if ($match('^\s+\'(?<task_name>[\w_:-]+?)\',$')) {
                        $currentTask->group[] = $m['task_name'];
                        break;
                    }
                    $state = 'root';
                    break;
            }
        }
        return false;
    }
}