"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var recast = require("recast");
var prettier = require("prettier");
var path_1 = require("path");
var _a = recast.types, namedTypes = _a.namedTypes, visit = _a.visit;
function tryResolve(path) {
    try {
        require.resolve(path);
        return true;
    }
    catch (error) {
        return false;
    }
}
function findModuleWithinDirs(modulePath, dirs, src) {
    var dir, newModulePath = modulePath;
    while (dirs.pop() !== "lib" && dirs.length > 0) {
        var remainingDirs = dirs.join(path_1.sep);
        var lookInDir = path_1.join(src, remainingDirs, newModulePath);
        newModulePath = path_1.join("..", newModulePath);
        if (tryResolve(lookInDir))
            return newModulePath;
    }
}
function relativeModulePath(modulePath, fileDir) {
    var paths = [];
    if (modulePath.indexOf("./") === -1)
        paths.push(".");
    if (fileDir === ".")
        paths.push("lib");
    paths.push(modulePath);
    return paths.join(path_1.sep);
}
function requireStatementProcessorFactory(options, pretty) {
    if (pretty === void 0) { pretty = true; }
    var src = options.get("src");
    return function (code, filePath) {
        var ast = recast.parse(code.toString());
        var filePathWithoutSrc = filePath.replace(new RegExp("" + path_1.join(src, path_1.sep)), "");
        var fileDir = path_1.dirname(filePathWithoutSrc);
        var baseDir = fileDir === "." ? "lib" : fileDir;
        var dirs = baseDir.split(path_1.sep);
        visit(ast, {
            visitCallExpression: function (path) {
                var node = path.node;
                // Check whether there are any calls to `require("some_module")`
                if (namedTypes.Identifier.check(node.callee) &&
                    node.callee.name === "require") {
                    // Keep the path to the module
                    var modulePath = node.arguments[0].value;
                    // Check whether the module can be resolved by node
                    // based on the existing path value
                    var fp = path_1.join(src, baseDir, modulePath);
                    if (tryResolve(fp)) {
                        node.arguments[0].value = relativeModulePath(modulePath, fileDir);
                    }
                    else {
                        var foundModulePath = findModuleWithinDirs(modulePath, dirs, src);
                        if (foundModulePath) {
                            node.arguments[0].value = foundModulePath;
                        }
                        else {
                            throw new Error("Unable to resolve Common JS module: " + modulePath);
                        }
                    }
                }
                this.traverse(path);
            }
        });
        code = recast.print(ast).code;
        return pretty ? prettier.format(code) : code;
    };
}
exports.requireStatementProcessorFactory = requireStatementProcessorFactory;
