mdzip_core/lib.rs
1//! Read and write **MDZip** (`.mdz`) archives: one or more Markdown documents
2//! and their images and other assets, in a single ZIP file.
3//!
4//! This crate implements the [MDZip specification] 1.2.0 and is tested
5//! against the specification's shared conformance fixtures, the same ones
6//! the JavaScript, .NET and Python cores run, so an archive written here
7//! opens the same way in every MDZip tool.
8//!
9//! [MDZip specification]: https://github.com/mdzip-project/mdzip-spec
10//!
11//! # Reading
12//!
13//! ```
14//! # let data = mdzip_core::create([("index.md", "# My guide\n")], &Default::default())?;
15//! use mdzip_core::MdzArchive;
16//!
17//! let archive = MdzArchive::open(data)?; // or MdzArchive::open_path("guide.mdz")
18//! let entry = archive.entry_point()?; // "index.md" (Section 5.5)
19//! let text = archive.read_text(&entry)?;
20//! assert_eq!(archive.title(), Some("My guide"));
21//! for finding in archive.validate() { // conformance notes; never fails
22//! println!("{} {} {}", finding.level, finding.code, finding.message);
23//! }
24//! # Ok::<(), mdzip_core::MdzError>(())
25//! ```
26//!
27//! Opening is safe for untrusted input: invalid or encrypted ZIPs, unsafe or
28//! duplicate entry names, ZIP bombs and newer major spec versions are
29//! rejected with a stable [`ErrorCode`], and symbolic links are never
30//! followed. See [`MdzArchive::open`].
31//!
32//! # Writing
33//!
34//! ```
35//! use mdzip_core::{create, Application, CreateOptions};
36//!
37//! let data = create(
38//! [
39//! ("index.md", "# My guide\n\n\n".as_bytes()),
40//! ("images/logo.png", b"\x89PNG..."),
41//! ],
42//! &CreateOptions::new().application(Application::new("my-editor", "1.0")),
43//! )?;
44//! # Ok::<(), mdzip_core::MdzError>(())
45//! ```
46//!
47//! Every archive gets the `manifest.json` the spec requires of producers.
48//! To change an existing archive, use [`MdzArchive::update`]: untouched
49//! entries and unknown manifest fields are kept exactly.
50//!
51//! # Links
52//!
53//! [`MdzArchive::resolve_link`] resolves a link written in a document, per
54//! Sections 9.3–9.6. For links out of the archive to files beside it, or
55//! into other archives, supply a [`LinkHost`] such as [`FilesystemHost`] to
56//! [`resolve_link`].
57
58#![warn(missing_docs)]
59
60mod archive;
61mod entrypoint;
62mod error;
63mod filters;
64mod links;
65mod manifest;
66mod paths;
67mod time;
68mod writer;
69mod zip;
70
71pub use archive::{Diagnostic, EntryInfo, Level, Limits, MANIFEST_NAME, MdzArchive};
72pub use entrypoint::resolve_entry_point;
73pub use error::{ErrorCode, MdzError, Result};
74pub use filters::{DEFAULT_FILTERS, matches_filters};
75pub use links::{
76 FilesystemHost, HostKind, HostOptions, LinkHost, LinkSource, LinkTarget, LinkUse, UnresolvedReason, is_mdz_name,
77 resolve_link,
78};
79pub use manifest::{
80 Manifest, Mode, ParsedManifest, SPEC_NAME, SPEC_VERSION, SUPPORTED_MAJOR, check_spec_version, manifest_mode,
81 parse_manifest, serialize_manifest, spec_version, validate_manifest,
82};
83pub use paths::{SUPPORT_FILE_NAMES, is_markdown, is_support_file, nfc, same_path, validate_entry_set, validate_path};
84pub use writer::{Application, CreateOptions, PRODUCER_CORE_NAME, Update, create, create_from_directory, update};