Skip to main content

specfold_core/import/
map.rs

1//! The import map: how files from another layout become typed documents. A project writes it
2//! once for its migration; nothing in it is specific to specfold's own layout.
3
4use anyhow::{Context, Result};
5use serde::{Deserialize, Serialize};
6use std::collections::BTreeMap;
7use std::path::Path;
8
9#[derive(Debug, Clone, Deserialize, Serialize)]
10#[serde(deny_unknown_fields)]
11pub struct ImportMap {
12    #[serde(default)]
13    pub sources: Vec<SourceRule>,
14    /// Old status → new status, for every source.
15    #[serde(default)]
16    pub status: BTreeMap<String, String>,
17    /// Old frontmatter key → new key, or "-" to drop it. `rel.<kind>` moves a value into rel.
18    #[serde(default)]
19    pub keys: BTreeMap<String, String>,
20}
21
22#[derive(Debug, Clone, Deserialize, Serialize)]
23#[serde(deny_unknown_fields)]
24pub struct SourceRule {
25    /// Files to import; a pattern ending in `/` matches directories, imported as bundles.
26    pub glob: String,
27    #[serde(default)]
28    pub exclude: Vec<String>,
29    /// The document type. Required unless `redirect` is set.
30    #[serde(rename = "type")]
31    pub ty: Option<String>,
32    /// `auto` (from governs, then from the code paths the text mentions) or a fixed owner id.
33    #[serde(default = "auto")]
34    pub owner: String,
35    /// How the key is chosen for timestamp types: `name` (from `name`'s `key` group),
36    /// `first-commit` (the file's first commit time) or `created` (frontmatter created date).
37    #[serde(default = "first_commit")]
38    pub key: String,
39    /// A regex over the file or directory name with optional named groups `key`, `slug`, `alias`.
40    pub name: Option<String>,
41    /// Status for documents without one.
42    pub default_status: Option<String>,
43    /// Status overrides for this source only.
44    #[serde(default)]
45    pub status: BTreeMap<String, String>,
46    /// The file is a "moved" stub: a regex with a `target` group naming the new path. Stubs become
47    /// alias rows and are removed.
48    pub redirect: Option<String>,
49    /// Extra frontmatter fields whose values become aliases (old ids).
50    #[serde(default)]
51    pub alias_fields: Vec<String>,
52    /// For files: also take the sibling directory `<stem>/` as the bundle.
53    #[serde(default)]
54    pub sibling_dir: bool,
55}
56
57fn auto() -> String {
58    "auto".into()
59}
60
61fn first_commit() -> String {
62    "first-commit".into()
63}
64
65impl ImportMap {
66    pub fn load(path: &Path) -> Result<Self> {
67        let text = std::fs::read_to_string(path).with_context(|| format!("cannot read {}", path.display()))?;
68        toml::from_str(&text).with_context(|| format!("invalid import map {}", path.display()))
69    }
70}