use std::num::NonZeroUsize;
use std::path::PathBuf;
use std::{path::Path, sync::Arc};
use ecow::EcoString;
use serde::Deserialize;
use tinymist_std::time::UtcDateTime;
pub use typst::diag::PackageError;
pub use typst::syntax::package::PackageSpec;
use typst::syntax::package::{PackageInfo, TemplateInfo, VersionlessPackageSpec};
mod dummy;
pub use dummy::*;
mod memory;
pub use memory::*;
#[cfg(feature = "browser")]
mod browser;
#[cfg(feature = "browser")]
pub use browser::*;
#[cfg(feature = "http-registry")]
mod http;
#[cfg(feature = "http-registry")]
pub use http::*;
pub const DEFAULT_REGISTRY: &str = "https://packages.typst.org";
pub const PREVIEW_NS: &str = "preview";
pub trait PackageSpecExt {
fn is_preview(&self) -> bool;
}
impl PackageSpecExt for PackageSpec {
fn is_preview(&self) -> bool {
self.namespace == PREVIEW_NS
}
}
impl PackageSpecExt for VersionlessPackageSpec {
fn is_preview(&self) -> bool {
self.namespace == PREVIEW_NS
}
}
pub trait PackageRegistry {
fn reset(&mut self) {}
fn revision(&self) -> Option<NonZeroUsize> {
None
}
fn resolve(&self, spec: &PackageSpec) -> Result<Arc<Path>, PackageError>;
fn packages(&self) -> &[PackageIndexEntry] {
&[]
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct PackageIndexEntry {
#[serde(default)]
pub namespace: EcoString,
#[serde(flatten)]
pub package: PackageInfo,
#[serde(default)]
pub template: Option<TemplateInfo>,
#[serde(rename = "updatedAt", deserialize_with = "deserialize_timestamp")]
pub updated_at: Option<UtcDateTime>,
#[serde(default)]
pub path: Option<PathBuf>,
}
impl PackageIndexEntry {
pub fn spec(&self) -> PackageSpec {
PackageSpec {
namespace: self.namespace.clone(),
name: self.package.name.clone(),
version: self.package.version,
}
}
pub fn matches(&self, spec: &PackageSpec) -> bool {
self.namespace == spec.namespace
&& self.package.name == spec.name
&& self.package.version == spec.version
}
pub fn matches_versionless(&self, spec: &VersionlessPackageSpec) -> bool {
self.namespace == spec.namespace && self.package.name == spec.name
}
}
fn deserialize_timestamp<'de, D>(deserializer: D) -> Result<Option<UtcDateTime>, D::Error>
where
D: serde::Deserializer<'de>,
{
let timestamp = i64::deserialize(deserializer)?;
Ok(UtcDateTime::from_unix_timestamp(timestamp).ok())
}
pub trait Notifier {
fn downloading(&self, _spec: &PackageSpec) {}
}
#[derive(Debug, Default, Clone, Copy, Hash)]
pub struct DummyNotifier;
impl Notifier for DummyNotifier {}