@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.
- package/.cargo/config.toml +2 -0
- package/.devalang +6 -10
- package/.github/workflows/ci.yml +19 -8
- package/Cargo.toml +18 -2
- package/README.md +80 -33
- package/docs/CHANGELOG.md +56 -0
- package/docs/ROADMAP.md +6 -3
- package/examples/index.deva +52 -35
- package/out-tsc/bin/index.d.ts +2 -0
- package/out-tsc/core/functions/index.d.ts +37 -0
- package/out-tsc/core/functions/index.js +76 -0
- package/out-tsc/core/index.d.ts +6 -0
- package/out-tsc/core/index.js +22 -0
- package/out-tsc/core/types/index.d.ts +4 -0
- package/out-tsc/core/types/index.js +20 -0
- package/out-tsc/core/types/plugin.d.ts +18 -0
- package/out-tsc/core/types/plugin.js +2 -0
- package/out-tsc/core/types/result.d.ts +27 -0
- package/out-tsc/core/types/result.js +2 -0
- package/out-tsc/core/types/statement.d.ts +106 -0
- package/out-tsc/core/types/statement.js +2 -0
- package/out-tsc/core/types/value.d.ts +43 -0
- package/out-tsc/core/types/value.js +2 -0
- package/out-tsc/index.d.ts +7 -0
- package/out-tsc/index.js +41 -2
- package/out-tsc/pkg/devalang_core.d.ts +7 -0
- package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +33 -0
- package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
- package/out-tsc/scripts/copy-wasm-dts.js +73 -0
- package/out-tsc/scripts/postinstall.d.ts +1 -0
- package/out-tsc/scripts/postinstall.js +33 -23
- package/out-tsc/scripts/version/bump.d.ts +1 -0
- package/out-tsc/scripts/version/fetch.d.ts +1 -0
- package/out-tsc/scripts/version/index.d.ts +1 -0
- package/out-tsc/scripts/version/sync.d.ts +1 -0
- package/package.json +16 -4
- package/project-version.json +3 -3
- package/rust/cli/bank/api.rs +122 -0
- package/rust/cli/bank/commands.rs +275 -0
- package/rust/cli/bank/mod.rs +29 -0
- package/rust/cli/build/commands.rs +97 -0
- package/rust/cli/build/mod.rs +2 -0
- package/rust/cli/build/process.rs +146 -0
- package/rust/cli/{check.rs → check/mod.rs} +18 -31
- package/rust/cli/discover/commands.rs +253 -0
- package/rust/cli/discover/config.rs +111 -0
- package/rust/cli/discover/fs.rs +19 -0
- package/rust/cli/discover/install.rs +103 -0
- package/rust/cli/discover/metadata.rs +48 -0
- package/rust/cli/discover/mod.rs +5 -0
- package/rust/cli/{init.rs → init/commands.rs} +88 -87
- package/rust/cli/init/mod.rs +1 -0
- package/rust/{installer → cli/install}/addon.rs +5 -9
- package/rust/cli/install/bank.rs +53 -0
- package/rust/cli/{install.rs → install/commands.rs} +9 -9
- package/rust/{installer → cli/install}/mod.rs +2 -3
- package/rust/cli/install/plugin.rs +61 -0
- package/rust/cli/{login.rs → login/commands.rs} +8 -11
- package/rust/cli/login/mod.rs +1 -0
- package/rust/cli/mod.rs +2 -3
- package/rust/cli/{driver.rs → parser.rs} +19 -2
- package/rust/cli/play/commands.rs +324 -0
- package/rust/cli/play/io.rs +17 -0
- package/rust/cli/play/mod.rs +5 -0
- package/rust/cli/play/process.rs +150 -0
- package/rust/cli/play/realtime.rs +91 -0
- package/rust/cli/play/utils.rs +23 -0
- package/rust/cli/telemetry/commands.rs +22 -0
- package/rust/cli/telemetry/event_creator.rs +80 -0
- package/rust/cli/telemetry/mod.rs +3 -0
- package/rust/cli/telemetry/send.rs +51 -0
- package/rust/cli/{template.rs → template/commands.rs} +1 -1
- package/rust/cli/template/mod.rs +1 -0
- package/rust/cli/{update.rs → update/commands.rs} +6 -6
- package/rust/cli/update/mod.rs +1 -0
- package/rust/config/driver.rs +57 -72
- package/rust/config/mod.rs +1 -2
- package/rust/config/ops.rs +26 -0
- package/rust/config/settings.rs +60 -50
- package/rust/core/audio/engine/helpers.rs +146 -0
- package/rust/core/audio/engine/mod.rs +7 -0
- package/rust/core/audio/engine/sample.rs +298 -0
- package/rust/core/audio/engine/synth.rs +310 -0
- package/rust/core/audio/evaluator.rs +15 -12
- package/rust/core/audio/interpreter/arrow_call.rs +99 -24
- package/rust/core/audio/interpreter/call.rs +81 -60
- package/rust/core/audio/interpreter/condition.rs +3 -2
- package/rust/core/audio/interpreter/driver.rs +206 -151
- package/rust/core/audio/interpreter/let_.rs +1 -1
- package/rust/core/audio/interpreter/load.rs +2 -1
- package/rust/core/audio/interpreter/loop_.rs +7 -6
- package/rust/core/audio/interpreter/sleep.rs +2 -1
- package/rust/core/audio/interpreter/spawn.rs +45 -57
- package/rust/core/audio/interpreter/tempo.rs +31 -10
- package/rust/core/audio/interpreter/trigger.rs +2 -2
- package/rust/core/audio/loader/trigger.rs +4 -7
- package/rust/core/audio/player.rs +6 -0
- package/rust/core/audio/renderer.rs +5 -7
- package/rust/core/audio/special/env.rs +3 -1
- package/rust/core/audio/special/math.rs +4 -4
- package/rust/core/audio/special/modulator.rs +2 -2
- package/rust/core/builder/mod.rs +9 -3
- package/rust/core/debugger/lexer.rs +1 -1
- package/rust/core/debugger/mod.rs +6 -0
- package/rust/core/debugger/module.rs +4 -4
- package/rust/core/debugger/preprocessor.rs +1 -1
- package/rust/core/debugger/store.rs +2 -2
- package/rust/core/error/mod.rs +189 -0
- package/rust/core/lexer/handler/arrow.rs +1 -1
- package/rust/core/lexer/handler/at.rs +1 -1
- package/rust/core/lexer/handler/brace.rs +2 -2
- package/rust/core/lexer/handler/colon.rs +1 -1
- package/rust/core/lexer/handler/comment.rs +1 -1
- package/rust/core/lexer/handler/dot.rs +1 -1
- package/rust/core/lexer/handler/driver.rs +1 -1
- package/rust/core/lexer/handler/identifier.rs +1 -1
- package/rust/core/lexer/handler/mod.rs +1 -2
- package/rust/core/lexer/handler/number.rs +1 -1
- package/rust/core/lexer/handler/operator.rs +1 -1
- package/rust/core/lexer/handler/parenthesis.rs +2 -2
- package/rust/core/lexer/handler/slash.rs +1 -1
- package/rust/core/lexer/handler/string.rs +1 -1
- package/rust/core/lexer/mod.rs +22 -12
- package/rust/core/lexer/token.rs +90 -97
- package/rust/core/mod.rs +0 -1
- package/rust/core/parser/driver.rs +66 -13
- package/rust/core/parser/handler/arrow_call.rs +28 -8
- package/rust/core/parser/handler/at.rs +55 -21
- package/rust/core/parser/handler/bank.rs +14 -4
- package/rust/core/parser/handler/condition.rs +6 -3
- package/rust/core/parser/handler/dot.rs +2 -1
- package/rust/core/parser/handler/identifier/automate.rs +13 -16
- package/rust/core/parser/handler/identifier/call.rs +4 -4
- package/rust/core/parser/handler/identifier/emit.rs +9 -5
- package/rust/core/parser/handler/identifier/function.rs +20 -7
- package/rust/core/parser/handler/identifier/group.rs +11 -7
- package/rust/core/parser/handler/identifier/let_.rs +24 -9
- package/rust/core/parser/handler/identifier/mod.rs +6 -5
- package/rust/core/parser/handler/identifier/on.rs +16 -7
- package/rust/core/parser/handler/identifier/print.rs +6 -9
- package/rust/core/parser/handler/identifier/sleep.rs +12 -5
- package/rust/core/parser/handler/identifier/spawn.rs +4 -4
- package/rust/core/parser/handler/identifier/synth.rs +79 -9
- package/rust/core/parser/handler/loop_.rs +39 -14
- package/rust/core/parser/handler/tempo.rs +9 -5
- package/rust/core/parser/mod.rs +0 -1
- package/rust/core/parser/statement.rs +6 -137
- package/rust/core/plugin/loader.rs +41 -27
- package/rust/core/plugin/runner.rs +68 -17
- package/rust/core/preprocessor/loader.rs +155 -33
- package/rust/core/preprocessor/processor.rs +2 -2
- package/rust/core/preprocessor/resolver/bank.rs +6 -8
- package/rust/core/preprocessor/resolver/call.rs +20 -24
- package/rust/core/preprocessor/resolver/condition.rs +6 -8
- package/rust/core/preprocessor/resolver/driver.rs +14 -16
- package/rust/core/preprocessor/resolver/function.rs +6 -6
- package/rust/core/preprocessor/resolver/group.rs +6 -8
- package/rust/core/preprocessor/resolver/loop_.rs +8 -10
- package/rust/core/preprocessor/resolver/spawn.rs +19 -23
- package/rust/core/preprocessor/resolver/synth.rs +6 -8
- package/rust/core/preprocessor/resolver/tempo.rs +6 -8
- package/rust/core/preprocessor/resolver/trigger.rs +22 -19
- package/rust/core/preprocessor/resolver/value.rs +99 -4
- package/rust/core/store/export.rs +28 -28
- package/rust/core/store/function.rs +6 -0
- package/rust/core/store/global.rs +7 -1
- package/rust/core/store/import.rs +28 -28
- package/rust/core/store/variable.rs +1 -1
- package/rust/core/utils/mod.rs +0 -1
- package/rust/lib.rs +102 -9
- package/rust/main.rs +156 -45
- package/rust/types/Cargo.toml +8 -0
- package/rust/types/src/addons.rs +55 -0
- package/rust/types/src/ast.rs +198 -0
- package/rust/types/src/config.rs +74 -0
- package/rust/types/src/lib.rs +12 -0
- package/rust/types/src/telemetry.rs +85 -0
- package/rust/utils/Cargo.toml +23 -0
- package/rust/utils/{error.rs → src/error.rs} +186 -200
- package/rust/utils/src/file.rs +94 -0
- package/rust/utils/src/first_usage.rs +97 -0
- package/rust/utils/{mod.rs → src/lib.rs} +1 -1
- package/rust/utils/{logger.rs → src/logger.rs} +17 -12
- package/rust/utils/src/path.rs +88 -0
- package/rust/utils/src/signature.rs +41 -0
- package/rust/utils/{spinner.rs → src/spinner.rs} +3 -5
- package/rust/utils/src/version.rs +27 -0
- package/rust/utils/{watcher.rs → src/watcher.rs} +13 -1
- package/rust/web/api.rs +5 -0
- package/rust/web/cdn.rs +34 -0
- package/templates/minimal/README.md +98 -54
- package/templates/welcome/README.md +98 -54
- package/templates/welcome/src/index.deva +56 -8
- package/templates/welcome/src/variables.deva +2 -4
- package/tests/rust/TODO.md +0 -0
- package/tests/typescript/index.spec.ts +136 -0
- package/tests/typescript/playhead.spec.ts +36 -0
- package/tests/typescript/render_e2e.spec.ts +77 -0
- package/tsconfig.json +1 -1
- package/typescript/core/functions/index.ts +83 -0
- package/typescript/core/index.ts +6 -0
- package/typescript/core/types/index.ts +4 -0
- package/typescript/core/types/plugin.ts +19 -0
- package/typescript/core/types/result.ts +29 -0
- package/typescript/core/types/statement.ts +47 -0
- package/typescript/core/types/value.ts +29 -0
- package/typescript/index.ts +7 -2
- package/typescript/pkg/devalang_core.d.ts +4 -0
- package/typescript/scripts/copy-wasm-dts.ts +41 -0
- package/typescript/scripts/postinstall.ts +45 -32
- package/rust/cli/bank.rs +0 -462
- package/rust/cli/build.rs +0 -252
- package/rust/cli/generator.rs +0 -1
- package/rust/cli/play.rs +0 -1123
- package/rust/cli/telemetry.rs +0 -19
- package/rust/common/api.rs +0 -5
- package/rust/common/cdn.rs +0 -5
- package/rust/config/loader.rs +0 -165
- package/rust/config/stats.rs +0 -257
- package/rust/core/audio/engine.rs +0 -696
- package/rust/core/shared/bank.rs +0 -21
- package/rust/core/shared/duration.rs +0 -9
- package/rust/core/shared/mod.rs +0 -3
- package/rust/core/shared/value.rs +0 -35
- package/rust/core/utils/validation.rs +0 -35
- package/rust/installer/bank.rs +0 -62
- package/rust/installer/plugin.rs +0 -54
- package/rust/installer/utils.rs +0 -56
- package/rust/utils/file.rs +0 -38
- package/rust/utils/first_usage.rs +0 -76
- package/rust/utils/signature.rs +0 -19
- package/rust/utils/telemetry.rs +0 -292
- package/rust/utils/version.rs +0 -15
- /package/rust/{common → web}/mod.rs +0 -0
- /package/rust/{common → web}/sso.rs +0 -0
package/rust/cli/telemetry.rs
DELETED
|
@@ -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
|
-
}
|
package/rust/common/api.rs
DELETED
package/rust/common/cdn.rs
DELETED
package/rust/config/loader.rs
DELETED
|
@@ -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
|
-
}
|
package/rust/config/stats.rs
DELETED
|
@@ -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
|
-
}
|