Skip to main content

switchback_traits/traits/
companion.rs

1//! Companion document discovery (sync + async varieties).
2
3use std::path::Path;
4
5use crate::companion::title_from_markdown;
6use crate::{CompanionFile, Result};
7
8/// Where a family searches for companion documents relative to contract inputs.
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum CompanionDiscovery {
11    /// Search in the same directory as the contract file.
12    Beside,
13    /// Walk ancestor directories from the contract file location.
14    Ancestors,
15    /// Search a `docs/` subdirectory relative to the contract root.
16    DocsSubdir,
17}
18
19/// How a family discovers, names, and places companion docs (sync, local).
20///
21/// Associated with [`ContractFamily`](super::contract_family::ContractFamily) via
22/// [`ContractFamily::CompanionStrategy`](super::contract_family::ContractFamily::CompanionStrategy).
23pub trait CompanionStrategy: Send + Sync {
24    /// Returns the filesystem search strategy for companion files.
25    fn discovery(&self) -> CompanionDiscovery;
26
27    /// Computes the output filename for a companion given its source directory path segments and stem.
28    fn output_name(&self, source_dir: &[&str], stem: &str) -> String;
29
30    /// MIME types accepted for companion documents in this family.
31    fn companion_media_types(&self) -> &'static [&'static str];
32
33    /// Human nav title for a companion (default: first markdown `#` heading).
34    fn companion_title(&self, stem: &str, bytes: &[u8]) -> String {
35        title_from_markdown(stem, bytes)
36    }
37
38    /// Discovers companions on the local filesystem relative to contract inputs.
39    ///
40    /// Default returns empty; families with companion docs override.
41    fn discover_local(&self, contract_root: &Path) -> Result<Vec<CompanionFile>> {
42        let _ = contract_root;
43        Ok(Vec::new())
44    }
45}
46
47/// Async companion fetch (remote registries, URL-backed docs).
48///
49/// Use when companion discovery requires network I/O beyond local filesystem search.
50pub trait AsyncCompanionStrategy: Send + Sync {
51    /// Returns the search strategy (local layout hint for remote-backed companions).
52    fn discovery(&self) -> CompanionDiscovery;
53
54    /// Computes the output filename for a companion given its source directory path segments and stem.
55    fn output_name(&self, source_dir: &[&str], stem: &str) -> String;
56
57    /// MIME types accepted for companion documents in this family.
58    fn companion_media_types(&self) -> &'static [&'static str];
59
60    /// Human nav title for a companion (default: first markdown `#` heading).
61    fn companion_title(&self, stem: &str, bytes: &[u8]) -> String {
62        title_from_markdown(stem, bytes)
63    }
64
65    /// Discovers companions asynchronously (remote fetch, registry lookup, etc.).
66    async fn discover(&self, contract_root: &Path) -> Result<Vec<CompanionFile>>;
67}