"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LernaGraph = exports.isService = void 0;
const fs_1 = require("fs");
const path_1 = require("path");
const _1 = require("./");
const _2 = require("./");
const resolve_ports_1 = require("../utils/resolve-ports");
const child_process_1 = require("child_process");
exports.isService = (location) => {
    return fs_1.existsSync(path_1.join(location, 'serverless.yml')) || fs_1.existsSync(path_1.join(location, 'serverless.yaml'));
};
class LernaGraph {
    constructor(scheduler, nodes, projectRoot, config, logger, defaultPort) {
        this._logger = logger;
        this._config = config;
        this._logger.log('graph').debug('Building graph with', nodes);
        this.projectRoot = projectRoot;
        const services = nodes.filter((n) => exports.isService(n.location));
        this.ports = resolve_ports_1.resolvePorts(services, config, this._logger, defaultPort);
        const builtNodes = new Set();
        for (const node of nodes) {
            if (!Array.from(builtNodes).some((n) => n.getName() === node.name)) {
                this._logger.log('graph').debug('Building node', node.name);
                this._logger.log('graph').debug('Already built', Array.from(builtNodes).map((b) => b.getName()));
                this._logger.log('graph').debug('Is service', exports.isService(node.location));
                exports.isService(node.location)
                    ? new _2.Service(scheduler, this, node, builtNodes, nodes)
                    : new _1.Package(scheduler, this, node, builtNodes, nodes);
            }
        }
        this.nodes = Array.from(builtNodes);
        this._logger.log('graph').debug('Built graph', this.nodes.map((n) => n.getName()));
        this._logger.log('graph').info(`Successfully built ${this.nodes.length} nodes`);
    }
    get logger() {
        return this._logger;
    }
    get io() {
        return this._io;
    }
    getPort(service) {
        return this.ports[service];
    }
    registerIPCServer(sockets) {
        this.getNodes().forEach((n) => n.registerIPCServer(sockets));
    }
    enableNodes() {
        this._logger.log('graph').debug('Enabling nodes descendants');
        this.nodes
            .filter((n) => n.isEnabled())
            .forEach((n) => {
            this._logger.log('graph').debug('Enabling node descendants', n.getName());
            const dependencies = n.getDependencies();
            this._logger.log('graph').silly('Descendants', n.getDependencies());
            dependencies.forEach((d) => d.enable());
        });
    }
    enableOne(node) {
        node.enable();
        node
            .getDependencies()
            .filter((n) => !n.isEnabled() && !this._config.noStart.includes(n.getName()))
            .forEach((n) => n.enable());
    }
    disableOne(node) {
        node.disable();
        node
            .getDependencies()
            .filter((n) => n.isEnabled() && !n.getDependent().some((ancestors) => ancestors.isEnabled()))
            .forEach((n) => n.disable());
    }
    enableAll() {
        this.nodes.filter((n) => !n.isEnabled() && !this._config.noStart.includes(n.getName())).forEach((n) => n.enable());
    }
    getProjectRoot() {
        return this.projectRoot;
    }
    getServices() {
        return this.nodes.filter((n) => n.isService());
    }
    getPackages() {
        return this.nodes.filter((n) => !n.isService());
    }
    getNodes() {
        return this.nodes;
    }
    get(name) {
        return this.nodes.find((n) => n.getName() === name);
    }
    bootstrap() {
        return __awaiter(this, void 0, void 0, function* () {
            this._logger.log('graph').info('Bootstrapping dependencies');
            const spawnedProcess = child_process_1.spawn('npx', ['lerna', 'bootstrap'], {
                cwd: this.projectRoot,
                stdio: 'ignore',
            });
            return new Promise((resolve, reject) => {
                spawnedProcess.on('close', (code) => {
                    if (code === 0) {
                        return resolve();
                    }
                    const err = `Process exited with status ${code}`;
                    this._logger.log('graph').error(err);
                    return reject(err);
                });
                spawnedProcess.on('error', (err) => {
                    this._logger.log('graph').error('Process errored: ', err.message);
                    return reject(err);
                });
            });
        });
    }
    registerIOSockets(io) {
        this._io = io;
    }
}
exports.LernaGraph = LernaGraph;
//# sourceMappingURL=lerna-graph.js.map