standarbuild-detect 0.1.0

Detect project kind (Rust, Node, Bun, Deno, Python, Lua, C/C++) and scan polyglot monorepo workspaces
Documentation
//! The [`ProjectKind`] enum and its string round-trip.

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
pub enum ProjectKind {
	Rust,
	Node,
	Bun,
	Deno,
	Python,
	Lua,
	C,
	Cpp,
	Unknown,
}

impl ProjectKind {
	pub fn parse(s: &str) -> Option<Self> {
		match s {
			"rust" => Some(Self::Rust),
			"node" => Some(Self::Node),
			"bun" => Some(Self::Bun),
			"deno" => Some(Self::Deno),
			"python" => Some(Self::Python),
			"lua" => Some(Self::Lua),
			"c" => Some(Self::C),
			"cpp" | "c++" => Some(Self::Cpp),
			_ => None,
		}
	}

	pub fn as_str(self) -> &'static str {
		match self {
			Self::Rust => "rust",
			Self::Node => "node",
			Self::Bun => "bun",
			Self::Deno => "deno",
			Self::Python => "python",
			Self::Lua => "lua",
			Self::C => "c",
			Self::Cpp => "cpp",
			Self::Unknown => "unknown",
		}
	}
}

impl std::fmt::Display for ProjectKind {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		f.write_str(self.as_str())
	}
}

#[cfg(test)]
mod tests {
	use super::*;

	#[test]
	fn roundtrip_all_known_kinds() {
		for k in [
			ProjectKind::Rust,
			ProjectKind::Node,
			ProjectKind::Bun,
			ProjectKind::Deno,
			ProjectKind::Python,
			ProjectKind::Lua,
			ProjectKind::C,
			ProjectKind::Cpp,
		] {
			assert_eq!(ProjectKind::parse(k.as_str()), Some(k));
		}
	}

	#[test]
	fn cpp_alias() {
		assert_eq!(ProjectKind::parse("c++"), Some(ProjectKind::Cpp));
		assert_eq!(ProjectKind::parse("cpp"), Some(ProjectKind::Cpp));
	}

	#[test]
	fn unknown_does_not_roundtrip_through_parse() {
		assert_eq!(ProjectKind::parse("unknown"), None);
	}
}