"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeResolver = void 0;
const metro_1 = require("@rnx-kit/tools-react-native/metro");
const resolver_1 = require("./resolver");
const enhancedResolve_1 = require("./utils/enhancedResolve");
const patchMetro_1 = require("./utils/patchMetro");
const remapImportPath_1 = require("./utils/remapImportPath");
function makeResolver(options = {}) {
    const { resolve: metroResolver } = (0, metro_1.requireModuleFromMetro)("metro-resolver");
    const { remapModule = (_, moduleName, __) => moduleName } = options;
    const enableRetryResolvingFromDisk = (0, patchMetro_1.shouldEnableRetryResolvingFromDisk)(options);
    const applyResolver = enableRetryResolvingFromDisk
        ? enhancedResolve_1.applyEnhancedResolver
        : resolver_1.applyMetroResolver;
    if (enableRetryResolvingFromDisk) {
        (0, patchMetro_1.patchMetro)(options);
    }
    const remappers = [remapModule, resolver_1.remapReactNativeModule];
    const symlinkResolver = (context, moduleName, platform, requestedModuleName) => {
        let resolve = metroResolver;
        const resolveRequest = context.resolveRequest;
        if (resolveRequest === symlinkResolver) {
            // @ts-expect-error We intentionally delete `resolveRequest` here and restore it later
            delete context.resolveRequest;
            // Metro enters a different code path than it should when `resolveRequest`
            // is set and the target package uses the `browser` field to redirect
            // modules. If detected, we need to unset `resolveRequest` and retry with
            // Metro's resolver to avoid interference.
            //
            // Ref: https://github.com/facebook/metro/blob/v0.67.0/packages/metro-resolver/src/resolve.js#L59
            if (typeof requestedModuleName === "string" &&
                requestedModuleName !== moduleName) {
                try {
                    // @ts-expect-error We pass 4 arguments instead of 3 to be backwards compatible
                    return resolve(context, requestedModuleName, platform, null);
                }
                finally {
                    // @ts-expect-error We intentionally deleted `resolveRequest` and restore it here
                    context.resolveRequest = resolveRequest;
                }
            }
        }
        else if (resolveRequest) {
            resolve = resolveRequest;
        }
        try {
            // If a module was excluded, `_getEmptyModule()` will be called with no
            // platform set. We should let Metro handle this without interfering. See
            // https://github.com/facebook/metro/blob/v0.71.0/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js#L97
            if (!platform) {
                // @ts-expect-error We pass 4 arguments instead of 3 to be backwards compatible
                return resolve(context, moduleName, platform, null);
            }
            const modifiedModuleName = remappers.reduce((modifiedName, remap) => remap(context, modifiedName, platform), moduleName);
            return applyResolver(resolve, context, modifiedModuleName, platform);
        }
        finally {
            if (!context.resolveRequest) {
                // Restoring `resolveRequest` must happen last
                // @ts-expect-error We intentionally deleted `resolveRequest` and restore it here
                context.resolveRequest = resolveRequest;
            }
        }
    };
    return symlinkResolver;
}
exports.makeResolver = makeResolver;
makeResolver.remapImportPath = remapImportPath_1.remapImportPath;
//# sourceMappingURL=symlinkResolver.js.map