"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.ComponentStatusLoader = void 0;
function _pMapSeries() {
  const data = _interopRequireDefault(require("p-map-series"));
  _pMapSeries = function () {
    return data;
  };
  return data;
}
function _componentId() {
  const data = require("@teambit/component-id");
  _componentId = function () {
    return data;
  };
  return data;
}
function _bitError() {
  const data = require("@teambit/bit-error");
  _bitError = function () {
    return data;
  };
  return data;
}
function _modelComponent() {
  const data = require("@teambit/legacy/dist/scope/models/model-component");
  _modelComponent = function () {
    return data;
  };
  return data;
}
function _constants() {
  const data = require("@teambit/legacy/dist/constants");
  _constants = function () {
    return data;
  };
  return data;
}
function _legacy() {
  const data = require("@teambit/legacy.bit-map");
  _legacy = function () {
    return data;
  };
  return data;
}
function _componentsPendingImport() {
  const data = _interopRequireDefault(require("@teambit/legacy/dist/consumer/exceptions/components-pending-import"));
  _componentsPendingImport = function () {
    return data;
  };
  return data;
}
function _componentNotFoundInPath() {
  const data = _interopRequireDefault(require("@teambit/legacy/dist/consumer/component/exceptions/component-not-found-in-path"));
  _componentNotFoundInPath = function () {
    return data;
  };
  return data;
}
function _componentOutOfSync() {
  const data = _interopRequireDefault(require("@teambit/legacy/dist/consumer/exceptions/component-out-of-sync"));
  _componentOutOfSync = function () {
    return data;
  };
  return data;
}
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
class ComponentStatusLoader {
  // cache loaded components
  constructor(workspace) {
    this.workspace = workspace;
    _defineProperty(this, "_componentsStatusCache", {});
  }
  get consumer() {
    return this.workspace.consumer;
  }
  async getManyComponentsStatuses(ids) {
    const results = [];
    await (0, _pMapSeries().default)(ids, async id => {
      const status = await this.getComponentStatusById(id);
      results.push({
        id,
        status
      });
    });
    return results;
  }

  /**
   * Get a component status by ID. Return a ComponentStatus object.
   * Keep in mind that a result can be a partial object of ComponentStatus, e.g. { notExist: true }.
   * Each one of the ComponentStatus properties can be undefined, true or false.
   * As a result, in order to check whether a component is not modified use (status.modified === false).
   * Don't use (!status.modified) because a component may not exist and the status.modified will be undefined.
   *
   * The status may have 'true' for several properties. For example, a component can be staged and modified at the
   * same time.
   *
   * The result is cached per ID and can be called several times with no penalties.
   */
  async getComponentStatusById(id) {
    if (!this._componentsStatusCache[id.toString()]) {
      // don't do this: `this._componentsStatusCache[id.toString()] = await this.getStatus(id);`
      // yes, it doesn't make sense right? turns out that "getStatus" can call `linkIfMissingWorkspaceAspects` which
      // calls `linkToNodeModulesByIds` which deletes this cache. and makes this: `this._componentsStatusCache[id.toString()]` undefined.
      const result = await this.getStatus(id);
      this._componentsStatusCache[id.toString()] = result;
    }
    return this._componentsStatusCache[id.toString()];
  }
  async getStatus(id) {
    // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
    const status = {};
    const componentFromModel = await this.consumer.scope.getModelComponentIfExist(id);
    let componentFromFileSystem;
    try {
      // change to 'latest' before loading from FS. don't change to null, otherwise, it'll cause
      // loadOne to not find model component as it assumes there is no version
      // also, don't leave the id as is, otherwise, it'll cause issues with import --merge, when
      // imported version is bigger than .bitmap, it won't find it and will consider as deleted
      const {
        components,
        removedComponents
      } = await this.consumer.loadComponents(new (_componentId().ComponentIdList)(id.changeVersion(_constants().LATEST)));
      if (removedComponents.length) {
        status.deleted = true;
        return status;
      }
      componentFromFileSystem = components[0];
    } catch (err) {
      if (err instanceof _componentNotFoundInPath().default || err instanceof _legacy().MissingBitMapComponent) {
        // the file/s have been deleted or the component doesn't exist in bit.map file
        if (componentFromModel) status.deleted = true;else status.notExist = true;
        return status;
      }
      if (err instanceof _componentsPendingImport().default) {
        status.missingFromScope;
        return status;
      }
      throw err;
    }
    if (!componentFromModel) {
      status.newlyCreated = true;
      return status;
    }
    if (componentFromModel.getHeadRegardlessOfLaneAsTagOrHash(true) === _modelComponent().VERSION_ZERO) {
      status.newlyCreated = true;
      return status;
    }
    const lane = await this.consumer.getCurrentLaneObject();
    await componentFromModel.setDivergeData(this.consumer.scope.objects);
    status.staged = await componentFromModel.isLocallyChanged(this.consumer.scope.objects, lane);
    const versionFromFs = componentFromFileSystem.id.version;
    const idStr = id.toString();
    if (!componentFromFileSystem.id.hasVersion()) {
      throw new (_componentOutOfSync().default)(idStr);
    }
    // TODO: instead of doing that like this we should use:
    // const versionFromModel = await componentFromModel.loadVersion(versionFromFs, this.consumer.scope.objects);
    // it looks like it's exactly the same code but it's not working from some reason
    const versionRef = componentFromModel.getRef(versionFromFs);
    if (!versionRef) throw new (_bitError().BitError)(`version ${versionFromFs} was not found in ${idStr}`);
    const versionFromModel = await this.consumer.scope.getObject(versionRef.hash);
    if (!versionFromModel) {
      throw new (_bitError().BitError)(`failed loading version ${versionFromFs} of ${idStr} from the scope`);
    }
    // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
    status.modified = await this.consumer.isComponentModified(versionFromModel, componentFromFileSystem);
    return status;
  }
  clearOneComponentCache(id) {
    delete this._componentsStatusCache[id.toString()];
  }
  clearCache() {
    this._componentsStatusCache = {};
  }
}
exports.ComponentStatusLoader = ComponentStatusLoader;

//# sourceMappingURL=component-status-loader.js.map