"use strict";
/*
 * Tencent is pleased to support the open source community by making
 * Hippy available.
 *
 * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.injectEntry = void 0;
const tslib_1 = require("tslib");
const webpack_1 = tslib_1.__importDefault(require("webpack"));
/**
 * inject entry to webpack config
 * @param options webpack config
 * @param entryName specific which entry will inject new files, will inject to all entries if not specific
 * @param prepends prepends those files to the head of original entry
 * @param appends appends those files to the end of original entry
 */
const injectEntry = (compiler, entryName, prepends = [], appends = []) => {
    const currentWebpack = compiler.webpack || webpack_1.default;
    if (!currentWebpack.version || currentWebpack.version.startsWith('4')) {
        injectEntryWebpack4(compiler, entryName, prepends, appends);
    }
    else {
        injectEntryWebpack5(compiler, entryName, prepends, appends);
    }
    compiler.hooks.entryOption.call(compiler.options.context, compiler.options.entry);
};
exports.injectEntry = injectEntry;
function injectEntryWebpack5(compiler, entryName, prepends = [], appends = []) {
    const { options } = compiler;
    /**
     * EntryPlugin will prepend entry to the head of entry list
     * when use EntryPlugin muti-times, such as `new EntryPlugin(a), new EntryPlugin(b)`,
     * the final entry will be like `[a, b, originalEntry]`
     * And EntryPlugin will have higher priority than change compiler.option.entry array,
     * so use EntryPlugin could ensure stable of entry sequence
     *
     * EntryPlugin is available in webpack 5+
     */
    // @ts-ignore
    const { EntryPlugin } = webpack_1.default;
    if (EntryPlugin) {
        // Prepended entries does not care about injection order,
        prepends.forEach((entry) => {
            new EntryPlugin(compiler.context, entry, { name: undefined }).apply(compiler);
        });
        prepends = [];
    }
    const entry = typeof options.entry === 'function' ? options.entry() : Promise.resolve(options.entry);
    options.entry = () => entry.then((entryObj) => {
        function injectOneEntry(entryName) {
            const injectEntry = entryObj[entryName];
            if (!(injectEntry === null || injectEntry === void 0 ? void 0 : injectEntry.import)) {
                throw new Error(`Could not find an entry named '${entryName}'. See https://webpack.js.org/concepts/entry-points/ for an overview of webpack entries.`);
            }
            prepends.reverse().forEach((prepend) => {
                if (!injectEntry.import.includes(prepend))
                    injectEntry.import.unshift(prepend);
            });
            appends.forEach((append) => {
                if (!injectEntry.import.includes(append))
                    injectEntry.import.push(append);
            });
            return entryObj;
        }
        if (entryName) {
            injectOneEntry(entryName);
        }
        else {
            Object.keys(entryObj).forEach((entryName) => {
                injectOneEntry(entryName);
            });
        }
        return entryObj;
    });
}
function injectEntryWebpack4(compiler, entryName, prepends = [], appends = []) {
    const { options } = compiler;
    function injectEntry(entry) {
        switch (typeof entry) {
            case 'undefined': {
                throw new Error(`Could not find an entry named '${entryName}'. See https://webpack.js.org/concepts/entry-points/ for an overview of webpack entries.`);
            }
            case 'string': {
                return [...prepends, entry, ...appends];
            }
            case 'object': {
                if (Array.isArray(entry)) {
                    prepends.reverse().forEach((file) => {
                        if (!entry.includes(file))
                            entry.unshift(file);
                    });
                    appends.forEach((file) => {
                        if (!entry.includes(file))
                            entry.push(file);
                    });
                    return entry;
                }
                if (entryName) {
                    return {
                        ...entry,
                        [entryName]: injectEntry(entry[entryName]),
                    };
                }
                Object.keys(entry).forEach((key) => {
                    entry[key] = injectEntry(entry[key]);
                });
                return entry;
            }
            default: {
                const _exhaust = entry;
                return _exhaust;
            }
        }
    }
    const { entry } = options;
    typeof entry === 'function'
        ? (options.entry = () => Promise.resolve(entry()).then(injectEntry))
        : (options.entry = () => injectEntry(entry));
}
