@devaloop/devalang 0.0.1-alpha.14 → 0.0.1-alpha.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/.devalang +10 -8
  2. package/.github/workflows/ci.yml +92 -0
  3. package/Cargo.toml +60 -58
  4. package/README.md +32 -15
  5. package/docs/CHANGELOG.md +93 -1
  6. package/docs/CONTRIBUTING.md +101 -1
  7. package/docs/ROADMAP.md +2 -2
  8. package/docs/TODO.md +1 -1
  9. package/examples/automation.deva +42 -0
  10. package/examples/bank.deva +4 -4
  11. package/examples/events.deva +12 -0
  12. package/examples/function.deva +4 -4
  13. package/examples/index.deva +39 -25
  14. package/examples/loop.deva +5 -11
  15. package/examples/pattern.deva +8 -0
  16. package/examples/plugin.deva +16 -0
  17. package/examples/variables.deva +1 -1
  18. package/out-tsc/bin/index.js +51 -7
  19. package/out-tsc/index.js +3 -1
  20. package/out-tsc/scripts/postbuild.js +9 -10
  21. package/out-tsc/scripts/postinstall.js +49 -0
  22. package/package.json +12 -4
  23. package/project-version.json +3 -3
  24. package/rust/cli/bank.rs +462 -456
  25. package/rust/cli/build.rs +252 -199
  26. package/rust/cli/check.rs +221 -180
  27. package/rust/cli/driver.rs +297 -292
  28. package/rust/cli/generator.rs +1 -0
  29. package/rust/cli/init.rs +87 -79
  30. package/rust/cli/install.rs +35 -32
  31. package/rust/cli/login.rs +127 -134
  32. package/rust/cli/mod.rs +13 -11
  33. package/rust/cli/play.rs +1123 -218
  34. package/rust/cli/telemetry.rs +19 -0
  35. package/rust/cli/template.rs +69 -57
  36. package/rust/cli/update.rs +6 -4
  37. package/rust/common/api.rs +5 -8
  38. package/rust/common/cdn.rs +3 -6
  39. package/rust/common/mod.rs +3 -3
  40. package/rust/common/sso.rs +3 -6
  41. package/rust/config/driver.rs +118 -94
  42. package/rust/config/loader.rs +165 -156
  43. package/rust/config/mod.rs +4 -2
  44. package/rust/config/settings.rs +91 -0
  45. package/rust/config/stats.rs +257 -0
  46. package/rust/core/audio/engine.rs +696 -518
  47. package/rust/core/audio/evaluator.rs +263 -31
  48. package/rust/core/audio/interpreter/arrow_call.rs +198 -161
  49. package/rust/core/audio/interpreter/automate.rs +18 -0
  50. package/rust/core/audio/interpreter/call.rs +98 -95
  51. package/rust/core/audio/interpreter/condition.rs +70 -71
  52. package/rust/core/audio/interpreter/driver.rs +487 -198
  53. package/rust/core/audio/interpreter/function.rs +26 -21
  54. package/rust/core/audio/interpreter/let_.rs +38 -19
  55. package/rust/core/audio/interpreter/load.rs +18 -18
  56. package/rust/core/audio/interpreter/loop_.rs +113 -73
  57. package/rust/core/audio/interpreter/mod.rs +14 -13
  58. package/rust/core/audio/interpreter/sleep.rs +27 -30
  59. package/rust/core/audio/interpreter/spawn.rs +105 -102
  60. package/rust/core/audio/interpreter/tempo.rs +19 -16
  61. package/rust/core/audio/interpreter/trigger.rs +239 -210
  62. package/rust/core/audio/loader/mod.rs +1 -1
  63. package/rust/core/audio/loader/trigger.rs +100 -97
  64. package/rust/core/audio/mod.rs +7 -6
  65. package/rust/core/audio/player.rs +64 -64
  66. package/rust/core/audio/renderer.rs +56 -53
  67. package/rust/core/audio/special/easing.rs +189 -0
  68. package/rust/core/audio/special/env.rs +43 -0
  69. package/rust/core/audio/special/math.rs +102 -0
  70. package/rust/core/audio/special/mod.rs +9 -0
  71. package/rust/core/audio/special/modulator.rs +143 -0
  72. package/rust/core/builder/mod.rs +80 -85
  73. package/rust/core/debugger/lexer.rs +27 -27
  74. package/rust/core/debugger/mod.rs +24 -23
  75. package/rust/core/debugger/module.rs +55 -47
  76. package/rust/core/debugger/preprocessor.rs +27 -27
  77. package/rust/core/debugger/store.rs +40 -39
  78. package/rust/core/error/mod.rs +80 -66
  79. package/rust/core/lexer/handler/arrow.rs +82 -31
  80. package/rust/core/lexer/handler/at.rs +21 -21
  81. package/rust/core/lexer/handler/brace.rs +41 -41
  82. package/rust/core/lexer/handler/colon.rs +21 -21
  83. package/rust/core/lexer/handler/comment.rs +30 -30
  84. package/rust/core/lexer/handler/dot.rs +21 -21
  85. package/rust/core/lexer/handler/driver.rs +337 -263
  86. package/rust/core/lexer/handler/identifier.rs +46 -42
  87. package/rust/core/lexer/handler/indent.rs +66 -66
  88. package/rust/core/lexer/handler/mod.rs +16 -16
  89. package/rust/core/lexer/handler/newline.rs +23 -23
  90. package/rust/core/lexer/handler/number.rs +31 -31
  91. package/rust/core/lexer/handler/operator.rs +46 -44
  92. package/rust/core/lexer/handler/parenthesis.rs +41 -41
  93. package/rust/core/lexer/handler/slash.rs +21 -21
  94. package/rust/core/lexer/handler/string.rs +63 -63
  95. package/rust/core/lexer/mod.rs +54 -51
  96. package/rust/core/lexer/token.rs +97 -91
  97. package/rust/core/mod.rs +11 -11
  98. package/rust/core/parser/driver.rs +513 -408
  99. package/rust/core/parser/handler/arrow_call.rs +233 -211
  100. package/rust/core/parser/handler/at.rs +245 -162
  101. package/rust/core/parser/handler/bank.rs +94 -69
  102. package/rust/core/parser/handler/condition.rs +80 -74
  103. package/rust/core/parser/handler/dot.rs +143 -135
  104. package/rust/core/parser/handler/identifier/automate.rs +257 -0
  105. package/rust/core/parser/handler/identifier/call.rs +91 -88
  106. package/rust/core/parser/handler/identifier/emit.rs +66 -0
  107. package/rust/core/parser/handler/identifier/function.rs +100 -92
  108. package/rust/core/parser/handler/identifier/group.rs +85 -75
  109. package/rust/core/parser/handler/identifier/let_.rs +158 -127
  110. package/rust/core/parser/handler/identifier/mod.rs +54 -52
  111. package/rust/core/parser/handler/identifier/on.rs +98 -0
  112. package/rust/core/parser/handler/identifier/print.rs +52 -0
  113. package/rust/core/parser/handler/identifier/sleep.rs +36 -33
  114. package/rust/core/parser/handler/identifier/spawn.rs +91 -88
  115. package/rust/core/parser/handler/identifier/synth.rs +65 -65
  116. package/rust/core/parser/handler/loop_.rs +170 -72
  117. package/rust/core/parser/handler/mod.rs +8 -8
  118. package/rust/core/parser/handler/tempo.rs +53 -47
  119. package/rust/core/parser/mod.rs +4 -4
  120. package/rust/core/parser/statement.rs +142 -108
  121. package/rust/core/plugin/loader.rs +123 -48
  122. package/rust/core/plugin/mod.rs +2 -1
  123. package/rust/core/plugin/runner.rs +296 -0
  124. package/rust/core/preprocessor/loader.rs +515 -326
  125. package/rust/core/preprocessor/mod.rs +4 -4
  126. package/rust/core/preprocessor/module.rs +60 -58
  127. package/rust/core/preprocessor/processor.rs +99 -101
  128. package/rust/core/preprocessor/resolver/bank.rs +51 -49
  129. package/rust/core/preprocessor/resolver/call.rs +100 -100
  130. package/rust/core/preprocessor/resolver/condition.rs +97 -97
  131. package/rust/core/preprocessor/resolver/driver.rs +310 -278
  132. package/rust/core/preprocessor/resolver/function.rs +69 -78
  133. package/rust/core/preprocessor/resolver/group.rs +96 -91
  134. package/rust/core/preprocessor/resolver/let_.rs +32 -28
  135. package/rust/core/preprocessor/resolver/loop_.rs +320 -91
  136. package/rust/core/preprocessor/resolver/mod.rs +15 -15
  137. package/rust/core/preprocessor/resolver/spawn.rs +76 -92
  138. package/rust/core/preprocessor/resolver/synth.rs +56 -50
  139. package/rust/core/preprocessor/resolver/tempo.rs +50 -49
  140. package/rust/core/preprocessor/resolver/trigger.rs +113 -116
  141. package/rust/core/preprocessor/resolver/value.rs +81 -87
  142. package/rust/core/shared/bank.rs +1 -1
  143. package/rust/core/shared/duration.rs +9 -9
  144. package/rust/core/shared/mod.rs +3 -3
  145. package/rust/core/shared/value.rs +35 -32
  146. package/rust/core/store/function.rs +34 -34
  147. package/rust/core/store/global.rs +55 -38
  148. package/rust/core/store/mod.rs +5 -5
  149. package/rust/core/store/variable.rs +37 -34
  150. package/rust/core/utils/mod.rs +2 -2
  151. package/rust/core/utils/path.rs +37 -31
  152. package/rust/core/utils/validation.rs +35 -37
  153. package/rust/installer/addon.rs +84 -80
  154. package/rust/installer/bank.rs +62 -65
  155. package/rust/installer/mod.rs +5 -5
  156. package/rust/installer/plugin.rs +54 -55
  157. package/rust/installer/utils.rs +56 -56
  158. package/rust/lib.rs +156 -164
  159. package/rust/main.rs +250 -145
  160. package/rust/utils/error.rs +200 -0
  161. package/rust/utils/file.rs +38 -35
  162. package/rust/utils/first_usage.rs +76 -0
  163. package/rust/utils/logger.rs +195 -139
  164. package/rust/utils/mod.rs +9 -50
  165. package/rust/utils/signature.rs +19 -17
  166. package/rust/utils/spinner.rs +22 -19
  167. package/rust/utils/telemetry.rs +292 -0
  168. package/rust/utils/watcher.rs +34 -33
  169. package/templates/minimal/README.md +97 -121
  170. package/templates/welcome/README.md +97 -121
  171. package/typescript/bin/index.ts +19 -5
  172. package/typescript/index.ts +3 -1
  173. package/typescript/scripts/postbuild.ts +10 -6
  174. package/typescript/scripts/postinstall.ts +56 -0
  175. package/typescript/scripts/version/bump.ts +0 -1
  176. package/typescript/scripts/version/index.ts +0 -1
  177. package/out-tsc/bin/devalang.exe +0 -0
@@ -0,0 +1,19 @@
1
+ use crate::config::settings::set_user_config_bool;
2
+
3
+ #[cfg(feature = "cli")]
4
+ pub async fn handle_telemetry_enable_command() -> Result<(), String> {
5
+ set_user_config_bool("telemetry", true);
6
+
7
+ println!("Telemetry has been enabled.");
8
+
9
+ Ok(())
10
+ }
11
+
12
+ #[cfg(feature = "cli")]
13
+ pub async fn handle_telemetry_disable_command() -> Result<(), String> {
14
+ set_user_config_bool("telemetry", false);
15
+
16
+ println!("Telemetry has been disabled.");
17
+
18
+ Ok(())
19
+ }
@@ -1,57 +1,69 @@
1
- use include_dir::{ include_dir, Dir, DirEntry };
2
- use crate::utils::file::format_file_size;
3
-
4
- static TEMPLATES_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/templates");
5
-
6
- #[cfg(feature = "cli")]
7
- pub fn handle_template_list_command() {
8
- let available_templates = get_available_templates();
9
-
10
- println!("📦 Available templates ({}) :\n", available_templates.len());
11
-
12
- for dir in available_templates {
13
- println!("• {}", dir);
14
- }
15
-
16
- println!("\nUsage : devalang init --name <project-name> --template <template-name>");
17
- }
18
-
19
- #[cfg(feature = "cli")]
20
- pub fn handle_template_info_command(name: String) {
21
- let template_dir = TEMPLATES_DIR.get_dir(name.clone()).unwrap_or_else(|| {
22
- println!("❌ The template '{}' is not found.", name);
23
-
24
- std::process::exit(1);
25
- });
26
-
27
- let mut file_count = 0;
28
- let mut dir_count = 0;
29
- let mut total_size: u64 = 0;
30
-
31
- fn walk(dir: &Dir, file_count: &mut u32, dir_count: &mut u32, total_size: &mut u64) {
32
- for entry in dir.entries() {
33
- match entry {
34
- DirEntry::File(file) => {
35
- *file_count += 1;
36
- *total_size += file.contents().len() as u64;
37
- }
38
- DirEntry::Dir(subdir) => {
39
- *dir_count += 1;
40
- walk(subdir, file_count, dir_count, total_size);
41
- }
42
- }
43
- }
44
- }
45
-
46
- walk(template_dir, &mut file_count, &mut dir_count, &mut total_size);
47
-
48
- println!("📦 Template : {}", name);
49
- println!("📂 Content : {file_count} file(s), {dir_count} folder(s)");
50
- println!("💾 Size : {}", format_file_size(total_size));
51
- }
52
-
53
- pub fn get_available_templates() -> Vec<String> {
54
- TEMPLATES_DIR.dirs()
55
- .map(|dir| dir.path().file_name().unwrap().to_string_lossy().to_string())
56
- .collect()
57
- }
1
+ use crate::utils::file::format_file_size;
2
+ use include_dir::{Dir, DirEntry, include_dir};
3
+
4
+ static TEMPLATES_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/templates");
5
+
6
+ #[cfg(feature = "cli")]
7
+ pub fn handle_template_list_command() {
8
+ let available_templates = get_available_templates();
9
+
10
+ println!("📦 Available templates ({}) :\n", available_templates.len());
11
+
12
+ for dir in available_templates {
13
+ println!("• {}", dir);
14
+ }
15
+
16
+ println!("\nUsage : devalang init --name <project-name> --template <template-name>");
17
+ }
18
+
19
+ #[cfg(feature = "cli")]
20
+ pub fn handle_template_info_command(name: String) {
21
+ let template_dir = TEMPLATES_DIR.get_dir(name.clone()).unwrap_or_else(|| {
22
+ println!("❌ The template '{}' is not found.", name);
23
+
24
+ std::process::exit(1);
25
+ });
26
+
27
+ let mut file_count = 0;
28
+ let mut dir_count = 0;
29
+ let mut total_size: u64 = 0;
30
+
31
+ fn walk(dir: &Dir, file_count: &mut u32, dir_count: &mut u32, total_size: &mut u64) {
32
+ for entry in dir.entries() {
33
+ match entry {
34
+ DirEntry::File(file) => {
35
+ *file_count += 1;
36
+ *total_size += file.contents().len() as u64;
37
+ }
38
+ DirEntry::Dir(subdir) => {
39
+ *dir_count += 1;
40
+ walk(subdir, file_count, dir_count, total_size);
41
+ }
42
+ }
43
+ }
44
+ }
45
+
46
+ walk(
47
+ template_dir,
48
+ &mut file_count,
49
+ &mut dir_count,
50
+ &mut total_size,
51
+ );
52
+
53
+ println!("📦 Template : {}", name);
54
+ println!("📂 Content : {file_count} file(s), {dir_count} folder(s)");
55
+ println!("💾 Size : {}", format_file_size(total_size));
56
+ }
57
+
58
+ pub fn get_available_templates() -> Vec<String> {
59
+ TEMPLATES_DIR
60
+ .dirs()
61
+ .map(|dir| {
62
+ dir.path()
63
+ .file_name()
64
+ .unwrap()
65
+ .to_string_lossy()
66
+ .to_string()
67
+ })
68
+ .collect()
69
+ }
@@ -1,4 +1,6 @@
1
- pub async fn handle_update_command(only: Option<String>) -> Result<(), Box<dyn std::error::Error>> {
2
- println!("Updates are not yet implemented. This is a placeholder function.");
3
- Ok(())
4
- }
1
+ pub async fn handle_update_command(
2
+ _only: Option<String>,
3
+ ) -> Result<(), Box<dyn std::error::Error>> {
4
+ println!("Updates are not yet implemented. This is a placeholder function.");
5
+ Ok(())
6
+ }
@@ -1,8 +1,5 @@
1
- pub fn get_api_url() -> String {
2
- let api_url = std::env
3
- ::var("API_URL")
4
- .unwrap_or_else(|_| "https://api.devalang.com".to_string());
5
- // .unwrap_or_else(|_| "http://127.0.0.1:8989".to_string());
6
-
7
- api_url
8
- }
1
+ pub fn get_api_url() -> String {
2
+ let api_url = "https://api.devalang.com";
3
+ // let api_url = "http://127.0.0.1:8989";
4
+ api_url.to_string()
5
+ }
@@ -1,8 +1,5 @@
1
1
  pub fn get_cdn_url() -> String {
2
- let cdn_url = std::env
3
- ::var("CDN_URL")
4
- .unwrap_or_else(|_| "https://cdn.devalang.com".to_string());
5
- // .unwrap_or_else(|_| "http://127.0.0.1:8888".to_string());
6
-
7
- cdn_url
2
+ let cdn_url = "https://cdn.devalang.com";
3
+ // let cdn_url = "http://127.0.0.1:8888";
4
+ cdn_url.to_string()
8
5
  }
@@ -1,3 +1,3 @@
1
- pub mod cdn;
2
- pub mod api;
3
- pub mod sso;
1
+ pub mod api;
2
+ pub mod cdn;
3
+ pub mod sso;
@@ -1,8 +1,5 @@
1
1
  pub fn get_sso_url() -> String {
2
- let sso_url = std::env
3
- ::var("SSO_URL")
4
- .unwrap_or_else(|_| "https://sso.devalang.com".to_string());
5
- // .unwrap_or_else(|_| "http://localhost:5174".to_string());
6
-
7
- sso_url
2
+ let sso_url = "https://sso.devalang.com";
3
+ // let sso_url = "http://localhost:5174";
4
+ sso_url.to_string()
8
5
  }
@@ -1,94 +1,118 @@
1
- use std::collections::HashMap;
2
-
3
- use serde::{ Deserialize, Serialize };
4
-
5
- #[derive(Debug, Deserialize, Clone, Serialize)]
6
- pub struct Config {
7
- pub defaults: ConfigDefaults,
8
- pub banks: Option<Vec<BankEntry>>,
9
- pub plugins: Option<Vec<PluginEntry>>,
10
- }
11
-
12
- #[derive(Debug, Deserialize, Clone, Serialize)]
13
- pub struct ConfigDefaults {
14
- pub entry: Option<String>,
15
- pub output: Option<String>,
16
- pub watch: Option<bool>,
17
- pub repeat: Option<bool>,
18
- }
19
-
20
- #[derive(Debug, Deserialize, Clone, Serialize)]
21
- pub struct BankMetadata {
22
- pub bank: HashMap<String, String>,
23
- pub triggers: Option<Vec<HashMap<String, String>>>,
24
- }
25
-
26
- #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
27
- pub struct BankEntry {
28
- pub path: String,
29
- pub version: Option<String>,
30
- }
31
-
32
- #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
33
- pub struct PluginEntry {
34
- pub path: String,
35
- pub version: String,
36
- pub author: String,
37
- pub access: String,
38
- }
39
-
40
- impl Config {
41
- pub fn new() -> Self {
42
- Config {
43
- defaults: ConfigDefaults {
44
- entry: None,
45
- output: None,
46
- watch: None,
47
- repeat: None,
48
- },
49
- banks: Some(Vec::new()),
50
- plugins: Some(Vec::new()),
51
- }
52
- }
53
-
54
- pub fn with_defaults(
55
- entry: Option<String>,
56
- output: Option<String>,
57
- watch: Option<bool>,
58
- repeat: Option<bool>
59
- ) -> Self {
60
- Config {
61
- defaults: ConfigDefaults {
62
- entry,
63
- output,
64
- watch,
65
- repeat,
66
- },
67
- banks: Some(Vec::new()),
68
- plugins: Some(Vec::new()),
69
- }
70
- }
71
-
72
- pub fn from_string(config_string: &str) -> Result<(Self, String), String> {
73
- let config: Config = toml
74
- ::from_str(config_string)
75
- .map_err(|e| format!("Failed to parse config string: {}", e))?;
76
- let config_path = ".devalang".to_string();
77
-
78
- Ok((config, config_path))
79
- }
80
-
81
- pub fn write(&self, new_config: &Config) -> Result<(), String> {
82
- let config_path = ".devalang";
83
-
84
- let content = toml
85
- ::to_string(new_config)
86
- .map_err(|e| format!("Failed to serialize config: {}", e))?;
87
-
88
- std::fs
89
- ::write(config_path, content)
90
- .map_err(|e| format!("Failed to write config to file '{}': {}", config_path, e))?;
91
-
92
- Ok(())
93
- }
94
- }
1
+ use serde::{Deserialize, Serialize};
2
+ use std::collections::HashMap;
3
+
4
+ #[derive(Debug, Deserialize, Clone, Serialize)]
5
+ pub struct ProjectConfig {
6
+ pub defaults: ProjectConfigDefaults,
7
+ pub banks: Option<Vec<ProjectConfigBankEntry>>,
8
+ pub plugins: Option<Vec<PluginEntry>>,
9
+ }
10
+
11
+ #[derive(Debug, Deserialize, Clone, Serialize)]
12
+ pub struct ProjectConfigDefaults {
13
+ pub entry: Option<String>,
14
+ pub output: Option<String>,
15
+ pub watch: Option<bool>,
16
+ pub repeat: Option<bool>,
17
+ pub debug: Option<bool>,
18
+ pub compress: Option<bool>,
19
+ }
20
+
21
+ #[derive(Debug, Deserialize, Clone, Serialize)]
22
+ pub struct ProjectConfigBankMetadata {
23
+ pub bank: HashMap<String, String>,
24
+ pub triggers: Option<Vec<HashMap<String, String>>>,
25
+ }
26
+
27
+ #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
28
+ pub struct ProjectConfigBankEntry {
29
+ pub path: String,
30
+ pub version: Option<String>,
31
+ }
32
+
33
+ #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
34
+ pub struct PluginEntry {
35
+ pub path: String,
36
+ pub version: String,
37
+ pub author: String,
38
+ pub access: String,
39
+ }
40
+
41
+ impl ProjectConfig {
42
+ pub fn new() -> Self {
43
+ ProjectConfig {
44
+ defaults: ProjectConfigDefaults {
45
+ entry: None,
46
+ output: None,
47
+ watch: None,
48
+ repeat: None,
49
+ debug: None,
50
+ compress: None,
51
+ },
52
+ banks: Some(Vec::new()),
53
+ plugins: Some(Vec::new()),
54
+ }
55
+ }
56
+
57
+ pub fn with_defaults(
58
+ entry: Option<String>,
59
+ output: Option<String>,
60
+ watch: Option<bool>,
61
+ repeat: Option<bool>,
62
+ debug: Option<bool>,
63
+ compress: Option<bool>,
64
+ ) -> Self {
65
+ ProjectConfig {
66
+ defaults: ProjectConfigDefaults {
67
+ entry,
68
+ output,
69
+ watch,
70
+ repeat,
71
+ debug,
72
+ compress,
73
+ },
74
+ banks: Some(Vec::new()),
75
+ plugins: Some(Vec::new()),
76
+ }
77
+ }
78
+
79
+ pub fn get() -> Result<ProjectConfig, String> {
80
+ let root = std::env::current_dir().unwrap();
81
+ let config_path = root.join(".devalang");
82
+
83
+ if config_path.try_exists().is_err() {
84
+ return Err(format!(
85
+ "Config file not found at path: {}",
86
+ config_path.display()
87
+ ));
88
+ }
89
+
90
+ let config_content = std::fs::read_to_string(&config_path)
91
+ .map_err(|e| format!("Failed to read config file: {}", e))?;
92
+
93
+ let config: ProjectConfig = toml::from_str(&config_content)
94
+ .map_err(|e| format!("Failed to parse config file: {}", e))?;
95
+
96
+ Ok(config)
97
+ }
98
+
99
+ pub fn from_string(config_string: &str) -> Result<(Self, String), String> {
100
+ let config: ProjectConfig = toml::from_str(config_string)
101
+ .map_err(|e| format!("Failed to parse config string: {}", e))?;
102
+ let config_path = ".devalang".to_string();
103
+
104
+ Ok((config, config_path))
105
+ }
106
+
107
+ pub fn write(&self, new_config: &ProjectConfig) -> Result<(), String> {
108
+ let config_path = ".devalang";
109
+
110
+ let content = toml::to_string(new_config)
111
+ .map_err(|e| format!("Failed to serialize config: {}", e))?;
112
+
113
+ std::fs::write(config_path, content)
114
+ .map_err(|e| format!("Failed to write config to file '{}': {}", config_path, e))?;
115
+
116
+ Ok(())
117
+ }
118
+ }