text: import { __awaiter } from "tslib";
  import * as semver from "semver";
  import { MixedCollection } from "./MixedCollection";
  import { EntityCollection } from "./EntityCollection";
  import { PluginApiRuntime } from "./PluginApiRuntime";
  import { PageStructureReader } from "./PageStructureReader";
  import { PluginLoader } from "./PluginLoader";
  import { PluginUrlBuilder } from "./PluginUrlBuilder";
  import { PluginValidator } from "./PluginValidator";
  import { PageStructureValidator } from "./PageStructureValidator";
  import { version as cmsVersion } from "./version";
  import { CancellationTokenSource } from "@puzzl/core/lib/async/cancellation";
  export class PluginManager {
      constructor(logger, config, inlinePlugins) {
          this.logger = logger;
          this.config = config;
          this.inlinePlugins = inlinePlugins;
      }
      loadPlugins() {
          return __awaiter(this, void 0, void 0, function* () {
              let plugins = new MixedCollection();
              let entitiesByPlugin = new Map();
              let allEntities = new EntityCollection();
              let pageEntityOwnerPlugins = new Map();
              let pluginConfigMetas = new MixedCollection();
              new PluginApiRuntime().init(window);
              for (let pluginUri of this.config.getPluginUris()) {
                  try {
                      let pluginConfigMeta = this.config.getPluginConfigMeta(pluginUri);
                      let pluginConfig = pluginConfigMeta.config || {};
                      let pluginVersion = new URL(pluginUri).searchParams.get("v") || void 0;
                      this.logger.info(`Loading plugin ${pluginUri}...`);
                      pluginUri = pluginUri.split("?")[0];
                      pluginConfigMetas.add(pluginUri, pluginConfigMeta);
                      let pluginEntities = new EntityCollection();
                      let plugin;
                      if (this.inlinePlugins && this.inlinePlugins.has(pluginUri) && pluginUri.match(/^inline-plugin:\/\//)) {
                          let inlinePlugin = yield this.inlinePlugins.get(pluginUri)();
                          inlinePlugin.init(pluginConfig, pluginEntities, this.logger);
                          plugin = inlinePlugin;
                      }
                      else {
                          let pluginUrlBuilder = new PluginUrlBuilder(this.config.getPluginsBaseUrl());
                          let pluginModule = yield new PluginLoader(pluginUrlBuilder).load(pluginUri, pluginVersion);
                          this.checkPluginManifest(pluginUri, pluginModule.manifest);
                          plugin = pluginModule.plugin;
                          let pluginPublicPath = pluginUrlBuilder.build(pluginUri, pluginVersion) + "/";
                          plugin.init(pluginConfig, pluginEntities, this.logger, pluginPublicPath);
                      }
                      new PluginValidator().validate(plugin, pluginEntities);
                      plugins.add(pluginUri, plugin);
                      entitiesByPlugin.set(pluginUri, pluginEntities);
                      allEntities.merge(pluginEntities);
                      [...pluginEntities.getPageEntities().values()].forEach(v => pageEntityOwnerPlugins.set(v, pluginUri));
                  }
                  catch (e) {
                      this.logger.error(`Failed loading plugin ${pluginUri}`, e);
                  }
              }
              this.logger.info("Plugins loaded.");
              let pagesConfig = this.config.getPages();
              let pageStructureReader = new PageStructureReader(allEntities.getPageEntities(), new PageStructureValidator(), pageEntityOwnerPlugins, this.logger);
              let rootModules = pageStructureReader.readModuleMap(this.config.getRootModules());
              let pages = pageStructureReader.read(pagesConfig);
              let dataAdapters = allEntities.getDataAdapters();
              this.logger.info("Loading data sources...");
              yield Promise.all([...allEntities.getDataSources().entries()].map(([uri, dataSource]) => __awaiter(this, void 0, void 0, function* () {
                  var _a;
                  let adapterDepData = new Map();
                  if ((_a = dataSource.dependencies) === null || _a === void 0 ? void 0 : _a.length) {
                      yield Promise.all(dataSource.dependencies.map((dep) => __awaiter(this, void 0, void 0, function* () {
                          var _b;
                          if (!dataAdapters.has(dep.ref)) {
                              if (dep.optional) {
                                  adapterDepData.set(dep.ref, void 0);
                              }
                              throw new Error(`Data source "${uri}" depends on a non-existing data adapter (${dep.ref})`);
                          }
                          let adapter = dataAdapters.get(dep.ref);
                          if (JSON.stringify(adapter.contextType) !== "{}") {
                              throw new Error(`Data source "${uri}" depends on an adapter with a non-root contextType` +
                                  `(adapterUri = "${dep.ref}", expected contextType={}, actual=${adapter.contextType})`);
                          }
                          if ((_b = adapter.dependencies) === null || _b === void 0 ? void 0 : _b.length) {
                              throw new Error(`Failed to load data source "${uri}". ` +
                                  `Adapter dependency ${dep.ref} must refer to a simple adapter, with no dependencies`);
                          }
                          let data = yield adapter.load({}, new CancellationTokenSource().token, new Map());
                          adapterDepData.set(dep.ref, data);
                          if (dep.alias) {
                              adapterDepData.set(dep.alias, data);
                          }
                      })));
                  }
                  yield dataSource.init(adapterDepData);
              })));
              this.logger.info("Data sources loaded.");
              let cmsRendererConfig = {
                  plugins,
                  pluginConfigMetas,
                  pages,
                  dataAdapters,
                  rootModules
              };
              return cmsRendererConfig;
          });
      }
      checkPluginManifest(pluginUri, manifest) {
          if (!manifest) {
              this.logger.warn(`Legacy plugin detected. Plugin "${pluginUri}" doesn't have a manifest. ` +
                  `\nMost likely the plugin was generated with an outdated cms-plugin-tool. ` +
                  `\n\nTo remove this warning, please migrate the plugin to the new format, ` +
                  `by applying the changes at https://github.com/Alethio/cms-plugin-tool/pull/8/files`);
              return;
          }
          if (manifest.cmsVersion) {
              if (!semver.validRange(manifest.cmsVersion)) {
                  this.logger.error(`Invalid manifest for plugin "${pluginUri}". ` +
                      `"${manifest.cmsVersion}" is not a valid semver range.`);
              }
              else if (!semver.satisfies(cmsVersion, manifest.cmsVersion)) {
                  this.logger.error(`Plugin "${pluginUri}" requires a different Alethio CMS version ` +
                      `(expected = "${manifest.cmsVersion}"; actual = "${cmsVersion}").` +
                      `\n\nWe will attempt to load the plugin now, but it may not work correctly.`);
              }
          }
      }
  }
  //# sourceMappingURL=PluginManager.js.map