Skip to main content

lade_sdk/
lib.rs

1use std::{
2    collections::HashMap,
3    path::{Path, PathBuf},
4};
5
6use anyhow::{Ok, Result};
7use providers::Providers;
8use rustc_hash::FxHashMap;
9
10mod providers;
11mod resolve;
12
13pub use resolve::{resolve, resolve_one};
14
15type Hydration = FxHashMap<String, String>;
16
17pub async fn hydrate(
18    env: HashMap<String, String>,
19    cwd: PathBuf,
20    extra_env: HashMap<String, String>,
21) -> Result<HashMap<String, String>> {
22    let mut providers = Providers::new();
23    for value_or_uri in env.values() {
24        providers.add(value_or_uri.clone())?;
25    }
26
27    let mut hydration = providers.resolve(&cwd, &extra_env).await?;
28
29    Ok(env
30        .into_iter()
31        .map(|(key, value_or_uri)| {
32            let value = hydration.remove(&value_or_uri).unwrap_or_else(|| {
33                panic!(
34                    "Cannot find {} in {}",
35                    value_or_uri,
36                    hydration
37                        .keys()
38                        .cloned()
39                        .collect::<Vec<String>>()
40                        .join(", ")
41                )
42            });
43            (key, value)
44        })
45        .collect())
46}
47
48pub async fn hydrate_one(
49    value: String,
50    cwd: &Path,
51    extra_env: &HashMap<String, String>,
52) -> Result<String> {
53    let mut providers = Providers::new();
54    providers.add(value.clone())?;
55    let hydration = providers.resolve(cwd, extra_env).await?;
56    Ok(hydration.get(&value).unwrap().to_owned())
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use std::path::PathBuf;
63
64    #[tokio::test]
65    async fn test_hydrate_raw_values_with_empty_extra_env() {
66        let env = HashMap::from([
67            ("KEY1".to_string(), "value1".to_string()),
68            ("KEY2".to_string(), "!value2".to_string()),
69        ]);
70        let result = hydrate(env, PathBuf::from("."), HashMap::new())
71            .await
72            .unwrap();
73        assert_eq!(result.get("KEY1").unwrap(), "value1");
74        assert_eq!(result.get("KEY2").unwrap(), "value2");
75    }
76
77    #[tokio::test]
78    async fn test_hydrate_raw_values_with_extra_env_ignored_by_raw_provider() {
79        let env = HashMap::from([("KEY".to_string(), "rawval".to_string())]);
80        let extra = HashMap::from([("INJECTED".to_string(), "token123".to_string())]);
81        let result = hydrate(env, PathBuf::from("."), extra).await.unwrap();
82        assert_eq!(result.get("KEY").unwrap(), "rawval");
83    }
84
85    #[tokio::test]
86    async fn test_hydrate_one_raw_with_empty_extra_env() {
87        let result = hydrate_one("mytoken".to_string(), &PathBuf::from("."), &HashMap::new())
88            .await
89            .unwrap();
90        assert_eq!(result, "mytoken");
91    }
92
93    #[tokio::test]
94    async fn test_hydrate_one_raw_bang_escape() {
95        let result = hydrate_one("!escaped".to_string(), &PathBuf::from("."), &HashMap::new())
96            .await
97            .unwrap();
98        assert_eq!(result, "escaped");
99    }
100}