@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,87 +1,88 @@
1
- use crate::{cli::template::get_available_templates, utils::file::copy_dir_recursive};
2
- use include_dir::{Dir, include_dir};
3
- use std::{fs, path::Path};
4
-
5
- #[cfg(feature = "cli")]
6
- use inquire::{Confirm, Select};
7
-
8
- static TEMPLATES_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/templates");
9
-
10
- #[cfg(feature = "cli")]
11
- pub fn handle_init_command(name: Option<String>, template: Option<String>) {
12
- let current_dir = std::env::current_dir().unwrap();
13
- let project_name = name.clone().unwrap_or_else(|| {
14
- current_dir
15
- .file_name()
16
- .unwrap_or_default()
17
- .to_string_lossy()
18
- .to_string()
19
- });
20
-
21
- // Select a template if not provided
22
- let selected_template = template.unwrap_or_else(|| {
23
- Select::new(
24
- "Select a template for your project:",
25
- get_available_templates(),
26
- )
27
- .prompt()
28
- .unwrap_or_else(|_| {
29
- eprintln!("No template selected. Exiting...");
30
- std::process::exit(1);
31
- })
32
- });
33
-
34
- if selected_template.is_empty() {
35
- eprintln!("Template cannot be empty.");
36
- std::process::exit(1);
37
- }
38
-
39
- if name.is_none() {
40
- // Case of initialization in the current directory
41
- if fs::read_dir(&current_dir).unwrap().next().is_some() {
42
- let confirm =
43
- Confirm::new("The current directory is not empty. Do you want to continue?")
44
- .with_default(false)
45
- .prompt()
46
- .unwrap_or(false);
47
-
48
- if !confirm {
49
- eprintln!("Operation cancelled by the user.");
50
- std::process::exit(0);
51
- }
52
- }
53
-
54
- scaffold_project_current_dir(current_dir.as_path(), selected_template);
55
- println!(
56
- "✅ Initialized '{}' project in current directory: {}",
57
- project_name,
58
- current_dir.display()
59
- );
60
- } else {
61
- // Case of initialization in a new directory
62
- let target_path = current_dir.join(&project_name);
63
-
64
- if target_path.exists() {
65
- eprintln!("❌ A folder named '{}' already exists.", project_name);
66
- std::process::exit(1);
67
- }
68
-
69
- fs::create_dir_all(&target_path).expect("Error creating project directory");
70
-
71
- scaffold_project_current_dir(&target_path, selected_template);
72
- println!(
73
- "✅ Initialized '{}' project in: {}",
74
- project_name,
75
- target_path.display()
76
- );
77
- }
78
- }
79
-
80
- fn scaffold_project_current_dir(path: &Path, template: String) {
81
- let template_dir = TEMPLATES_DIR.get_dir(&template).unwrap_or_else(|| {
82
- eprintln!("❌ The template '{}' doesn't exist.", template);
83
- std::process::exit(1);
84
- });
85
-
86
- copy_dir_recursive(template_dir, path, &template_dir.path());
87
- }
1
+ use crate::cli::template::commands::get_available_templates;
2
+ use devalang_utils::file::copy_dir_recursive;
3
+ use include_dir::{Dir, include_dir};
4
+ use std::{fs, path::Path};
5
+
6
+ #[cfg(feature = "cli")]
7
+ use inquire::{Confirm, Select};
8
+
9
+ static TEMPLATES_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/templates");
10
+
11
+ #[cfg(feature = "cli")]
12
+ pub fn handle_init_command(name: Option<String>, template: Option<String>) {
13
+ let current_dir = std::env::current_dir().unwrap();
14
+ let project_name = name.clone().unwrap_or_else(|| {
15
+ current_dir
16
+ .file_name()
17
+ .unwrap_or_default()
18
+ .to_string_lossy()
19
+ .to_string()
20
+ });
21
+
22
+ // Select a template if not provided
23
+ let selected_template = template.unwrap_or_else(|| {
24
+ Select::new(
25
+ "Select a template for your project:",
26
+ get_available_templates(),
27
+ )
28
+ .prompt()
29
+ .unwrap_or_else(|_| {
30
+ eprintln!("No template selected. Exiting...");
31
+ std::process::exit(1);
32
+ })
33
+ });
34
+
35
+ if selected_template.is_empty() {
36
+ eprintln!("Template cannot be empty.");
37
+ std::process::exit(1);
38
+ }
39
+
40
+ if name.is_none() {
41
+ // Case of initialization in the current directory
42
+ if fs::read_dir(&current_dir).unwrap().next().is_some() {
43
+ let confirm =
44
+ Confirm::new("The current directory is not empty. Do you want to continue?")
45
+ .with_default(false)
46
+ .prompt()
47
+ .unwrap_or(false);
48
+
49
+ if !confirm {
50
+ eprintln!("Operation cancelled by the user.");
51
+ std::process::exit(0);
52
+ }
53
+ }
54
+
55
+ scaffold_project_current_dir(current_dir.as_path(), selected_template);
56
+ println!(
57
+ "✅ Initialized '{}' project in current directory: {}",
58
+ project_name,
59
+ current_dir.display()
60
+ );
61
+ } else {
62
+ // Case of initialization in a new directory
63
+ let target_path = current_dir.join(&project_name);
64
+
65
+ if target_path.exists() {
66
+ eprintln!("❌ A folder named '{}' already exists.", project_name);
67
+ std::process::exit(1);
68
+ }
69
+
70
+ fs::create_dir_all(&target_path).expect("Error creating project directory");
71
+
72
+ scaffold_project_current_dir(&target_path, selected_template);
73
+ println!(
74
+ "✅ Initialized '{}' project in: {}",
75
+ project_name,
76
+ target_path.display()
77
+ );
78
+ }
79
+ }
80
+
81
+ fn scaffold_project_current_dir(path: &Path, template: String) {
82
+ let template_dir = TEMPLATES_DIR.get_dir(&template).unwrap_or_else(|| {
83
+ eprintln!("❌ The template '{}' doesn't exist.", template);
84
+ std::process::exit(1);
85
+ });
86
+
87
+ copy_dir_recursive(template_dir, path, template_dir.path());
88
+ }
@@ -0,0 +1 @@
1
+ pub mod commands;
@@ -1,17 +1,11 @@
1
1
  use crate::{
2
- common::api::get_api_url,
2
+ cli::install::{bank::install_bank, plugin::install_plugin},
3
3
  config::settings::get_user_config,
4
- installer::{bank::install_bank, plugin::install_plugin},
4
+ web::api::get_api_url,
5
5
  };
6
+ use devalang_types::AddonType;
6
7
  use std::path::Path;
7
8
 
8
- #[derive(Debug, Clone)]
9
- pub enum AddonType {
10
- Bank,
11
- Plugin,
12
- Preset,
13
- }
14
-
15
9
  pub async fn install_addon(
16
10
  addon_type: AddonType,
17
11
  name: &str,
@@ -21,6 +15,7 @@ pub async fn install_addon(
21
15
  AddonType::Bank => install_bank(name, target_dir).await,
22
16
  AddonType::Plugin => install_plugin(name, target_dir).await,
23
17
  AddonType::Preset => Err("Preset installation not implemented".into()),
18
+ AddonType::Template => Err("Template installation not implemented".into()),
24
19
  }
25
20
  }
26
21
 
@@ -41,6 +36,7 @@ pub async fn ask_api_for_signed_url(addon_type: AddonType, slug: &str) -> Result
41
36
  AddonType::Bank => "bank",
42
37
  AddonType::Plugin => "plugin",
43
38
  AddonType::Preset => "preset",
39
+ AddonType::Template => "template",
44
40
  },
45
41
  slug,
46
42
  stored_token
@@ -0,0 +1,53 @@
1
+ use crate::{
2
+ cli::install::addon::ask_api_for_signed_url, config::ops::load_config,
3
+ web::cdn::download_from_cdn,
4
+ };
5
+ use devalang_types::AddonType;
6
+ use devalang_utils::{
7
+ logger::{LogLevel, Logger},
8
+ path as path_utils,
9
+ };
10
+ use std::path::Path;
11
+
12
+ pub async fn install_bank(name: &str, target_dir: &Path) -> Result<(), String> {
13
+ let logger = Logger::new();
14
+
15
+ let signed_url = ask_api_for_signed_url(AddonType::Bank, name).await?;
16
+
17
+ let bank_dir = target_dir.join("banks");
18
+ let archive_path = path_utils::ensure_deva_dir()?
19
+ .join("tmp")
20
+ .join(format!("{}.devabank", name));
21
+ let extract_path = bank_dir.join(name);
22
+
23
+ download_from_cdn(&signed_url, &archive_path)
24
+ .await
25
+ .map_err(|e| format!("Failed to download: {}", e))?;
26
+
27
+ if extract_path.exists() {
28
+ logger.log_message(
29
+ LogLevel::Warning,
30
+ &format!(
31
+ "Bank '{}' already exists at '{}'. Skipping install.",
32
+ name,
33
+ extract_path.display()
34
+ ),
35
+ );
36
+
37
+ return Ok(());
38
+ }
39
+
40
+ // Add the bank to the config
41
+ let config_path = path_utils::get_devalang_config_path()?;
42
+ let _config = load_config(Some(&config_path))
43
+ .ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
44
+
45
+ let _dependency_path = &format!("devalang://bank/{}", name);
46
+
47
+ devalang_utils::file::extract_zip_safely(&archive_path, &extract_path)
48
+ .map_err(|e| format!("Failed to extract: {}", e))?;
49
+
50
+ // TODO: Add the bank to the config
51
+
52
+ Ok(())
53
+ }
@@ -1,22 +1,22 @@
1
- use crate::installer::addon::{AddonType, install_addon};
1
+ use crate::cli::install::addon::install_addon;
2
+ #[cfg(feature = "cli")]
3
+ use devalang_types::AddonType;
4
+ use devalang_utils::path as path_utils;
2
5
 
3
6
  /// Handles the installation command for a given addon type and name.
4
7
  #[cfg(feature = "cli")]
5
8
  pub async fn handle_install_command(name: String, addon_type: AddonType) -> Result<(), String> {
6
- use crate::utils::{
9
+ use devalang_utils::{
7
10
  logger::{LogLevel, Logger},
8
- spinner::with_spinner,
11
+ spinner::start_spinner,
9
12
  };
10
- use std::{thread, time::Duration};
11
13
 
12
14
  let logger = Logger::new();
13
- let deva_dir = std::path::Path::new("./.deva/");
15
+ let deva_dir = path_utils::ensure_deva_dir()?;
14
16
 
15
- let spinner = with_spinner("Installing...", || {
16
- thread::sleep(Duration::from_millis(800));
17
- });
17
+ let spinner = start_spinner("Installing...");
18
18
 
19
- if let Err(e) = install_addon(addon_type.clone(), name.as_str(), deva_dir).await {
19
+ if let Err(e) = install_addon(addon_type.clone(), name.as_str(), &deva_dir).await {
20
20
  spinner.finish_and_clear();
21
21
  logger.log_message_with_trace(
22
22
  LogLevel::Error,
@@ -1,5 +1,4 @@
1
+ pub mod addon;
1
2
  pub mod bank;
3
+ pub mod commands;
2
4
  pub mod plugin;
3
-
4
- pub mod addon;
5
- pub mod utils;
@@ -0,0 +1,61 @@
1
+ use crate::{
2
+ config::ops::load_config,
3
+ web::cdn::{download_from_cdn, get_cdn_url},
4
+ };
5
+ use devalang_utils::path as path_utils;
6
+ use std::{fs, path::Path};
7
+
8
+ pub async fn install_plugin(name: &str, target_dir: &Path) -> Result<(), String> {
9
+ let cdn_url = get_cdn_url();
10
+ let url = format!("{}/plugin/{}/download", cdn_url, name);
11
+
12
+ let plugin_dir = target_dir.join("plugins");
13
+
14
+ // Ensure .deva/tmp exists and build archive path
15
+ let deva_dir = path_utils::ensure_deva_dir()?;
16
+ let tmp_dir = deva_dir.join("tmp");
17
+ if !tmp_dir.exists() {
18
+ fs::create_dir_all(&tmp_dir)
19
+ .map_err(|e| format!("Failed to create tmp dir '{}': {}", tmp_dir.display(), e))?;
20
+ }
21
+
22
+ let archive_path = tmp_dir.join(format!("{}.devaplugin", name));
23
+ let extract_path = plugin_dir.join(name);
24
+
25
+ if extract_path.exists() {
26
+ println!(
27
+ "Plugin '{}' already exists at '{}'. Skipping install.",
28
+ name,
29
+ extract_path.display()
30
+ );
31
+ return Ok(());
32
+ }
33
+
34
+ download_from_cdn(&url, &archive_path)
35
+ .await
36
+ .map_err(|e| format!("Failed to download: {}", e))?;
37
+
38
+ // Add the plugin to the config: locate project root from target_dir
39
+ let project_root = path_utils::find_project_root_from(target_dir)
40
+ .ok_or_else(|| "Failed to determine project root from target_dir".to_string())?;
41
+
42
+ let config_path = project_root.join(path_utils::DEVALANG_CONFIG);
43
+ if !config_path.exists() {
44
+ return Err(format!(
45
+ "Config file not found at '{}'. Please run 'devalang init' before adding an addon",
46
+ config_path.display()
47
+ ));
48
+ }
49
+
50
+ let _config = load_config(Some(&config_path))
51
+ .ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
52
+
53
+ let _dependency_path = &format!("devalang://plugin/{}", name);
54
+
55
+ devalang_utils::file::extract_zip_safely(&archive_path, &extract_path)
56
+ .map_err(|e| format!("Failed to extract: {}", e))?;
57
+
58
+ // TODO: Add the plugin to the config
59
+
60
+ Ok(())
61
+ }
@@ -1,7 +1,6 @@
1
- use crate::common::sso::get_sso_url;
2
- use crate::config::settings::set_user_config_string;
1
+ use crate::config::settings::set_user_config_value;
2
+ use crate::web::sso::get_sso_url;
3
3
  use std::str::FromStr;
4
- use std::{thread, time::Duration};
5
4
  use tiny_http::Header;
6
5
  use tiny_http::{Response, Server};
7
6
  use webbrowser;
@@ -10,9 +9,9 @@ use webbrowser;
10
9
  /// This function initiates the login process by opening the browser and waiting for the callback.
11
10
  #[cfg(feature = "cli")]
12
11
  pub async fn handle_login_command() -> Result<(), String> {
13
- use crate::utils::logger::LogLevel;
14
- use crate::utils::logger::Logger;
15
- use crate::utils::spinner::with_spinner;
12
+ use devalang_utils::logger::LogLevel;
13
+ use devalang_utils::logger::Logger;
14
+ use devalang_utils::spinner::start_spinner;
16
15
 
17
16
  let logger = Logger::new();
18
17
 
@@ -49,9 +48,7 @@ pub async fn handle_login_command() -> Result<(), String> {
49
48
 
50
49
  let server = Server::http(format!("127.0.0.1:{}", listener_port)).unwrap();
51
50
 
52
- let spinner = with_spinner("Waiting for authentication...", || {
53
- thread::sleep(Duration::from_millis(800));
54
- });
51
+ let spinner = start_spinner("Waiting for authentication...");
55
52
 
56
53
  for request in server.incoming_requests() {
57
54
  let query = request.url().to_string();
@@ -59,7 +56,7 @@ pub async fn handle_login_command() -> Result<(), String> {
59
56
  if query.contains("session=") || query.contains("error=") {
60
57
  let token = query.split("session=").nth(1).unwrap_or("").to_string();
61
58
 
62
- if token.len() > 0 {
59
+ if !token.is_empty() {
63
60
  let response_html = r#"
64
61
  <html>
65
62
  <body>
@@ -123,5 +120,5 @@ pub async fn handle_login_command() -> Result<(), String> {
123
120
 
124
121
  /// Save the session token to a file in the user's home directory
125
122
  fn save_token(token: &str) {
126
- set_user_config_string("session", token.to_string());
123
+ set_user_config_value("session", serde_json::Value::String(token.to_string()));
127
124
  }
@@ -0,0 +1 @@
1
+ pub mod commands;
package/rust/cli/mod.rs CHANGED
@@ -1,12 +1,11 @@
1
- pub mod driver;
2
-
3
1
  pub mod bank;
4
2
  pub mod build;
5
3
  pub mod check;
6
- pub mod generator;
4
+ pub mod discover;
7
5
  pub mod init;
8
6
  pub mod install;
9
7
  pub mod login;
8
+ pub mod parser;
10
9
  pub mod play;
11
10
  pub mod telemetry;
12
11
  pub mod template;
@@ -1,10 +1,8 @@
1
- use crate::utils::version::get_version;
2
1
  use clap::{Parser, Subcommand};
3
2
 
4
3
  #[derive(Parser)]
5
4
  #[command(name = "devalang")]
6
5
  #[command(author = "Devaloop")]
7
- #[command(version = get_version())]
8
6
  #[command(about = "🦊 Devalang – A programming language for music and sound.")]
9
7
  pub struct Cli {
10
8
  #[arg(long, global = true)]
@@ -25,6 +23,8 @@ pub enum TelemetryCommand {
25
23
 
26
24
  #[derive(Subcommand)]
27
25
  pub enum InstallCommand {
26
+ /// Installs a template.
27
+ Template { name: String },
28
28
  /// Installs a bank.
29
29
  Bank { name: String },
30
30
  /// Installs a plugin.
@@ -259,12 +259,17 @@ pub enum Commands {
259
259
  /// - `template` - Installs a template.
260
260
  /// - `bank` - Installs a bank.
261
261
  /// - `plugin` - Installs a plugin.
262
+ /// - `preset` - Installs a preset.
262
263
  ///
263
264
  Install {
264
265
  #[command(subcommand)]
265
266
  command: InstallCommand,
266
267
  },
267
268
 
269
+ /// Discover available local addons for Devalang.
270
+ ///
271
+ Discover {},
272
+
268
273
  /// Manage banks for Devalang projects.
269
274
  ///
270
275
  /// ### Subcommands
@@ -287,6 +292,18 @@ pub enum Commands {
287
292
  command: TelemetryCommand,
288
293
  },
289
294
 
295
+ /// Generate addon scaffolding for Devalang.
296
+ ///
297
+ /// ### Subcommands
298
+ /// - `bank` - Generates a bank scaffold.
299
+ /// - `plugin` - Generates a plugin scaffold.
300
+ /// - `preset` - Generates a preset scaffold.
301
+ ///
302
+ // Scaffold {
303
+ // #[command(subcommand)]
304
+ // command: ScaffoldCommand,
305
+ // },
306
+
290
307
  /// Log in to your Devaloop account.
291
308
  ///
292
309
  Login {},