/*
 * Formats errors
 *
 * @module midwest/util/format-error
 */
'use strict';

// modules > native
const http = require('http');

// modules > 3rd party
const _ = require('lodash');
const debug = require('debug')('midwest:errorHandler');

const fileLocationPattern = new RegExp(`${process.cwd()}\\/([\\/\\w-_\\.]+\\.js):(\\d*):(\\d*)`);

/*
 * @private
 */
// eslint-disable-next-line consistent-return
function parseFileLocation(stack) {
  if (_.isString(stack)) {
    return _.zipObject(['fileName', 'lineNumber', 'columnNumber'],
      _.tail(stack.match(fileLocationPattern)));
  }
}

/*
 * Formats an error and converts it to a plain object.
 *
 * @param {Error} error - Error to be logged
 * @param {IncomingMessage} req - Request object of current request.
 * Used to add additional info to error such as logged in user.
 *
 * @returns The formatted error as a plain object.
 */
module.exports = function (error, req) {
  // pick all important properties on Error prototype and any
  // own properties
  let err = _.pick(error, ['stack', 'message', 'name'].concat(_.keys(error)));

  debug(`unformatted error: ${JSON.stringify(error, null, '\t')}`);

  err.status = err.status || 500;
  err.statusText = http.STATUS_CODES[err.status];

  if (req) {
    _.assignIn(err, {
      path: req.path,
      method: req.method,
      ip: req.ip,
      user: req.user && req.user.id,
      userAgent: req.headers['user-agent'],
    });

    err.xhr = req.xhr;

    // We mapKeys because Mongo does not allow keys with dots stored to DB.
    if (!_.isEmpty(req.body)) err.body = _.mapKeys(req.body, (value, key) => key.replace('.', 'DOT'));
    if (!_.isEmpty(req.query)) err.query = req.query;
  }

  if (error.name === 'ValidationError') {
    err.status = 422;

    err.details = _.assignIn(err.details, { validationErrors: _.map(error.errors, 'message') });

    delete err.errors;
  }

  if (err.status >= 500) {
    _.defaults(err, parseFileLocation(err.stack));
  } else {
    delete err.stack;
  }

  // sort properties by name
  err = _.fromPairs(_.sortBy(_.toPairs(err), (pair) => pair[0]));

  debug(`formatted error: ${JSON.stringify(err, null, '\t')}`);

  return err;
};

@@ -489,17 +489,17 @@
 t(%5B'file
-N
+n
 ame', 'l
@@ -880,16 +880,270 @@
 ct.%0A */%0A
+%0Aconst allowedProperties = %5B'id', 'body', 'columnNumber', 'dateCreated', 'description', 'details', 'filename', 'ip', 'lineNumber', 'method', 'message', 'name', 'path', 'query', 'session', 'stack', 'status', 'statusText', 'user_id', 'userAgent', 'xhr'%5D;%0A%0A
 module.e
@@ -1258,16 +1258,19 @@
 erties%0A 
+ //
  let err
@@ -1317,33 +1317,297 @@
 ame'
-%5D.concat(_.keys(error)));
+, ...Object.keys(error)%5D;%0A%0A  let err = _.pick(error, allowedProperties);%0A%0A  const nonStandardProperties = _.difference(Object.keys(error), allowedProperties);%0A%0A  if (nonStandardProperties.length) %7B%0A    err.details = Object.assign(%7B%7D, err.details, _.pick(error, nonStandardProperties));%0A  %7D
 %0A%0A  
@@ -1869,16 +1869,19 @@
     user
+_id
 : req.us

Update format error for postgres