searchfox_lib/
spec_refs.rs1use crate::client::SearchfoxClient;
2use crate::search::{SearchOptions, SearchResult};
3use anyhow::Result;
4use url::Url;
5
6const SPEC_REF_PATH_CATEGORIES: &[(&str, &str)] = &[
7 ("testing/web-platform", "Web-Platform Test"),
8 ("js/src/tests/test262", "Test262"),
9 ("js/src/jit-test/tests/wasm", "WebAssembly Test"),
10];
11
12pub fn categorize_spec_ref(path: &str) -> &'static str {
13 let lower = path.to_lowercase();
14 for (prefix, category) in SPEC_REF_PATH_CATEGORIES {
15 if lower.starts_with(prefix) {
16 return category;
17 }
18 }
19 if lower.contains("test") {
20 return "Test";
21 }
22 "Code"
23}
24
25pub fn spec_ref_category_names() -> &'static [&'static str] {
26 &[
27 "Code",
28 "Test",
29 "Test262",
30 "WebAssembly Test",
31 "Web-Platform Test",
32 ]
33}
34
35pub fn spec_refs_query(spec_url: &str) -> Result<String> {
36 let parsed = Url::parse(spec_url).map_err(|_| anyhow::anyhow!("Invalid URL: {spec_url}"))?;
37 let domain = parsed
38 .host_str()
39 .ok_or_else(|| anyhow::anyhow!("No host in URL: {spec_url}"))?
40 .to_string();
41 let anchor = parsed
42 .fragment()
43 .ok_or_else(|| anyhow::anyhow!("URL must contain a #fragment: {spec_url}"))?
44 .to_string();
45 Ok(format!(
46 "re:{}[^\\s]*#{}\\b",
47 regex::escape(&domain),
48 regex::escape(&anchor)
49 ))
50}
51
52impl SearchfoxClient {
53 pub async fn search_spec_refs(
54 &self,
55 spec_url: &str,
56 limit: usize,
57 ) -> Result<Vec<SearchResult>> {
58 let query = spec_refs_query(spec_url)?;
59 let options = SearchOptions {
60 query: Some(query),
61 limit,
62 ..Default::default()
63 };
64 self.search(&options).await
65 }
66}