"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const process = __importStar(require("process"));
const open_1 = __importDefault(require("open"));
const inquirer_1 = __importDefault(require("inquirer"));
const webpack_1 = __importDefault(require("webpack"));
const webpack_dev_server_1 = __importDefault(require("webpack-dev-server"));
const node_watch_1 = __importDefault(require("node-watch"));
const body_parser_1 = __importDefault(require("body-parser"));
const autoRequire = __importStar(require("../tools/scripts/autoRequire"));
const generateMeta = __importStar(require("../tools/scripts/generateMeta"));
const webpackConfig = __importStar(require("../tools/webpack"));
const util_1 = require("../util");
const preview_1 = require("./preview");
class LibraryBuilder {
    constructor(options, isDev, port = 4567) {
        this.containerMap = {};
        this.run = () => {
            this.isDev ? this.dev() : this.dist();
        };
        this.dist = () => __awaiter(this, void 0, void 0, function* () {
            if (this.options.proxy) {
                process.env.http_proxy = this.options.proxy;
            }
            try {
                yield this.beforeDist();
                yield this.runBuild();
                yield this.runMetaBuild();
                this.afterDist();
                util_1.log('构建成功', 'ok');
            }
            catch (err) {
                util_1.stopSpinner(false);
                util_1.error(err);
                process.exit(1);
            }
            finally {
                util_1.stopSpinner(false);
            }
        });
        this.dev = () => __awaiter(this, void 0, void 0, function* () {
            if (this.options.proxy) {
                process.env.http_proxy = this.options.proxy;
            }
            try {
                yield this.chooseContainer();
                yield this.beforeDist();
                this.runWatchServer();
                this.runDevServer();
            }
            catch (err) {
                util_1.stopSpinner(false);
                util_1.error(err);
                process.exit(1);
            }
        });
        this.getContainerMap = () => {
            const map = {};
            Object.keys(this.paths.containersMap).forEach(i => {
                const configPath = path.resolve(this.paths.containersMap[i], './config.json');
                const { name, desc, author, type = '*' } = require(configPath);
                map[i] = {
                    name,
                    desc,
                    author,
                    type,
                    pathName: i,
                };
            });
            return map;
        };
        this.chooseContainer = () => __awaiter(this, void 0, void 0, function* () {
            const containers = Object.entries(this.containerMap).map(([, v]) => v);
            if (containers.length === 1) {
                this.container = containers[0];
            }
            else {
                const options = containers.map(i => ({
                    key: i.pathName,
                    name: [
                        `[${i.type ? i.type.toUpperCase() : '*'}]`,
                        `[${i.pathName}]`,
                        i.name,
                        `(Created by: ${i.author})`,
                    ].join(' '),
                }));
                const { container: c } = yield inquirer_1.default.prompt([
                    {
                        type: 'list',
                        name: 'container',
                        message: '选择 Container',
                        default: options[0].key,
                        choices: options,
                    },
                ]);
                const containerPath = c.split(' ')[1];
                this.container = this.containerMap[containerPath.slice(1, containerPath.length - 1)];
            }
        });
        this.runWatchServer = () => {
            util_1.logWithSpinner('🤖', '启动 File Watcher');
            ['components', 'plugins', 'actions'].forEach((name) => {
                node_watch_1.default(path.resolve(this.paths.srcPath, `./${name}`), { recursive: false }, () => {
                    util_1.log(`🔥  ${name} 目录更新`);
                    this.paths = util_1.getPaths(this.paths.rootPath);
                    return this.afterUpdate();
                });
            });
            util_1.stopSpinner();
        };
        this.beforeDist = () => __awaiter(this, void 0, void 0, function* () {
            yield this.clearTemp();
            util_1.logWithSpinner('⛽️', '执行前置脚本');
            this.generateAutoRequireTempFile();
            util_1.stopSpinner();
        });
        this.generateAutoRequireTempFile = () => {
            if (this.isDev) {
                const type = this.container ? this.container.type : '*';
                util_1.logWithSpinner('📃', `生成 AutoRequireTemp[${type}] 文件`);
                autoRequire.writeTempFile(this.paths, type, this.container ? this.container.pathName : undefined);
            }
            else {
                util_1.logWithSpinner('📃', '生成 AutoRequire[*] 文件');
                autoRequire.writeTempFile(this.paths, '*');
                util_1.logWithSpinner('📃', '生成 AutoRequire[h5] 文件');
                autoRequire.writeTempFile(this.paths, 'h5');
                util_1.logWithSpinner('📃', '生成 AutoRequire[pc] 文件');
                autoRequire.writeTempFile(this.paths, 'pc');
            }
        };
        this.runDevServer = () => {
            return new Promise(resolve => {
                util_1.logWithSpinner('💫', '生成 Webpack 配置');
                const config = webpackConfig.getLibDevConfig(this.paths, this.container.type);
                util_1.stopSpinner();
                util_1.logWithSpinner('🚀', '等待 Dev Server');
                const compiler = webpack_1.default(config);
                new webpack_dev_server_1.default(compiler, {
                    hot: true,
                    inline: false,
                    contentBase: [this.paths.staticPath, this.paths.outputPath],
                    compress: false,
                    headers: {
                        'Access-Control-Allow-Origin': '*',
                        'Access-Control-Allow-Headers': '*',
                    },
                    after: this.openEditor,
                    setup: app => {
                        app.post('/cgi/preview', body_parser_1.default.json(), (req, res) => preview_1.preview(req, res, this.paths, this.container.pathName));
                    },
                }).listen(4567);
                compiler.hooks.done.tap('IDoNotUnderstandWhatThisStringIsForButItCannotBeEmpty', () => {
                    util_1.stopSpinner();
                    resolve();
                });
            });
        };
        this.clearTemp = () => __awaiter(this, void 0, void 0, function* () {
            util_1.logWithSpinner('💭', '清除缓存');
            yield Promise.all([fs.emptyDir(this.paths.tempPath), fs.emptyDir(this.paths.outputPath)]);
            util_1.stopSpinner();
        });
        this.afterUpdate = () => {
            util_1.logWithSpinner('🔥', '重新执行前置脚本');
            this.generateAutoRequireTempFile();
            util_1.stopSpinner();
        };
        this.getContainerTypes = () => {
            return Object.entries(this.containerMap).reduce((accu, [, { type }]) => {
                if (!accu.includes(type)) {
                    accu.push(type);
                }
                return accu;
            }, []);
        };
        this.openEditor = () => {
            const url = `http://127.0.0.1:${this.port}/editor/cli-debug.html?debugPort=${this.port}&libName=${this.paths.libName}${this.container.type === '*' ? '' : `&type=${this.container.type}`}`;
            setTimeout(() => open_1.default(url), 5000);
        };
        if (options.proxy) {
            process.env.http_proxy = options.proxy;
        }
        this.isDev = isDev;
        this.port = port;
        this.options = options;
        this.paths = util_1.getPaths(process.cwd());
        this.containerMap = this.getContainerMap();
    }
    afterDist() {
        util_1.logWithSpinner('⛽️', '执行后置脚本');
        const meta = generateMeta.getMaterialsMeta(this.paths);
        util_1.logWithSpinner('📃', '生成 MetaTempForSync 文件');
        generateMeta.generateMeta(this.paths, meta);
        util_1.logWithSpinner('📃', '生成 StyleSchemaTemp 文件');
        generateMeta.generateStyleSchema(this.paths, meta);
        util_1.stopSpinner();
    }
    runBuild() {
        util_1.logWithSpinner('💫', '生成 Webpack 配置');
        const config = webpackConfig.getLibProdConfig(this.paths, this.getContainerTypes());
        util_1.stopSpinner();
        util_1.logWithSpinner('🚀', '运行 Webpack 构建');
        return new Promise((resolve, reject) => {
            webpack_1.default(config).run(LibraryBuilder.webpackCallback(resolve, reject));
        });
    }
    runMetaBuild() {
        util_1.logWithSpinner('💫', '生成 Meta Webpack 配置');
        const config = webpackConfig.getLibMetaConfig(this.paths);
        util_1.stopSpinner();
        util_1.log('⚡️ 启动 Meta 构建...');
        return new Promise((resolve, reject) => {
            webpack_1.default(config).run(LibraryBuilder.webpackCallback(resolve, reject));
        });
    }
}
LibraryBuilder.webpackCallback = (resolve, reject) => {
    return (err, stats) => {
        if (err) {
            util_1.error('fatal webpack errors:', (err.stack.toString() || err.toString()).trim());
            if (err.details) {
                util_1.error('fatal webpack errors:', err.details.trim());
            }
            reject();
        }
        const info = stats.toJson();
        if (stats.hasErrors()) {
            info.errors.forEach((e) => {
                if (e.trim()) {
                    util_1.error('\n\nWebpack compilation errors:', e.trim());
                }
            });
            return reject();
        }
        return resolve();
    };
};
exports.LibraryBuilder = LibraryBuilder;
//# sourceMappingURL=buildLibrary.js.map