"use strict";

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function _bluebird() {
  const data = require("bluebird");

  _bluebird = function () {
    return data;
  };

  return data;
}

function _objectSpread2() {
  const data = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread"));

  _objectSpread2 = function () {
    return data;
  };

  return data;
}

function _defineProperty2() {
  const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

  _defineProperty2 = function () {
    return data;
  };

  return data;
}

function _ramda() {
  const data = _interopRequireDefault(require("ramda"));

  _ramda = function () {
    return data;
  };

  return data;
}

function _baseExtension() {
  const data = _interopRequireDefault(require("./base-extension"));

  _baseExtension = function () {
    return data;
  };

  return data;
}

function _logger() {
  const data = _interopRequireDefault(require("../logger/logger"));

  _logger = function () {
    return data;
  };

  return data;
}

function _extensionCommand() {
  const data = _interopRequireDefault(require("./extension-command"));

  _extensionCommand = function () {
    return data;
  };

  return data;
}

function _environment() {
  const data = _interopRequireDefault(require("../environment"));

  _environment = function () {
    return data;
  };

  return data;
}

function _scope() {
  const data = require("../scope");

  _scope = function () {
    return data;
  };

  return data;
}

function _consumer() {
  const data = require("../consumer");

  _consumer = function () {
    return data;
  };

  return data;
}

function _loader() {
  const data = _interopRequireDefault(require("../cli/loader"));

  _loader = function () {
    return data;
  };

  return data;
}

function _hooks() {
  const data = _interopRequireWildcard(require("../hooks"));

  _hooks = function () {
    return data;
  };

  return data;
}

function _constants() {
  const data = require("../constants");

  _constants = function () {
    return data;
  };

  return data;
}

const HooksManagerInstance = _hooks().default.getInstance();

/**
 * A class which represent an extension
 * The different attributes,
 * Extension API,
 * Load extension
 * Config
 */
class Extension extends _baseExtension().default {
  constructor(extensionProps) {
    super(extensionProps);
    (0, _defineProperty2().default)(this, "api", (0, _objectSpread2().default)({
      /**
       * API to resiter new command to bit
       */
      registerCommand: newCommand => {
        // TODO: validate new command format
        _logger().default.info(`registering new command ${newCommand.name}`); // $FlowFixMe


        this.commands.push(new (_extensionCommand().default)(newCommand));
      },

      /**
       * API to register action to an existing hook (hook name might be a hook defined by another extension)
       */
      registerActionToHook: (hookName, hookAction) => {
        _logger().default.info(`registering ${hookAction.name} to hook ${hookName}`);

        this.registeredHooksActions[hookName] = hookAction;
      },

      /**
       * API to register a new hook name, usuful for communicate between different extensions
       */
      registerNewHook: hookName => {
        _logger().default.info(`registering new global hook ${hookName}`);

        this.newHooks.push(hookName); // Register the new hook in the global hooks manager

        HooksManagerInstance.registerNewHook(hookName, {
          extension: this.name
        });
      },

      /**
       * API to trigger a hook registered by this extension.
       * trigger hook are available only for hooks registered by you.
       */
      triggerHook: (hookName, args) => {
        if (!_ramda().default.contains(hookName, this.newHooks)) {
          _logger().default.debug(`trying to trigger the hook ${hookName} which not registered by this extension`);

          return;
        }

        HooksManagerInstance.triggerHook(hookName, args);
      },
      getLoader: () => _loader().default,
      HOOKS_NAMES: _getHooksNames(),
      createIsolatedEnv: _createIsolatedEnv
    }, super.api));
    this.extendAPI(extensionProps.api, this.api);
    this.commands = extensionProps.commands || [];
    this.registeredHooksActions = extensionProps.registeredHooksActions || {};
    this.newHooks = extensionProps.newHooks || [];
  }
  /**
   * Load extension by name
   * The extension will be from scope by default or from file
   * if there is file(path) in the options
   * The file path is relative to the bit.json of the project or absolute
   * @param {string} props - loading properties with the following fields:
   * {string} name - name of the extension
   * {Object} rawConfig - raw config for the extension
   * {Object} options - extension options such as - disabled, file, core
   * {string} consumerPath - path to the consumer folder (to load the file relatively)
   * {string} scopePath - scope which stores the extension code
   */
  // $FlowFixMe


  static load(props) {
    var _superprop_callLoad = (..._args) => super.load(..._args);

    return (0, _bluebird().coroutine)(function* () {
      props.rawConfig = props.rawConfig || {};
      props.options = props.options || {};
      const baseExtensionProps = yield _superprop_callLoad(props); // const extensionProps: ExtensionProps = ((await super.load(props): BaseExtensionProps): ExtensionProps);
      // const extensionProps: ExtensionProps = (baseExtensionProps: ExtensionProps);

      const extensionProps = (0, _objectSpread2().default)({
        commands: [],
        registeredHooksActions: {},
        newHooks: []
      }, baseExtensionProps);

      const dynamicConfig = _baseExtension().default.loadDynamicConfig(extensionProps); // $FlowFixMe


      extensionProps.dynamicConfig = dynamicConfig;
      const extension = new Extension(extensionProps);

      if (extension.loaded) {
        yield extension.init();
      }

      return extension;
    })();
  }
  /**
   * Register the hooks on the global hooks manager
   * We don't do this directly on the api in order to be able to register to hooks defined by another extensions
   * So we want to make sure to first load and register all new hooks from all extensions and only then register the actions
   */


  registerHookActionsOnHooksManager() {
    const registerAction = (hookAction, hookName) => {
      HooksManagerInstance.registerActionToHook(hookName, hookAction, {
        extension: this.name
      });
    };

    _ramda().default.forEachObjIndexed(registerAction, this.registeredHooksActions);
  }

}

exports.default = Extension;

const _createIsolatedEnv =
/*#__PURE__*/
function () {
  var _ref = (0, _bluebird().coroutine)(function* (scopePath, dirPath) {
    const scope = yield _loadScope(scopePath);
    const isolatedEnvironment = new (_environment().default)(scope, dirPath);
    yield isolatedEnvironment.create();
    return isolatedEnvironment;
  });

  return function _createIsolatedEnv(_x, _x2) {
    return _ref.apply(this, arguments);
  };
}();

const _loadScope =
/*#__PURE__*/
function () {
  var _ref2 = (0, _bluebird().coroutine)(function* (scopePath) {
    // If a scope path provided we will take the component from that scope
    if (scopePath) {
      return (0, _scope().loadScope)(scopePath);
    } // If a scope path was not provided we will get the consumer's scope


    const consumer = yield (0, _consumer().loadConsumer)();
    return consumer.scope;
  });

  return function _loadScope(_x3) {
    return _ref2.apply(this, arguments);
  };
}();

const _getHooksNames = () => {
  const hooks = {};

  _constants().HOOKS_NAMES.forEach(hook => {
    hooks[hook] = hook;
  });

  return hooks;
};