"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CombineJavascriptsCompiler = void 0;
const path = require("path");
const interfaces_1 = require("./interfaces");
const utils_1 = require("../utils");
const fs = require("fs");
const rimraf = require("rimraf");
const webpack = require("webpack");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
class CombineJavascriptsCompiler {
    constructor(pluginName, dependencyPaths, assetsPath, mainRepoDir, isProduction) {
        this.pluginName = pluginName;
        this.dependencyPaths = dependencyPaths;
        this.assetsPath = assetsPath;
        this.mainRepoDir = mainRepoDir;
        this.isProduction = isProduction;
        this.pathToEntryFile = '';
        this.pathToEntryFile = path.join(this.assetsPath, CombineJavascriptsCompiler.ENTRY_FILE_NAME);
    }
    compile() {
        return new Promise((resolve, reject) => {
            const generatedDir = CombineJavascriptsCompiler.getOutputDir(this.assetsPath);
            const outputFile = path.join(generatedDir, CombineJavascriptsCompiler.OUTPUT_FILE_NAME);
            if (!fs.existsSync(this.pathToEntryFile)) {
                this.cleanOutput(outputFile);
                return resolve(interfaces_1.CompilationResult.CHANGED);
            }
            if (!fs.existsSync(generatedDir)) {
                fs.mkdirSync(generatedDir);
            }
            const start = new Date().getTime();
            console.log(`⟲ [${this.pluginName}] starting to combine javascripts...`);
            const sourcesToCombine = this.getCombineJavascriptSources();
            if (sourcesToCombine.length == 0) {
                console.log(utils_1.cgreen `⇢`, `[${this.pluginName}] No javascripts specified to combine.`);
                return resolve(interfaces_1.CompilationResult.UNCHANGED);
            }
            this.combineJavascripts(sourcesToCombine)
                .then(() => {
                let end = new Date().getTime();
                console.log(utils_1.GREEN_CHECK, `[${this.pluginName}] Combining javascripts finished (${utils_1.formatDuration(end - start)})`);
                return resolve(interfaces_1.CompilationResult.CHANGED);
            })
                .catch((err) => {
                console.error(utils_1.cerr `${err}`);
                reject(`[${this.pluginName}] Failed to combine javascripts`);
            });
        }).catch((err) => {
            throw Error(err);
        });
    }
    static getOutputDir(assetsPath) {
        return path.resolve(assetsPath, CombineJavascriptsCompiler.OUTPUT_DIR);
    }
    combineJavascripts(sourcesToCombine) {
        return new Promise((resolve, reject) => {
            // @ts-ignore
            webpack(this.getCombineJavascriptWebpackConfig(sourcesToCombine), (err, stats) => {
                if (err) {
                    reject(err);
                }
                else if (stats.hasErrors()) {
                    reject(stats.toString());
                }
                else {
                    resolve();
                }
            });
        });
    }
    getCombineJavascriptWebpackConfig(sourcesToCombine) {
        const config = {
            mode: 'production',
            context: path.resolve(this.assetsPath),
            externals: {
                jquery: 'jQuery',
            },
            resolveLoader: {
                modules: [path.resolve(__dirname, '../../', 'node_modules')],
            },
            entry: {
                compressed: sourcesToCombine,
            },
            module: {
                rules: [
                    {
                        // Load everything with script-loader since all libraries are needed as gloabls in cplace.
                        // Webpack minimization/uglifying does not work with script-loader as the whole script is wrapped as is.
                        // For that reason, an uglify-loader first uglifies the input script (using UglifyJsPlugin with default options)
                        // and then loads it with script-loader
                        test: /\.js$/,
                        use: ['script-loader', 'uglify-loader'],
                    },
                ],
            },
            optimization: {
                minimize: true,
                minimizer: [
                    new UglifyJsPlugin({
                        uglifyOptions: {
                            comments: false,
                        },
                    }),
                ],
            },
            output: {
                filename: '[name].js',
                path: CombineJavascriptsCompiler.getOutputDir(this.assetsPath),
            },
        };
        return config;
    }
    getCombineJavascriptSources() {
        const result = [];
        const includesFile = fs.readFileSync(this.pathToEntryFile, 'utf8');
        let includePaths = includesFile.replace(/\r/g, '').split('\n');
        includePaths.forEach((includeLine) => {
            // skip empty lines and lines beggining with '#'
            if (includeLine.trim().length > 0 &&
                !includeLine
                    .trim()
                    .startsWith(CombineJavascriptsCompiler.INCLUDE_COMMENT)) {
                if (includeLine.endsWith('*')) {
                    // read all files from a potential folder and add them to combine
                    const lineWithoutAsterix = includeLine
                        .trim()
                        .substring(0, includeLine.length - 2);
                    const resolvedFolder = path.resolve(this.assetsPath, '.' + lineWithoutAsterix);
                    if (fs.existsSync(resolvedFolder) &&
                        fs.lstatSync(resolvedFolder).isDirectory()) {
                        fs.readdirSync(resolvedFolder).forEach((file) => {
                            const absolutePath = path.join(resolvedFolder, file);
                            if (fs.lstatSync(absolutePath).isFile()) {
                                const relativePath = path.relative(this.assetsPath, absolutePath);
                                result.push(`.${path.sep}${relativePath}`);
                            }
                        });
                    }
                }
                else {
                    const resolvedFile = path.resolve(this.assetsPath, '.' + includeLine);
                    const relativePath = path.relative(this.assetsPath, resolvedFile);
                    result.push(`.${path.sep}${relativePath}`);
                }
            }
        });
        utils_1.debug(`(CombineJavascriptsCompiler) [${this.pluginName}] will combine following files: \n ${result}`);
        return result;
    }
    cleanOutput(outputFile) {
        rimraf.sync(outputFile);
        rimraf.sync(outputFile.concat('.map'));
    }
}
exports.CombineJavascriptsCompiler = CombineJavascriptsCompiler;
CombineJavascriptsCompiler.OUTPUT_DIR = '_generated_';
CombineJavascriptsCompiler.ENTRY_FILE_NAME = 'javaScriptIncludesToBeCompressed.txt';
CombineJavascriptsCompiler.OUTPUT_FILE_NAME = 'compressed.js';
CombineJavascriptsCompiler.INCLUDE_COMMENT = '#';
//# sourceMappingURL=CombineJavascriptsCompiler.js.map