import { parseArgs } from 'node:util';
import { InvalidArgumentError } from 'next/dist/compiled/commander';
export function printAndExit(message, code = 1) {
    if (code === 0) {
        console.log(message);
    } else {
        console.error(message);
    }
    return process.exit(code);
}
const parseNodeArgs = (args)=>{
    const { values, tokens } = parseArgs({
        args,
        strict: false,
        tokens: true
    });
    // For the `NODE_OPTIONS`, we support arguments with values without the `=`
    // sign. We need to parse them manually.
    let orphan = null;
    for(let i = 0; i < tokens.length; i++){
        const token = tokens[i];
        if (token.kind === 'option-terminator') {
            break;
        }
        // When we encounter an option, if it's value is undefined, we should check
        // to see if the following tokens are positional parameters. If they are,
        // then the option is orphaned, and we can assign it.
        if (token.kind === 'option') {
            orphan = typeof token.value === 'undefined' ? token : null;
            continue;
        }
        // If the token isn't a positional one, then we can't assign it to the found
        // orphaned option.
        if (token.kind !== 'positional') {
            orphan = null;
            continue;
        }
        // If we don't have an orphan, then we can skip this token.
        if (!orphan) {
            continue;
        }
        // If the token is a positional one, and it has a value, so add it to the
        // values object. If it already exists, append it with a space.
        if (orphan.name in values && typeof values[orphan.name] === 'string') {
            values[orphan.name] += ` ${token.value}`;
        } else {
            values[orphan.name] = token.value;
        }
    }
    return values;
};
/**
 * Tokenizes the arguments string into an array of strings, supporting quoted
 * values and escaped characters.
 * Converted from: https://github.com/nodejs/node/blob/c29d53c5cfc63c5a876084e788d70c9e87bed880/src/node_options.cc#L1401
 *
 * @param input The arguments string to be tokenized.
 * @returns An array of strings with the tokenized arguments.
 */ export const tokenizeArgs = (input)=>{
    let args = [];
    let isInString = false;
    let willStartNewArg = true;
    for(let i = 0; i < input.length; i++){
        let char = input[i];
        // Skip any escaped characters in strings.
        if (char === '\\' && isInString) {
            // Ensure we don't have an escape character at the end.
            if (input.length === i + 1) {
                throw Object.defineProperty(new Error('Invalid escape character at the end.'), "__NEXT_ERROR_CODE", {
                    value: "E168",
                    enumerable: false,
                    configurable: true
                });
            }
            // Skip the next character.
            char = input[++i];
        } else if (char === ' ' && !isInString) {
            willStartNewArg = true;
            continue;
        } else if (char === '"') {
            isInString = !isInString;
            continue;
        }
        // If we're starting a new argument, we should add it to the array.
        if (willStartNewArg) {
            args.push(char);
            willStartNewArg = false;
        } else {
            args[args.length - 1] += char;
        }
    }
    if (isInString) {
        throw Object.defineProperty(new Error('Unterminated string'), "__NEXT_ERROR_CODE", {
            value: "E208",
            enumerable: false,
            configurable: true
        });
    }
    return args;
};
/**
 * Get the node options from the environment variable `NODE_OPTIONS` and returns
 * them as an array of strings.
 *
 * @returns An array of strings with the node options.
 */ export const getNodeOptionsArgs = ()=>{
    if (!process.env.NODE_OPTIONS) return [];
    return tokenizeArgs(process.env.NODE_OPTIONS);
};
/**
 * Formats the debug address into a string.
 */ export const formatDebugAddress = ({ host, port })=>{
    if (host) return `${host}:${port}`;
    return `${port}`;
};
/**
 * Get's the debug address from the `NODE_OPTIONS` environment variable. If the
 * address is not found, it returns the default host (`undefined`) and port
 * (`9229`).
 *
 * @returns An object with the host and port of the debug address.
 */ export const getParsedDebugAddress = (address)=>{
    if (!address || typeof address !== 'string') {
        return {
            host: undefined,
            port: 9229
        };
    }
    // The address is in the form of `[host:]port`. Let's parse the address.
    if (address.includes(':')) {
        const [host, port] = address.split(':');
        return {
            host,
            port: parseInt(port, 10)
        };
    }
    return {
        host: undefined,
        port: parseInt(address, 10)
    };
};
/**
 * Node.js CLI flags that are not allowed in NODE_OPTIONS and must be
 * passed as direct CLI arguments via execArgv.
 * This set is the difference between all Node.js CLI flags and the ones **not**
 * allowed in NODE_OPTIONS, as listed in the Node.js documentation:
 * https://nodejs.org/api/cli.html#node_optionsoptions
 *
 * It is not exhaustive since not all options make sense for Next.js (e.g. --test)
 */ const EXEC_ARGV_ONLY_OPTIONS = new Set([
    'experimental-network-inspection',
    'experimental-storage-inspection',
    'experimental-worker-inspection',
    'experimental-inspector-network-resource'
]);
function formatArg(key, value) {
    if (value === true) {
        return `--${key}`;
    }
    if (value) {
        return `--${key}=${// Values with spaces need to be quoted. We use JSON.stringify to
        // also escape any nested quotes.
        value.includes(' ') && !value.startsWith('"') ? JSON.stringify(value) : value}`;
    }
    return null;
}
/**
 * Stringify the arguments to be used in a command line. It will ignore any
 * argument that has a value of `undefined`. Options that are not allowed in
 * NODE_OPTIONS are returned separately as execArgv.
 *
 * @param args The arguments to be stringified.
 * @returns An object with `nodeOptions` string and `execArgv` array.
 */ export function formatNodeOptions(args) {
    const nodeOptionsParts = [];
    const execArgv = [];
    for (const [key, value] of Object.entries(args)){
        const formatted = formatArg(key, value);
        if (formatted === null) continue;
        if (EXEC_ARGV_ONLY_OPTIONS.has(key)) {
            execArgv.push(formatted);
        } else {
            nodeOptionsParts.push(formatted);
        }
    }
    return {
        nodeOptions: nodeOptionsParts.join(' '),
        execArgv
    };
}
export function getParsedNodeOptions() {
    const args = [
        ...process.execArgv,
        ...getNodeOptionsArgs()
    ];
    if (args.length === 0) return {};
    return parseNodeArgs(args);
}
/**
 * Get the node options from the `NODE_OPTIONS` environment variable and parse
 * them into an object without the inspect options.
 *
 * @returns An object with the parsed node options.
 */ export function getParsedNodeOptionsWithoutInspect() {
    const args = getNodeOptionsArgs();
    if (args.length === 0) return {};
    const parsed = parseNodeArgs(args);
    // Remove inspect options.
    delete parsed.inspect;
    delete parsed['inspect-brk'];
    delete parsed['inspect_brk'];
    return parsed;
}
/**
 * Get the node options from the `NODE_OPTIONS` environment variable and format
 * them into a string without the inspect options.
 *
 * @returns A string with the formatted node options.
 */ export function getFormattedNodeOptionsWithoutInspect() {
    const args = getParsedNodeOptionsWithoutInspect();
    if (Object.keys(args).length === 0) return '';
    return formatNodeOptions(args).nodeOptions;
}
/**
 * Check if the value is a valid positive integer and parse it. If it's not, it will throw an error.
 *
 * @param value The value to be parsed.
 */ export function parseValidPositiveInteger(value) {
    const parsedValue = parseInt(value, 10);
    if (isNaN(parsedValue) || !isFinite(parsedValue) || parsedValue < 0) {
        throw new InvalidArgumentError(`'${value}' is not a non-negative number.`);
    }
    return parsedValue;
}
export const RESTART_EXIT_CODE = 77;
/**
 * Get the debug type from the `NODE_OPTIONS` environment variable.
 */ export function getNodeDebugType(nodeOptions) {
    if (nodeOptions.inspect) {
        return 'inspect';
    }
    if (nodeOptions['inspect-brk'] || nodeOptions['inspect_brk']) {
        return 'inspect-brk';
    }
}
/**
 * Get the `max-old-space-size` value from the `NODE_OPTIONS` environment
 * variable.
 *
 * @returns The value of the `max-old-space-size` option as a number.
 */ export function getMaxOldSpaceSize() {
    const args = getNodeOptionsArgs();
    if (args.length === 0) return;
    const parsed = parseNodeArgs(args);
    const size = parsed['max-old-space-size'] || parsed['max_old_space_size'];
    if (!size || typeof size !== 'string') return;
    return parseInt(size, 10);
}

//# sourceMappingURL=utils.js.map