"use strict";
const path = require("path");
const fs = require("fs");
class NodeModulesDependenciesBuilder {
    constructor($fs) {
        this.$fs = $fs;
        this.seen = {};
        this.resolvedDependencies = [];
    }
    getProductionDependencies(projectPath) {
        this.projectPath = projectPath;
        this.rootNodeModulesPath = path.join(this.projectPath, "node_modules");
        let projectPackageJsonpath = path.join(this.projectPath, "package.json");
        let packageJsonContent = this.$fs.readJson(projectPackageJsonpath).wait();
        _.keys(packageJsonContent.dependencies).forEach(dependencyName => {
            let depth = 0;
            let directory = path.join(this.rootNodeModulesPath, dependencyName);
            this.traverseDependency(dependencyName, directory, depth);
        });
        return this.resolvedDependencies;
    }
    traverseDependency(name, currentModulePath, depth) {
        let modulePath = path.join(currentModulePath, "node_modules", name);
        let alternativeModulePath = path.join(this.rootNodeModulesPath, name);
        this.findModule(modulePath, alternativeModulePath, name, depth);
    }
    findModule(modulePath, alternativeModulePath, name, depth) {
        let exists = this.moduleExists(modulePath);
        if (exists) {
            if (this.seen[modulePath]) {
                return;
            }
            let dependency = this.addDependency(name, modulePath, depth + 1);
            this.readModuleDependencies(modulePath, depth + 1, dependency);
        }
        else {
            modulePath = alternativeModulePath;
            exists = this.moduleExists(modulePath);
            if (!exists) {
                return;
            }
            if (this.seen[modulePath]) {
                return;
            }
            let dependency = this.addDependency(name, modulePath, 0);
            this.readModuleDependencies(modulePath, 0, dependency);
        }
        this.seen[modulePath] = true;
    }
    readModuleDependencies(modulePath, depth, currentModule) {
        let packageJsonPath = path.join(modulePath, 'package.json');
        let packageJsonExists = fs.lstatSync(packageJsonPath).isFile();
        if (packageJsonExists) {
            let packageJsonContents = this.$fs.readJson(packageJsonPath).wait();
            if (!!packageJsonContents.nativescript) {
                currentModule.nativescript = packageJsonContents.nativescript;
            }
            _.keys(packageJsonContents.dependencies).forEach((dependencyName) => {
                this.traverseDependency(dependencyName, modulePath, depth);
            });
        }
    }
    addDependency(name, directory, depth) {
        let dependency = {
            name,
            directory,
            depth
        };
        this.resolvedDependencies.push(dependency);
        return dependency;
    }
    moduleExists(modulePath) {
        try {
            let exists = fs.lstatSync(modulePath);
            if (exists.isSymbolicLink()) {
                exists = fs.lstatSync(fs.realpathSync(modulePath));
            }
            return exists.isDirectory();
        }
        catch (e) {
            return false;
        }
    }
}
exports.NodeModulesDependenciesBuilder = NodeModulesDependenciesBuilder;
$injector.register("nodeModulesDependenciesBuilder", NodeModulesDependenciesBuilder);
