"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true,
});
exports.default = void 0;
var _constants = _interopRequireDefault(require("./constants"));
var _DuplicateHasteCandidatesError = require("./lib/DuplicateHasteCandidatesError");
var fastPath = _interopRequireWildcard(require("./lib/fast_path"));
function _getRequireWildcardCache(nodeInterop) {
  if (typeof WeakMap !== "function") return null;
  var cacheBabelInterop = new WeakMap();
  var cacheNodeInterop = new WeakMap();
  return (_getRequireWildcardCache = function (nodeInterop) {
    return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
  })(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
  if (!nodeInterop && obj && obj.__esModule) {
    return obj;
  }
  if (obj === null || (typeof obj !== "object" && typeof obj !== "function")) {
    return { default: obj };
  }
  var cache = _getRequireWildcardCache(nodeInterop);
  if (cache && cache.has(obj)) {
    return cache.get(obj);
  }
  var newObj = {};
  var hasPropertyDescriptor =
    Object.defineProperty && Object.getOwnPropertyDescriptor;
  for (var key in obj) {
    if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
      var desc = hasPropertyDescriptor
        ? Object.getOwnPropertyDescriptor(obj, key)
        : null;
      if (desc && (desc.get || desc.set)) {
        Object.defineProperty(newObj, key, desc);
      } else {
        newObj[key] = obj[key];
      }
    }
  }
  newObj.default = obj;
  if (cache) {
    cache.set(obj, newObj);
  }
  return newObj;
}
function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };
}
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 *
 * @format
 * @oncall react_native
 */

const EMPTY_OBJ = {};
const EMPTY_MAP = new Map();
class ModuleMap {
  #raw;
  constructor(raw) {
    // $FlowIssue[cannot-write] - should be fixed in Flow 0.193 (D41130671)
    this.#raw = raw;
  }
  getModule(name, platform, supportsNativePlatform, type) {
    const module = this._getModuleMetadata(
      name,
      platform,
      !!supportsNativePlatform
    );
    if (
      module &&
      module[_constants.default.TYPE] ===
        (type !== null && type !== void 0 ? type : _constants.default.MODULE)
    ) {
      const modulePath = module[_constants.default.PATH];
      return modulePath && fastPath.resolve(this.#raw.rootDir, modulePath);
    }
    return null;
  }
  getPackage(name, platform, _supportsNativePlatform) {
    return this.getModule(name, platform, null, _constants.default.PACKAGE);
  }
  getMockModule(name) {
    const mockPath =
      this.#raw.mocks.get(name) || this.#raw.mocks.get(name + "/index");
    return mockPath != null
      ? fastPath.resolve(this.#raw.rootDir, mockPath)
      : null;
  }

  // FIXME: This is only used by Meta-internal validation and should be
  // removed or replaced with a less leaky API.
  getRawModuleMap() {
    return {
      duplicates: this.#raw.duplicates,
      map: this.#raw.map,
      mocks: this.#raw.mocks,
      rootDir: this.#raw.rootDir,
    };
  }

  /**
   * When looking up a module's data, we walk through each eligible platform for
   * the query. For each platform, we want to check if there are known
   * duplicates for that name+platform pair. The duplication logic normally
   * removes elements from the `map` object, but we want to check upfront to be
   * extra sure. If metadata exists both in the `duplicates` object and the
   * `map`, this would be a bug.
   */
  _getModuleMetadata(name, platform, supportsNativePlatform) {
    const map = this.#raw.map.get(name) || EMPTY_OBJ;
    const dupMap = this.#raw.duplicates.get(name) || EMPTY_MAP;
    if (platform != null) {
      this._assertNoDuplicates(
        name,
        platform,
        supportsNativePlatform,
        dupMap.get(platform)
      );
      if (map[platform] != null) {
        return map[platform];
      }
    }
    if (supportsNativePlatform) {
      this._assertNoDuplicates(
        name,
        _constants.default.NATIVE_PLATFORM,
        supportsNativePlatform,
        dupMap.get(_constants.default.NATIVE_PLATFORM)
      );
      if (map[_constants.default.NATIVE_PLATFORM]) {
        return map[_constants.default.NATIVE_PLATFORM];
      }
    }
    this._assertNoDuplicates(
      name,
      _constants.default.GENERIC_PLATFORM,
      supportsNativePlatform,
      dupMap.get(_constants.default.GENERIC_PLATFORM)
    );
    if (map[_constants.default.GENERIC_PLATFORM]) {
      return map[_constants.default.GENERIC_PLATFORM];
    }
    return null;
  }
  _assertNoDuplicates(name, platform, supportsNativePlatform, relativePathSet) {
    if (relativePathSet == null) {
      return;
    }
    const duplicates = new Map();
    for (const [relativePath, type] of relativePathSet) {
      const duplicatePath = fastPath.resolve(this.#raw.rootDir, relativePath);
      duplicates.set(duplicatePath, type);
    }
    throw new _DuplicateHasteCandidatesError.DuplicateHasteCandidatesError(
      name,
      platform,
      supportsNativePlatform,
      duplicates
    );
  }
  static create(rootDir) {
    return new ModuleMap({
      duplicates: new Map(),
      map: new Map(),
      mocks: new Map(),
      rootDir,
    });
  }
}
exports.default = ModuleMap;
