tinymist_package/
registry.rs1use std::num::NonZeroUsize;
4use std::path::PathBuf;
5use std::{path::Path, sync::Arc};
6
7use ecow::EcoString;
8use serde::Deserialize;
9use tinymist_std::time::UtcDateTime;
10pub use typst::diag::PackageError;
11pub use typst::syntax::package::PackageSpec;
12use typst::syntax::package::{PackageInfo, TemplateInfo, VersionlessPackageSpec};
13
14mod dummy;
15pub use dummy::*;
16
17mod memory;
18pub use memory::*;
19
20#[cfg(feature = "browser")]
21mod browser;
22#[cfg(feature = "browser")]
23pub use browser::*;
24
25#[cfg(feature = "http-registry")]
26mod http;
27#[cfg(feature = "http-registry")]
28pub use http::*;
29
30pub const DEFAULT_REGISTRY: &str = "https://packages.typst.org";
32
33pub const PREVIEW_NS: &str = "preview";
35
36pub trait PackageSpecExt {
38 fn is_preview(&self) -> bool;
40}
41
42impl PackageSpecExt for PackageSpec {
43 fn is_preview(&self) -> bool {
44 self.namespace == PREVIEW_NS
45 }
46}
47
48impl PackageSpecExt for VersionlessPackageSpec {
49 fn is_preview(&self) -> bool {
50 self.namespace == PREVIEW_NS
51 }
52}
53
54pub trait PackageRegistry {
56 fn reset(&mut self) {}
58
59 fn revision(&self) -> Option<NonZeroUsize> {
63 None
64 }
65
66 fn resolve(&self, spec: &PackageSpec) -> Result<Arc<Path>, PackageError>;
68
69 fn packages(&self) -> &[PackageIndexEntry] {
76 &[]
77 }
78}
79
80#[derive(Debug, Clone, Deserialize)]
82pub struct PackageIndexEntry {
83 #[serde(default)]
85 pub namespace: EcoString,
86 #[serde(flatten)]
88 pub package: PackageInfo,
89 #[serde(default)]
91 pub template: Option<TemplateInfo>,
92 #[serde(rename = "updatedAt", deserialize_with = "deserialize_timestamp")]
94 pub updated_at: Option<UtcDateTime>,
95 #[serde(default)]
97 pub path: Option<PathBuf>,
98}
99
100impl PackageIndexEntry {
101 pub fn spec(&self) -> PackageSpec {
103 PackageSpec {
104 namespace: self.namespace.clone(),
105 name: self.package.name.clone(),
106 version: self.package.version,
107 }
108 }
109
110 pub fn matches_versionless(&self, spec: &VersionlessPackageSpec) -> bool {
112 self.namespace == spec.namespace && self.package.name == spec.name
113 }
114}
115
116fn deserialize_timestamp<'de, D>(deserializer: D) -> Result<Option<UtcDateTime>, D::Error>
117where
118 D: serde::Deserializer<'de>,
119{
120 let timestamp = i64::deserialize(deserializer)?;
121 Ok(UtcDateTime::from_unix_timestamp(timestamp).ok())
122}
123
124pub trait Notifier {
126 fn downloading(&self, _spec: &PackageSpec) {}
128}
129
130#[derive(Debug, Default, Clone, Copy, Hash)]
132pub struct DummyNotifier;
133
134impl Notifier for DummyNotifier {}