polykit_core/
package.rs

1//! Package data models and language definitions.
2
3use std::path::PathBuf;
4
5use serde::{Deserialize, Serialize};
6use smallvec::SmallVec;
7
8/// Supported programming languages.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(rename_all = "lowercase")]
11pub enum Language {
12    Js,
13    Ts,
14    Python,
15    Go,
16    Rust,
17}
18
19impl Language {
20    #[inline]
21    pub fn as_str(&self) -> &'static str {
22        match self {
23            Language::Js => "js",
24            Language::Ts => "ts",
25            Language::Python => "python",
26            Language::Go => "go",
27            Language::Rust => "rust",
28        }
29    }
30
31    /// Parses a language string into a `Language` variant.
32    ///
33    /// Supports aliases (e.g., "javascript" for "js", "typescript" for "ts").
34    #[allow(clippy::should_implement_trait)]
35    pub fn from_str(s: &str) -> Option<Self> {
36        match s.to_lowercase().as_str() {
37            "js" | "javascript" => Some(Language::Js),
38            "ts" | "typescript" => Some(Language::Ts),
39            "python" => Some(Language::Python),
40            "go" => Some(Language::Go),
41            "rust" => Some(Language::Rust),
42            _ => None,
43        }
44    }
45}
46
47/// A task that can be executed for a package.
48#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
49pub struct Task {
50    pub name: String,
51    pub command: String,
52    #[serde(default)]
53    pub depends_on: Vec<String>,
54}
55
56/// Represents a package in the monorepo.
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct Package {
59    pub name: String,
60    pub language: Language,
61    pub public: bool,
62    pub path: PathBuf,
63    #[serde(
64        deserialize_with = "deserialize_deps",
65        serialize_with = "serialize_deps"
66    )]
67    pub deps: SmallVec<[String; 4]>,
68    pub tasks: Vec<Task>,
69    pub version: Option<String>,
70}
71
72fn deserialize_deps<'de, D>(deserializer: D) -> Result<SmallVec<[String; 4]>, D::Error>
73where
74    D: serde::Deserializer<'de>,
75{
76    use serde::Deserialize;
77    let vec: Vec<String> = Vec::deserialize(deserializer)?;
78    Ok(SmallVec::from_vec(vec))
79}
80
81fn serialize_deps<S>(deps: &SmallVec<[String; 4]>, serializer: S) -> Result<S::Ok, S::Error>
82where
83    S: serde::Serializer,
84{
85    use serde::Serialize;
86    let vec: Vec<&String> = deps.iter().collect();
87    vec.serialize(serializer)
88}
89
90impl Package {
91    pub fn new(
92        name: String,
93        language: Language,
94        public: bool,
95        path: PathBuf,
96        deps: Vec<String>,
97        tasks: Vec<Task>,
98    ) -> Self {
99        Self {
100            name,
101            language,
102            public,
103            path,
104            deps: SmallVec::from_vec(deps),
105            tasks,
106            version: None,
107        }
108    }
109
110    #[inline]
111    pub fn get_task(&self, name: &str) -> Option<&Task> {
112        self.tasks.iter().find(|t| t.name == name)
113    }
114}