"use strict";
/*
 * Copyright 2018, collaboration Factory AG. All rights reserved.
 */
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.AbstractTypescriptCompiler = void 0;
const path = require("path");
const crypto = require("crypto");
const spawn = require("cross-spawn");
const interfaces_1 = require("./interfaces");
const utils_1 = require("../utils");
const fs = require("fs");
const glob = require("glob");
class AbstractTypescriptCompiler {
    constructor(pluginName, dependencyPaths, assetsPath, mainRepoDir, isProduction, srcFolderName, outputDirName) {
        this.pluginName = pluginName;
        this.dependencyPaths = dependencyPaths;
        this.assetsPath = assetsPath;
        this.mainRepoDir = mainRepoDir;
        this.isProduction = isProduction;
        this.srcFolderName = srcFolderName;
        this.outputDirName = outputDirName;
    }
    compile() {
        return __awaiter(this, void 0, void 0, function* () {
            const start = new Date().getTime();
            console.log(`⟲ [${this.pluginName}] starting ${this.getJobName()} compilation...`);
            this.runTsc();
            let end = new Date().getTime();
            console.log(utils_1.cgreen `⇢`, `[${this.pluginName}] ${this.getJobName()} compiled, starting bundling... (${utils_1.formatDuration(end - start)})`);
            yield this.doPostProcessing();
            end = new Date().getTime();
            console.log(utils_1.GREEN_CHECK, `[${this.pluginName}] ${this.getJobName()} finished (${utils_1.formatDuration(end - start)})`);
            try {
                const oldHash = this.readCompilationHash();
                const newHash = yield this.computeAndUpdateCompilationHash();
                utils_1.debug(`(TypescriptCompiler - ${this.getJobName()}) [${this.pluginName}] Old hash: ${oldHash} - New hash: ${newHash}`);
                if (newHash && oldHash === newHash) {
                    console.log(utils_1.cgreen `⇢`, `[${this.pluginName}] TypeScript API did not change, no recompilation of dependants required`);
                    return interfaces_1.CompilationResult.UNCHANGED;
                }
            }
            catch (e) {
                utils_1.debug(`(TypescriptCompiler - ${this.getJobName()}) [${this.pluginName}] Failed to get and compute hashes: ${e}`);
            }
            return interfaces_1.CompilationResult.CHANGED;
        });
    }
    doPostProcessing() {
        return __awaiter(this, void 0, void 0, function* () { });
    }
    runTsc() {
        const tsAssetsPath = path.resolve(this.assetsPath, this.srcFolderName);
        const tscExecutable = this.getTscExecutable();
        let args = ['--project', tsAssetsPath];
        if (utils_1.isDebugEnabled()) {
            args.push('--extendedDiagnostics');
        }
        utils_1.debug(`(TypescriptCompiler) [${this.pluginName}] executing command '${tscExecutable} ${args.join(' ')}'`);
        const result = spawn.sync(tscExecutable, args, {
            stdio: [process.stdin, process.stdout, process.stderr],
        });
        utils_1.debug(`(TypescriptCompiler) [${this.pluginName}] tsc return code: ${result.status}`);
        if (result.status !== 0) {
            throw Error(`[${this.pluginName}] TypeScript compilation failed...`);
        }
    }
    getTscExecutable() {
        return path.resolve(this.mainRepoDir, 'node_modules', 'typescript', 'bin', 'tsc');
    }
    getHashFilePath() {
        return path.resolve(this.assetsPath, this.outputDirName, AbstractTypescriptCompiler.HASH_FILE);
    }
    readCompilationHash() {
        const hashPath = this.getHashFilePath();
        if (fs.existsSync(hashPath)) {
            return fs.readFileSync(hashPath, { encoding: 'utf8' });
        }
        else {
            return null;
        }
    }
    computeAndUpdateCompilationHash() {
        const generatedJsPath = path.resolve(this.assetsPath, this.outputDirName);
        const hashPath = this.getHashFilePath();
        return new Promise((resolve, reject) => {
            const hash = crypto.createHash('sha256');
            glob(`${generatedJsPath}/**/*.d.ts`, {}, (err, files) => {
                if (err) {
                    reject(err);
                    return;
                }
                files.forEach((f) => {
                    const data = fs.readFileSync(f);
                    hash.update(data);
                });
                const newHash = hash.digest('hex');
                try {
                    fs.writeFileSync(hashPath, newHash, { encoding: 'utf8' });
                    resolve(newHash);
                }
                catch (e) {
                    reject(e);
                }
            });
        });
    }
}
exports.AbstractTypescriptCompiler = AbstractTypescriptCompiler;
AbstractTypescriptCompiler.HASH_FILE = 'typings.hash';
//# sourceMappingURL=AbstractTypescriptCompiler.js.map