use std::borrow::Cow;
use tracing::debug;
use crate::{
error::{Error, Result},
Version,
};
const DOCSRS_URL: &str = "https://docs.rs";
pub(crate) fn get_page_url(std: bool, name: &str, version: &Version) -> Cow<'static, str> {
if std {
Cow::Borrowed(STDLIB_INDEX_URL)
} else {
Cow::Owned(format!("{DOCSRS_URL}/{name}/{version}/{name}/"))
}
}
pub(crate) fn find_index_url(
std: bool,
name: &str,
version: Version,
body: &str,
) -> Result<(Version, String)> {
let index_path = find_url(body).ok_or(Error::IndexNotFound)?;
debug!("found index path: {index_path}");
if std {
let version = index_path
.strip_prefix("search-index")
.and_then(|url| url.strip_suffix(".js"))
.ok_or_else(|| Error::InvalidVersionFormat(index_path.clone()))?
.parse()?;
Ok((version, format!("{STDLIB_URL}/{index_path}")))
} else {
let url = format!("{DOCSRS_URL}/{name}/{version}/{index_path}");
Ok((version, url))
}
}
pub const STDLIB_INDEX_URL: &str = "https://doc.rust-lang.org/nightly/std/index.html";
const STDLIB_URL: &str = "https://doc.rust-lang.org/nightly";
fn find_url(body: &str) -> Option<String> {
let v1 = body
.rfind("src=\"../search-index-")
.and_then(|pos| body[pos..].split_once("src=\"../"))
.and_then(|(_, start)| start.split_once('\"'))
.map(|(url, _)| url.to_owned());
let v2 = body
.rsplit_once("data-search-index-js=\"../")
.and_then(|(_, start)| start.split_once('\"'))
.map(|(url, _)| url.to_owned());
let v3 = body
.rsplit_once("data-resource-suffix=\"")
.and_then(|(_, start)| start.split_once('\"'))
.map(|(suffix, _)| format!("search-index{suffix}.js"));
v3.or(v2).or(v1)
}
#[cfg(test)]
mod tests {
use std::fs;
use insta::glob;
use super::*;
#[test]
fn test_find_index_path() {
glob!("fixtures/*.html", |path| {
let input = fs::read_to_string(path).unwrap();
let data = find_url(&input).unwrap();
insta::assert_yaml_snapshot!(data);
});
}
}