specfold_core/import/
key.rs1use super::map::SourceRule;
4use crate::model::doctype::{KeyKind, TypeDef};
5use crate::model::stamp;
6use crate::workspace::vcs;
7use regex::Captures;
8use std::path::Path;
9
10pub fn normalize_stamp(s: &str) -> Option<String> {
12 let digits: String = s.chars().filter(|c| c.is_ascii_digit()).collect();
13 let full = match digits.len() {
14 8 => format!("{digits}000000"),
15 12 => format!("{digits}00"),
16 14 => digits,
17 _ => return None,
18 };
19 stamp::is_stamp(&full).then_some(full)
20}
21
22pub struct Source<'a> {
24 pub path: &'a str,
25 pub caps: Option<&'a Captures<'a>>,
26 pub created: Option<&'a str>,
27 pub title: &'a str,
28 pub name_stem: &'a str,
29}
30
31pub fn choose(root: &Path, rule: &SourceRule, ty: &TypeDef, src: &Source) -> (String, String) {
32 let Source { path, caps, created, title, name_stem } = *src;
33 let cap = |g: &str| caps.and_then(|c| c.name(g)).map(|m| m.as_str().to_string());
34 let slug = cap("slug")
35 .map(|s| stamp::slugify(&s))
36 .filter(|s| stamp::is_slug(s))
37 .or_else(|| Some(stamp::slugify(title)).filter(|s| stamp::is_slug(s)))
38 .or_else(|| Some(stamp::slugify(name_stem)).filter(|s| stamp::is_slug(s)))
39 .unwrap_or_else(|| "untitled".into());
40 if ty.key == KeyKind::Slug {
41 return (slug.clone(), slug);
42 }
43 let from_name = || cap("key").and_then(|k| normalize_stamp(&k));
44 let from_created = || created.and_then(normalize_stamp);
45 let from_commit = || vcs::first_commit_stamp(root, path);
46 let key = match rule.key.as_str() {
47 "name" => from_name().or_else(from_commit).or_else(from_created),
48 "created" => from_created().or_else(from_commit),
49 _ => from_commit().or_else(from_name).or_else(from_created),
50 }
51 .unwrap_or_else(stamp::now_stamp);
52 (key, slug)
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn stamps() {
61 assert_eq!(normalize_stamp("20260101").as_deref(), Some("20260101000000"));
62 assert_eq!(normalize_stamp("20260101-120000").as_deref(), Some("20260101120000"));
63 assert_eq!(normalize_stamp("2026-01-01").as_deref(), Some("20260101000000"));
64 assert!(normalize_stamp("ADR-001").is_none());
65 }
66}