aidoc_core/config.rs
1//! Configuration for the aidoc pipeline.
2//!
3//! The `Config` merges three sources with a fixed precedence:
4//!
5//! 1. CLI arguments (highest precedence, wins over anything else)
6//! 2. `[package.metadata.aidoc]` in a member crate's `Cargo.toml`
7//! 3. `[workspace.metadata.aidoc]` in the workspace `Cargo.toml`
8//!
9//! Values not set by any source fall back to the defaults documented on each
10//! field. `Config` itself is a plain struct; the merge logic lives in the
11//! index stage where the workspace layout is already known.
12
13use std::path::PathBuf;
14
15/// Runtime configuration for a single aidoc invocation.
16#[derive(Debug, Clone)]
17pub struct Config {
18 /// Output directory for generated artifacts. Defaults to
19 /// `<repo>/docs/aidoc/` relative to the workspace root.
20 pub out_dir: PathBuf,
21
22 /// Which artifact set to emit. Currently only [`Preset::Publish`].
23 pub preset: Preset,
24
25 /// If true, promote lint warnings to errors and cause the pipeline to
26 /// exit with a non-zero code. Wired to `--strict` on the CLI.
27 pub strict: bool,
28
29 /// If true, run in check mode: generate artifacts into a temporary
30 /// directory and diff against the committed `out_dir`. Wired to
31 /// `--check` on the CLI. No files are written to `out_dir`.
32 pub check: bool,
33
34 /// Crate names to skip when enumerating the workspace. Sourced from
35 /// `[workspace.metadata.aidoc].exclude`.
36 pub exclude: Vec<String>,
37
38 /// External LLM-doc platforms to emit overlay artifacts for.
39 ///
40 /// Each entry adds platform-specific files on top of the core
41 /// `docs/aidoc/` output (e.g. `context7.json` at the repo root for
42 /// [`Platform::Context7`]). See the `platform` module for what each
43 /// overlay emits.
44 pub platforms: Vec<Platform>,
45}
46
47impl Default for Config {
48 fn default() -> Self {
49 Self {
50 out_dir: PathBuf::from("docs/aidoc"),
51 preset: Preset::Publish,
52 strict: false,
53 check: false,
54 exclude: Vec::new(),
55 platforms: Vec::new(),
56 }
57 }
58}
59
60/// Which artifact set the pipeline should emit.
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum Preset {
63 /// Emit the full artifact set intended for publishing:
64 /// `llms.txt`, per-crate narrative markdown, `llms-full.txt`, and
65 /// deterministic `api/<crate>.json`.
66 Publish,
67}
68
69/// External LLM-doc platform this crate can emit overlay artifacts for.
70///
71/// Each variant maps to a small set of extra files (typically a
72/// platform manifest at the repo root) that a downstream service
73/// consumes. Layouts and required fields are captured in the
74/// `platform` module.
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub enum Platform {
77 /// [Context7](https://context7.com): manual-submit + GitHub Action
78 /// service. Overlay emits `context7.json` at the repo root
79 /// (`projectTitle`, `description`, `folders`, `branch`).
80 Context7,
81 /// [DeepWiki](https://deepwiki.com): auto-crawl service. Overlay
82 /// emits `.devin/wiki.json` at the repo root for workspaces large
83 /// enough to hit DeepWiki's page-count limit.
84 DeepWiki,
85 /// Anthropic-style: `.md` page mirror + reverse cross-ref hint
86 /// pointing back at the workspace `llms.txt`. Modifies existing
87 /// per-module `.md` artifacts in place; adds no new files.
88 AnthropicStyle,
89}
90
91impl Platform {
92 /// The name expected by the CLI (`--platform <name>`) and by any
93 /// future configuration parser.
94 pub fn as_str(self) -> &'static str {
95 match self {
96 Self::Context7 => "context7",
97 Self::DeepWiki => "deepwiki",
98 Self::AnthropicStyle => "anthropic-style",
99 }
100 }
101}
102
103impl std::str::FromStr for Platform {
104 type Err = UnknownPlatform;
105 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
106 match s {
107 "context7" => Ok(Self::Context7),
108 "deepwiki" => Ok(Self::DeepWiki),
109 "anthropic-style" => Ok(Self::AnthropicStyle),
110 other => Err(UnknownPlatform(other.to_owned())),
111 }
112 }
113}
114
115/// Returned by [`Platform::from_str`] when the input doesn't match any
116/// known platform name.
117#[derive(Debug, Clone)]
118pub struct UnknownPlatform(pub String);
119
120impl std::fmt::Display for UnknownPlatform {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 write!(
123 f,
124 "unknown platform `{}`; expected one of: context7, deepwiki, anthropic-style",
125 self.0
126 )
127 }
128}
129
130impl std::error::Error for UnknownPlatform {}