searchfox-lib 0.20.4

Library for searchfox.org API access
Documentation
use crate::client::SearchfoxClient;
use crate::search::{SearchOptions, SearchResult};
use anyhow::Result;
use url::Url;

const SPEC_REF_PATH_CATEGORIES: &[(&str, &str)] = &[
    ("testing/web-platform", "Web-Platform Test"),
    ("js/src/tests/test262", "Test262"),
    ("js/src/jit-test/tests/wasm", "WebAssembly Test"),
];

pub fn categorize_spec_ref(path: &str) -> &'static str {
    let lower = path.to_lowercase();
    for (prefix, category) in SPEC_REF_PATH_CATEGORIES {
        if lower.starts_with(prefix) {
            return category;
        }
    }
    if lower.contains("test") {
        return "Test";
    }
    "Code"
}

pub fn spec_ref_category_names() -> &'static [&'static str] {
    &[
        "Code",
        "Test",
        "Test262",
        "WebAssembly Test",
        "Web-Platform Test",
    ]
}

pub fn spec_refs_query(spec_url: &str) -> Result<String> {
    let parsed = Url::parse(spec_url).map_err(|_| anyhow::anyhow!("Invalid URL: {spec_url}"))?;
    let domain = parsed
        .host_str()
        .ok_or_else(|| anyhow::anyhow!("No host in URL: {spec_url}"))?
        .to_string();
    let anchor = parsed
        .fragment()
        .ok_or_else(|| anyhow::anyhow!("URL must contain a #fragment: {spec_url}"))?
        .to_string();
    Ok(format!(
        "re:{}[^\\s]*#{}\\b",
        regex::escape(&domain),
        regex::escape(&anchor)
    ))
}

impl SearchfoxClient {
    pub async fn search_spec_refs(
        &self,
        spec_url: &str,
        limit: usize,
    ) -> Result<Vec<SearchResult>> {
        let query = spec_refs_query(spec_url)?;
        let options = SearchOptions {
            query: Some(query),
            limit,
            ..Default::default()
        };
        self.search(&options).await
    }
}