/**
 * Copyright © 2022 650 Industries.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */ "use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: all[name]
    });
}
_export(exports, {
    getNodejsExtensions: ()=>getNodejsExtensions,
    withExtendedResolver: ()=>withExtendedResolver,
    shouldAliasModule: ()=>shouldAliasModule,
    withMetroMultiPlatformAsync: ()=>withMetroMultiPlatformAsync
});
function _fs() {
    const data = /*#__PURE__*/ _interopRequireDefault(require("fs"));
    _fs = function() {
        return data;
    };
    return data;
}
function _metroResolver() {
    const data = /*#__PURE__*/ _interopRequireWildcard(require("metro-resolver"));
    _metroResolver = function() {
        return data;
    };
    return data;
}
function _path() {
    const data = /*#__PURE__*/ _interopRequireDefault(require("path"));
    _path = function() {
        return data;
    };
    return data;
}
function _resolveFrom() {
    const data = /*#__PURE__*/ _interopRequireDefault(require("resolve-from"));
    _resolveFrom = function() {
        return data;
    };
    return data;
}
const _createExpoMetroResolver = require("./createExpoMetroResolver");
const _externals = require("./externals");
const _metroErrors = require("./metroErrors");
const _metroVirtualModules = require("./metroVirtualModules");
const _withMetroResolvers = require("./withMetroResolvers");
const _log = require("../../../log");
const _fileNotifier = require("../../../utils/FileNotifier");
const _env = require("../../../utils/env");
const _errors = require("../../../utils/errors");
const _exit = require("../../../utils/exit");
const _interactive = require("../../../utils/interactive");
const _loadTsConfigPaths = require("../../../utils/tsconfig/loadTsConfigPaths");
const _resolveWithTsConfigPaths = require("../../../utils/tsconfig/resolveWithTsConfigPaths");
const _metroOptions = require("../middleware/metroOptions");
function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
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;
}
const ASSET_REGISTRY_SRC = `const assets=[];module.exports={registerAsset:s=>assets.push(s),getAssetByID:s=>assets[s-1]};`;
const debug = require("debug")("expo:start:server:metro:multi-platform");
function withWebPolyfills(config, { getMetroBundler  }) {
    const originalGetPolyfills = config.serializer.getPolyfills ? config.serializer.getPolyfills.bind(config.serializer) : ()=>[];
    const getPolyfills = (ctx)=>{
        const virtualEnvVarId = `\0polyfill:environment-variables`;
        (0, _metroVirtualModules.getMetroBundlerWithVirtualModules)(getMetroBundler()).setVirtualModule(virtualEnvVarId, (()=>{
            return `//`;
        })());
        const virtualModuleId = `\0polyfill:external-require`;
        (0, _metroVirtualModules.getMetroBundlerWithVirtualModules)(getMetroBundler()).setVirtualModule(virtualModuleId, (()=>{
            if (ctx.platform === "web") {
                return `global.$$require_external = typeof window === "undefined" ? require : () => null;`;
            } else {
                // Wrap in try/catch to support Android.
                return 'try { global.$$require_external = typeof expo === "undefined" ? require : (moduleId) => { throw new Error(`Node.js standard library module ${moduleId} is not available in this JavaScript environment`);} } catch { global.$$require_external = (moduleId) => { throw new Error(`Node.js standard library module ${moduleId} is not available in this JavaScript environment`);} }';
            }
        })());
        if (ctx.platform === "web") {
            return [
                virtualModuleId,
                virtualEnvVarId,
                // Ensure that the error-guard polyfill is included in the web polyfills to
                // make metro-runtime work correctly.
                // TODO: This module is pretty big for a function that simply re-throws an error that doesn't need to be caught.
                require.resolve("@react-native/js-polyfills/error-guard"), 
            ];
        }
        // Generally uses `rn-get-polyfills`
        const polyfills = originalGetPolyfills(ctx);
        return [
            ...polyfills,
            virtualModuleId,
            virtualEnvVarId
        ];
    };
    return {
        ...config,
        serializer: {
            ...config.serializer,
            getPolyfills
        }
    };
}
function normalizeSlashes(p) {
    return p.replace(/\\/g, "/");
}
function getNodejsExtensions(srcExts) {
    const mjsExts = srcExts.filter((ext)=>/mjs$/.test(ext));
    const nodejsSourceExtensions = srcExts.filter((ext)=>!/mjs$/.test(ext));
    // find index of last `*.js` extension
    const jsIndex = nodejsSourceExtensions.reduce((index, ext, i)=>{
        return /jsx?$/.test(ext) ? i : index;
    }, -1);
    // insert `*.mjs` extensions after `*.js` extensions
    nodejsSourceExtensions.splice(jsIndex + 1, 0, ...mjsExts);
    return nodejsSourceExtensions;
}
function withExtendedResolver(config, { tsconfig , isTsconfigPathsEnabled , isFastResolverEnabled , isExporting , isReactCanaryEnabled , isReactServerComponentsEnabled , getMetroBundler  }) {
    var ref, ref1, ref2, ref3, ref4;
    if (isReactServerComponentsEnabled) {
        _log.Log.warn(`Experimental React Server Components is enabled. Production exports are not supported yet.`);
    }
    if (isFastResolverEnabled) {
        _log.Log.warn(`Experimental module resolution is enabled.`);
    }
    if (isReactCanaryEnabled) {
        _log.Log.warn(`Experimental React Canary version is enabled.`);
    }
    const defaultResolver = _metroResolver().resolve;
    const resolver = isFastResolverEnabled ? (0, _createExpoMetroResolver.createFastResolver)({
        preserveSymlinks: true,
        blockList: !((ref = config.resolver) == null ? void 0 : ref.blockList) ? [] : Array.isArray((ref1 = config.resolver) == null ? void 0 : ref1.blockList) ? (ref2 = config.resolver) == null ? void 0 : ref2.blockList : [
            (ref3 = config.resolver) == null ? void 0 : ref3.blockList
        ]
    }) : defaultResolver;
    const aliases = {
        web: {
            "react-native": "react-native-web",
            "react-native/index": "react-native-web",
            "react-native/Libraries/Image/resolveAssetSource": "expo-asset/build/resolveAssetSource"
        }
    };
    let _universalAliases;
    function getUniversalAliases() {
        if (_universalAliases) {
            return _universalAliases;
        }
        _universalAliases = [];
        // This package is currently always installed as it is included in the `expo` package.
        if (_resolveFrom().default.silent(config.projectRoot, "@expo/vector-icons")) {
            debug("Enabling alias: react-native-vector-icons -> @expo/vector-icons");
            _universalAliases.push([
                /^react-native-vector-icons(\/.*)?/,
                "@expo/vector-icons$1"
            ]);
        }
        if (isReactServerComponentsEnabled) {
            if (_resolveFrom().default.silent(config.projectRoot, "expo-router/rsc")) {
                debug("Enabling bridge alias: expo-router -> expo-router/rsc");
                _universalAliases.push([
                    /^expo-router$/,
                    "expo-router/rsc"
                ]);
                // Bridge the internal entry point which is a standalone import to ensure package.json resolution works as expected.
                _universalAliases.push([
                    /^expo-router\/entry-classic$/,
                    "expo-router/rsc/entry"
                ]);
            }
        }
        return _universalAliases;
    }
    const preferredMainFields = {
        // Defaults from Expo Webpack. Most packages using `react-native` don't support web
        // in the `react-native` field, so we should prefer the `browser` field.
        // https://github.com/expo/router/issues/37
        web: [
            "browser",
            "module",
            "main"
        ]
    };
    let tsConfigResolve = isTsconfigPathsEnabled && ((tsconfig == null ? void 0 : tsconfig.paths) || (tsconfig == null ? void 0 : tsconfig.baseUrl) != null) ? _resolveWithTsConfigPaths.resolveWithTsConfigPaths.bind(_resolveWithTsConfigPaths.resolveWithTsConfigPaths, {
        paths: tsconfig.paths ?? {},
        baseUrl: tsconfig.baseUrl ?? config.projectRoot,
        hasBaseUrl: !!tsconfig.baseUrl
    }) : null;
    // TODO: Move this to be a transform key for invalidation.
    if (!isExporting && (0, _interactive.isInteractive)()) {
        if (isTsconfigPathsEnabled) {
            // TODO: We should track all the files that used imports and invalidate them
            // currently the user will need to save all the files that use imports to
            // use the new aliases.
            const configWatcher = new _fileNotifier.FileNotifier(config.projectRoot, [
                "./tsconfig.json",
                "./jsconfig.json", 
            ]);
            configWatcher.startObserving(()=>{
                debug("Reloading tsconfig.json");
                (0, _loadTsConfigPaths.loadTsConfigPathsAsync)(config.projectRoot).then((tsConfigPaths)=>{
                    if ((tsConfigPaths == null ? void 0 : tsConfigPaths.paths) && !!Object.keys(tsConfigPaths.paths).length) {
                        debug("Enabling tsconfig.json paths support");
                        tsConfigResolve = _resolveWithTsConfigPaths.resolveWithTsConfigPaths.bind(_resolveWithTsConfigPaths.resolveWithTsConfigPaths, {
                            paths: tsConfigPaths.paths ?? {},
                            baseUrl: tsConfigPaths.baseUrl ?? config.projectRoot,
                            hasBaseUrl: !!tsConfigPaths.baseUrl
                        });
                    } else {
                        debug("Disabling tsconfig.json paths support");
                        tsConfigResolve = null;
                    }
                });
            });
            // TODO: This probably prevents the process from exiting.
            (0, _exit.installExitHooks)(()=>{
                configWatcher.stopObserving();
            });
        } else {
            debug("Skipping tsconfig.json paths support");
        }
    }
    let nodejsSourceExtensions = null;
    function getStrictResolver({ resolveRequest , ...context }, platform) {
        return function doResolve(moduleName) {
            return resolver(context, moduleName, platform);
        };
    }
    function getOptionalResolver(context, platform) {
        const doResolve = getStrictResolver(context, platform);
        return function optionalResolve(moduleName) {
            try {
                return doResolve(moduleName);
            } catch (error) {
                // If the error is directly related to a resolver not being able to resolve a module, then
                // we can ignore the error and try the next resolver. Otherwise, we should throw the error.
                const isResolutionError = (0, _metroErrors.isFailedToResolveNameError)(error) || (0, _metroErrors.isFailedToResolvePathError)(error);
                if (!isResolutionError) {
                    throw error;
                }
            }
            return null;
        };
    }
    // TODO: This is a hack to get resolveWeak working.
    const idFactory = ((ref4 = config.serializer) == null ? void 0 : ref4.createModuleIdFactory == null ? void 0 : ref4.createModuleIdFactory()) ?? ((id, context)=>id);
    const getAssetRegistryModule = ()=>{
        const virtualModuleId = `\0polyfill:assets-registry`;
        (0, _metroVirtualModules.getMetroBundlerWithVirtualModules)(getMetroBundler()).setVirtualModule(virtualModuleId, ASSET_REGISTRY_SRC);
        return {
            type: "sourceFile",
            filePath: virtualModuleId
        };
    };
    // If Node.js pass-through, then remap to a module like `module.exports = $$require_external(<module>)`.
    // If module should be shimmed, remap to an empty module.
    const externals = [
        {
            match: (context, moduleName)=>{
                var ref, ref1;
                if (// Disable internal externals when exporting for production.
                context.customResolverOptions.exporting || // These externals are only for Node.js environments.
                !(0, _metroOptions.isServerEnvironment)((ref = context.customResolverOptions) == null ? void 0 : ref.environment)) {
                    return false;
                }
                if (((ref1 = context.customResolverOptions) == null ? void 0 : ref1.environment) === "react-server") {
                    // Ensure these non-react-server modules are excluded when bundling for React Server Components in development.
                    return /^(source-map-support(\/.*)?|@babel\/runtime\/.+|debug|metro-runtime\/src\/modules\/HMRClient|metro|acorn-loose|acorn|chalk|ws|ansi-styles|supports-color|color-convert|has-flag|utf-8-validate|color-name|react-refresh\/runtime|@remix-run\/node\/.+)$/.test(moduleName);
                }
                // TODO: Windows doesn't support externals somehow.
                if (process.platform === "win32") {
                    return /^(source-map-support(\/.*)?)$/.test(moduleName);
                }
                // Extern these modules in standard Node.js environments in development to prevent API routes side-effects
                // from leaking into the dev server process.
                return /^(source-map-support(\/.*)?|react|react-native-helmet-async|@radix-ui\/.+|@babel\/runtime\/.+|react-dom(\/.+)?|debug|acorn-loose|acorn|css-in-js-utils\/lib\/.+|hyphenate-style-name|color|color-string|color-convert|color-name|fontfaceobserver|fast-deep-equal|query-string|escape-string-regexp|invariant|postcss-value-parser|memoize-one|nullthrows|strict-uri-encode|decode-uri-component|split-on-first|filter-obj|warn-once|simple-swizzle|is-arrayish|inline-style-prefixer\/.+)$/.test(moduleName);
            },
            replace: "node"
        },
        // Externals to speed up async split chunks by extern-ing common packages that appear in the root client chunk.
        {
            match: (context, moduleName, platform)=>{
                var ref;
                if (// Disable internal externals when exporting for production.
                context.customResolverOptions.exporting || // These externals are only for client environments.
                (0, _metroOptions.isServerEnvironment)((ref = context.customResolverOptions) == null ? void 0 : ref.environment) || // Only enable for client boundaries
                !context.customResolverOptions.clientboundary) {
                    return false;
                }
                // We don't support this in the resolver at the moment.
                if (moduleName.endsWith("/package.json")) {
                    return false;
                }
                const isExternal = /^(deprecated-react-native-prop-types|react|react\/jsx-dev-runtime|scheduler|react-native|react-dom(\/.+)?|metro-runtime(\/.+)?)$/.test(moduleName) || // TODO: Add more
                /^@babel\/runtime\/helpers\/(wrapNativeSuper)$/.test(moduleName);
                return isExternal;
            },
            replace: "weak"
        }, 
    ];
    const metroConfigWithCustomResolver = (0, _withMetroResolvers.withMetroResolvers)(config, [
        // Mock out production react imports in development.
        (context, moduleName, platform)=>{
            // This resolution is dev-only to prevent bundling the production React packages in development.
            if (!context.dev) return null;
            if (// Match react-native renderers.
            (platform !== "web" && context.originModulePath.match(/[\\/]node_modules[\\/]react-native[\\/]/) && moduleName.match(/([\\/]ReactFabric|ReactNativeRenderer)-prod/)) || // Match react production imports.
            (moduleName.match(/\.production(\.min)?\.js$/) && // Match if the import originated from a react package.
            context.originModulePath.match(/[\\/]node_modules[\\/](react[-\\/]|scheduler[\\/])/))) {
                debug(`Skipping production module: ${moduleName}`);
                // /Users/path/to/expo/node_modules/react/index.js ./cjs/react.production.min.js
                // /Users/path/to/expo/node_modules/react/jsx-dev-runtime.js ./cjs/react-jsx-dev-runtime.production.min.js
                // /Users/path/to/expo/node_modules/react-is/index.js ./cjs/react-is.production.min.js
                // /Users/path/to/expo/node_modules/react-refresh/runtime.js ./cjs/react-refresh-runtime.production.min.js
                // /Users/path/to/expo/node_modules/react-native/node_modules/scheduler/index.native.js ./cjs/scheduler.native.production.min.js
                // /Users/path/to/expo/node_modules/react-native/node_modules/react-is/index.js ./cjs/react-is.production.min.js
                return {
                    type: "empty"
                };
            }
            return null;
        },
        // tsconfig paths
        (context, moduleName, platform)=>{
            return (tsConfigResolve == null ? void 0 : tsConfigResolve({
                originModulePath: context.originModulePath,
                moduleName
            }, getOptionalResolver(context, platform))) ?? null;
        },
        // Node.js externals support
        (context, moduleName, platform)=>{
            var ref, ref1;
            const isServer = ((ref = context.customResolverOptions) == null ? void 0 : ref.environment) === "node" || ((ref1 = context.customResolverOptions) == null ? void 0 : ref1.environment) === "react-server";
            const moduleId = (0, _externals.isNodeExternal)(moduleName);
            if (!moduleId) {
                return null;
            }
            if (// In browser runtimes, we want to either resolve a local node module by the same name, or shim the module to
            // prevent crashing when Node.js built-ins are imported.
            !isServer) {
                // Perform optional resolve first. If the module doesn't exist (no module in the node_modules)
                // then we can mock the file to use an empty module.
                const result = getOptionalResolver(context, platform)(moduleName);
                if (!result && platform !== "web") {
                    // Preserve previous behavior where native throws an error on node.js internals.
                    return null;
                }
                return result ?? {
                    // In this case, mock the file to use an empty module.
                    type: "empty"
                };
            }
            const contents = `module.exports=$$require_external('node:${moduleId}');`;
            debug(`Virtualizing Node.js "${moduleId}"`);
            const virtualModuleId = `\0node:${moduleId}`;
            (0, _metroVirtualModules.getMetroBundlerWithVirtualModules)(getMetroBundler()).setVirtualModule(virtualModuleId, contents);
            return {
                type: "sourceFile",
                filePath: virtualModuleId
            };
        },
        // Custom externals support
        (context, moduleName, platform)=>{
            var ref;
            // We don't support this in the resolver at the moment.
            if (moduleName.endsWith("/package.json")) {
                return null;
            }
            const environment = (ref = context.customResolverOptions) == null ? void 0 : ref.environment;
            const strictResolve = getStrictResolver(context, platform);
            for (const external of externals){
                if (external.match(context, moduleName, platform)) {
                    if (external.replace === "empty") {
                        debug(`Redirecting external "${moduleName}" to "${external.replace}"`);
                        return {
                            type: external.replace
                        };
                    } else if (external.replace === "weak") {
                        // TODO: Make this use require.resolveWeak again. Previously this was just resolving to the same path.
                        const realModule = strictResolve(moduleName);
                        const realPath = realModule.type === "sourceFile" ? realModule.filePath : moduleName;
                        const opaqueId = idFactory(realPath, {
                            platform: platform,
                            environment
                        });
                        const contents = typeof opaqueId === "number" ? `module.exports=/*${moduleName}*/__r(${opaqueId})` : `module.exports=/*${moduleName}*/__r(${JSON.stringify(opaqueId)})`;
                        // const contents = `module.exports=/*${moduleName}*/__r(require.resolveWeak('${moduleName}'))`;
                        // const generatedModuleId = fastHashMemoized(contents);
                        const virtualModuleId = `\0weak:${opaqueId}`;
                        debug("Virtualizing module:", moduleName, "->", virtualModuleId);
                        (0, _metroVirtualModules.getMetroBundlerWithVirtualModules)(getMetroBundler()).setVirtualModule(virtualModuleId, contents);
                        return {
                            type: "sourceFile",
                            filePath: virtualModuleId
                        };
                    } else if (external.replace === "node") {
                        const contents1 = `module.exports=$$require_external('${moduleName}')`;
                        const virtualModuleId1 = `\0node:${moduleName}`;
                        debug("Virtualizing Node.js (custom):", moduleName, "->", virtualModuleId1);
                        (0, _metroVirtualModules.getMetroBundlerWithVirtualModules)(getMetroBundler()).setVirtualModule(virtualModuleId1, contents1);
                        return {
                            type: "sourceFile",
                            filePath: virtualModuleId1
                        };
                    } else {
                        throw new _errors.CommandError(`Invalid external alias type: "${external.replace}" for module "${moduleName}" (platform: ${platform}, originModulePath: ${context.originModulePath})`);
                    }
                }
            }
            return null;
        },
        // Basic moduleId aliases
        (context, moduleName, platform)=>{
            // Conditionally remap `react-native` to `react-native-web` on web in
            // a way that doesn't require Babel to resolve the alias.
            if (platform && platform in aliases && aliases[platform][moduleName]) {
                const redirectedModuleName = aliases[platform][moduleName];
                return getStrictResolver(context, platform)(redirectedModuleName);
            }
            for (const [matcher, alias] of getUniversalAliases()){
                const match = moduleName.match(matcher);
                if (match) {
                    const aliasedModule = alias.replace(/\$(\d+)/g, (_, index)=>match[parseInt(index, 10)] ?? "");
                    const doResolve = getStrictResolver(context, platform);
                    debug(`Alias "${moduleName}" to "${aliasedModule}"`);
                    return doResolve(aliasedModule);
                }
            }
            return null;
        },
        // Polyfill for asset registry
        (context, moduleName, platform)=>{
            if (/^@react-native\/assets-registry\/registry(\.js)?$/.test(moduleName)) {
                return getAssetRegistryModule();
            }
            if (platform === "web" && context.originModulePath.match(/node_modules[\\/]react-native-web[\\/]/) && moduleName.includes("/modules/AssetRegistry")) {
                return getAssetRegistryModule();
            }
            return null;
        },
        // TODO: Reduce these as much as possible in the future.
        // Complex post-resolution rewrites.
        (context, moduleName, platform)=>{
            const doResolve = getStrictResolver(context, platform);
            const result = doResolve(moduleName);
            if (result.type !== "sourceFile") {
                return result;
            }
            if (platform === "web") {
                if (result.filePath.includes("node_modules")) {
                    // // Disallow importing confusing native modules on web
                    if (moduleName.includes("react-native/Libraries/Utilities/codegenNativeCommands")) {
                        throw new _createExpoMetroResolver.FailedToResolvePathError(`Importing native-only module "${moduleName}" on web from: ${context.originModulePath}`);
                    }
                    // Replace with static shims
                    const normalName = normalizeSlashes(result.filePath)// Drop everything up until the `node_modules` folder.
                    .replace(/.*node_modules\//, "");
                    const shimFile = (0, _externals.shouldCreateVirtualShim)(normalName);
                    if (shimFile) {
                        const virtualId = `\0shim:${normalName}`;
                        const bundler = (0, _metroVirtualModules.getMetroBundlerWithVirtualModules)(getMetroBundler());
                        if (!bundler.hasVirtualModule(virtualId)) {
                            bundler.setVirtualModule(virtualId, _fs().default.readFileSync(shimFile, "utf8"));
                        }
                        debug(`Redirecting module "${result.filePath}" to shim`);
                        return {
                            ...result,
                            filePath: virtualId
                        };
                    }
                }
            } else {
                var ref, ref1;
                const isServer = ((ref = context.customResolverOptions) == null ? void 0 : ref.environment) === "node" || ((ref1 = context.customResolverOptions) == null ? void 0 : ref1.environment) === "react-server";
                // react-native/Libraries/Core/InitializeCore
                const normal = normalizeSlashes(result.filePath);
                // Shim out React Native native runtime globals in server mode for native.
                if (isServer) {
                    if (normal.endsWith("react-native/Libraries/Core/InitializeCore.js")) {
                        console.log("Shimming out InitializeCore for React Native in native SSR bundle");
                        return {
                            type: "empty"
                        };
                    }
                }
                // When server components are enabled, redirect React Native's renderer to the canary build
                // this will enable the use hook and other requisite features from React 19.
                if (isReactCanaryEnabled && result.filePath.includes("node_modules")) {
                    const normalName1 = normalizeSlashes(result.filePath)// Drop everything up until the `node_modules` folder.
                    .replace(/.*node_modules\//, "");
                    const canaryFile = (0, _externals.shouldCreateVirtualCanary)(normalName1);
                    if (canaryFile) {
                        debug(`Redirecting React Native module "${result.filePath}" to canary build`);
                        return {
                            ...result,
                            filePath: canaryFile
                        };
                    }
                }
            }
            return result;
        }, 
    ]);
    // Ensure we mutate the resolution context to include the custom resolver options for server and web.
    const metroConfigWithCustomContext = (0, _withMetroResolvers.withMetroMutatedResolverContext)(metroConfigWithCustomResolver, (immutableContext, moduleName, platform)=>{
        var ref;
        const context = {
            ...immutableContext,
            preferNativePlatform: platform !== "web"
        };
        // TODO: Remove this when we have React 19 in the expo/expo monorepo.
        if (isReactCanaryEnabled && // Change the node modules path for react and react-dom to use the vendor in Expo CLI.
        /^(react|react\/.*|react-dom|react-dom\/.*)$/.test(moduleName)) {
            context.nodeModulesPaths = [
                _path().default.join(require.resolve("@expo/cli/package.json"), "../static/canary-full"), 
            ];
        }
        if ((0, _metroOptions.isServerEnvironment)((ref = context.customResolverOptions) == null ? void 0 : ref.environment)) {
            var ref1, ref2;
            // Adjust nodejs source extensions to sort mjs after js, including platform variants.
            if (nodejsSourceExtensions === null) {
                nodejsSourceExtensions = getNodejsExtensions(context.sourceExts);
            }
            context.sourceExts = nodejsSourceExtensions;
            context.unstable_enablePackageExports = true;
            context.unstable_conditionsByPlatform = {};
            const isReactServerComponents = ((ref1 = context.customResolverOptions) == null ? void 0 : ref1.environment) === "react-server";
            if (isReactServerComponents) {
                // NOTE: Align the behavior across server and client. This is a breaking change so we'll just roll it out with React Server Components.
                // This ensures that react-server and client code both resolve `module` and `main` in the same order.
                if (platform === "web") {
                    // Node.js runtimes should only be importing main at the moment.
                    // This is a temporary fix until we can support the package.json exports.
                    context.mainFields = [
                        "module",
                        "main"
                    ];
                } else {
                    // In Node.js + native, use the standard main fields.
                    context.mainFields = [
                        "react-native",
                        "module",
                        "main"
                    ];
                }
            } else {
                if (platform === "web") {
                    // Node.js runtimes should only be importing main at the moment.
                    // This is a temporary fix until we can support the package.json exports.
                    context.mainFields = [
                        "main",
                        "module"
                    ];
                } else {
                    // In Node.js + native, use the standard main fields.
                    context.mainFields = [
                        "react-native",
                        "main",
                        "module"
                    ];
                }
            }
            // Enable react-server import conditions.
            if (((ref2 = context.customResolverOptions) == null ? void 0 : ref2.environment) === "react-server") {
                context.unstable_conditionNames = [
                    "node",
                    "import",
                    "require",
                    "react-server",
                    "workerd", 
                ];
            } else {
                context.unstable_conditionNames = [
                    "node",
                    "require"
                ];
            }
        } else {
            // Non-server changes
            if (!_env.env.EXPO_METRO_NO_MAIN_FIELD_OVERRIDE && platform && platform in preferredMainFields) {
                context.mainFields = preferredMainFields[platform];
            }
        }
        return context;
    });
    return (0, _withMetroResolvers.withMetroErrorReportingResolver)(metroConfigWithCustomContext);
}
function shouldAliasModule(input, alias) {
    var ref, ref1;
    return input.platform === alias.platform && ((ref = input.result) == null ? void 0 : ref.type) === "sourceFile" && typeof ((ref1 = input.result) == null ? void 0 : ref1.filePath) === "string" && normalizeSlashes(input.result.filePath).endsWith(alias.output);
}
async function withMetroMultiPlatformAsync(projectRoot, { config , exp , platformBundlers , isTsconfigPathsEnabled , isFastResolverEnabled , isExporting , isReactCanaryEnabled , isNamedRequiresEnabled , isReactServerComponentsEnabled , getMetroBundler  }) {
    if (isNamedRequiresEnabled) {
        debug("Using Expo metro require runtime.");
        // Change the default metro-runtime to a custom one that supports bundle splitting.
        require("metro-config/src/defaults/defaults").moduleSystem = require.resolve("@expo/cli/build/metro-require/require");
    }
    if (!config.projectRoot) {
        // @ts-expect-error: read-only types
        config.projectRoot = projectRoot;
    }
    // Required for @expo/metro-runtime to format paths in the web LogBox.
    process.env.EXPO_PUBLIC_PROJECT_ROOT = process.env.EXPO_PUBLIC_PROJECT_ROOT ?? projectRoot;
    // This is used for running Expo CLI in development against projects outside the monorepo.
    if (!isDirectoryIn(__dirname, projectRoot)) {
        if (!config.watchFolders) {
            // @ts-expect-error: watchFolders is readonly
            config.watchFolders = [];
        }
        // @ts-expect-error: watchFolders is readonly
        config.watchFolders.push(_path().default.join(require.resolve("metro-runtime/package.json"), "../.."));
        if (isReactCanaryEnabled) {
            // @ts-expect-error: watchFolders is readonly
            config.watchFolders.push(_path().default.join(require.resolve("@expo/cli/package.json"), ".."));
        }
    }
    // TODO: Remove this
    // @ts-expect-error: Invalidate the cache when the location of expo-router changes on-disk.
    config.transformer._expoRouterPath = _resolveFrom().default.silent(projectRoot, "expo-router");
    let tsconfig = null;
    if (isTsconfigPathsEnabled) {
        tsconfig = await (0, _loadTsConfigPaths.loadTsConfigPathsAsync)(projectRoot);
    }
    let expoConfigPlatforms = Object.entries(platformBundlers).filter(([platform, bundler])=>{
        var ref;
        return bundler === "metro" && ((ref = exp.platforms) == null ? void 0 : ref.includes(platform));
    }).map(([platform])=>platform);
    if (Array.isArray(config.resolver.platforms)) {
        expoConfigPlatforms = [
            ...new Set(expoConfigPlatforms.concat(config.resolver.platforms))
        ];
    }
    // @ts-expect-error: typed as `readonly`.
    config.resolver.platforms = expoConfigPlatforms;
    config = withWebPolyfills(config, {
        getMetroBundler
    });
    return withExtendedResolver(config, {
        tsconfig,
        isExporting,
        isTsconfigPathsEnabled,
        isFastResolverEnabled,
        isReactCanaryEnabled,
        isReactServerComponentsEnabled,
        getMetroBundler
    });
}
function isDirectoryIn(targetPath, rootPath) {
    return targetPath.startsWith(rootPath) && targetPath.length >= rootPath.length;
}

//# sourceMappingURL=withMetroMultiPlatform.js.map