Skip to main content

wdl_modules/
lib.rs

1//! Implementation of the WDL module specification.
2//!
3//! `wdl-modules` provides the local, deterministic pieces of WDL module
4//! handling: `module.json` manifest parsing, `module-lock.json` lockfile
5//! parsing, symbolic import paths, deterministic content hashing, Ed25519
6//! `module.sig` signing and verification, SPDX license validation, and
7//! module file-tree checks.
8//!
9//! # Quickstart
10//!
11//! Parse `module.json` with [`Manifest::parse`], parse `module-lock.json` with
12//! [`Lockfile::parse`], and compute a content hash with
13//! [`hash::hash_directory`]. These entry points reject duplicate JSON object
14//! keys, invalid relative paths, invalid dependency declarations, and module
15//! trees that violate the reserved-filename or Unicode-normalization rules.
16//!
17//! ```rust
18//! use wdl_modules::Manifest;
19//!
20//! let manifest = Manifest::parse(
21//!     br#"{
22//!         "name": "spellbook",
23//!         "version": "1.0.0",
24//!         "license": "MIT"
25//!     }"#,
26//! )?;
27//!
28//! assert_eq!(manifest.name, "spellbook");
29//! # Ok::<(), Box<dyn std::error::Error>>(())
30//! ```
31
32pub mod dependency;
33pub mod hash;
34pub mod license;
35pub mod lockfile;
36pub mod manifest;
37pub mod relative_path;
38pub mod signing;
39mod strict_json;
40pub mod symbolic_path;
41pub mod tree;
42pub mod version_requirement;
43
44pub use crate::dependency::DependencyName;
45pub use crate::dependency::DependencyNameError;
46pub use crate::dependency::DependencySource;
47pub use crate::dependency::DependencySourceError;
48pub use crate::dependency::GitSelector;
49pub use crate::hash::ContentHash;
50pub use crate::hash::HashError;
51pub use crate::hash::Hasher;
52pub use crate::license::LicenseError;
53pub use crate::license::LicenseExpression;
54pub use crate::lockfile::DependencyEntry;
55pub use crate::lockfile::DependencyMap;
56pub use crate::lockfile::GitCommit;
57pub use crate::lockfile::GitCommitError;
58pub use crate::lockfile::LOCKFILE_VERSION;
59pub use crate::lockfile::Lockfile;
60pub use crate::lockfile::LockfileError;
61pub use crate::lockfile::ResolvedSource;
62pub use crate::manifest::Manifest;
63pub use crate::manifest::ManifestError;
64pub use crate::manifest::Readme;
65pub use crate::manifest::Tool;
66pub use crate::relative_path::RelativePath;
67pub use crate::relative_path::RelativePathError;
68pub use crate::signing::KeyError;
69pub use crate::signing::ModuleSignature;
70pub use crate::signing::Signature;
71pub use crate::signing::SignatureError;
72pub use crate::signing::SignatureFileError;
73pub use crate::signing::SigningKey;
74pub use crate::signing::VerifyError;
75pub use crate::signing::VerifyingKey;
76pub use crate::symbolic_path::SymbolicPath;
77pub use crate::symbolic_path::SymbolicPathError;
78pub use crate::tree::TreeError;
79pub use crate::tree::validate_tree;
80pub use crate::version_requirement::VersionRequirement;
81pub use crate::version_requirement::VersionRequirementError;
82
83/// The filename of a module manifest.
84pub const MANIFEST_FILENAME: &str = "module.json";
85
86/// The filename of a module lockfile.
87pub const LOCKFILE_FILENAME: &str = "module-lock.json";
88
89/// The filename of a module signature.
90pub const SIGNATURE_FILENAME: &str = "module.sig";
91
92/// The default filename of a module entrypoint, used when
93/// `Manifest::entrypoint` is not set.
94pub const DEFAULT_ENTRYPOINT_FILENAME: &str = "index.wdl";
95
96/// The default filename of a module readme, used when `Manifest::readme` is
97/// `Readme::Default`.
98pub const DEFAULT_README_FILENAME: &str = "README.md";
99
100/// Returns `true` if `s` begins with a Windows-style drive letter (e.g.
101/// `C:`, `c:\\`, `Z:/`). The spec rejects these as cross-platform unsafe
102/// even on non-Windows hosts where `Path::is_absolute` does not flag
103/// them.
104pub(crate) fn starts_with_windows_drive(s: &str) -> bool {
105    let mut bytes = s.bytes();
106    matches!(
107        (bytes.next(), bytes.next()),
108        (Some(b'A'..=b'Z' | b'a'..=b'z'), Some(b':'))
109    )
110}