"use strict";

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

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

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

  _objectSpread2 = function () {
    return data;
  };

  return data;
}

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

  _bluebird = function () {
    return data;
  };

  return data;
}

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

  _ramda = function () {
    return data;
  };

  return data;
}

function _path() {
  const data = _interopRequireDefault(require("path"));

  _path = function () {
    return data;
  };

  return data;
}

function _stringFormat() {
  const data = _interopRequireDefault(require("string-format"));

  _stringFormat = function () {
    return data;
  };

  return data;
}

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

  _baseExtension = function () {
    return data;
  };

  return data;
}

function _bitId() {
  const data = _interopRequireDefault(require("../bit-id/bit-id"));

  _bitId = function () {
    return data;
  };

  return data;
}

function _extensionFile() {
  const data = _interopRequireDefault(require("./extension-file"));

  _extensionFile = function () {
    return data;
  };

  return data;
}

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

  _objects = function () {
    return data;
  };

  return data;
}

function _utils() {
  const data = require("../utils");

  _utils = function () {
    return data;
  };

  return data;
}

function _removeFilesAndEmptyDirsRecursively() {
  const data = _interopRequireDefault(require("../utils/fs/remove-files-and-empty-dirs-recursively"));

  _removeFilesAndEmptyDirsRecursively = function () {
    return data;
  };

  return data;
}

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

  _scope = function () {
    return data;
  };

  return data;
}

function _analytics() {
  const data = require("../analytics/analytics");

  _analytics = function () {
    return data;
  };

  return data;
}

function _extensionGetDynamicPackagesError() {
  const data = _interopRequireDefault(require("./exceptions/extension-get-dynamic-packages-error"));

  _extensionGetDynamicPackagesError = function () {
    return data;
  };

  return data;
}

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

  _constants = function () {
    return data;
  };

  return data;
}

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

  _logger = function () {
    return data;
  };

  return data;
}

function _dependencies() {
  const data = require("../consumer/component/dependencies");

  _dependencies = function () {
    return data;
  };

  return data;
}

function _configDir() {
  const data = _interopRequireDefault(require("../consumer/bit-map/config-dir"));

  _configDir = function () {
    return data;
  };

  return data;
}

function _extensionGetDynamicConfigError() {
  const data = _interopRequireDefault(require("./exceptions/extension-get-dynamic-config-error"));

  _extensionGetDynamicConfigError = function () {
    return data;
  };

  return data;
}

function _installExtensions() {
  const data = _interopRequireDefault(require("../scope/extensions/install-extensions"));

  _installExtensions = function () {
    return data;
  };

  return data;
}

function _dataToPersist() {
  const data = _interopRequireDefault(require("../consumer/component/sources/data-to-persist"));

  _dataToPersist = function () {
    return data;
  };

  return data;
}

function _removePath() {
  const data = _interopRequireDefault(require("../consumer/component/sources/remove-path"));

  _removePath = function () {
    return data;
  };

  return data;
}

function _abstractConfig() {
  const data = _interopRequireDefault(require("../consumer/config/abstract-config"));

  _abstractConfig = function () {
    return data;
  };

  return data;
}

function _envFactory() {
  const data = _interopRequireDefault(require("./env-factory"));

  _envFactory = function () {
    return data;
  };

  return data;
}

class EnvExtension extends _baseExtension().default {
  /**
   * Return the action
   */
  get action() {
    if (this.script && this.script.action && typeof this.script.action === 'function') {
      return this.script.action;
    }

    return undefined;
  }
  /**
   * return old actions (to support old compilers / testers which uses run / compile functions)
   */


  get oldAction() {
    if (this.script && this.script.run && typeof this.script.run === 'function') {
      return this.script.run;
    }

    if (this.script && this.script.compile && typeof this.script.compile === 'function') {
      return this.script.compile;
    }

    return undefined;
  }

  constructor(extensionProps) {
    super(extensionProps);
    this.envType = extensionProps.envType;
    this.dynamicPackageDependencies = extensionProps.dynamicPackageDependencies;
    this.files = extensionProps.files;
  }

  install(scope, opts, context) {
    var _this = this;

    return (0, _bluebird().coroutine)(function* () {
      _analytics().Analytics.addBreadCrumb('env-extension', 'install env extension');

      _logger().default.debug('env-extension - install env extension'); // Skip the installation in case of using specific file
      // options.file usually used for develop your extension


      if (_this.options.file) {
        return undefined;
      }

      const dependentId = _ramda().default.path(['dependentId'], context);

      const installOpts = (0, _objectSpread2().default)({
        ids: [{
          componentId: _bitId().default.parse(_this.name, true),
          type: _this.envType.toLowerCase()
        }],
        // @todo: make sure it always has a scope name
        dependentId,
        scope
      }, opts);
      const installResult = yield (0, _installExtensions().default)(installOpts);

      _this.setExtensionPathInScope(scope.getPath());

      yield _this.reload(scope.getPath(), context);
      return installResult;
    })();
  }

  toModelObject() {
    const baseObject = super.toModelObject();
    const files = this.files.map(file => file.toModelObject());
    const modelObject = (0, _objectSpread2().default)({
      files
    }, baseObject);
    return modelObject;
  }

  toObject() {
    const baseObject = super.toObject();
    const files = this.files;
    const object = (0, _objectSpread2().default)({}, baseObject, {
      files
    });
    return object;
  }
  /**
   * Get a bit.json representation of the env instance
   * @param {string} ejectedEnvDirectory - The base path of where the env config files are stored
   * $FlowFixMe seems to be an issue opened for this https://github.com/facebook/flow/issues/4953
   */


  toBitJsonObject(ejectedEnvDirectory) {
    _logger().default.debug('env-extension', 'toBitJsonObject');

    const files = {};
    this.files.forEach(file => {
      const relativePath = (0, _utils().pathJoinLinux)(ejectedEnvDirectory, file.relative);
      files[file.name] = `./${relativePath}`;
    });
    const envVal = {
      rawConfig: this.dynamicConfig,
      options: this.options,
      files
    };
    return {
      [this.name]: envVal
    };
  }

  populateDataToPersist({
    configDir,
    envType,
    deleteOldFiles,
    consumer,
    verbose = false
  }) {
    const resolvedEjectedEnvsDirectory = (0, _stringFormat().default)(configDir, {
      ENV_TYPE: envType
    });
    const filePathsToRemove = [];
    this.files.forEach(file => {
      if (deleteOldFiles) {
        const pathToDelete = consumer ? consumer.getPathRelativeToConsumer(file.path) : file.path;
        filePathsToRemove.push(pathToDelete);
      }

      file.updatePaths({
        newBase: resolvedEjectedEnvsDirectory,
        newRelative: file.relative
      });
      file.verbose = verbose;
    });
    this.dataToPersist = new (_dataToPersist().default)();
    this.files.forEach(file => {
      const cloned = file.clone();
      cloned.verbose = verbose;
      this.dataToPersist.addFile(cloned);
    });
    filePathsToRemove.map(file => this.dataToPersist.removePath(new (_removePath().default)(file, true)));
    return resolvedEjectedEnvsDirectory;
  }
  /**
   * Delete env files from file system
   */


  removeFilesFromFs(dependencies, configDir, envType, consumerPath) {
    var _this2 = this;

    return (0, _bluebird().coroutine)(function* () {
      _analytics().Analytics.addBreadCrumb('env-extension', 'removeFilesFromFs');

      const filePaths = _this2.files.map(file => file.path);

      const relativeSourcePaths = dependencies.getSourcesPaths();
      if (!_this2.context) throw new Error('env-extension.removeFilesFromFs, this.context is missing');
      const componentDir = _this2.context.componentDir;
      const configDirResolved = configDir.getResolved({
        componentDir,
        envType
      });
      const configDirPath = configDirResolved.dirPath;
      const absoluteEnvsDirectory = _path().default.isAbsolute(configDirPath) ? configDirPath : _path().default.join(consumerPath, configDirPath);
      const linkPaths = relativeSourcePaths.map(relativePath => _path().default.join(absoluteEnvsDirectory, relativePath));
      return (0, _removeFilesAndEmptyDirsRecursively().default)([...filePaths, ...linkPaths]);
    })();
  }

  reload(scopePath, context) {
    var _this3 = this,
        _superprop_callReload = (..._args) => super.reload(..._args);

    return (0, _bluebird().coroutine)(function* () {
      _logger().default.debug('env-extension', 'reload');

      if (context) {
        _this3.context = context;
      }

      const throws = true;
      yield _superprop_callReload(scopePath, {
        throws
      }); // $FlowFixMe

      const dynamicPackageDependencies = EnvExtension.loadDynamicPackageDependencies(_this3);
      _this3.dynamicPackageDependencies = dynamicPackageDependencies;
    })();
  }
  /**
   * Loading from props (usually from bit.json)
   * @param {*} props
   * $FlowFixMe seems to be an issue opened for this https://github.com/facebook/flow/issues/4953
   */


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

    return (0, _bluebird().coroutine)(function* () {
      const baseExtensionProps = yield _superprop_callLoad(props); // $FlowFixMe

      const files = yield _extensionFile().default.loadFromBitJsonObject( // $FlowFixMe
      props.files, // $FlowFixMe
      props.consumerPath, props.bitJsonPath, props.envType);
      const envExtensionProps = (0, _objectSpread2().default)({
        envType: props.envType,
        files
      }, baseExtensionProps);
      const dynamicPackageDependencies = EnvExtension.loadDynamicPackageDependencies(envExtensionProps);
      envExtensionProps.dynamicPackageDependencies = dynamicPackageDependencies;
      const dynamicConfig = EnvExtension.loadDynamicConfig(envExtensionProps); // $FlowFixMe

      envExtensionProps.dynamicConfig = dynamicConfig;
      return envExtensionProps;
    })();
  }

  static loadDynamicPackageDependencies(envExtensionProps) {
    const getDynamicPackageDependencies = _ramda().default.path(['script', 'getDynamicPackageDependencies'], envExtensionProps);

    if (getDynamicPackageDependencies && typeof getDynamicPackageDependencies === 'function') {
      try {
        const dynamicPackageDependencies = getDynamicPackageDependencies({
          rawConfig: envExtensionProps.rawConfig,
          dynamicConfig: envExtensionProps.dynamicConfig,
          configFiles: envExtensionProps.files,
          context: envExtensionProps.context
        });
        return dynamicPackageDependencies;
      } catch (err) {
        throw new (_extensionGetDynamicPackagesError().default)(err, envExtensionProps.name);
      }
    }

    return undefined;
  } // $FlowFixMe


  static loadDynamicConfig(envExtensionProps) {
    const getDynamicConfig = _ramda().default.path(['script', 'getDynamicConfig'], envExtensionProps);

    if (getDynamicConfig && typeof getDynamicConfig === 'function') {
      try {
        const dynamicConfig = getDynamicConfig({
          rawConfig: envExtensionProps.rawConfig,
          configFiles: envExtensionProps.files,
          context: envExtensionProps.context
        });
        return dynamicConfig;
      } catch (err) {
        throw new (_extensionGetDynamicConfigError().default)(err, envExtensionProps.name);
      }
    }

    return undefined;
  }
  /**
   * $FlowFixMe seems to be an issue opened for this https://github.com/facebook/flow/issues/4953
   */


  static loadFromModelObject( // $FlowFixMe
  modelObject, repository) {
    var _superprop_callLoadFromModelObject = (..._args3) => super.loadFromModelObject(..._args3);

    return (0, _bluebird().coroutine)(function* () {
      // $FlowFixMe
      const baseExtensionProps = _superprop_callLoadFromModelObject(modelObject);

      let files = [];

      if (modelObject.files && !_ramda().default.isEmpty(modelObject.files)) {
        const loadFilesP = modelObject.files.map(file => _extensionFile().default.loadFromExtensionFileModel(file, repository));
        files = yield Promise.all(loadFilesP);
      }

      const envExtensionProps = (0, _objectSpread2().default)({
        envType: modelObject.envType,
        files
      }, baseExtensionProps);
      return envExtensionProps;
    })();
  }

  static loadFromSerializedModelObject(modelObject) {
    var _superprop_callLoadFromModelObject2 = (..._args4) => super.loadFromModelObject(..._args4);

    return (0, _bluebird().coroutine)(function* () {
      _logger().default.debug('env-extension', 'loadFromModelObject'); // $FlowFixMe


      const baseExtensionProps = _superprop_callLoadFromModelObject2(modelObject);

      let files = [];

      if (modelObject.files && !_ramda().default.isEmpty(modelObject.files)) {
        const loadFilesP = modelObject.files.map(file => _extensionFile().default.loadFromExtensionFileSerializedModel(file));
        files = yield Promise.all(loadFilesP);
      }

      const envExtensionProps = (0, _objectSpread2().default)({
        envType: modelObject.envType,
        files
      }, baseExtensionProps);
      return envExtensionProps;
    })();
  }
  /**
   * load the compiler/tester according to the following strategies:
   * 1. from component config (bit.json/package.json of the component) if it was written.
   * 2. from component model. an imported component might not have the config written.
   * for author, it's irrelevant, because upon import it's written to consumer config (if changed).
   * 3. from consumer config overrides. (bit.json/package.json of the consumer when this component
   * overrides the general env config).
   * 4. from consumer config.
   */


  static loadFromCorrectSource({
    consumerPath,
    scopePath,
    componentOrigin,
    componentFromModel,
    componentConfig,
    overridesFromConsumer,
    workspaceConfig,
    envType,
    context
  }) {
    return (0, _bluebird().coroutine)(function* () {
      _logger().default.debug('env-extension', `(${envType}) loadFromCorrectSource`);

      const isAuthor = componentOrigin === _constants().COMPONENT_ORIGINS.AUTHORED; // $FlowFixMe


      if (componentConfig && componentConfig.componentHasWrittenConfig && componentConfig[envType]) {
        // load from component config.
        const envConfig = {
          [envType]: componentConfig[envType]
        };

        const configPath = _path().default.dirname(componentConfig.path);

        _logger().default.debug(`env-extension loading ${envType} from component config`);

        return loadFromConfig({
          envConfig,
          envType,
          consumerPath,
          scopePath,
          configPath,
          context
        });
      }

      if (!isAuthor && componentFromModel && componentFromModel[envType]) {
        // config was not written into component dir, load the config from the model
        _logger().default.debug(`env-extension, loading ${envType} from the model`);

        return componentFromModel[envType];
      }

      if (overridesFromConsumer && overridesFromConsumer.env && overridesFromConsumer.env[envType]) {
        if (overridesFromConsumer.env[envType] === _constants().MANUALLY_REMOVE_ENVIRONMENT) {
          _logger().default.debug(`env-extension, ${envType} was manually removed from the consumer config overrides`);

          return null;
        }

        _logger().default.debug(`env-extension, loading ${envType} from the consumer config overrides`); // $FlowFixMe


        const envConfig = {
          [envType]: _abstractConfig().default.transformEnvToObject(overridesFromConsumer.env[envType])
        };
        return loadFromConfig({
          envConfig,
          envType,
          consumerPath,
          scopePath,
          configPath: consumerPath,
          context
        });
      } // $FlowFixMe


      if (isAuthor && workspaceConfig[envType]) {
        _logger().default.debug(`env-extension, loading ${envType} from the consumer config`); // $FlowFixMe


        const envConfig = {
          [envType]: workspaceConfig[envType]
        };
        return loadFromConfig({
          envConfig,
          envType,
          consumerPath,
          scopePath,
          configPath: consumerPath,
          context
        });
      }

      return null;
    })();
  }
  /**
   * are two envs (in the model/scope format) different
   */


  static areEnvsDifferent(envModelA, envModelB) {
    const sortEnv = env => {
      env.files = _ramda().default.sortBy(_ramda().default.prop('name'), env.files);
      env.config = (0, _utils().sortObject)(env.config);
      const result = (0, _utils().sortObject)(env);
      return result;
    };

    const stringifyEnv = env => {
      if (!env) {
        return '';
      }

      if (typeof env === 'string') {
        return env;
      }

      return JSON.stringify(sortEnv(env));
    };

    const envModelAString = stringifyEnv(envModelA);
    const envModelBString = stringifyEnv(envModelB);
    return (0, _utils().sha1)(envModelAString) !== (0, _utils().sha1)(envModelBString);
  }

}

exports.default = EnvExtension;

function loadFromConfig(_x) {
  return _loadFromConfig.apply(this, arguments);
}

function _loadFromConfig() {
  _loadFromConfig = (0, _bluebird().coroutine)(function* ({
    envConfig,
    envType,
    consumerPath,
    scopePath,
    configPath,
    context
  }) {
    const env = envConfig[envType];
    if (!env) return null;
    const envName = Object.keys(env)[0];
    const envObject = env[envName];
    const envProps = {
      name: envName,
      consumerPath,
      scopePath,
      rawConfig: envObject.rawConfig,
      files: envObject.files,
      bitJsonPath: configPath,
      options: envObject.options,
      envType,
      context
    }; // $FlowFixMe

    return (0, _envFactory().default)(envType, envProps);
  });
  return _loadFromConfig.apply(this, arguments);
}