pisarevdmitry/frontend-project-lvl2

View on GitHub
src/formatters/stylish.js

Summary

Maintainability
A
30 mins
Test Coverage
A
100%
import _ from 'lodash';

const calcIndent = (depth, isCompared = false) => {
  const baseIndent = 4;
  const comparedMargin = 2;
  const indent = isCompared ? (depth * baseIndent) - comparedMargin : depth * baseIndent;
  return ' '.repeat(indent);
};

const formatNotCompared = (obj, depth) => {
  const keys = _.sortBy(_.keys(obj));
  return keys.map((key) => {
    const space = calcIndent(depth);
    return _.isPlainObject(obj[key])
      ? `${space}${key}: {\n${formatNotCompared(obj[key], depth + 1)}\n${space}}`
      : `${space}${key}: ${obj[key]}`;
  }).join('\n');
};

const styleChangedValue = (key, value, depth, symbol) => {
  const indentCompared = calcIndent(depth, true);
  return _.isPlainObject(value)
    ? `${indentCompared}${symbol} ${key}: {\n${formatNotCompared(value, depth + 1)}\n${calcIndent(depth)}}`
    : `${indentCompared}${symbol} ${key}: ${value}`;
};

const buildFormat = (children, depth) => {
  const result = children.map((node) => {
    const { type, value, name } = node;
    switch (type) {
      case 'unchanged': {
        return `${calcIndent(depth)}${name}: ${value}`;
      }
      case 'added': {
        return styleChangedValue(name, value, depth, '+');
      }
      case 'deleted': {
        return styleChangedValue(name, value, depth, '-');
      }
      case 'changed': {
        const { oldValue, newValue } = node;
        const deleted = styleChangedValue(name, oldValue, depth, '-');
        const added = styleChangedValue(name, newValue, depth, '+');
        return `${deleted}\n${added}`;
      }
      case 'parent': {
        const space = calcIndent(depth);
        const { children: nodeChildren } = node;
        return `${space}${name}: {\n${buildFormat(nodeChildren, depth + 1)}\n${space}}`;
      }
      default:
        throw new Error(`unsupported ${type} type`);
    }
  }).join('\n');
  return result;
};

export default ({ children }) => {
  const result = buildFormat(children, 1);
  return `{\n${result}\n}`;
};