@devaloop/devalang 0.0.1-alpha.16-hotfix.1 → 0.0.1-alpha.17

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 (235) hide show
  1. package/.cargo/config.toml +2 -0
  2. package/.devalang +6 -10
  3. package/.github/workflows/ci.yml +19 -8
  4. package/Cargo.toml +18 -2
  5. package/README.md +80 -33
  6. package/docs/CHANGELOG.md +56 -0
  7. package/docs/ROADMAP.md +6 -3
  8. package/examples/index.deva +52 -35
  9. package/out-tsc/bin/index.d.ts +2 -0
  10. package/out-tsc/core/functions/index.d.ts +37 -0
  11. package/out-tsc/core/functions/index.js +76 -0
  12. package/out-tsc/core/index.d.ts +6 -0
  13. package/out-tsc/core/index.js +22 -0
  14. package/out-tsc/core/types/index.d.ts +4 -0
  15. package/out-tsc/core/types/index.js +20 -0
  16. package/out-tsc/core/types/plugin.d.ts +18 -0
  17. package/out-tsc/core/types/plugin.js +2 -0
  18. package/out-tsc/core/types/result.d.ts +27 -0
  19. package/out-tsc/core/types/result.js +2 -0
  20. package/out-tsc/core/types/statement.d.ts +106 -0
  21. package/out-tsc/core/types/statement.js +2 -0
  22. package/out-tsc/core/types/value.d.ts +43 -0
  23. package/out-tsc/core/types/value.js +2 -0
  24. package/out-tsc/index.d.ts +7 -0
  25. package/out-tsc/index.js +41 -2
  26. package/out-tsc/pkg/devalang_core.d.ts +7 -0
  27. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +33 -0
  28. package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
  29. package/out-tsc/scripts/copy-wasm-dts.js +73 -0
  30. package/out-tsc/scripts/postinstall.d.ts +1 -0
  31. package/out-tsc/scripts/postinstall.js +33 -23
  32. package/out-tsc/scripts/version/bump.d.ts +1 -0
  33. package/out-tsc/scripts/version/fetch.d.ts +1 -0
  34. package/out-tsc/scripts/version/index.d.ts +1 -0
  35. package/out-tsc/scripts/version/sync.d.ts +1 -0
  36. package/package.json +16 -4
  37. package/project-version.json +3 -3
  38. package/rust/cli/bank/api.rs +122 -0
  39. package/rust/cli/bank/commands.rs +275 -0
  40. package/rust/cli/bank/mod.rs +29 -0
  41. package/rust/cli/build/commands.rs +97 -0
  42. package/rust/cli/build/mod.rs +2 -0
  43. package/rust/cli/build/process.rs +146 -0
  44. package/rust/cli/{check.rs → check/mod.rs} +18 -31
  45. package/rust/cli/discover/commands.rs +253 -0
  46. package/rust/cli/discover/config.rs +111 -0
  47. package/rust/cli/discover/fs.rs +19 -0
  48. package/rust/cli/discover/install.rs +103 -0
  49. package/rust/cli/discover/metadata.rs +48 -0
  50. package/rust/cli/discover/mod.rs +5 -0
  51. package/rust/cli/{init.rs → init/commands.rs} +88 -87
  52. package/rust/cli/init/mod.rs +1 -0
  53. package/rust/{installer → cli/install}/addon.rs +5 -9
  54. package/rust/cli/install/bank.rs +53 -0
  55. package/rust/cli/{install.rs → install/commands.rs} +9 -9
  56. package/rust/{installer → cli/install}/mod.rs +2 -3
  57. package/rust/cli/install/plugin.rs +61 -0
  58. package/rust/cli/{login.rs → login/commands.rs} +8 -11
  59. package/rust/cli/login/mod.rs +1 -0
  60. package/rust/cli/mod.rs +2 -3
  61. package/rust/cli/{driver.rs → parser.rs} +19 -2
  62. package/rust/cli/play/commands.rs +324 -0
  63. package/rust/cli/play/io.rs +17 -0
  64. package/rust/cli/play/mod.rs +5 -0
  65. package/rust/cli/play/process.rs +150 -0
  66. package/rust/cli/play/realtime.rs +91 -0
  67. package/rust/cli/play/utils.rs +23 -0
  68. package/rust/cli/telemetry/commands.rs +22 -0
  69. package/rust/cli/telemetry/event_creator.rs +80 -0
  70. package/rust/cli/telemetry/mod.rs +3 -0
  71. package/rust/cli/telemetry/send.rs +51 -0
  72. package/rust/cli/{template.rs → template/commands.rs} +1 -1
  73. package/rust/cli/template/mod.rs +1 -0
  74. package/rust/cli/{update.rs → update/commands.rs} +6 -6
  75. package/rust/cli/update/mod.rs +1 -0
  76. package/rust/config/driver.rs +57 -72
  77. package/rust/config/mod.rs +1 -2
  78. package/rust/config/ops.rs +26 -0
  79. package/rust/config/settings.rs +60 -50
  80. package/rust/core/audio/engine/helpers.rs +146 -0
  81. package/rust/core/audio/engine/mod.rs +7 -0
  82. package/rust/core/audio/engine/sample.rs +298 -0
  83. package/rust/core/audio/engine/synth.rs +310 -0
  84. package/rust/core/audio/evaluator.rs +15 -12
  85. package/rust/core/audio/interpreter/arrow_call.rs +99 -24
  86. package/rust/core/audio/interpreter/call.rs +81 -60
  87. package/rust/core/audio/interpreter/condition.rs +3 -2
  88. package/rust/core/audio/interpreter/driver.rs +206 -151
  89. package/rust/core/audio/interpreter/let_.rs +1 -1
  90. package/rust/core/audio/interpreter/load.rs +2 -1
  91. package/rust/core/audio/interpreter/loop_.rs +7 -6
  92. package/rust/core/audio/interpreter/sleep.rs +2 -1
  93. package/rust/core/audio/interpreter/spawn.rs +45 -57
  94. package/rust/core/audio/interpreter/tempo.rs +31 -10
  95. package/rust/core/audio/interpreter/trigger.rs +2 -2
  96. package/rust/core/audio/loader/trigger.rs +4 -7
  97. package/rust/core/audio/player.rs +6 -0
  98. package/rust/core/audio/renderer.rs +5 -7
  99. package/rust/core/audio/special/env.rs +3 -1
  100. package/rust/core/audio/special/math.rs +4 -4
  101. package/rust/core/audio/special/modulator.rs +2 -2
  102. package/rust/core/builder/mod.rs +9 -3
  103. package/rust/core/debugger/lexer.rs +1 -1
  104. package/rust/core/debugger/mod.rs +6 -0
  105. package/rust/core/debugger/module.rs +4 -4
  106. package/rust/core/debugger/preprocessor.rs +1 -1
  107. package/rust/core/debugger/store.rs +2 -2
  108. package/rust/core/error/mod.rs +189 -0
  109. package/rust/core/lexer/handler/arrow.rs +1 -1
  110. package/rust/core/lexer/handler/at.rs +1 -1
  111. package/rust/core/lexer/handler/brace.rs +2 -2
  112. package/rust/core/lexer/handler/colon.rs +1 -1
  113. package/rust/core/lexer/handler/comment.rs +1 -1
  114. package/rust/core/lexer/handler/dot.rs +1 -1
  115. package/rust/core/lexer/handler/driver.rs +1 -1
  116. package/rust/core/lexer/handler/identifier.rs +1 -1
  117. package/rust/core/lexer/handler/mod.rs +1 -2
  118. package/rust/core/lexer/handler/number.rs +1 -1
  119. package/rust/core/lexer/handler/operator.rs +1 -1
  120. package/rust/core/lexer/handler/parenthesis.rs +2 -2
  121. package/rust/core/lexer/handler/slash.rs +1 -1
  122. package/rust/core/lexer/handler/string.rs +1 -1
  123. package/rust/core/lexer/mod.rs +22 -12
  124. package/rust/core/lexer/token.rs +90 -97
  125. package/rust/core/mod.rs +0 -1
  126. package/rust/core/parser/driver.rs +66 -13
  127. package/rust/core/parser/handler/arrow_call.rs +28 -8
  128. package/rust/core/parser/handler/at.rs +55 -21
  129. package/rust/core/parser/handler/bank.rs +14 -4
  130. package/rust/core/parser/handler/condition.rs +6 -3
  131. package/rust/core/parser/handler/dot.rs +2 -1
  132. package/rust/core/parser/handler/identifier/automate.rs +13 -16
  133. package/rust/core/parser/handler/identifier/call.rs +4 -4
  134. package/rust/core/parser/handler/identifier/emit.rs +9 -5
  135. package/rust/core/parser/handler/identifier/function.rs +20 -7
  136. package/rust/core/parser/handler/identifier/group.rs +11 -7
  137. package/rust/core/parser/handler/identifier/let_.rs +24 -9
  138. package/rust/core/parser/handler/identifier/mod.rs +6 -5
  139. package/rust/core/parser/handler/identifier/on.rs +16 -7
  140. package/rust/core/parser/handler/identifier/print.rs +6 -9
  141. package/rust/core/parser/handler/identifier/sleep.rs +12 -5
  142. package/rust/core/parser/handler/identifier/spawn.rs +4 -4
  143. package/rust/core/parser/handler/identifier/synth.rs +79 -9
  144. package/rust/core/parser/handler/loop_.rs +39 -14
  145. package/rust/core/parser/handler/tempo.rs +9 -5
  146. package/rust/core/parser/mod.rs +0 -1
  147. package/rust/core/parser/statement.rs +6 -137
  148. package/rust/core/plugin/loader.rs +41 -27
  149. package/rust/core/plugin/runner.rs +68 -17
  150. package/rust/core/preprocessor/loader.rs +155 -33
  151. package/rust/core/preprocessor/processor.rs +2 -2
  152. package/rust/core/preprocessor/resolver/bank.rs +6 -8
  153. package/rust/core/preprocessor/resolver/call.rs +20 -24
  154. package/rust/core/preprocessor/resolver/condition.rs +6 -8
  155. package/rust/core/preprocessor/resolver/driver.rs +14 -16
  156. package/rust/core/preprocessor/resolver/function.rs +6 -6
  157. package/rust/core/preprocessor/resolver/group.rs +6 -8
  158. package/rust/core/preprocessor/resolver/loop_.rs +8 -10
  159. package/rust/core/preprocessor/resolver/spawn.rs +19 -23
  160. package/rust/core/preprocessor/resolver/synth.rs +6 -8
  161. package/rust/core/preprocessor/resolver/tempo.rs +6 -8
  162. package/rust/core/preprocessor/resolver/trigger.rs +22 -19
  163. package/rust/core/preprocessor/resolver/value.rs +99 -4
  164. package/rust/core/store/export.rs +28 -28
  165. package/rust/core/store/function.rs +6 -0
  166. package/rust/core/store/global.rs +7 -1
  167. package/rust/core/store/import.rs +28 -28
  168. package/rust/core/store/variable.rs +1 -1
  169. package/rust/core/utils/mod.rs +0 -1
  170. package/rust/lib.rs +102 -9
  171. package/rust/main.rs +156 -45
  172. package/rust/types/Cargo.toml +8 -0
  173. package/rust/types/src/addons.rs +55 -0
  174. package/rust/types/src/ast.rs +198 -0
  175. package/rust/types/src/config.rs +74 -0
  176. package/rust/types/src/lib.rs +12 -0
  177. package/rust/types/src/telemetry.rs +85 -0
  178. package/rust/utils/Cargo.toml +23 -0
  179. package/rust/utils/{error.rs → src/error.rs} +186 -200
  180. package/rust/utils/src/file.rs +94 -0
  181. package/rust/utils/src/first_usage.rs +97 -0
  182. package/rust/utils/{mod.rs → src/lib.rs} +1 -1
  183. package/rust/utils/{logger.rs → src/logger.rs} +17 -12
  184. package/rust/utils/src/path.rs +88 -0
  185. package/rust/utils/src/signature.rs +41 -0
  186. package/rust/utils/{spinner.rs → src/spinner.rs} +3 -5
  187. package/rust/utils/src/version.rs +27 -0
  188. package/rust/utils/{watcher.rs → src/watcher.rs} +13 -1
  189. package/rust/web/api.rs +5 -0
  190. package/rust/web/cdn.rs +34 -0
  191. package/templates/minimal/README.md +98 -54
  192. package/templates/welcome/README.md +98 -54
  193. package/templates/welcome/src/index.deva +56 -8
  194. package/templates/welcome/src/variables.deva +2 -4
  195. package/tests/rust/TODO.md +0 -0
  196. package/tests/typescript/index.spec.ts +136 -0
  197. package/tests/typescript/playhead.spec.ts +36 -0
  198. package/tests/typescript/render_e2e.spec.ts +77 -0
  199. package/tsconfig.json +1 -1
  200. package/typescript/core/functions/index.ts +83 -0
  201. package/typescript/core/index.ts +6 -0
  202. package/typescript/core/types/index.ts +4 -0
  203. package/typescript/core/types/plugin.ts +19 -0
  204. package/typescript/core/types/result.ts +29 -0
  205. package/typescript/core/types/statement.ts +47 -0
  206. package/typescript/core/types/value.ts +29 -0
  207. package/typescript/index.ts +7 -2
  208. package/typescript/pkg/devalang_core.d.ts +4 -0
  209. package/typescript/scripts/copy-wasm-dts.ts +41 -0
  210. package/typescript/scripts/postinstall.ts +45 -32
  211. package/rust/cli/bank.rs +0 -462
  212. package/rust/cli/build.rs +0 -252
  213. package/rust/cli/generator.rs +0 -1
  214. package/rust/cli/play.rs +0 -1123
  215. package/rust/cli/telemetry.rs +0 -19
  216. package/rust/common/api.rs +0 -5
  217. package/rust/common/cdn.rs +0 -5
  218. package/rust/config/loader.rs +0 -165
  219. package/rust/config/stats.rs +0 -257
  220. package/rust/core/audio/engine.rs +0 -696
  221. package/rust/core/shared/bank.rs +0 -21
  222. package/rust/core/shared/duration.rs +0 -9
  223. package/rust/core/shared/mod.rs +0 -3
  224. package/rust/core/shared/value.rs +0 -35
  225. package/rust/core/utils/validation.rs +0 -35
  226. package/rust/installer/bank.rs +0 -62
  227. package/rust/installer/plugin.rs +0 -54
  228. package/rust/installer/utils.rs +0 -56
  229. package/rust/utils/file.rs +0 -38
  230. package/rust/utils/first_usage.rs +0 -76
  231. package/rust/utils/signature.rs +0 -19
  232. package/rust/utils/telemetry.rs +0 -292
  233. package/rust/utils/version.rs +0 -15
  234. /package/rust/{common → web}/mod.rs +0 -0
  235. /package/rust/{common → web}/sso.rs +0 -0
@@ -1,19 +0,0 @@
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,5 +0,0 @@
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,5 +0,0 @@
1
- pub fn get_cdn_url() -> String {
2
- let cdn_url = "https://cdn.devalang.com";
3
- // let cdn_url = "http://127.0.0.1:8888";
4
- cdn_url.to_string()
5
- }
@@ -1,165 +0,0 @@
1
- use crate::config::driver::{ProjectConfig, ProjectConfigBankEntry, ProjectConfigBankMetadata};
2
- use std::{fs, path::Path};
3
-
4
- pub fn load_config(path: Option<&Path>) -> Option<ProjectConfig> {
5
- let config_path = path.unwrap_or_else(|| Path::new(".devalang"));
6
-
7
- if config_path.exists() {
8
- let content = fs::read_to_string(config_path).ok()?;
9
- toml::from_str(&content).ok()
10
- } else {
11
- None
12
- }
13
- }
14
-
15
- pub fn update_bank_version_in_config(
16
- config: &mut ProjectConfig,
17
- dependency: &str,
18
- new_version: &str,
19
- ) {
20
- if config.banks.is_none() {
21
- println!("No banks configured.");
22
- return;
23
- }
24
-
25
- let banks = config.banks.as_mut().unwrap();
26
-
27
- if let Some(bank) = banks.iter_mut().find(|b| b.path.contains(dependency)) {
28
- bank.version = Some(new_version.to_string());
29
-
30
- if let Err(e) = config.write(config) {
31
- eprintln!("❌ Failed to write config: {}", e);
32
- } else {
33
- println!(
34
- "✅ Bank '{}' updated to version '{}'",
35
- dependency, new_version
36
- );
37
- }
38
- } else {
39
- println!("Bank '{}' not found in config", dependency);
40
- }
41
- }
42
-
43
- pub fn remove_bank_from_config(config: &mut ProjectConfig, dependency: &str) {
44
- if config.banks.is_none() {
45
- println!("No banks configured.");
46
- return;
47
- }
48
-
49
- let banks = config.banks.as_mut().unwrap();
50
-
51
- if let Some(index) = banks.iter().position(|b| b.path.contains(dependency)) {
52
- banks.remove(index);
53
-
54
- if let Err(e) = config.write(config) {
55
- eprintln!("❌ Failed to write config: {}", e);
56
- } else {
57
- println!("✅ Bank '{}' removed from config", dependency);
58
- }
59
- } else {
60
- println!("Bank '{}' not found in config", dependency);
61
- }
62
- }
63
-
64
- pub fn add_plugin_to_config(config: &mut ProjectConfig, real_path: &Path, dependency: &str) {
65
- if config.plugins.is_none() {
66
- config.plugins = Some(Vec::new());
67
- }
68
-
69
- let plugins = config.plugins.as_mut().unwrap();
70
-
71
- let exists = plugins.iter().any(|p| p.path == dependency);
72
- if exists {
73
- println!("Plugin '{}' already in config", dependency);
74
- return;
75
- }
76
-
77
- let metadata_path = Path::new(real_path).join("plugin.toml");
78
-
79
- if !metadata_path.exists() {
80
- eprintln!(
81
- "❌ Plugin metadata file '{}' does not exist",
82
- metadata_path.display()
83
- );
84
- return;
85
- }
86
-
87
- let metadata_content =
88
- std::fs::read_to_string(&metadata_path).expect("Failed to read plugin metadata file");
89
-
90
- let metadata: std::collections::HashMap<String, String> =
91
- toml::from_str(&metadata_content).expect("Failed to parse plugin metadata file");
92
-
93
- let plugin_entry = crate::config::driver::PluginEntry {
94
- path: dependency.to_string(),
95
- version: metadata
96
- .get("version")
97
- .cloned()
98
- .unwrap_or_else(|| "0.0.1".to_string()),
99
- author: metadata
100
- .get("author")
101
- .cloned()
102
- .unwrap_or_else(|| "unknown".to_string()),
103
- access: metadata
104
- .get("access")
105
- .cloned()
106
- .unwrap_or_else(|| "public".to_string()),
107
- };
108
-
109
- plugins.push(plugin_entry);
110
-
111
- if let Err(e) = config.write(config) {
112
- eprintln!("❌ Failed to write config: {}", e);
113
- } else {
114
- println!("✅ Plugin '{}' added to config", dependency);
115
- }
116
- }
117
-
118
- pub fn add_bank_to_config(config: &mut ProjectConfig, real_path: &Path, dependency: &str) {
119
- if config.banks.is_none() {
120
- config.banks = Some(Vec::new());
121
- }
122
-
123
- let banks = config.banks.as_mut().unwrap();
124
-
125
- let exists = banks.iter().any(|b| b.path == dependency);
126
- if exists {
127
- println!("Bank '{}' already in config", dependency);
128
- return;
129
- }
130
-
131
- let metadata_path = Path::new(real_path).join("bank.toml");
132
-
133
- if !metadata_path.exists() {
134
- eprintln!(
135
- "❌ Bank metadata file '{}' does not exist",
136
- metadata_path.display()
137
- );
138
- return;
139
- }
140
-
141
- let metadata_content =
142
- fs::read_to_string(&metadata_path).expect("Failed to read bank metadata file");
143
-
144
- let metadata: ProjectConfigBankMetadata =
145
- toml::from_str(&metadata_content).expect("Failed to parse bank metadata file");
146
-
147
- let bank_to_insert = ProjectConfigBankEntry {
148
- path: dependency.to_string(),
149
- version: Some(
150
- metadata
151
- .bank
152
- .get("version")
153
- .cloned()
154
- .unwrap_or_else(|| "0.0.1".to_string()),
155
- ),
156
- };
157
-
158
- banks.push(bank_to_insert);
159
-
160
- if let Err(e) = config.write(config) {
161
- eprintln!("❌ Failed to write config: {}", e);
162
- } else {
163
- println!("✅ Bank '{}' added to config", dependency);
164
- }
165
- }
@@ -1,257 +0,0 @@
1
- use super::settings::get_devalang_homedir;
2
- use crate::config::driver::ProjectConfig;
3
- use crate::core::{
4
- parser::statement::{Statement, StatementKind},
5
- store::global::GlobalStore,
6
- };
7
- use serde::{Deserialize, Serialize};
8
- use std::collections::HashMap;
9
- use std::{
10
- fs,
11
- io::Write,
12
- path::Path,
13
- path::PathBuf,
14
- sync::{Mutex, OnceLock},
15
- };
16
-
17
- #[derive(Debug, Deserialize, Clone, Serialize)]
18
- pub struct StatsCounts {
19
- pub nb_files: usize,
20
- pub nb_modules: usize,
21
- pub nb_lines: usize,
22
- pub nb_banks: usize,
23
- pub nb_plugins: usize,
24
- }
25
-
26
- #[derive(Debug, Deserialize, Clone, Serialize)]
27
- pub struct StatsFeatures {
28
- pub uses_imports: bool,
29
- pub uses_functions: bool,
30
- pub uses_groups: bool,
31
- pub uses_automations: bool,
32
- pub uses_loops: bool,
33
- }
34
-
35
- #[derive(Debug, Deserialize, Clone, Serialize)]
36
- pub struct StatsAudio {
37
- pub avg_bpm: Option<u32>,
38
- pub has_synths: bool,
39
- pub has_samples: bool,
40
- }
41
-
42
- #[derive(Debug, Deserialize, Clone, Serialize)]
43
- pub struct ProjectStats {
44
- pub counts: StatsCounts,
45
- pub features: StatsFeatures,
46
- pub audio: StatsAudio,
47
- }
48
-
49
- impl ProjectStats {
50
- pub fn new() -> Self {
51
- ProjectStats {
52
- counts: StatsCounts {
53
- nb_files: 0,
54
- nb_modules: 0,
55
- nb_lines: 0,
56
- nb_banks: 0,
57
- nb_plugins: 0,
58
- },
59
- features: StatsFeatures {
60
- uses_imports: false,
61
- uses_functions: false,
62
- uses_groups: false,
63
- uses_automations: false,
64
- uses_loops: false,
65
- },
66
- audio: StatsAudio {
67
- avg_bpm: None,
68
- has_synths: false,
69
- has_samples: false,
70
- },
71
- }
72
- }
73
-
74
- // Returns the in-memory stats if available, otherwise loads from file,
75
- // otherwise returns a default struct.
76
- pub fn get() -> Result<Self, String> {
77
- if let Some(stats) = get_memory_stats() {
78
- return Ok(stats);
79
- }
80
- if let Some(stats) = load_from_file() {
81
- return Ok(stats);
82
- }
83
- Ok(Self::new())
84
- }
85
-
86
- // Saves stats to stats.json under the devalang home directory.
87
- pub fn persist(&self) -> Result<(), String> {
88
- save_to_file(self)
89
- }
90
- }
91
-
92
- // ----------------------------
93
- // Storage helpers (memory/file)
94
- // ----------------------------
95
-
96
- static STATS_MEMORY: OnceLock<Mutex<ProjectStats>> = OnceLock::new();
97
-
98
- fn stats_file_path() -> PathBuf {
99
- get_devalang_homedir().join("stats.json")
100
- }
101
-
102
- pub fn set_memory_stats(stats: ProjectStats) {
103
- let m = STATS_MEMORY.get_or_init(|| Mutex::new(ProjectStats::new()));
104
- if let Ok(mut guard) = m.lock() {
105
- *guard = stats;
106
- }
107
- }
108
-
109
- pub fn get_memory_stats() -> Option<ProjectStats> {
110
- let m = STATS_MEMORY.get_or_init(|| Mutex::new(ProjectStats::new()));
111
- if let Ok(guard) = m.lock() {
112
- // If it's the default value (all zero/false/None), still return it; caller can decide.
113
- return Some(guard.clone());
114
- }
115
- None
116
- }
117
-
118
- pub fn load_from_file() -> Option<ProjectStats> {
119
- let path = stats_file_path();
120
- if !path.exists() {
121
- return None;
122
- }
123
- match fs::read_to_string(&path) {
124
- Ok(content) => match serde_json::from_str::<ProjectStats>(&content) {
125
- Ok(stats) => Some(stats),
126
- Err(_) => None,
127
- },
128
- Err(_) => None,
129
- }
130
- }
131
-
132
- pub fn save_to_file(stats: &ProjectStats) -> Result<(), String> {
133
- let path = stats_file_path();
134
- let dir = path
135
- .parent()
136
- .unwrap_or(&get_devalang_homedir())
137
- .to_path_buf();
138
- if !dir.exists() {
139
- fs::create_dir_all(&dir).map_err(|e| format!("failed to create stats dir: {}", e))?;
140
- }
141
- let json = serde_json::to_string_pretty(stats)
142
- .map_err(|e| format!("failed to serialize stats: {}", e))?;
143
- let mut file =
144
- fs::File::create(&path).map_err(|e| format!("failed to create stats file: {}", e))?;
145
- file.write_all(json.as_bytes())
146
- .map_err(|e| format!("failed to write stats file: {}", e))?;
147
- Ok(())
148
- }
149
-
150
- // Compute stats from modules and store
151
- pub fn compute_from(
152
- statements_by_module: &HashMap<String, Vec<Statement>>,
153
- global_store: &GlobalStore,
154
- config: &Option<ProjectConfig>,
155
- _output_dir: Option<&str>,
156
- ) -> ProjectStats {
157
- let mut stats = ProjectStats::new();
158
-
159
- // Counts
160
- stats.counts.nb_modules = statements_by_module.len();
161
- stats.counts.nb_files = stats.counts.nb_modules; // number of source files loaded
162
-
163
- let mut total_lines = 0usize;
164
- for (path, _stmts) in statements_by_module.iter() {
165
- let p = Path::new(path);
166
- if let Ok(content) = fs::read_to_string(p) {
167
- total_lines += content.lines().count();
168
- }
169
- }
170
- stats.counts.nb_lines = total_lines;
171
-
172
- // Banks/Plugins from config
173
- if let Some(cfg) = config {
174
- stats.counts.nb_banks = cfg.banks.as_ref().map(|v| v.len()).unwrap_or(0);
175
- stats.counts.nb_plugins = cfg.plugins.as_ref().map(|v| v.len()).unwrap_or(0);
176
- }
177
-
178
- // Features and audio
179
- let mut bpm_sum: f32 = 0.0;
180
- let mut bpm_count: usize = 0;
181
-
182
- fn visit(
183
- stmts: &[Statement],
184
- acc: &mut ProjectStats,
185
- bpm_sum: &mut f32,
186
- bpm_count: &mut usize,
187
- ) {
188
- for s in stmts {
189
- match &s.kind {
190
- StatementKind::Import { .. } => acc.features.uses_imports = true,
191
- StatementKind::Function { body, .. } => {
192
- acc.features.uses_functions = true;
193
- visit(body, acc, bpm_sum, bpm_count);
194
- }
195
- StatementKind::Group => {
196
- acc.features.uses_groups = true;
197
- if let Some(body) = extract_body_block(&s.value) {
198
- visit(body, acc, bpm_sum, bpm_count);
199
- }
200
- }
201
- StatementKind::Automate { .. } => acc.features.uses_automations = true,
202
- StatementKind::Loop => {
203
- acc.features.uses_loops = true;
204
- if let Some(body) = extract_body_block(&s.value) {
205
- visit(body, acc, bpm_sum, bpm_count);
206
- }
207
- }
208
- StatementKind::Synth => acc.audio.has_synths = true,
209
- StatementKind::Tempo => {
210
- if let crate::core::shared::value::Value::Number(bpm) = &s.value {
211
- *bpm_sum += *bpm as f32;
212
- *bpm_count += 1;
213
- }
214
- }
215
- StatementKind::Trigger { entity, .. } => {
216
- let e = entity.to_lowercase();
217
- if e.ends_with(".wav") || e.ends_with(".mp3") || e.contains("devalang://bank/")
218
- {
219
- acc.audio.has_samples = true;
220
- }
221
- }
222
- _ => {}
223
- }
224
- }
225
- }
226
-
227
- fn extract_body_block(v: &crate::core::shared::value::Value) -> Option<&[Statement]> {
228
- use crate::core::shared::value::Value;
229
- if let Value::Map(map) = v {
230
- if let Some(Value::Block(stmts)) = map.get("body") {
231
- return Some(stmts.as_slice());
232
- }
233
- }
234
- None
235
- }
236
-
237
- for (_path, stmts) in statements_by_module.iter() {
238
- visit(stmts, &mut stats, &mut bpm_sum, &mut bpm_count);
239
- }
240
-
241
- if !stats.audio.has_samples {
242
- for (_k, v) in global_store.variables.variables.iter() {
243
- if let crate::core::shared::value::Value::String(s) = v {
244
- if s.starts_with("devalang://bank/") {
245
- stats.audio.has_samples = true;
246
- break;
247
- }
248
- }
249
- }
250
- }
251
-
252
- if bpm_count > 0 {
253
- stats.audio.avg_bpm = Some((bpm_sum / bpm_count as f32).round() as u32);
254
- }
255
-
256
- stats
257
- }