ikijime/php-project-lvl2

View on GitHub
src/formatters/Stylish.php

Summary

Maintainability
A
0 mins
Test Coverage
A
97%
<?php

declare(strict_types=1);

namespace Differ\Formatters;

use function Functional\flatten;

const INDENT_WIDTH = 4;

function makeIndent(int $depth): string
{
    return str_repeat(' ', INDENT_WIDTH * $depth);
}

function parseValue(mixed $value, int $depth): string
{
    if (is_bool($value) || is_null($value)) {
        return json_encode($value, JSON_THROW_ON_ERROR);
    }

    if (is_object($value)) {
        $indent = makeIndent($depth);

        $leafs = array_map(function ($key) use ($value, $depth): string {
            $doubleIndent = makeIndent($depth + 1);
            return "{$doubleIndent}{$key}: " . parseValue($value->$key, $depth + 1);
        }, array_keys((array) $value));

        $branch = implode("\n", flatten($leafs));
        return "{\n{$branch}\n{$indent}}";
    }

    return (string) $value;
}

function stylish(object $AST): string
{
    $iter = function (object $AST, int $depth) use (&$iter): array {
        return array_map(function ($node) use ($iter, $depth): string {
            [
                'type' => $type,
                'key' => $key,
                'oldValue' => $oldValue,
                'newValue' => $newValue
            ] = (array) $node;

            $indent = makeIndent($depth - 1);

            switch ($type) {
                case 'added':
                    return "{$indent}  + {$node->key}: " . parseValue($newValue, $depth);
                case 'removed':
                    return "{$indent}  - {$node->key}: " . parseValue($oldValue, $depth);
                case 'unchanged':
                    return "{$indent}    {$key}: " . parseValue($oldValue, $depth);
                case 'changed':
                    $oldLine = "{$indent}  - {$key}: " . parseValue($oldValue, $depth);
                    $newLine = "{$indent}  + {$key}: " . parseValue($newValue, $depth);
                    return "{$oldLine}\n{$newLine}";
                case 'children':
                    return makeIndent($depth) .
                        "{$key}: {\n" .
                         implode("\n", flatten($iter($node->oldValue, $depth + 1))) .
                         "\n" . makeIndent($depth) . "}";
                default:
                    throw new \Exception("Type {$type} not supported");
            }
        }, (array) $AST);
    };

    return implode("\n", flatten(['{', $iter($AST, 1), '}']));
}