AlexP11223/php-project-lvl2

View on GitHub
src/formatters/pretty.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

namespace Differ\formatters\pretty;

use function Funct\Collection\flatten;
use const Differ\ADDED;
use const Differ\NESTED;
use const Differ\REMOVED;
use const Differ\CHANGED;
use const Differ\UNCHANGED;

const INDENT_SIZE = 4;

function removeQuotes($json)
{
    return preg_replace('/"(.*?)"/', '$1', $json);
}

function removeCommas($json)
{
    return preg_replace('/,$/m', '', $json);
}

function prettifyJson($json)
{
    return removeCommas(removeQuotes($json));
}

function stateToChar($state)
{
    switch ($state) {
        case ADDED:
            return '+';
        case REMOVED:
            return '-';
        case UNCHANGED:
            return ' ';
    }
    throw new \Exception("Unsupported state $state");
}

function indent($level, $state = UNCHANGED, $size = INDENT_SIZE)
{
    if ($level === 0) {
        return '';
    }
    if ($level < 0) {
        throw new \Exception("Indent level cannot be less than 0, $level given");
    }
    if ($size < 2) {
        throw new \Exception("Indent size cannot be less than 2, $size given");
    }
    return str_repeat(' ', $level * $size - 2) . stateToChar($state) . ' ';
}

function formatValue($value, $level)
{
    $json = json_encode($value, JSON_PRETTY_PRINT);
    $prettyJson = prettifyJson($json);
    $lines = explode(PHP_EOL, $prettyJson);
    $indentedLines = flatten([ // no ... here until 7.4 :(
        $lines[0],
        array_map(function ($line) use ($level) {
            return indent($level) . $line;
        }, array_slice($lines, 1))
    ]);
    return implode(PHP_EOL, $indentedLines);
}

function traverse($nodes, $level = 0)
{
    $lines = array_map(function ($node) use ($level) {
        $name = $node['name'] ?? null;
        switch ($node['state']) {
            case UNCHANGED:
                return indent($level) . "$name: " . formatValue($node['oldValue'], $level);
            case ADDED:
                return indent($level, ADDED) . "$name: " . formatValue($node['newValue'], $level);
            case REMOVED:
                return indent($level, REMOVED) . "$name: " . formatValue($node['oldValue'], $level);
            case CHANGED:
                return indent($level, REMOVED) . "$name: " . formatValue($node['oldValue'], $level) . PHP_EOL .
                    indent($level, ADDED) . "$name: " . formatValue($node['newValue'], $level);
            case NESTED:
                return indent($level) . "$name: {" . PHP_EOL .
                    traverse($node['children'], $level + 1) . PHP_EOL .
                    indent($level) . '}';
        }
        throw new \Exception("Unsupported state ${node['state']}");
    }, $nodes);

    return implode(PHP_EOL, $lines);
}

function format($diffTree)
{
    return '{' . PHP_EOL . traverse($diffTree, 1) . PHP_EOL . '}';
}