1#![allow(dead_code)]
6
7pub mod app_yaml_existing;
8pub mod bin_detect;
9pub mod env_production;
10pub mod secret_keys;
11
12use toml::Value;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct EnvEntry {
20 pub key: String,
21 pub value: String,
22}
23
24pub fn parse_env_entries(content: &str) -> Vec<EnvEntry> {
28 let mut out = Vec::new();
29 for raw in content.lines() {
30 let trimmed = raw.trim_start();
31 if trimmed.is_empty() || trimmed.starts_with('#') {
32 continue;
33 }
34 let Some((key, value)) = raw.split_once('=') else {
35 continue;
36 };
37 let key = key.trim().to_string();
38 if key.is_empty() {
39 continue;
40 }
41 let stripped = strip_inline_comment(value.trim());
42 out.push(EnvEntry {
43 key,
44 value: stripped.to_string(),
45 });
46 }
47 out
48}
49
50fn strip_inline_comment(value: &str) -> &str {
51 let bytes = value.as_bytes();
52 if bytes.first() == Some(&b'"') || bytes.first() == Some(&b'\'') {
53 return value;
54 }
55 let mut prev_ws = false;
56 for (i, b) in bytes.iter().enumerate() {
57 if *b == b'#' && prev_ws {
58 return value[..i].trim_end();
59 }
60 prev_ws = *b == b' ' || *b == b'\t';
61 }
62 value
63}
64
65const DEP_TABLES: &[&str] = &["dependencies", "dev-dependencies", "build-dependencies"];
70
71pub fn find_ferro_path_deps(content: &str) -> Vec<String> {
74 let parsed: Value = match content.parse() {
75 Ok(v) => v,
76 Err(_) => return Vec::new(),
77 };
78 let mut out: Vec<String> = Vec::new();
79 for table_name in DEP_TABLES {
80 let Some(table) = parsed.get(*table_name).and_then(|v| v.as_table()) else {
81 continue;
82 };
83 for (key, value) in table {
84 if !key.starts_with("ferro") {
85 continue;
86 }
87 let is_path_dep = value
88 .as_table()
89 .map(|t| t.contains_key("path"))
90 .unwrap_or(false);
91 if is_path_dep && !out.iter().any(|k| k == key) {
92 out.push(key.clone());
93 }
94 }
95 }
96 out
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn parse_env_entries_basic() {
105 let got = parse_env_entries("# c\nFOO=bar\n\nBAZ=qux # tail");
106 assert_eq!(got.len(), 2);
107 assert_eq!(got[0].key, "FOO");
108 assert_eq!(got[0].value, "bar");
109 assert_eq!(got[1].value, "qux");
110 }
111
112 #[test]
113 fn finds_ferro_path_deps() {
114 let deps = find_ferro_path_deps("[dependencies]\nferro = { path = \"..\" }\n");
115 assert_eq!(deps, vec!["ferro".to_string()]);
116 }
117}