text: 'use strict';
  
  /**
  @module ember-cli
  */
  
  const DAGMap = require('dag-map').default;
  const logger = require('heimdalljs-logger')('ember-cli:addons-factory');
  const heimdall = require('heimdalljs');
  const SilentError = require('silent-error');
  
  /**
   * Create instances of a set of "child" addons for a parent addon or project.
   *
   * @method instantiateAddons
   * @param {Object} parent an Addon or Project that is the direct containing object of the list
   *   of children defined in addonPackages.
   * @param {Project} project the project that contains the parent (so either the addon's project
   *   if parent is an addon, or the project itself if it is a project). It is possible when
   *   constructing custom addon instances that the project will actually be undefined--various
   *   addon tests do this, for example.
   * @param {Object} a map of addon name (including scope) to an AddonInfo with the name, path and
   *   'pkg' object for that addon's package.json). These are what is turned into addons.
   */
  function instantiateAddons(parent, project, addonPackages) {
    // depending on whether this is really a project or an addon, the 'name' property may be a getter.
    let parentName = typeof parent.name === 'function' ? parent.name() : parent.name;
  
    logger.info('instantiateAddons for: ', parentName);
  
    let addonNames = Object.keys(addonPackages || {});
  
    if (addonNames.length === 0) {
      logger.info('    no addons');
      return [];
    } else {
      logger.info('    addon names are:', addonNames);
    }
  
    let initializeAddonsToken = heimdall.start(`${parentName}: initializeAddons`);
    let graph = new DAGMap();
    let addonInfo, emberAddonConfig;
  
    addonNames.forEach((name) => {
      addonInfo = addonPackages[name];
      emberAddonConfig = addonInfo.pkg['ember-addon'];
  
      graph.add(name, addonInfo, emberAddonConfig.before, emberAddonConfig.after);
    });
  
    let addons = [];
    graph.each((key, value) => {
      let addonInfo = value;
      if (addonInfo) {
        let initializeAddonToken = heimdall.start({
          name: `initialize ${addonInfo.name}`,
          addonName: addonInfo.name,
          addonInitializationNode: true,
        });
  
        let start = Date.now();
  
        let pkgInfo = parent.packageInfoCache.getEntry(addonInfo.path);
  
        if (!pkgInfo || !pkgInfo.valid) {
          throw new SilentError(
            `The \`${addonInfo.pkg.name}\` addon could not be found at \`${addonInfo.path}\` or was otherwise invalid.`
          );
        }
  
        let AddonConstructor = pkgInfo.getAddonConstructor();
  
        let addon;
  
        try {
          addon = new AddonConstructor(parent, project);
        } catch (e) {
          if (parent && parent.ui) {
            parent.ui.writeError(e);
          }
          const SilentError = require('silent-error');
          throw new SilentError(`An error occurred in the constructor for ${addonInfo.name} at ${addonInfo.path}`);
        }
  
        if (addon.initializeAddons) {
          addon.initializeAddons();
        } else {
          addon.addons = [];
        }
  
        AddonConstructor._meta_.initializeIn = Date.now() - start;
        addon.constructor = AddonConstructor;
        initializeAddonToken.stop();
  
        addons.push(addon);
      }
    });
  
    logger.info(
      ' addon info %o',
      addons.map((addon) => ({
        name: addon.name,
        times: {
          initialize: addon.constructor._meta_.initializeIn,
          lookup: addon.constructor._meta_.lookupIn,
        },
      }))
    );
  
    initializeAddonsToken.stop();
  
    return addons;
  }
  
  module.exports = instantiateAddons;
  