tovuk 0.1.68

Deploy Rust workers, static frontends, and worker-static apps to Tovuk.
use super::super::{
    command_policy::{command_name_from_token, command_tokens},
    constants::{FRONTEND_INSTALL_COMMANDS, FRONTEND_PACKAGE_MANAGERS, JAVASCRIPT_LINTERS},
};

pub(crate) fn uses_javascript_linter(command: &str) -> bool {
    let tokens = command_tokens(command);
    tokens.iter().enumerate().any(|(index, token)| {
        let command_name = command_name_from_token(token);
        JAVASCRIPT_LINTERS.contains(&command_name.as_str())
            || (command_name == "next"
                && tokens.get(index + 1).is_some_and(|value| value == "lint"))
    })
}

pub(super) fn uses_strict_frontend_typechecker(command: &str) -> bool {
    let tokens = command_tokens(command);
    tokens.iter().enumerate().any(|(index, token)| {
        let command_name = command_name_from_token(token);
        (command_name == "oxlint"
            && tokens.iter().any(|value| value == "--type-aware")
            && tokens.iter().any(|value| value == "--type-check"))
            || (command_name == "deno"
                && tokens.get(index + 1).is_some_and(|value| value == "check"))
    })
}

pub(super) fn uses_native_frontend_linter(command: &str) -> bool {
    let tokens = command_tokens(command);
    tokens.iter().enumerate().any(|(index, token)| {
        let command_name = command_name_from_token(token);
        command_name == "oxlint"
            || (command_name == "biome"
                && tokens
                    .get(index + 1)
                    .is_some_and(|value| value == "check" || value == "lint"))
            || (command_name == "deno"
                && tokens.get(index + 1).is_some_and(|value| value == "lint"))
    })
}

pub(super) fn uses_native_dead_code_checker(command: &str) -> bool {
    uses_fallow_subcommand(command, "dead-code")
}

pub(super) fn uses_native_duplicate_checker(command: &str) -> bool {
    uses_fallow_subcommand(command, "dupes")
}

pub(super) fn uses_native_health_checker(command: &str) -> bool {
    uses_fallow_subcommand(command, "health")
}

fn uses_fallow_subcommand(command: &str, subcommand: &str) -> bool {
    let tokens = command_tokens(command);
    tokens.iter().enumerate().any(|(index, token)| {
        command_name_from_token(token) == "fallow"
            && tokens
                .get(index + 1)
                .is_some_and(|value| value == subcommand)
    })
}

pub(crate) fn has_frontend_install_command(tokens: &[String]) -> bool {
    tokens.iter().enumerate().any(|(index, token)| {
        FRONTEND_INSTALL_COMMANDS.contains(
            &format!(
                "{} {}",
                command_name_from_token(token),
                tokens.get(index + 1).map_or("", String::as_str)
            )
            .as_str(),
        )
    })
}

pub(crate) fn has_frontend_script_run(tokens: &[String], script: &str) -> bool {
    tokens.iter().enumerate().any(|(index, token)| {
        if !FRONTEND_PACKAGE_MANAGERS.contains(&command_name_from_token(token).as_str())
            || tokens.get(index + 1).is_none_or(|value| value != "run")
        {
            return false;
        }
        tokens.get(index + 2).is_some_and(|value| value == script)
            || (tokens
                .get(index + 2)
                .is_some_and(|value| value.starts_with('-'))
                && tokens.get(index + 3).is_some_and(|value| value == script))
    })
}

pub(super) fn referenced_package_scripts(command: &str) -> Vec<String> {
    let tokens = command_tokens(command);
    let mut scripts = Vec::new();
    for (index, token) in tokens.iter().enumerate() {
        if !FRONTEND_PACKAGE_MANAGERS.contains(&command_name_from_token(token).as_str())
            || tokens.get(index + 1).is_none_or(|value| value != "run")
        {
            continue;
        }
        if let Some(script) = script_name_after_run(&tokens, index + 2) {
            scripts.push(script);
        }
    }
    scripts
}

fn script_name_after_run(tokens: &[String], start: usize) -> Option<String> {
    let mut index = start;
    while tokens
        .get(index)
        .is_some_and(|token| token.starts_with('-'))
    {
        index += 1;
    }
    tokens.get(index).cloned()
}