function unstringify(cfg) {
  Object.keys(cfg)
    .filter(
      (k) =>
        !/version$/i.test(k) &&
        (typeof cfg[k] === "string" || cfg[k] instanceof Object),
    )
    .forEach((k) => {
      if (typeof cfg[k] === "string") {
        if (cfg[k] === "true") {
          cfg[k] = true;
        } else if (cfg[k] === "false") {
          cfg[k] = false;
        } else if (cfg[k].startsWith("*json:")) {
          try {
            cfg[k] = JSON.parse(cfg[k].replace(/^\*json:/, ""));
          } catch (e) {
            throw kerror.get(
              "cannot_parse",
              `the key "${k}" does not contain a valid stringified JSON (${cfg[k]})`,
            );
          }
        } else if (/^(-|\+)?([0-9]+)$/.test(cfg[k])) {
          cfg[k] = Number.parseInt(cfg[k]);
        } else if (/^(-|\+)?([0-9]+(\.[0-9]+)?)$/.test(cfg[k])) {
          cfg[k] = parseFloat(cfg[k]);
        }
      } else {
        cfg[k] = unstringify(cfg[k]);
      }
    });

  return cfg;
}
RC params can be overriden using environment variables,
in which case all values are passed as strings.

When dealing with configuration, we can safely assume the expected
correct type

@param {object} cfg - configuration loaded using RC
@returns {object} correctly typed configuration