"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadEntry = void 0;
var tslib_1 = require("tslib");
/* eslint-disable @typescript-eslint/prefer-interface */
var path = (0, tslib_1.__importStar)(require("path"));
var url = (0, tslib_1.__importStar)(require("url"));
var semver_1 = require("semver");
var searequire_1 = (0, tslib_1.__importDefault)(require("searequire"));
var core_module_1 = (0, tslib_1.__importDefault)(require("./core_module"));
var index_1 = require("./index");
function loadEntry(entry, opts, taskId) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
        var allLoaded, loadedNpmPkgs;
        return (0, tslib_1.__generator)(this, function (_a) {
            switch (_a.label) {
                case 0:
                    allLoaded = {};
                    loadedNpmPkgs = {};
                    return [4 /*yield*/, Promise.all(entry.map(function (ent) {
                            return loadModule(ent, null, allLoaded, loadedNpmPkgs, opts, taskId).catch(function (e) {
                                e.message = ent + ": " + e.message;
                                throw e;
                            });
                        }))];
                case 1:
                    _a.sent();
                    opts.debug && console.log('All loaded modules', allLoaded);
                    return [2 /*return*/, allLoaded];
            }
        });
    });
}
exports.loadEntry = loadEntry;
// https://nodejs.org/api/modules.html#modules_all_together
function loadModule(requirePath, from, allModules, pkgs, opts, taskId) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
        var loadedMod, absoluteReqPath, possibleModuleIds, possibleModuleIds_1, possibleModuleIds_1_1, id, possibleModuleIds_2, possibleModuleIds_2_1, id, res, e_1, fromPkg, curPkg, curPkgInfo, scope, versionRange, version, res_1, deps, deps_1, deps_1_1, dep, mod, e_2_1;
        var e_3, _a, e_4, _b, e_2, _c;
        return (0, tslib_1.__generator)(this, function (_d) {
            switch (_d.label) {
                case 0:
                    if (!index_1.taskCtrl.isActive(taskId)) {
                        return [2 /*return*/];
                    }
                    // # core module
                    if (core_module_1.default[requirePath]) {
                        console.log('load core module', requirePath);
                        return [2 /*return*/];
                    }
                    absoluteReqPath = requirePath;
                    if (absoluteReqPath.startsWith('.')) {
                        absoluteReqPath = url.resolve(from.id, absoluteReqPath);
                    }
                    if (absoluteReqPath.endsWith('/')) {
                        // normalize folder module
                        absoluteReqPath = absoluteReqPath.substr(0, absoluteReqPath.length - 1);
                    }
                    possibleModuleIds = addModuleExts(absoluteReqPath, opts.extensions);
                    try {
                        // check loaded
                        for (possibleModuleIds_1 = (0, tslib_1.__values)(possibleModuleIds), possibleModuleIds_1_1 = possibleModuleIds_1.next(); !possibleModuleIds_1_1.done; possibleModuleIds_1_1 = possibleModuleIds_1.next()) {
                            id = possibleModuleIds_1_1.value;
                            if (allModules[id]) {
                                return [2 /*return*/, allModules[id]];
                            }
                        }
                    }
                    catch (e_3_1) { e_3 = { error: e_3_1 }; }
                    finally {
                        try {
                            if (possibleModuleIds_1_1 && !possibleModuleIds_1_1.done && (_a = possibleModuleIds_1.return)) _a.call(possibleModuleIds_1);
                        }
                        finally { if (e_3) throw e_3.error; }
                    }
                    try {
                        // # try all extensions from preload
                        for (possibleModuleIds_2 = (0, tslib_1.__values)(possibleModuleIds), possibleModuleIds_2_1 = possibleModuleIds_2.next(); !possibleModuleIds_2_1.done; possibleModuleIds_2_1 = possibleModuleIds_2.next()) {
                            id = possibleModuleIds_2_1.value;
                            if (opts.preload[id]) {
                                // TODO set up alias
                                loadedMod = {
                                    id: id,
                                    url: id,
                                    code: opts.preload[id],
                                    requires: {},
                                    alias: [],
                                };
                                break;
                            }
                        }
                    }
                    catch (e_4_1) { e_4 = { error: e_4_1 }; }
                    finally {
                        try {
                            if (possibleModuleIds_2_1 && !possibleModuleIds_2_1.done && (_b = possibleModuleIds_2.return)) _b.call(possibleModuleIds_2);
                        }
                        finally { if (e_4) throw e_4.error; }
                    }
                    if (!!loadedMod) return [3 /*break*/, 7];
                    res = void 0;
                    if (!absoluteReqPath.startsWith('/')) return [3 /*break*/, 5];
                    _d.label = 1;
                case 1:
                    _d.trys.push([1, 3, , 4]);
                    return [4 /*yield*/, loadModuleAsFile(absoluteReqPath, opts.projFilePrefix)];
                case 2:
                    res = _d.sent();
                    if (res) {
                        loadedMod = {
                            id: absoluteReqPath,
                            url: res.url,
                            code: res.content,
                            requires: {},
                            alias: [],
                        };
                    }
                    return [3 /*break*/, 4];
                case 3:
                    e_1 = _d.sent();
                    e_1.absoluteReqPath = absoluteReqPath;
                    throw e_1;
                case 4: return [3 /*break*/, 7];
                case 5:
                    fromPkg = getPackageName(from.id);
                    curPkg = getPackageName(absoluteReqPath);
                    curPkgInfo = pkgs[curPkg];
                    scope = curPkg.split('/')[0];
                    versionRange = '';
                    if (curPkgInfo) {
                        // already loaded package, use loaded package version
                        versionRange = curPkgInfo.version;
                    }
                    else if (fromPkg) {
                        // import by another module
                        versionRange = pkgs[fromPkg].dependencies[curPkg];
                    }
                    else {
                        // import by current project
                        versionRange = opts.dependencies[curPkg];
                    }
                    version = void 0;
                    try {
                        version = versionRange ? (0, semver_1.minVersion)(versionRange) : versionRange;
                    }
                    catch (e) {
                        opts.onError(new Error("Package(" + curPkg + "@" + versionRange + ") version error, specific version required."));
                    }
                    return [4 /*yield*/, loadNodeModule(absoluteReqPath, opts.npmFilePrefixByScope[scope] || opts.npmFilePrefix, pkgs, opts.extensions, version)];
                case 6:
                    res_1 = _d.sent();
                    if (res_1) {
                        if (!versionRange) {
                            opts.onDependencyMiss &&
                                opts.onDependencyMiss(curPkg, pkgs[curPkg].version);
                        }
                        loadedMod = {
                            id: res_1.id,
                            url: res_1.url,
                            code: res_1.content,
                            alias: res_1.alias,
                            requires: {},
                        };
                    }
                    _d.label = 7;
                case 7:
                    if (!loadedMod) {
                        console.error('Fail to load', requirePath, 'from', from);
                        return [2 /*return*/];
                    }
                    if (allModules[loadedMod.id]) {
                        console.warn("Duplicated load of module " + requirePath + " from " + from.id);
                    }
                    else {
                        opts.debug && console.log('Module loaded', loadedMod.id);
                    }
                    allModules[loadedMod.id] = loadedMod;
                    loadedMod.alias.forEach(function (a) {
                        allModules[a] = loadedMod;
                    });
                    deps = (0, searequire_1.default)(loadedMod.code);
                    _d.label = 8;
                case 8:
                    _d.trys.push([8, 13, 14, 15]);
                    deps_1 = (0, tslib_1.__values)(deps), deps_1_1 = deps_1.next();
                    _d.label = 9;
                case 9:
                    if (!!deps_1_1.done) return [3 /*break*/, 12];
                    dep = deps_1_1.value;
                    return [4 /*yield*/, loadModule(dep.path, loadedMod, allModules, pkgs, opts, taskId)];
                case 10:
                    mod = _d.sent();
                    if (mod) {
                        loadedMod.requires[dep.path] = mod.id;
                    }
                    _d.label = 11;
                case 11:
                    deps_1_1 = deps_1.next();
                    return [3 /*break*/, 9];
                case 12: return [3 /*break*/, 15];
                case 13:
                    e_2_1 = _d.sent();
                    e_2 = { error: e_2_1 };
                    return [3 /*break*/, 15];
                case 14:
                    try {
                        if (deps_1_1 && !deps_1_1.done && (_c = deps_1.return)) _c.call(deps_1);
                    }
                    finally { if (e_2) throw e_2.error; }
                    return [7 /*endfinally*/];
                case 15: return [2 /*return*/, loadedMod];
            }
        });
    });
}
function loadModuleAsFile(uri, urlPrefix) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
        var res, content;
        return (0, tslib_1.__generator)(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, fetch(urlPrefix + uri)];
                case 1:
                    res = _a.sent();
                    return [4 /*yield*/, res.text()];
                case 2:
                    content = _a.sent();
                    return [2 /*return*/, { content: content, url: res.url }];
            }
        });
    });
}
function getPackageName(uri) {
    var parts = uri.split('/');
    var partCount = uri.startsWith('@') ? 2 : 1;
    return parts.slice(0, partCount).join('/');
}
/**
 * load package name without version
 * load package name with version
 * npm and relative import in modules
 */
function loadNodeModule(uri, urlPrefix, pkgs, exts, version) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
        var pkg, pkgInfo, pkgUri, pathInPkg, browser, res, alias;
        return (0, tslib_1.__generator)(this, function (_a) {
            switch (_a.label) {
                case 0: 
                /**
                 * do not support custom node_modules
                 */
                throw new Error("Package(" + uri + "@" + version + ") load fail, do not support  custom_node modules");
                case 1:
                    pkgInfo = _a.sent();
                    if (!pkgInfo) {
                        return [2 /*return*/, null]; // package not exist
                    }
                    pkgs[pkg] = pkgInfo;
                    version = pkgInfo.version;
                    pkgUri = "" + urlPrefix + pkg + "@" + version;
                    _a.label = 2;
                case 2:
                    pathInPkg = uri.substr(pkg.length);
                    browser = pkgInfo.browser;
                    if (!pathInPkg) {
                        pathInPkg =
                            (typeof browser === 'string' ? browser : pkgInfo.main) || 'index.js';
                    }
                    else if (browser && browser[pathInPkg]) {
                        pathInPkg = browser[pathInPkg];
                    }
                    if (pathInPkg.startsWith('.')) {
                        pathInPkg = pathInPkg.substr(1); // Remove the first dot
                    }
                    else if (!pathInPkg.startsWith('/')) {
                        pathInPkg = "/" + pathInPkg;
                    }
                    return [4 /*yield*/, fetchModule(pkgUri + pathInPkg, exts)];
                case 3:
                    res = _a.sent();
                    if (!res) {
                        return [2 /*return*/, null];
                    }
                    alias = [];
                    if (pkg === uri || res.isFolder) {
                        alias.push(uri); // package name & folder is alias
                    }
                    pathInPkg = res.url.substr(pkgUri.length); // Get real path of in package
                    return [2 /*return*/, {
                            content: res.content,
                            id: "" + pkg + pathInPkg,
                            url: res.url,
                            alias: alias,
                            version: pkgInfo.version,
                        }];
            }
        });
    });
}
/**
 * fetch specifed module path, if it's a folder try load package.json and index.js in the folder
 * @param modPath e.g. antd/lib/index
 * @param baseUrl cdn host base url
 * @param tryExts extensions to try
 */
function fetchModule(modUrl, tryExts, fromFolder) {
    if (fromFolder === void 0) { fromFolder = false; }
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
        var withExt, res_2, extAdded, res, tryExts_1, tryExts_1_1, ext, e_5_1, pkgInfoRes, fileInFolder, pkgInfo;
        var _a, e_5, _b, _c;
        return (0, tslib_1.__generator)(this, function (_d) {
            switch (_d.label) {
                case 0:
                    withExt = !!path.extname(modUrl);
                    if (!withExt) return [3 /*break*/, 3];
                    return [4 /*yield*/, fetch(modUrl)];
                case 1:
                    res_2 = _d.sent();
                    if (!(res_2.status !== 404)) return [3 /*break*/, 3];
                    _a = {};
                    return [4 /*yield*/, res_2.text()];
                case 2: return [2 /*return*/, (_a.content = _d.sent(),
                        _a.url = res_2.url,
                        _a)];
                case 3:
                    extAdded = '';
                    _d.label = 4;
                case 4:
                    _d.trys.push([4, 9, 10, 11]);
                    tryExts_1 = (0, tslib_1.__values)(tryExts), tryExts_1_1 = tryExts_1.next();
                    _d.label = 5;
                case 5:
                    if (!!tryExts_1_1.done) return [3 /*break*/, 8];
                    ext = tryExts_1_1.value;
                    return [4 /*yield*/, fetch(modUrl + ext)];
                case 6:
                    res = _d.sent();
                    if (res.status !== 404) {
                        extAdded = ext;
                        return [3 /*break*/, 8];
                    }
                    _d.label = 7;
                case 7:
                    tryExts_1_1 = tryExts_1.next();
                    return [3 /*break*/, 5];
                case 8: return [3 /*break*/, 11];
                case 9:
                    e_5_1 = _d.sent();
                    e_5 = { error: e_5_1 };
                    return [3 /*break*/, 11];
                case 10:
                    try {
                        if (tryExts_1_1 && !tryExts_1_1.done && (_b = tryExts_1.return)) _b.call(tryExts_1);
                    }
                    finally { if (e_5) throw e_5.error; }
                    return [7 /*endfinally*/];
                case 11:
                    if (!(!extAdded && !fromFolder)) return [3 /*break*/, 15];
                    return [4 /*yield*/, fetch(path.join(modUrl, 'package.json'))];
                case 12:
                    pkgInfoRes = _d.sent();
                    fileInFolder = '';
                    if (!(pkgInfoRes.status !== 404)) return [3 /*break*/, 14];
                    return [4 /*yield*/, pkgInfoRes.json()];
                case 13:
                    pkgInfo = _d.sent();
                    fileInFolder = pkgInfo.main;
                    _d.label = 14;
                case 14:
                    if (!fileInFolder) {
                        fileInFolder = 'index';
                    }
                    else if (fileInFolder.startsWith('.')) {
                        fileInFolder = fileInFolder.substr(1);
                    }
                    return [2 /*return*/, fetchModule(path.join(modUrl, fileInFolder), tryExts, true)];
                case 15:
                    if (res.status === 404) {
                        return [2 /*return*/, null];
                    }
                    _c = {};
                    return [4 /*yield*/, res.text()];
                case 16: return [2 /*return*/, (_c.content = _d.sent(),
                        _c.url = res.url,
                        _c.extAdded = extAdded,
                        _c.isFolder = fromFolder,
                        _c)];
            }
        });
    });
}
function addModuleExts(modBase, possibleExts) {
    if (isNpmPackage(modBase)) {
        return [modBase];
    }
    return possibleExts.concat(['']).map(function (ext) { return modBase + ext; });
}
function isNpmPackage(pkg) {
    var parts = pkg.split('/');
    return parts.length === 1 || (parts[0].startsWith('@') && parts.length === 2);
}
//# sourceMappingURL=loader.js.map