1use std::path::PathBuf;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum SourceScope {
14 User,
15 Project,
16 Temporary,
17}
18
19impl SourceScope {
20 pub fn as_str(self) -> &'static str {
21 match self {
22 Self::User => "user",
23 Self::Project => "project",
24 Self::Temporary => "temporary",
25 }
26 }
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum SourceOrigin {
32 Package,
33 TopLevel,
34}
35
36impl SourceOrigin {
37 pub fn as_str(self) -> &'static str {
38 match self {
39 Self::Package => "package",
40 Self::TopLevel => "top-level",
41 }
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
47pub struct SourceInfo {
48 pub path: PathBuf,
49 pub source: String,
51 pub scope: SourceScope,
52 pub origin: SourceOrigin,
53 pub base_dir: Option<PathBuf>,
54}
55
56impl SourceInfo {
57 pub fn new(
59 path: impl Into<PathBuf>,
60 source: impl Into<String>,
61 scope: SourceScope,
62 origin: SourceOrigin,
63 base_dir: Option<PathBuf>,
64 ) -> Self {
65 Self {
66 path: path.into(),
67 source: source.into(),
68 scope,
69 origin,
70 base_dir,
71 }
72 }
73
74 pub fn synthetic(path: impl Into<PathBuf>, source: impl Into<String>) -> Self {
77 Self {
78 path: path.into(),
79 source: source.into(),
80 scope: SourceScope::Temporary,
81 origin: SourceOrigin::TopLevel,
82 base_dir: None,
83 }
84 }
85
86 pub fn label(&self) -> String {
88 format!("{} · {}", self.source, self.scope.as_str())
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn synthetic_defaults() {
98 let info = SourceInfo::synthetic("/x/SKILL.md", "local");
99 assert_eq!(info.scope, SourceScope::Temporary);
100 assert_eq!(info.origin, SourceOrigin::TopLevel);
101 assert_eq!(info.label(), "local · temporary");
102 }
103
104 #[test]
105 fn explicit_fields() {
106 let info = SourceInfo::new(
107 "/p/SKILL.md",
108 "npm:foo",
109 SourceScope::Project,
110 SourceOrigin::Package,
111 Some(PathBuf::from("/p")),
112 );
113 assert_eq!(info.origin.as_str(), "package");
114 assert_eq!(info.base_dir, Some(PathBuf::from("/p")));
115 }
116}