cdx_core/document/
builder.rs1use crate::archive::{CONTENT_PATH, DUBLIN_CORE_PATH};
2use crate::content::{Block, Content, Text};
3use crate::metadata::DublinCore;
4use crate::{DocumentId, DocumentState, HashAlgorithm, Manifest, Result};
5
6use super::Document;
7
8#[derive(Debug, Clone)]
10pub struct DocumentBuilder {
11 title: String,
12 creator: String,
13 description: Option<String>,
14 language: Option<String>,
15 blocks: Vec<Block>,
16 state: DocumentState,
17 hash_algorithm: HashAlgorithm,
18 content_override: Option<Content>,
19 dublin_core_override: Option<DublinCore>,
20}
21
22impl Default for DocumentBuilder {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl DocumentBuilder {
29 #[must_use]
31 pub fn new() -> Self {
32 Self {
33 title: "Untitled".to_string(),
34 creator: "Unknown".to_string(),
35 description: None,
36 language: None,
37 blocks: Vec::new(),
38 state: DocumentState::Draft,
39 hash_algorithm: HashAlgorithm::default(),
40 content_override: None,
41 dublin_core_override: None,
42 }
43 }
44
45 #[must_use]
47 pub fn title(mut self, title: impl Into<String>) -> Self {
48 self.title = title.into();
49 self
50 }
51
52 #[must_use]
54 pub fn creator(mut self, creator: impl Into<String>) -> Self {
55 self.creator = creator.into();
56 self
57 }
58
59 #[must_use]
61 pub fn description(mut self, description: impl Into<String>) -> Self {
62 self.description = Some(description.into());
63 self
64 }
65
66 #[must_use]
68 pub fn language(mut self, language: impl Into<String>) -> Self {
69 self.language = Some(language.into());
70 self
71 }
72
73 #[must_use]
75 pub fn state(mut self, state: DocumentState) -> Self {
76 self.state = state;
77 self
78 }
79
80 #[must_use]
82 pub fn hash_algorithm(mut self, algorithm: HashAlgorithm) -> Self {
83 self.hash_algorithm = algorithm;
84 self
85 }
86
87 #[must_use]
89 pub fn add_block(mut self, block: Block) -> Self {
90 self.blocks.push(block);
91 self
92 }
93
94 #[must_use]
96 pub fn add_heading(self, level: u8, text: impl Into<String>) -> Self {
97 self.add_block(Block::heading(level, vec![Text::plain(text)]))
98 }
99
100 #[must_use]
102 pub fn add_paragraph(self, text: impl Into<String>) -> Self {
103 self.add_block(Block::paragraph(vec![Text::plain(text)]))
104 }
105
106 #[must_use]
108 pub fn add_code_block(self, code: impl Into<String>, language: Option<String>) -> Self {
109 self.add_block(Block::code_block(code, language))
110 }
111
112 #[must_use]
114 pub fn with_content(mut self, content: Content) -> Self {
115 self.content_override = Some(content);
116 self
117 }
118
119 #[must_use]
121 pub fn with_dublin_core(mut self, dublin_core: DublinCore) -> Self {
122 self.dublin_core_override = Some(dublin_core);
123 self
124 }
125
126 pub fn build(self) -> Result<Document> {
132 use crate::manifest::{ContentRef, Metadata};
133
134 let content = self
135 .content_override
136 .unwrap_or_else(|| Content::new(self.blocks));
137 let dublin_core = self.dublin_core_override.unwrap_or_else(|| {
138 let mut dc = DublinCore::new(&self.title, &self.creator);
139 dc.terms.description = self.description;
140 dc.terms.language = self.language;
141 dc
142 });
143
144 let content_ref = ContentRef {
145 path: CONTENT_PATH.to_string(),
146 hash: DocumentId::pending(),
147 compression: Some("deflate".to_string()),
148 merkle_root: None,
149 block_count: None,
150 };
151
152 let metadata = Metadata {
153 dublin_core: DUBLIN_CORE_PATH.to_string(),
154 custom: None,
155 };
156
157 let mut manifest = Manifest::new(content_ref, metadata);
158 manifest.state = self.state;
159 manifest.hash_algorithm = self.hash_algorithm;
160
161 Ok(Document {
162 manifest,
163 content,
164 dublin_core,
165 #[cfg(feature = "signatures")]
166 signature_file: None,
167 #[cfg(feature = "encryption")]
168 encryption_metadata: None,
169 academic_numbering: None,
170 comments: None,
171 phantom_clusters: None,
172 form_data: None,
173 bibliography: None,
174 jsonld_metadata: None,
175 })
176 }
177}