// MIT © 2017 azu
// MIT © Zoltan Kochan
// Original https://github.com/zkochan/rcfile
"use strict";

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

var path = require("path");
var debug = require("debug")("rc-config-loader");
var requireFromString = require("require-from-string");
var JSON5 = require("json5");
var fs = require("fs");
var pathExists = require("path-exists");
var objectAssign = require("object-assign");
var keys = require("object-keys");

var defaultLoaderByExt = {
    ".js": loadJSConfigFile,
    ".json": loadJSONConfigFile,
    ".yaml": loadYAMLConfigFile,
    ".yml": loadYAMLConfigFile
};

var defaultOptions = {
    // does look for `package.json`
    packageJSON: false,
    // treat default(no ext file) as some extension
    defaultExtension: [".json", ".yaml", ".yml", ".js"],
    cwd: process.cwd()
};

/**
 * @param {string} pkgName
 * @param {rcConfigLoaderOption} [opts]
 * @returns {{ config: Object, filePath:string } | undefined}
 */
module.exports = function rcConfigLoader(pkgName) {
    var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    // path/to/config or basename of config file.
    var configFileName = opts.configFileName || "." + pkgName + "rc";
    var defaultExtension = opts.defaultExtension || defaultOptions.defaultExtension;
    var cwd = opts.cwd || defaultOptions.cwd;
    var packageJSON = opts.packageJSON || defaultOptions.packageJSON;
    var packageJSONFieldName = (typeof packageJSON === "undefined" ? "undefined" : _typeof(packageJSON)) === "object" ? packageJSON.fieldName : pkgName;

    var parts = splitPath(cwd);

    var loaders = Array.isArray(defaultExtension) ? defaultExtension.map(function (extension) {
        return defaultLoaderByExt[extension];
    }) : defaultLoaderByExt[defaultExtension];

    var loaderByExt = objectAssign({}, defaultLoaderByExt, {
        "": loaders
    });

    return findConfig({ parts: parts, loaderByExt: loaderByExt, configFileName: configFileName, packageJSON: packageJSON, packageJSONFieldName: packageJSONFieldName });
};

/**
 *
 * @param {string[]} parts
 * @param {Object} loaderByExt
 * @param {string} configFileName
 * @param {boolean|Object} packageJSON
 * @param {string} packageJSONFieldName
 * @returns {{
 *  config: string,
 *  filePath: string
 * }|undefined}
 */
function findConfig(_ref) {
    var parts = _ref.parts,
        loaderByExt = _ref.loaderByExt,
        configFileName = _ref.configFileName,
        packageJSON = _ref.packageJSON,
        packageJSONFieldName = _ref.packageJSONFieldName;

    var exts = keys(loaderByExt);
    while (exts.length) {
        var ext = exts.shift();
        var configLocation = join(parts, configFileName + ext);
        if (!pathExists.sync(configLocation)) {
            continue;
        }
        var loaders = loaderByExt[ext];
        if (!Array.isArray(loaders)) {
            var loader = loaders;
            var result = loader(configLocation);
            if (!result) {
                continue;
            }
            return {
                config: loader(configLocation),
                filePath: configLocation
            };
        }
        for (var i = 0; i < loaders.length; i++) {
            var _loader = loaders[i];
            var _result = _loader(configLocation, true);
            if (!_result) {
                continue;
            }
            return {
                config: _result,
                filePath: configLocation
            };
        }
    }

    if (packageJSON) {
        var pkgJSONLoc = join(parts, "package.json");
        if (pathExists.sync(pkgJSONLoc)) {
            var pkgJSON = require(pkgJSONLoc);
            if (pkgJSON[packageJSONFieldName]) {
                return {
                    config: pkgJSON[packageJSONFieldName],
                    filePath: pkgJSONLoc
                };
            }
        }
    }
    if (parts.pop()) {
        return findConfig({ parts: parts, loaderByExt: loaderByExt, configFileName: configFileName, packageJSON: packageJSON, packageJSONFieldName: packageJSONFieldName });
    }
    return undefined;
}

function splitPath(x) {
    return path.resolve(x || "").split(path.sep);
}

function join(parts, filename) {
    return path.resolve(parts.join(path.sep) + path.sep, filename);
}

function loadJSConfigFile(filePath, suppress) {
    debug("Loading JavaScript config file: " + filePath);
    try {
        var content = fs.readFileSync(filePath, "utf-8");
        return requireFromString(content, filePath);
    } catch (e) {
        debug("Error reading JavaScript file: " + filePath);
        if (!suppress) {
            e.message = "Cannot read config file: " + filePath + "\nError: " + e.message;
            throw e;
        }
    }
}

function loadJSONConfigFile(filePath, suppress) {
    debug("Loading JSON config file: " + filePath);

    try {
        return JSON5.parse(readFile(filePath));
    } catch (e) {
        debug("Error reading JSON file: " + filePath);
        if (!suppress) {
            e.message = "Cannot read config file: " + filePath + "\nError: " + e.message;
            throw e;
        }
    }
}

function readFile(filePath) {
    return fs.readFileSync(filePath, "utf8");
}

function loadYAMLConfigFile(filePath, suppress) {
    debug("Loading YAML config file: " + filePath);

    // lazy load YAML to improve performance when not used
    var yaml = require("js-yaml");

    try {
        // empty YAML file can be null, so always use
        return yaml.safeLoad(readFile(filePath)) || {};
    } catch (e) {
        debug("Error reading YAML file: " + filePath);
        if (!suppress) {
            e.message = "Cannot read config file: " + filePath + "\nError: " + e.message;
            throw e;
        }
    }
}
//# sourceMappingURL=rc-config-loader.js.map