use typst::syntax::package::PackageSpec;
#[cfg_attr(not(feature = "package-reading"), allow(dead_code))]
pub(crate) const PACKAGE_REGISTRY_URL: &str = "https://packages.typst.org";
#[cfg_attr(not(feature = "package-reading"), allow(dead_code))]
pub(crate) const PACKAGE_REGISTRY_NAMESPACE: &str = "preview";
#[cfg_attr(not(feature = "fs"), allow(dead_code))]
pub(crate) const FONT_CONTAINER_EXTENSIONS: [&str; 4] = ["ttf", "ttc", "otf", "otc"];
#[cfg_attr(not(feature = "egress"), allow(dead_code))]
pub(crate) fn package_tree_key(spec: &PackageSpec) -> String {
format!("{}/{}/{}", spec.namespace, spec.name, spec.version)
}
#[allow(
dead_code,
reason = "no shipped adapter reads a raw archive cache yet; the layout is derived here so the first one cannot invent its own"
)]
pub(crate) fn package_archive_cache_key(spec: &PackageSpec) -> String {
format!("{}.tar.gz", package_tree_key(spec))
}
#[cfg_attr(not(feature = "package-reading"), allow(dead_code))]
pub(crate) fn official_registry_serves(spec: &PackageSpec) -> bool {
spec.namespace == PACKAGE_REGISTRY_NAMESPACE
}
#[cfg_attr(not(feature = "package-reading"), allow(dead_code))]
pub(crate) fn official_registry_archive_key(spec: &PackageSpec) -> Option<String> {
official_registry_serves(spec)
.then(|| format!("{}/{}-{}.tar.gz", spec.namespace, spec.name, spec.version))
}
#[cfg_attr(not(feature = "package-reading"), allow(dead_code))]
pub(crate) fn official_registry_archive_url(spec: &PackageSpec) -> Option<String> {
let key = official_registry_archive_key(spec)?;
Some(format!("{PACKAGE_REGISTRY_URL}/{key}"))
}
#[cfg_attr(not(feature = "fs"), allow(dead_code))]
pub(crate) fn is_font_container_extension(extension: &str) -> bool {
FONT_CONTAINER_EXTENSIONS
.iter()
.any(|supported| extension.eq_ignore_ascii_case(supported))
}
#[cfg_attr(
not(feature = "opendal"),
allow(
dead_code,
reason = "no enabled source addresses Font Containers by key"
)
)]
pub(crate) fn is_font_container_key(key: &str) -> bool {
key.rsplit_once('.')
.is_some_and(|(_, suffix)| is_font_container_extension(suffix))
}
#[cfg(test)]
mod tests {
use super::*;
fn spec(text: &str) -> PackageSpec {
text.parse().expect("the test specification parses")
}
#[test]
fn every_source_derives_one_specification_from_its_namespace_name_and_version() {
let layouts = [
(
"@preview/example:1.2.3",
"preview/example/1.2.3",
"preview/example/1.2.3.tar.gz",
Some("https://packages.typst.org/preview/example-1.2.3.tar.gz"),
),
(
"@local/example:0.1.0",
"local/example/0.1.0",
"local/example/0.1.0.tar.gz",
None,
),
(
"@preview/nested-name:10.0.1",
"preview/nested-name/10.0.1",
"preview/nested-name/10.0.1.tar.gz",
Some("https://packages.typst.org/preview/nested-name-10.0.1.tar.gz"),
),
];
for (text, tree, cache, registry) in layouts {
let spec = spec(text);
assert_eq!(package_tree_key(&spec), tree, "{text}");
assert_eq!(package_archive_cache_key(&spec), cache, "{text}");
assert_eq!(
official_registry_archive_url(&spec).as_deref(),
registry,
"{text}"
);
}
}
#[test]
fn only_the_served_namespace_has_an_official_registry_candidate() {
for text in ["@local/example:1.0.0", "@custom/example:1.0.0"] {
let unserved = spec(text);
assert!(!official_registry_serves(&unserved), "{text}");
assert_eq!(official_registry_archive_key(&unserved), None, "{text}");
assert_eq!(official_registry_archive_url(&unserved), None, "{text}");
}
let served = spec("@preview/example:1.0.0");
assert!(official_registry_serves(&served));
}
#[test]
fn supported_font_container_extensions_are_matched_case_insensitively() {
let extensions = [
("ttf", true),
("TTF", true),
("ttc", true),
("Ttc", true),
("otf", true),
("OTF", true),
("otc", true),
("oTc", true),
("woff", false),
("woff2", false),
("txt", false),
("", false),
("ttf ", false),
(".ttf", false),
];
for (extension, supported) in extensions {
assert_eq!(
is_font_container_extension(extension),
supported,
"{extension:?}"
);
}
}
#[test]
fn a_key_names_a_font_container_when_a_supported_suffix_terminates_it() {
let keys = [
("container.ttf", true),
("container.TTF", true),
("fonts/nested/container.otc", true),
("container.Ttc", true),
("container.oTf", true),
(".ttf", true),
("container.woff", false),
("container.ttf.txt", false),
("container", false),
("ttf", false),
("fonts.ttf/container", false),
("", false),
];
for (key, supported) in keys {
assert_eq!(is_font_container_key(key), supported, "{key:?}");
}
}
}