"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, {
    MetroTerminalReporter: ()=>MetroTerminalReporter,
    formatUsingNodeStandardLibraryError: ()=>formatUsingNodeStandardLibraryError,
    isNodeStdLibraryModule: ()=>isNodeStdLibraryModule,
    stripMetroInfo: ()=>stripMetroInfo
});
function _chalk() {
    const data = /*#__PURE__*/ _interopRequireDefault(require("chalk"));
    _chalk = function() {
        return data;
    };
    return data;
}
function _path() {
    const data = /*#__PURE__*/ _interopRequireDefault(require("path"));
    _path = function() {
        return data;
    };
    return data;
}
const _terminalReporter = require("./TerminalReporter");
const _externals = require("./externals");
const _link = require("../../../utils/link");
function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
const MAX_PROGRESS_BAR_CHAR_WIDTH = 16;
const DARK_BLOCK_CHAR = "▓";
const LIGHT_BLOCK_CHAR = "░";
class MetroTerminalReporter extends _terminalReporter.TerminalReporter {
    constructor(projectRoot, terminal){
        super(terminal);
        this.projectRoot = projectRoot;
    }
    // Used for testing
    _getElapsedTime(startTime) {
        return process.hrtime.bigint() - startTime;
    }
    /**
   * Extends the bundle progress to include the current platform that we're bundling.
   *
   * @returns `iOS path/to/bundle.js ▓▓▓▓▓░░░░░░░░░░░ 36.6% (4790/7922)`
   */ _getBundleStatusMessage(progress, phase) {
        var ref, ref1;
        const env = getEnvironmentForBuildDetails(progress.bundleDetails);
        const platform = env || getPlatformTagForBuildDetails(progress.bundleDetails);
        const inProgress = phase === "in_progress";
        let localPath;
        if (typeof ((ref = progress.bundleDetails) == null ? void 0 : (ref1 = ref.customTransformOptions) == null ? void 0 : ref1.dom) === "string" && progress.bundleDetails.customTransformOptions.dom.includes(_path().default.sep)) {
            // Because we use a generated entry file for DOM components, we need to adjust the logging path so it
            // shows a unique path for each component.
            // Here, we take the relative import path and remove all the starting slashes.
            localPath = progress.bundleDetails.customTransformOptions.dom.replace(/^(\.?\.[\\/])+/, "");
        } else {
            const inputFile = progress.bundleDetails.entryFile;
            localPath = _path().default.isAbsolute(inputFile) ? _path().default.relative(this.projectRoot, inputFile) : inputFile;
        }
        if (!inProgress) {
            const status = phase === "done" ? `Bundled ` : `Bundling failed `;
            const color = phase === "done" ? _chalk().default.green : _chalk().default.red;
            const startTime = this._bundleTimers.get(progress.bundleDetails.buildID);
            let time = "";
            if (startTime != null) {
                const elapsed = this._getElapsedTime(startTime);
                const micro = Number(elapsed) / 1000;
                const converted = Number(elapsed) / 1e6;
                // If the milliseconds are < 0.5 then it will display as 0, so we display in microseconds.
                if (converted <= 0.5) {
                    const tenthFractionOfMicro = (micro * 10 / 1000).toFixed(0);
                    // Format as microseconds to nearest tenth
                    time = _chalk().default.cyan.bold(`0.${tenthFractionOfMicro}ms`);
                } else {
                    time = _chalk().default.dim(converted.toFixed(0) + "ms");
                }
            }
            // iOS Bundled 150ms
            const plural = progress.totalFileCount === 1 ? "" : "s";
            return color(platform + status) + time + _chalk().default.reset.dim(` ${localPath} (${progress.totalFileCount} module${plural})`);
        }
        const filledBar = Math.floor(progress.ratio * MAX_PROGRESS_BAR_CHAR_WIDTH);
        const _progress = inProgress ? _chalk().default.green.bgGreen(DARK_BLOCK_CHAR.repeat(filledBar)) + _chalk().default.bgWhite.white(LIGHT_BLOCK_CHAR.repeat(MAX_PROGRESS_BAR_CHAR_WIDTH - filledBar)) + _chalk().default.bold(` ${(100 * progress.ratio).toFixed(1).padStart(4)}% `) + _chalk().default.dim(`(${progress.transformedFileCount.toString().padStart(progress.totalFileCount.toString().length)}/${progress.totalFileCount})`) : "";
        return platform + _chalk().default.reset.dim(`${_path().default.dirname(localPath)}${_path().default.sep}`) + _chalk().default.bold(_path().default.basename(localPath)) + " " + _progress;
    }
    _logInitializing(port, hasReducedPerformance) {
        // Don't print a giant logo...
        this.terminal.log(_chalk().default.dim("Starting Metro Bundler"));
    }
    shouldFilterClientLog(event) {
        return isAppRegistryStartupMessage(event.data);
    }
    shouldFilterBundleEvent(event) {
        var ref;
        return "bundleDetails" in event && ((ref = event.bundleDetails) == null ? void 0 : ref.bundleType) === "map";
    }
    /** Print the cache clear message. */ transformCacheReset() {
        (0, _terminalReporter.logWarning)(this.terminal, (0, _chalk().default)`Bundler cache is empty, rebuilding {dim (this may take a minute)}`);
    }
    /** One of the first logs that will be printed */ dependencyGraphLoading(hasReducedPerformance) {
        // this.terminal.log('Dependency graph is loading...');
        if (hasReducedPerformance) {
            // Extends https://github.com/facebook/metro/blob/347b1d7ed87995d7951aaa9fd597c04b06013dac/packages/metro/src/lib/TerminalReporter.js#L283-L290
            this.terminal.log(_chalk().default.red([
                "Metro is operating with reduced performance.",
                "Please fix the problem above and restart Metro.", 
            ].join("\n")));
        }
    }
    _logBundlingError(error) {
        const moduleResolutionError = formatUsingNodeStandardLibraryError(this.projectRoot, error);
        const cause = error.cause;
        if (moduleResolutionError) {
            let message = maybeAppendCodeFrame(moduleResolutionError, error.message);
            if (cause == null ? void 0 : cause._expoImportStack) {
                message += `\n\n${cause == null ? void 0 : cause._expoImportStack}`;
            }
            return this.terminal.log(message);
        }
        if (cause == null ? void 0 : cause._expoImportStack) {
            error.message += `\n\n${cause._expoImportStack}`;
        }
        return super._logBundlingError(error);
    }
}
function formatUsingNodeStandardLibraryError(projectRoot, error) {
    if (!error.message) {
        return null;
    }
    const { targetModuleName , originModulePath  } = error;
    if (!targetModuleName || !originModulePath) {
        return null;
    }
    const relativePath = _path().default.relative(projectRoot, originModulePath);
    const DOCS_PAGE_URL = "https://docs.expo.dev/workflow/using-libraries/#using-third-party-libraries";
    if (isNodeStdLibraryModule(targetModuleName)) {
        if (originModulePath.includes("node_modules")) {
            return [
                `The package at "${_chalk().default.bold(relativePath)}" attempted to import the Node standard library module "${_chalk().default.bold(targetModuleName)}".`,
                `It failed because the native React runtime does not include the Node standard library.`,
                (0, _link.learnMore)(DOCS_PAGE_URL), 
            ].join("\n");
        } else {
            return [
                `You attempted to import the Node standard library module "${_chalk().default.bold(targetModuleName)}" from "${_chalk().default.bold(relativePath)}".`,
                `It failed because the native React runtime does not include the Node standard library.`,
                (0, _link.learnMore)(DOCS_PAGE_URL), 
            ].join("\n");
        }
    }
    return `Unable to resolve "${targetModuleName}" from "${relativePath}"`;
}
function isNodeStdLibraryModule(moduleName) {
    return /^node:/.test(moduleName) || _externals.NODE_STDLIB_MODULES.includes(moduleName);
}
/** If the code frame can be found then append it to the existing message.  */ function maybeAppendCodeFrame(message, rawMessage) {
    const codeFrame = stripMetroInfo(rawMessage);
    if (codeFrame) {
        message += "\n" + codeFrame;
    }
    return message;
}
function stripMetroInfo(errorMessage) {
    // Newer versions of Metro don't include the list.
    if (!errorMessage.includes("4. Remove the cache")) {
        return null;
    }
    const lines = errorMessage.split("\n");
    const index = lines.findIndex((line)=>line.includes("4. Remove the cache"));
    if (index === -1) {
        return null;
    }
    return lines.slice(index + 1).join("\n");
}
/** @returns if the message matches the initial startup log */ function isAppRegistryStartupMessage(body) {
    return body.length === 1 && (/^Running application "main" with appParams:/.test(body[0]) || /^Running "main" with \{/.test(body[0]));
}
/** @returns platform specific tag for a `BundleDetails` object */ function getPlatformTagForBuildDetails(bundleDetails) {
    const platform = (bundleDetails == null ? void 0 : bundleDetails.platform) ?? null;
    if (platform) {
        const formatted = {
            ios: "iOS",
            android: "Android",
            web: "Web"
        }[platform] || platform;
        return `${_chalk().default.bold(formatted)} `;
    }
    return "";
}
/** @returns platform specific tag for a `BundleDetails` object */ function getEnvironmentForBuildDetails(bundleDetails) {
    var ref, ref1, ref2;
    // Expo CLI will pass `customTransformOptions.environment = 'node'` when bundling for the server.
    const env = (bundleDetails == null ? void 0 : (ref = bundleDetails.customTransformOptions) == null ? void 0 : ref.environment) ?? null;
    if (env === "node") {
        return _chalk().default.bold("λ") + " ";
    } else if (env === "react-server") {
        return _chalk().default.bold(`RSC(${getPlatformTagForBuildDetails(bundleDetails).trim()})`) + " ";
    }
    if ((bundleDetails == null ? void 0 : (ref1 = bundleDetails.customTransformOptions) == null ? void 0 : ref1.dom) && typeof (bundleDetails == null ? void 0 : (ref2 = bundleDetails.customTransformOptions) == null ? void 0 : ref2.dom) === "string") {
        return _chalk().default.bold(`DOM`) + " ";
    }
    return "";
}

//# sourceMappingURL=MetroTerminalReporter.js.map