"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, {
    isServerEnvironment: ()=>isServerEnvironment,
    shouldEnableAsyncImports: ()=>shouldEnableAsyncImports,
    getBaseUrlFromExpoConfig: ()=>getBaseUrlFromExpoConfig,
    getAsyncRoutesFromExpoConfig: ()=>getAsyncRoutesFromExpoConfig,
    getMetroDirectBundleOptionsForExpoConfig: ()=>getMetroDirectBundleOptionsForExpoConfig,
    getMetroDirectBundleOptions: ()=>getMetroDirectBundleOptions,
    createBundleUrlPathFromExpoConfig: ()=>createBundleUrlPathFromExpoConfig,
    createBundleUrlPath: ()=>createBundleUrlPath,
    createBundleUrlOsPath: ()=>createBundleUrlOsPath,
    createBundleUrlSearchParams: ()=>createBundleUrlSearchParams,
    convertPathToModuleSpecifier: ()=>convertPathToModuleSpecifier,
    getMetroOptionsFromUrl: ()=>getMetroOptionsFromUrl
});
function _resolveFrom() {
    const data = /*#__PURE__*/ _interopRequireDefault(require("resolve-from"));
    _resolveFrom = function() {
        return data;
    };
    return data;
}
const _env = require("../../../utils/env");
const _errors = require("../../../utils/errors");
const _filePath = require("../../../utils/filePath");
const _router = require("../metro/router");
function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
const debug = require("debug")("expo:metro:options");
function isServerEnvironment(environment) {
    return environment === "node" || environment === "react-server";
}
function shouldEnableAsyncImports(projectRoot) {
    if (_env.env.EXPO_NO_METRO_LAZY) {
        return false;
    }
    // `@expo/metro-runtime` includes support for the fetch + eval runtime code required
    // to support async imports. If it's not installed, we can't support async imports.
    // If it is installed, the user MUST import it somewhere in their project.
    // Expo Router automatically pulls this in, so we can check for it.
    return _resolveFrom().default.silent(projectRoot, "@expo/metro-runtime") != null;
}
function withDefaults({ mode ="development" , minify =mode === "production" , preserveEnvVars =mode !== "development" && _env.env.EXPO_NO_CLIENT_ENV_VARS , lazy , environment , ...props }) {
    if (props.bytecode) {
        if (props.platform === "web") {
            throw new _errors.CommandError("Cannot use bytecode with the web platform");
        }
        if (props.engine !== "hermes") {
            throw new _errors.CommandError("Bytecode is only supported with the Hermes engine");
        }
    }
    const optimize = props.optimize ?? (environment !== "node" && mode === "production" && _env.env.EXPO_UNSTABLE_METRO_OPTIMIZE_GRAPH);
    return {
        mode,
        minify,
        preserveEnvVars,
        optimize,
        usedExports: optimize && _env.env.EXPO_UNSTABLE_TREE_SHAKING,
        lazy: !props.isExporting && lazy,
        environment: environment === "client" ? undefined : environment,
        ...props
    };
}
function getBaseUrlFromExpoConfig(exp) {
    var ref, ref1;
    return ((ref = exp.experiments) == null ? void 0 : (ref1 = ref.baseUrl) == null ? void 0 : ref1.trim().replace(/\/+$/, "")) ?? "";
}
function getAsyncRoutesFromExpoConfig(exp, mode, platform) {
    var ref, ref1;
    let asyncRoutesSetting;
    if ((ref = exp.extra) == null ? void 0 : (ref1 = ref.router) == null ? void 0 : ref1.asyncRoutes) {
        var ref2, ref3;
        const asyncRoutes = (ref2 = exp.extra) == null ? void 0 : (ref3 = ref2.router) == null ? void 0 : ref3.asyncRoutes;
        if ([
            "boolean",
            "string"
        ].includes(typeof asyncRoutes)) {
            asyncRoutesSetting = asyncRoutes;
        } else if (typeof asyncRoutes === "object") {
            asyncRoutesSetting = asyncRoutes[platform] ?? asyncRoutes.default;
        }
    }
    return [
        mode,
        true
    ].includes(asyncRoutesSetting);
}
function getMetroDirectBundleOptionsForExpoConfig(projectRoot, exp, options) {
    var ref;
    return getMetroDirectBundleOptions({
        ...options,
        reactCompiler: !!((ref = exp.experiments) == null ? void 0 : ref.reactCompiler),
        baseUrl: getBaseUrlFromExpoConfig(exp),
        routerRoot: (0, _router.getRouterDirectoryModuleIdWithManifest)(projectRoot, exp),
        asyncRoutes: getAsyncRoutesFromExpoConfig(exp, options.mode, options.platform)
    });
}
function getMetroDirectBundleOptions(options) {
    const { mainModuleName , platform , mode , minify , environment , serializerOutput , serializerIncludeMaps , bytecode , lazy , engine , preserveEnvVars , asyncRoutes , baseUrl , routerRoot , isExporting , inlineSourceMap , splitChunks , usedExports , reactCompiler , optimize , domRoot , clientBoundaries , runModule , modulesOnly , useMd5Filename ,  } = withDefaults(options);
    const dev = mode !== "production";
    const isHermes = engine === "hermes";
    if (isExporting) {
        debug("Disabling lazy bundling for export build");
        options.lazy = false;
    }
    let fakeSourceUrl;
    let fakeSourceMapUrl;
    // TODO: Upstream support to Metro for passing custom serializer options.
    if (serializerIncludeMaps != null || serializerOutput != null) {
        fakeSourceUrl = new URL(createBundleUrlPath(options).replace(/^\//, ""), "http://localhost:8081").toString();
        if (serializerIncludeMaps) {
            fakeSourceMapUrl = fakeSourceUrl.replace(".bundle?", ".map?");
        }
    }
    const customTransformOptions = {
        __proto__: null,
        optimize: optimize || undefined,
        engine,
        clientBoundaries,
        preserveEnvVars: preserveEnvVars || undefined,
        // Use string to match the query param behavior.
        asyncRoutes: asyncRoutes ? String(asyncRoutes) : undefined,
        environment,
        baseUrl: baseUrl || undefined,
        routerRoot,
        bytecode: bytecode ? "1" : undefined,
        reactCompiler: reactCompiler ? String(reactCompiler) : undefined,
        dom: domRoot,
        useMd5Filename: useMd5Filename || undefined
    };
    // Iterate and delete undefined values
    for(const key in customTransformOptions){
        if (customTransformOptions[key] === undefined) {
            delete customTransformOptions[key];
        }
    }
    const bundleOptions = {
        platform,
        entryFile: mainModuleName,
        dev,
        minify: minify ?? !dev,
        inlineSourceMap: inlineSourceMap ?? false,
        lazy: !isExporting && lazy || undefined,
        unstable_transformProfile: isHermes ? "hermes-stable" : "default",
        customTransformOptions,
        runModule,
        modulesOnly,
        customResolverOptions: {
            __proto__: null,
            environment,
            exporting: isExporting || undefined
        },
        sourceMapUrl: fakeSourceMapUrl,
        sourceUrl: fakeSourceUrl,
        serializerOptions: {
            splitChunks,
            usedExports: usedExports || undefined,
            output: serializerOutput,
            includeSourceMaps: serializerIncludeMaps
        }
    };
    return bundleOptions;
}
function createBundleUrlPathFromExpoConfig(projectRoot, exp, options) {
    var ref;
    return createBundleUrlPath({
        ...options,
        reactCompiler: !!((ref = exp.experiments) == null ? void 0 : ref.reactCompiler),
        baseUrl: getBaseUrlFromExpoConfig(exp),
        routerRoot: (0, _router.getRouterDirectoryModuleIdWithManifest)(projectRoot, exp)
    });
}
function createBundleUrlPath(options) {
    const queryParams = createBundleUrlSearchParams(options);
    return `/${encodeURI(options.mainModuleName.replace(/^\/+/, ""))}.bundle?${queryParams.toString()}`;
}
function createBundleUrlOsPath(options) {
    const queryParams = createBundleUrlSearchParams(options);
    const mainModuleName = encodeURI((0, _filePath.toPosixPath)(options.mainModuleName));
    return `${mainModuleName}.bundle?${queryParams.toString()}`;
}
function createBundleUrlSearchParams(options) {
    const { platform , mode , minify , environment , serializerOutput , serializerIncludeMaps , lazy , bytecode , engine , preserveEnvVars , asyncRoutes , baseUrl , routerRoot , reactCompiler , inlineSourceMap , isExporting , clientBoundaries , splitChunks , usedExports , optimize , domRoot , modulesOnly , runModule ,  } = withDefaults(options);
    const dev = String(mode !== "production");
    const queryParams = new URLSearchParams({
        platform: encodeURIComponent(platform),
        dev,
        // TODO: Is this still needed?
        hot: String(false)
    });
    // Lazy bundling must be disabled for bundle splitting to work.
    if (!isExporting && lazy) {
        queryParams.append("lazy", String(lazy));
    }
    if (inlineSourceMap) {
        queryParams.append("inlineSourceMap", String(inlineSourceMap));
    }
    if (minify) {
        queryParams.append("minify", String(minify));
    }
    // We split bytecode from the engine since you could technically use Hermes without bytecode.
    // Hermes indicates the type of language features you want to transform out of the JS, whereas bytecode
    // indicates whether you want to use the Hermes bytecode format.
    if (engine) {
        queryParams.append("transform.engine", engine);
    }
    if (bytecode) {
        queryParams.append("transform.bytecode", "1");
    }
    if (asyncRoutes) {
        queryParams.append("transform.asyncRoutes", String(asyncRoutes));
    }
    if (preserveEnvVars) {
        queryParams.append("transform.preserveEnvVars", String(preserveEnvVars));
    }
    if (baseUrl) {
        queryParams.append("transform.baseUrl", baseUrl);
    }
    if (clientBoundaries == null ? void 0 : clientBoundaries.length) {
        queryParams.append("transform.clientBoundaries", JSON.stringify(clientBoundaries));
    }
    if (routerRoot != null) {
        queryParams.append("transform.routerRoot", routerRoot);
    }
    if (reactCompiler) {
        queryParams.append("transform.reactCompiler", String(reactCompiler));
    }
    if (domRoot) {
        queryParams.append("transform.dom", domRoot);
    }
    if (environment) {
        queryParams.append("resolver.environment", environment);
        queryParams.append("transform.environment", environment);
    }
    if (isExporting) {
        queryParams.append("resolver.exporting", String(isExporting));
    }
    if (splitChunks) {
        queryParams.append("serializer.splitChunks", String(splitChunks));
    }
    if (usedExports) {
        queryParams.append("serializer.usedExports", String(usedExports));
    }
    if (optimize) {
        queryParams.append("transform.optimize", String(optimize));
    }
    if (serializerOutput) {
        queryParams.append("serializer.output", serializerOutput);
    }
    if (serializerIncludeMaps) {
        queryParams.append("serializer.map", String(serializerIncludeMaps));
    }
    if (engine === "hermes") {
        queryParams.append("unstable_transformProfile", "hermes-stable");
    }
    if (modulesOnly != null) {
        queryParams.set("modulesOnly", String(modulesOnly));
    }
    if (runModule != null) {
        queryParams.set("runModule", String(runModule));
    }
    return queryParams;
}
function convertPathToModuleSpecifier(pathLike) {
    return (0, _filePath.toPosixPath)(pathLike);
}
function getMetroOptionsFromUrl(urlFragment) {
    const url = new URL(urlFragment, "http://localhost:0");
    const getStringParam = (key)=>{
        const param = url.searchParams.get(key);
        if (Array.isArray(param)) {
            throw new Error(`Expected single value for ${key}`);
        }
        return param;
    };
    let pathname = url.pathname;
    if (pathname.endsWith(".bundle")) {
        pathname = pathname.slice(0, -".bundle".length);
    }
    const options = {
        mode: isTruthy(getStringParam("dev") ?? "true") ? "development" : "production",
        minify: isTruthy(getStringParam("minify") ?? "false"),
        lazy: isTruthy(getStringParam("lazy") ?? "false"),
        routerRoot: getStringParam("transform.routerRoot") ?? "app",
        isExporting: isTruthy(getStringParam("resolver.exporting") ?? "false"),
        environment: assertEnvironment(getStringParam("transform.environment") ?? "node"),
        platform: url.searchParams.get("platform") ?? "web",
        bytecode: isTruthy(getStringParam("transform.bytecode") ?? "false"),
        mainModuleName: convertPathToModuleSpecifier(pathname),
        reactCompiler: isTruthy(getStringParam("transform.reactCompiler") ?? "false"),
        asyncRoutes: isTruthy(getStringParam("transform.asyncRoutes") ?? "false"),
        baseUrl: getStringParam("transform.baseUrl") ?? undefined,
        // clientBoundaries: JSON.parse(getStringParam('transform.clientBoundaries') ?? '[]'),
        engine: assertEngine(getStringParam("transform.engine")),
        runModule: isTruthy(getStringParam("runModule") ?? "true"),
        modulesOnly: isTruthy(getStringParam("modulesOnly") ?? "false")
    };
    return options;
}
function isTruthy(value) {
    return value === "true" || value === "1";
}
function assertEnvironment(environment) {
    if (!environment) {
        return undefined;
    }
    if (![
        "node",
        "react-server",
        "client"
    ].includes(environment)) {
        throw new Error(`Expected transform.environment to be one of: node, react-server, client`);
    }
    return environment;
}
function assertEngine(engine) {
    if (!engine) {
        return undefined;
    }
    if (![
        "hermes"
    ].includes(engine)) {
        throw new Error(`Expected transform.engine to be one of: hermes`);
    }
    return engine;
}

//# sourceMappingURL=metroOptions.js.map