use std::path::Path;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PkgType {
Runnable,
Library,
}
impl std::fmt::Display for PkgType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Runnable => write!(f, "runnable"),
Self::Library => write!(f, "library"),
}
}
}
impl FromStr for PkgType {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"runnable" => Ok(Self::Runnable),
"library" => Ok(Self::Library),
other => Err(format!("unknown package type: {other:?}")),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TypeSource {
AutoDetectedRunnable,
AutoDetectedLibrary,
}
impl FromStr for TypeSource {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"auto_detected_runnable" => Ok(Self::AutoDetectedRunnable),
"auto_detected_library" => Ok(Self::AutoDetectedLibrary),
other => Err(format!("unknown type_source: {other:?}")),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct PkgEntity {
pub name: String,
#[serde(default)]
pub version: Option<String>,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub category: Option<String>,
#[serde(default)]
pub docstring: Option<String>,
#[serde(default)]
pub tags: Option<Vec<String>>,
#[serde(default, rename = "type")]
pub pkg_type: Option<PkgType>,
#[serde(default, deserialize_with = "deserialize_type_source_lenient")]
pub type_source: Option<TypeSource>,
}
fn deserialize_type_source_lenient<'de, D>(d: D) -> Result<Option<TypeSource>, D::Error>
where
D: serde::Deserializer<'de>,
{
let s: Option<String> = Option::deserialize(d)?;
Ok(s.and_then(|v| TypeSource::from_str(&v).ok()))
}
impl PkgEntity {
pub fn parse_from_init_lua(path: &Path) -> Option<Self> {
let content = std::fs::read_to_string(path).ok()?;
let parsed = parse_meta(&content)?;
let docstring = extract_docstring_from(&content);
let pkg_type: Option<PkgType> = None;
let type_source: Option<TypeSource> = None;
Some(PkgEntity {
name: parsed.name,
version: option_from_str(parsed.version),
description: option_from_str(parsed.description),
category: option_from_str(parsed.category),
docstring: option_from_str(docstring),
tags: if parsed.tags.is_empty() {
None
} else {
Some(parsed.tags)
},
pkg_type,
type_source,
})
}
}
fn option_from_str(s: String) -> Option<String> {
if s.is_empty() {
None
} else {
Some(s)
}
}
fn extract_docstring_from(content: &str) -> String {
let mut lines = Vec::new();
for line in content.lines() {
let trimmed = line.trim_start();
if let Some(rest) = trimmed.strip_prefix("---") {
lines.push(rest.trim().to_string());
} else if trimmed.is_empty() {
continue;
} else {
break;
}
}
lines.join("\n")
}
struct ParsedMeta {
name: String,
version: String,
description: String,
category: String,
tags: Vec<String>,
}
fn parse_meta(content: &str) -> Option<ParsedMeta> {
let head = content;
let mut search_from = 0;
let meta_start = loop {
let rel = head[search_from..].find("M.meta")?;
let pos = search_from + rel;
let line_start = head[..pos].rfind('\n').map(|i| i + 1).unwrap_or(0);
if !head[line_start..pos].contains("--") {
break pos;
}
search_from = pos + "M.meta".len();
};
let brace_start = head[meta_start..].find('{')? + meta_start;
let mut depth = 0;
let mut brace_end = None;
for (i, ch) in head[brace_start..].char_indices() {
match ch {
'{' => depth += 1,
'}' => {
depth -= 1;
if depth == 0 {
brace_end = Some(brace_start + i);
break;
}
}
_ => {}
}
}
let brace_end = brace_end?;
let block = &head[brace_start + 1..brace_end];
let extract = |field: &str| -> String {
let mut search_from = 0;
while let Some(rel) = block[search_from..].find(field) {
let pos = search_from + rel;
let word_boundary = pos == 0 || {
let prev = block.as_bytes()[pos - 1];
!(prev.is_ascii_alphanumeric() || prev == b'_')
};
if word_boundary {
let after = &block[pos + field.len()..];
let mut collected = String::new();
let mut cursor = 0usize;
let mut found_any = false;
loop {
let rest = &after[cursor..];
let Some(q_start_rel) = rest.find('"') else {
break;
};
if found_any {
let between = &rest[..q_start_rel];
if between.trim() != ".." {
break;
}
}
let lit_start = cursor + q_start_rel + 1;
let Some(q_end_rel) = after[lit_start..].find('"') else {
break;
};
collected.push_str(&after[lit_start..lit_start + q_end_rel]);
cursor = lit_start + q_end_rel + 1;
found_any = true;
}
if found_any {
return collected;
}
}
search_from = pos + field.len();
}
String::new()
};
let name = extract("name");
if name.is_empty() {
return None;
}
let tags = extract_string_array(block, "tags");
Some(ParsedMeta {
name,
version: extract("version"),
description: extract("description"),
category: extract("category"),
tags,
})
}
fn extract_string_array(block: &str, field: &str) -> Vec<String> {
let mut result = Vec::new();
let mut search_from = 0;
while let Some(rel) = block[search_from..].find(field) {
let pos = search_from + rel;
let word_boundary = pos == 0 || {
let prev = block.as_bytes()[pos - 1];
!(prev.is_ascii_alphanumeric() || prev == b'_')
};
if word_boundary {
let after = &block[pos + field.len()..];
if let Some(brace_start) = after.find('{') {
let inner_start = brace_start + 1;
let mut depth = 1;
let mut brace_end = None;
for (i, ch) in after[inner_start..].char_indices() {
match ch {
'{' => depth += 1,
'}' => {
depth -= 1;
if depth == 0 {
brace_end = Some(inner_start + i);
break;
}
}
_ => {}
}
}
if let Some(end) = brace_end {
let inner = &after[inner_start..end];
let mut cursor = 0;
while let Some(q_start) = inner[cursor..].find('"') {
let lit_start = cursor + q_start + 1;
if let Some(q_end) = inner[lit_start..].find('"') {
let s = &inner[lit_start..lit_start + q_end];
if !s.is_empty() {
result.push(s.to_string());
}
cursor = lit_start + q_end + 1;
} else {
break;
}
}
}
}
break;
}
search_from = pos + field.len();
}
result
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
fn write_init_lua(dir: &Path, body: &str) -> std::path::PathBuf {
let path = dir.join("init.lua");
fs::write(&path, body).unwrap();
path
}
#[test]
fn parse_flat_meta() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"
local M = {}
M.meta = {
name = "my_pkg",
version = "1.0.0",
description = "A test package",
category = "reasoning",
}
return M
"#,
);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert_eq!(pkg.name, "my_pkg");
assert_eq!(pkg.version.as_deref(), Some("1.0.0"));
assert_eq!(pkg.description.as_deref(), Some("A test package"));
assert_eq!(pkg.category.as_deref(), Some("reasoning"));
}
#[test]
fn parse_tags_from_nested_table() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"
local M = {}
M.meta = {
name = "nested_pkg",
tags = { "a", "b" },
description = "After nested",
}
return M
"#,
);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert_eq!(pkg.name, "nested_pkg");
assert_eq!(pkg.description.as_deref(), Some("After nested"));
assert_eq!(
pkg.tags.as_deref(),
Some(vec!["a".to_string(), "b".to_string()].as_slice())
);
}
#[test]
fn parse_tags_absent() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"
local M = {}
M.meta = {
name = "no_tags_pkg",
description = "No tags",
}
return M
"#,
);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert_eq!(pkg.name, "no_tags_pkg");
assert!(pkg.tags.is_none());
}
#[test]
fn parse_tags_empty_array() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"
local M = {}
M.meta = {
name = "empty_tags_pkg",
tags = {},
description = "Empty tags",
}
return M
"#,
);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert_eq!(pkg.name, "empty_tags_pkg");
assert!(pkg.tags.is_none());
}
#[test]
fn parse_concat_string_literals() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"
local M = {}
M.meta = {
name = "concat_pkg",
version = "0.1.0",
description = "foo "
.. "bar "
.. "baz",
category = "reasoning",
}
return M
"#,
);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert_eq!(pkg.description.as_deref(), Some("foo bar baz"));
}
#[test]
fn parse_word_boundary_for_description() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"
local M = {}
M.meta = {
name = "wb_pkg",
short_description = "should not match",
description = "correct one",
}
return M
"#,
);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert_eq!(pkg.name, "wb_pkg");
assert_eq!(pkg.description.as_deref(), Some("correct one"));
}
#[test]
fn parse_meta_large_leading_docstring() {
let tmp = tempfile::tempdir().unwrap();
let mut content = String::new();
for i in 0..120 {
content.push_str(&format!("--- line {i}: long doc comment\n"));
}
content.push_str(
r#"
local M = {}
M.meta = {
name = "late_meta_pkg",
version = "0.2.0",
description = "Located past 2KB",
category = "test",
}
return M
"#,
);
assert!(content.len() > 2048, "fixture should exceed 2KB");
let path = write_init_lua(tmp.path(), &content);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert_eq!(pkg.name, "late_meta_pkg");
assert_eq!(pkg.version.as_deref(), Some("0.2.0"));
assert_eq!(pkg.description.as_deref(), Some("Located past 2KB"));
assert_eq!(pkg.category.as_deref(), Some("test"));
}
#[test]
fn parse_returns_none_without_meta_block() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"
--- alc_shapes — type DSL (not a package)
local M = {}
return M
"#,
);
assert!(PkgEntity::parse_from_init_lua(&path).is_none());
}
#[test]
fn parse_returns_none_when_name_empty() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"
local M = {}
M.meta = {
name = "",
version = "1.0.0",
}
return M
"#,
);
assert!(PkgEntity::parse_from_init_lua(&path).is_none());
}
#[test]
fn parse_returns_none_when_file_missing() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join("nonexistent.lua");
assert!(PkgEntity::parse_from_init_lua(&path).is_none());
}
#[test]
fn extracts_docstring_and_meta() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"--- cascade — Multi-level routing with confidence gating
--- Based on: "FrugalGPT" (Chen et al., 2023)
local M = {}
M.meta = {
name = "cascade",
version = "0.1.0",
description = "Multi-level routing",
category = "meta",
}
return M
"#,
);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert_eq!(pkg.name, "cascade");
let doc = pkg.docstring.expect("docstring should be present");
assert!(doc.contains("FrugalGPT"));
assert!(doc.contains("Multi-level"));
assert!(!doc.contains("local M"));
}
#[test]
fn docstring_absent_when_no_leading_comments() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"local M = {}
M.meta = { name = "nodoc" }
return M
"#,
);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert!(pkg.docstring.is_none());
}
#[test]
fn m_dot_meta_inside_comment_is_ignored() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"
-- example: M.meta = { name = "decoy" }
local M = {}
M.meta = {
name = "real",
}
return M
"#,
);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert_eq!(pkg.name, "real");
}
#[test]
fn serde_round_trip_preserves_none_vs_empty() {
let pkg = PkgEntity {
name: "p".into(),
version: None,
description: Some(String::new()),
category: Some("meta".into()),
docstring: None,
tags: None,
pkg_type: None,
type_source: None,
};
let json = serde_json::to_string(&pkg).unwrap();
assert!(json.contains("\"version\":null"), "version null: {json}");
assert!(
json.contains("\"description\":\"\""),
"description empty string: {json}"
);
assert!(
json.contains("\"docstring\":null"),
"docstring null: {json}"
);
let back: PkgEntity = serde_json::from_str(&json).unwrap();
assert_eq!(back, pkg);
}
#[test]
fn serde_deserialize_accepts_missing_optional_fields() {
let json = r#"{"name":"minimal"}"#;
let pkg: PkgEntity = serde_json::from_str(json).unwrap();
assert_eq!(pkg.name, "minimal");
assert!(pkg.version.is_none());
assert!(pkg.description.is_none());
assert!(pkg.category.is_none());
assert!(pkg.docstring.is_none());
}
#[test]
fn parse_from_init_lua_pkg_type_is_none() {
let tmp = tempfile::tempdir().unwrap();
let path = write_init_lua(
tmp.path(),
r#"
local M = {}
M.meta = {
name = "any_pkg",
version = "1.0.0",
}
function M.run(ctx) end
return M
"#,
);
let pkg = PkgEntity::parse_from_init_lua(&path).expect("should parse");
assert_eq!(pkg.name, "any_pkg");
assert!(
pkg.pkg_type.is_none(),
"parse_from_init_lua must not set pkg_type"
);
assert!(
pkg.type_source.is_none(),
"parse_from_init_lua must not set type_source"
);
}
#[test]
fn serde_round_trip_with_pkg_type() {
let pkg = PkgEntity {
name: "lib".into(),
version: Some("0.1.0".into()),
description: None,
category: None,
docstring: None,
tags: None,
pkg_type: Some(PkgType::Library),
type_source: None,
};
let json = serde_json::to_string(&pkg).unwrap();
assert!(
json.contains("\"type\":\"library\""),
"wire key must be 'type': {json}"
);
let back: PkgEntity = serde_json::from_str(&json).unwrap();
assert_eq!(back.pkg_type, Some(PkgType::Library));
assert_eq!(back, pkg);
}
#[test]
fn serde_deserialize_missing_pkg_type() {
let json = r#"{"name":"legacy_pkg","version":"1.0.0"}"#;
let pkg: PkgEntity = serde_json::from_str(json).unwrap();
assert_eq!(pkg.name, "legacy_pkg");
assert!(
pkg.pkg_type.is_none(),
"missing 'type' key must deserialize as None"
);
}
#[test]
fn serde_round_trip_with_type_source() {
let pkg = PkgEntity {
name: "rt_lib".into(),
version: None,
description: None,
category: None,
docstring: None,
tags: None,
pkg_type: Some(PkgType::Library),
type_source: Some(TypeSource::AutoDetectedLibrary),
};
let json = serde_json::to_string(&pkg).unwrap();
assert!(
json.contains("\"type_source\":\"auto_detected_library\""),
"wire string must be 'auto_detected_library': {json}"
);
let back: PkgEntity = serde_json::from_str(&json).unwrap();
assert_eq!(back.type_source, Some(TypeSource::AutoDetectedLibrary));
assert_eq!(back, pkg);
}
#[test]
fn serde_deserialize_missing_type_source_is_none() {
let json = r#"{"name":"legacy_no_source","type":"library"}"#;
let pkg: PkgEntity = serde_json::from_str(json).unwrap();
assert_eq!(pkg.name, "legacy_no_source");
assert_eq!(pkg.pkg_type, Some(PkgType::Library));
assert!(
pkg.type_source.is_none(),
"missing 'type_source' key must deserialize as None (legacy compat)"
);
}
#[test]
fn serde_deserialize_explicit_type_source_degrades_to_none() {
let json = r#"{"name":"legacy_explicit","type_source":"explicit"}"#;
let pkg: PkgEntity = serde_json::from_str(json).expect("must not error on unknown variant");
assert!(
pkg.type_source.is_none(),
"\"explicit\" must degrade to None, got: {:?}",
pkg.type_source
);
}
#[test]
fn serde_deserialize_known_type_source_parses_correctly() {
let json = r#"{"name":"lib_auto","type_source":"auto_detected_library"}"#;
let pkg: PkgEntity = serde_json::from_str(json).expect("must not error");
assert_eq!(pkg.type_source, Some(TypeSource::AutoDetectedLibrary));
}
}