text: /**
   * Holds instances of configured DataSources
   * @type {Map<string, DataSource>}
   */
  class DataSourceRegistry extends Map {
    /**
     * @param {Function} requireFn used to require() the loader
     * @param {string} rootPath project root
     * @param {object} config configuration to load
     */
    load(requireFn, rootPath, config = {}) {
      for (const [name, settings] of Object.entries(config)) {
        if (!settings.hasOwnProperty('require')) {
          throw new Error(`DataSource [${name}] does not specify a 'require'`);
        }
  
        if (typeof settings.require !== 'string') {
          throw new TypeError(`DataSource [${name}] has an invalid 'require'`);
        }
  
        const sourceConfig = settings.config || {};
  
        let loader = null;
  
        // relative path to require
        if (settings.require[0] === '.') {
          loader = require(`${rootPath}/${settings.require}`);
        } else if (!settings.require.includes('.')) {
          loader = require(settings.require);
        } else {
          const [moduleName, exportName] = settings.require.split('.');
          loader = requireFn(moduleName)[exportName];
        }
  
        const instance = new loader(sourceConfig, rootPath);
        if (!('hasData' in instance)) {
          throw new Error(`Data Source ${name} requires at minimum a 'hasData(config): boolean' method`);
        }
        instance.name = name;
  
        this.set(name, instance);
      }
    }
  }
  
  module.exports = DataSourceRegistry;
  