"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SPComponentLoader = void 0;
var tslib_1 = require("tslib");
var sp_telemetry_1 = require("@ms/sp-telemetry");
var DebugManager_1 = require("../../debug/DebugManager");
var ComponentStore_1 = tslib_1.__importDefault(require("../../stores/ComponentStore"));
var ManifestStore_1 = tslib_1.__importDefault(require("../../stores/ManifestStore"));
var componentConstants_1 = require("../../utilities/componentConstants");
var KillSwitches_1 = require("../../utilities/KillSwitches");
var telemetryConstants_1 = require("../../utilities/telemetryConstants");
var normalize_1 = require("../common/normalize");
var platformLoader_1 = require("../common/platformLoader");
var SP_CORE_MODULE_NAME = '@microsoft/sp-core-library';
/**
 * SPFx component loader.
 *
 * @public
 */
var SPComponentLoader = /** @class */ (function () {
    function SPComponentLoader(loaderArgs) {
        var assemblyComponents = loaderArgs.assemblyComponents, ctor = loaderArgs.ctor, _a = loaderArgs.debugData, debugLoader = _a.debugLoader, debugManifests = _a.debugManifests, registerAsNonDebug = _a.registerAsNonDebug, preloadedData = loaderArgs.preloadedData, serviceScope = loaderArgs.serviceScope, useSecondaryCdn = loaderArgs.useSecondaryCdn;
        this._serviceScope = serviceScope;
        if (useSecondaryCdn) {
            // _TraceLogger.logError
        }
        // Let's see if we should stop here.  In order to facilitate easier diagnosis of
        // customer issues - and in particular custom code messing with common
        // functionality, we make it possible to disable all 3rd party code by using
        // the query string ?disable3PCode
        var urlParams = new URLSearchParams(window.location.search);
        this._skipThirdPartyCode = urlParams.has('disable3PCode');
        this._loader = new ctor(this._serviceScope, useSecondaryCdn);
        SPComponentLoader._headElement = document === null || document === void 0 ? void 0 : document.getElementsByTagName('head')[0];
        ManifestStore_1.default.instance.registerPreloadedManifests(preloadedData);
        if (debugManifests) {
            if (!registerAsNonDebug) {
                ManifestStore_1.default.instance.registerDebugManifests(debugManifests);
            }
            else {
                ManifestStore_1.default.instance.registerManifests(debugManifests, registerAsNonDebug);
            }
        }
        var monitor = new sp_telemetry_1._QosMonitor('SPComponentLoader.pinnedManifests');
        var pinnedManifests = [];
        // Pin and store bundled components in the assembly
        for (var _i = 0, assemblyComponents_1 = assemblyComponents; _i < assemblyComponents_1.length; _i++) {
            var _b = assemblyComponents_1[_i], id = _b[0], version = _b[1], component = _b[2];
            var shouldPin = !debugLoader && id !== componentConstants_1.reactComponentId && id !== componentConstants_1.reactDomComponentId && id !== componentConstants_1.tslibComponentId;
            // Only pin with the production loader to allow debug manifests to be loaded
            if (shouldPin) {
                ManifestStore_1.default.instance._pinManifest(id);
            }
            var manifest = ManifestStore_1.default.instance.tryGetManifest(id, version);
            if (manifest) {
                var cid = (0, normalize_1.normalizeComponentId)(manifest.id, manifest.version);
                if (shouldPin) {
                    pinnedManifests.push(cid);
                }
                this._loader.ensure(cid, component);
                ComponentStore_1.default.instance.storeLoadedComponent(manifest.id, manifest.version, component);
            }
        }
        monitor.writeSuccess({ pinnedManifests: pinnedManifests });
    }
    /**
     * {@inheritDoc  ISPComponentLoader.loadComponent}
     */
    SPComponentLoader.prototype.loadComponent = function (manifest) {
        var monitor;
        var extraData;
        if (!manifest.isInternal && this._skipThirdPartyCode) {
            // Return an indefinitely pending promise to avoid loading the code and error handling
            return new Promise(function () { }); // tslint:disable-line:no-empty
        }
        if (!manifest.isInternal) {
            monitor = new sp_telemetry_1._QosMonitor(telemetryConstants_1.loadComponentQosScenarioName);
            extraData = {
                alias: manifest.alias,
                isDebug: manifest._isDebug,
                isInternal: manifest.isInternal,
                manifestId: manifest.id,
                version: manifest.version
            };
            if (!(0, KillSwitches_1.isLogSPFxVersionFor3pComponentsKSActivated)()) {
                extraData.spfxVersion = this._getSPFxVersionFor3PComponent(manifest);
            }
        }
        return this._loader
            .loadComponent(manifest)
            .then(function (c) {
            if (monitor) {
                monitor.writeSuccess(extraData);
            }
            return c;
        })
            .catch(function (e) {
            if (monitor) {
                monitor.writeUnexpectedFailure(undefined, undefined, e);
            }
            throw e.systemjsError || e.requirejsError || e;
        });
    };
    /**
     * {@inheritDoc  ISPComponentLoader.loadComponentById}
     *
     * @public
     */
    SPComponentLoader.prototype.loadComponentById = function (id, version) {
        var _this = this;
        var manifest = ManifestStore_1.default.instance.tryGetManifest(id, version);
        if (manifest) {
            return this.loadComponent(manifest);
        }
        else {
            return ManifestStore_1.default.instance.requestManifest(id, version).then(function (m) { return _this.loadComponent(m); });
        }
    };
    /**
     * {@inheritDoc  ISPComponentLoader.loadCss}
     */
    SPComponentLoader.prototype.loadCss = function (url) {
        var link = document.createElement('link');
        link.rel = 'stylesheet';
        link.type = 'text/css';
        link.href = url;
        SPComponentLoader._headElement.appendChild(link);
    };
    /**
     * {@inheritDoc  ISPComponentLoader.loadScript}
     */
    SPComponentLoader.prototype.loadScript = function (url, options) {
        var monitor = new sp_telemetry_1._QosMonitor('TinySPComponentLoader.loadScript');
        return this._loader
            .loadScript(url, options)
            .then(function (m) {
            monitor.writeSuccess();
            return m;
        })
            .catch(function (e) {
            monitor.writeUnexpectedFailure(undefined, e);
            throw e;
        });
    };
    /**
     * {@inheritdoc ISPComponentLoader._loadDebugManifestsForWorkbench}
     *
     * @internal
     */
    SPComponentLoader.prototype._loadDebugManifestsForWorkbench = function (manifestsFileUrl) {
        return DebugManager_1.DebugManager.loadAndRegisterManifestsFile(this, manifestsFileUrl, true);
    };
    /**
     * {@inheritdoc ISPComponentLoader._startApplication}
     *
     * @internal
     */
    SPComponentLoader.prototype._startApplication = function (preloadedData) {
        return (0, platformLoader_1.startApplication)(preloadedData, this._serviceScope).then(function (app) {
            /*
             * Normally non-SPFx environments locate their SPFx host application via a window variable
             * that our startup code assigns like this:
             *
             *   global.moduleLoaderPromise = global.spModuleLoader.start(spClientSidePageContext, handleFailure)
             *
             * However, in the case of the modern ListView, the "listview-spfx-host" loads after the main scripts,
             * which creates a race condition where window.moduleLoaderPromise sometimes might not be assigned yet
             * when their code tries to read it.  In that situation, they can register a callback like this:
             *
             * if (window['moduleLoaderPromise']) {
             *   window['moduleLoaderPromise'].then((application) => {
             *     doSomething(application);
             *   });
             * } else {
             *   window['_spLoaderCallback'] = function(application) {
             *     doSomething(application);
             *   };
             * }
             */
            /* tslint:disable:no-string-literal */
            if (window['_spLoaderCallback']) {
                var _spLoaderCallback = window['_spLoaderCallback']; // tslint:disable-line:no-any
                _spLoaderCallback(app);
            }
            /* tslint:enable:no-string-literal */
            return app;
        });
    };
    /**
     * {@inheritdoc ISPComponentLoader._preloadComponents}
     *
     * @internal
     */
    SPComponentLoader.prototype._preloadComponents = function () {
        var _this = this;
        if (document === null || document === void 0 ? void 0 : document.head) {
            var attributeName = 'data-sp-componentId';
            var preloadElements = document.head.querySelectorAll("link[rel=preload][".concat(attributeName, "],script[").concat(attributeName, "]"));
            var preloadedIdSet = new Set();
            for (var i = 0; i < preloadElements.length; i++) {
                var componentId = preloadElements[i].getAttribute(attributeName);
                if (componentId && !preloadedIdSet.has(componentId)) {
                    preloadedIdSet.add(componentId);
                }
            }
            preloadedIdSet.forEach(function (id) {
                var manifest = _this.tryGetManifestById(id);
                if (manifest) {
                    // We don't need to care if these succeed or fail here, and are just focused on starting the load.
                    _this.loadComponent(manifest); // tslint:disable-line:no-floating-promises
                }
            });
        }
        else {
            ManifestStore_1.default.instance.getRegisteredManifests(true).forEach(function (manifest) {
                // We don't need to care if these succeed or fail here, and are just focused on starting the load.
                _this.loadComponent(manifest); // tslint:disable-line:no-floating-promises
            });
        }
    };
    /**
     * {@inheritdoc ISPComponentLoader._unloadComponents}
     *
     * @internal
     */
    SPComponentLoader.prototype._unloadComponents = function () {
        for (var _i = 0, _a = ManifestStore_1.default.instance.getRegisteredManifests(); _i < _a.length; _i++) {
            var m = _a[_i];
            ComponentStore_1.default.instance.deleteComponent(m.id, m.version);
            this._loader.delete(m);
        }
    };
    // #region Candidates for deletion
    SPComponentLoader.prototype.registerManifests = function (manifests) {
        ManifestStore_1.default.instance.registerManifests(manifests, false);
    };
    SPComponentLoader.prototype.refreshWebPartManifests = function (manifests) {
        ManifestStore_1.default.instance.refreshWebPartManifests(manifests);
    };
    SPComponentLoader.prototype.requestManifest = function (id, version) {
        return ManifestStore_1.default.instance.requestManifest(id, version);
    };
    SPComponentLoader.prototype.tryGetLoadedComponent = function (manifest) {
        return ComponentStore_1.default.instance.tryGetComponentReference(manifest.id, manifest.version);
    };
    SPComponentLoader.prototype.tryGetManifestById = function (id, version) {
        return ManifestStore_1.default.instance.tryGetManifest(id, version);
    };
    Object.defineProperty(SPComponentLoader.prototype, "_manifestReferences", {
        get: function () {
            return ManifestStore_1.default.instance.getRegisteredManifests();
        },
        enumerable: false,
        configurable: true
    });
    SPComponentLoader.prototype._initialize = function (preloadedData, assemblyComponents, debugData) {
        /* no-op*/
    };
    // #endregion
    SPComponentLoader.prototype._getSPFxVersionFor3PComponent = function (manifest) {
        var scriptResources = manifest.loaderConfig.scriptResources;
        var spfxVersion = '';
        //
        // we know each SPFx app should reference @microsoft/sp-core-library
        // so we can use it to determine the SPFx version
        //
        if (scriptResources && scriptResources[SP_CORE_MODULE_NAME]) {
            spfxVersion = scriptResources[SP_CORE_MODULE_NAME].version;
        }
        return spfxVersion;
    };
    return SPComponentLoader;
}());
exports.SPComponentLoader = SPComponentLoader;
//# sourceMappingURL=SPComponentLoader.js.map