@devaloop/devalang 0.0.1-beta.1 → 0.0.1-beta.3

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 (207) hide show
  1. package/.devalang +9 -10
  2. package/Cargo.toml +84 -80
  3. package/README.md +10 -7
  4. package/docs/CHANGELOG.md +83 -0
  5. package/docs/ROADMAP.md +6 -2
  6. package/docs/TODO.md +3 -14
  7. package/examples/bus.deva +10 -0
  8. package/examples/chain.deva +19 -0
  9. package/examples/effect.deva +2 -0
  10. package/examples/filter.deva +11 -0
  11. package/examples/lfo.deva +9 -0
  12. package/examples/plugin.deva +10 -10
  13. package/examples/routing.deva +23 -0
  14. package/examples/synth.deva +11 -1
  15. package/examples/synth_types.deva +17 -0
  16. package/out-tsc/bin/project-version.json +6 -0
  17. package/out-tsc/core/functions/index.d.ts +5 -0
  18. package/out-tsc/core/functions/index.js +11 -0
  19. package/out-tsc/pkg/devalang_core.d.ts +2 -0
  20. package/out-tsc/pkg/devalang_core.js +17 -2
  21. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +1 -0
  22. package/out-tsc/scripts/version/copy-to-binary.d.ts +1 -0
  23. package/out-tsc/scripts/version/copy-to-binary.js +79 -0
  24. package/package.json +23 -10
  25. package/project-version.json +3 -3
  26. package/rust/bindings/Cargo.toml +9 -0
  27. package/rust/bindings/src/lib.rs +86 -0
  28. package/rust/cli/addon/commands.rs +35 -0
  29. package/rust/cli/addon/download.rs +234 -0
  30. package/rust/cli/addon/install.rs +33 -0
  31. package/rust/cli/addon/list.rs +224 -0
  32. package/rust/cli/addon/metadata.rs +124 -0
  33. package/rust/cli/addon/mod.rs +8 -0
  34. package/rust/cli/addon/remove.rs +271 -0
  35. package/rust/cli/addon/update.rs +305 -0
  36. package/rust/cli/{install/addon.rs → addon/utils.rs} +34 -43
  37. package/rust/cli/build/commands.rs +153 -103
  38. package/rust/cli/build/mod.rs +2 -2
  39. package/rust/cli/build/process.rs +165 -146
  40. package/rust/cli/check/mod.rs +208 -208
  41. package/rust/cli/discover/commands.rs +53 -31
  42. package/rust/cli/discover/config.rs +2 -4
  43. package/rust/cli/discover/install.rs +139 -28
  44. package/rust/cli/discover/metadata.rs +3 -3
  45. package/rust/cli/login/commands.rs +124 -124
  46. package/rust/cli/me/commands.rs +52 -0
  47. package/rust/cli/me/mod.rs +1 -0
  48. package/rust/cli/mod.rs +2 -2
  49. package/rust/cli/parser.rs +76 -70
  50. package/rust/cli/play/commands.rs +375 -324
  51. package/rust/cli/play/mod.rs +5 -5
  52. package/rust/cli/play/process.rs +159 -150
  53. package/rust/cli/play/realtime.rs +91 -91
  54. package/rust/cli/telemetry/commands.rs +22 -22
  55. package/rust/cli/telemetry/event_creator.rs +80 -80
  56. package/rust/cli/telemetry/mod.rs +3 -3
  57. package/rust/cli/telemetry/send.rs +51 -51
  58. package/rust/cli/template/commands.rs +69 -69
  59. package/rust/config/driver.rs +112 -103
  60. package/rust/config/mod.rs +3 -3
  61. package/rust/config/ops.rs +26 -26
  62. package/rust/config/settings.rs +101 -101
  63. package/rust/core/audio/engine/driver.rs +237 -0
  64. package/rust/core/audio/engine/export.rs +169 -0
  65. package/rust/core/audio/engine/helpers.rs +178 -170
  66. package/rust/core/audio/engine/mod.rs +56 -7
  67. package/rust/core/audio/engine/notes/dsp.rs +88 -0
  68. package/rust/core/audio/engine/notes/mod.rs +53 -0
  69. package/rust/core/audio/engine/notes/params.rs +294 -0
  70. package/rust/core/audio/engine/sample/insert.rs +300 -0
  71. package/rust/core/audio/engine/sample/mod.rs +40 -0
  72. package/rust/core/audio/engine/sample/padding.rs +170 -0
  73. package/rust/core/audio/evaluator/condition.rs +61 -0
  74. package/rust/core/audio/evaluator/mod.rs +9 -0
  75. package/rust/core/audio/{evaluator.rs → evaluator/numeric.rs} +152 -310
  76. package/rust/core/audio/evaluator/rhs.rs +16 -0
  77. package/rust/core/audio/evaluator/string_expr.rs +94 -0
  78. package/rust/core/audio/interpreter/driver.rs +574 -542
  79. package/rust/core/audio/interpreter/mod.rs +2 -14
  80. package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +179 -0
  81. package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +398 -0
  82. package/rust/core/audio/interpreter/statements/arrow_call/methods/effects.rs +323 -0
  83. package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +3 -0
  84. package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +371 -0
  85. package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +3 -0
  86. package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +192 -0
  87. package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +24 -0
  88. package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +116 -0
  89. package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +97 -0
  90. package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +100 -0
  91. package/rust/core/audio/interpreter/{automate.rs → statements/automate.rs} +2 -4
  92. package/rust/core/audio/interpreter/{call.rs → statements/call.rs} +36 -5
  93. package/rust/core/audio/interpreter/{condition.rs → statements/condition.rs} +72 -71
  94. package/rust/core/audio/interpreter/{function.rs → statements/function.rs} +24 -26
  95. package/rust/core/audio/interpreter/{let_.rs → statements/let_.rs} +36 -38
  96. package/rust/core/audio/interpreter/{load.rs → statements/load.rs} +17 -19
  97. package/rust/core/audio/interpreter/{loop_.rs → statements/loop_.rs} +115 -114
  98. package/rust/core/audio/interpreter/statements/mod.rs +12 -0
  99. package/rust/core/audio/interpreter/{sleep.rs → statements/sleep.rs} +28 -28
  100. package/rust/core/audio/interpreter/{spawn.rs → statements/spawn.rs} +54 -4
  101. package/rust/core/audio/interpreter/{tempo.rs → statements/tempo.rs} +40 -40
  102. package/rust/core/audio/interpreter/{trigger.rs → statements/trigger.rs} +242 -239
  103. package/rust/core/audio/loader/trigger.rs +98 -97
  104. package/rust/core/audio/mod.rs +6 -7
  105. package/rust/core/audio/special/easing.rs +189 -189
  106. package/rust/core/audio/special/env.rs +45 -45
  107. package/rust/core/audio/special/math.rs +134 -134
  108. package/rust/core/audio/special/modulator.rs +143 -143
  109. package/rust/core/builder/mod.rs +129 -86
  110. package/rust/core/debugger/{module.rs → logs.rs} +52 -55
  111. package/rust/core/debugger/mod.rs +30 -30
  112. package/rust/core/debugger/store.rs +38 -40
  113. package/rust/core/error/mod.rs +269 -269
  114. package/rust/core/lexer/driver.rs +2 -4
  115. package/rust/core/mod.rs +9 -10
  116. package/rust/core/parser/driver/block.rs +111 -0
  117. package/rust/core/parser/driver/cursor.rs +82 -0
  118. package/rust/core/parser/driver/driver_impl.rs +159 -0
  119. package/rust/core/parser/driver/mod.rs +6 -0
  120. package/rust/core/parser/driver/parse_array.rs +120 -0
  121. package/rust/core/parser/driver/parse_map.rs +247 -0
  122. package/rust/core/parser/driver/parser.rs +160 -0
  123. package/rust/core/parser/handler/arrow_call.rs +90 -15
  124. package/rust/core/parser/handler/at.rs +279 -279
  125. package/rust/core/parser/handler/bank.rs +104 -104
  126. package/rust/core/parser/handler/condition.rs +83 -83
  127. package/rust/core/parser/handler/dot.rs +148 -148
  128. package/rust/core/parser/handler/identifier/automate.rs +254 -254
  129. package/rust/core/parser/handler/identifier/call.rs +91 -91
  130. package/rust/core/parser/handler/identifier/emit.rs +70 -70
  131. package/rust/core/parser/handler/identifier/function.rs +113 -113
  132. package/rust/core/parser/handler/identifier/group.rs +89 -89
  133. package/rust/core/parser/handler/identifier/let_.rs +173 -173
  134. package/rust/core/parser/handler/identifier/mod.rs +55 -55
  135. package/rust/core/parser/handler/identifier/on.rs +107 -107
  136. package/rust/core/parser/handler/identifier/print.rs +49 -49
  137. package/rust/core/parser/handler/identifier/sleep.rs +96 -43
  138. package/rust/core/parser/handler/identifier/spawn.rs +91 -91
  139. package/rust/core/parser/handler/identifier/synth.rs +39 -3
  140. package/rust/core/parser/handler/loop_.rs +194 -194
  141. package/rust/core/parser/handler/pattern.rs +25 -2
  142. package/rust/core/parser/handler/tempo.rs +105 -57
  143. package/rust/core/parser/statement.rs +10 -11
  144. package/rust/core/plugin/loader.rs +137 -137
  145. package/rust/core/plugin/runner/mod.rs +11 -0
  146. package/rust/core/plugin/{runner.rs → runner/non_wasm.rs} +206 -72
  147. package/rust/core/plugin/runner/wasm32.rs +44 -0
  148. package/rust/core/preprocessor/loader/inject.rs +313 -0
  149. package/rust/core/preprocessor/loader/loader_helpers.rs +110 -0
  150. package/rust/core/preprocessor/loader/mod.rs +235 -0
  151. package/rust/core/preprocessor/module.rs +55 -60
  152. package/rust/core/preprocessor/{processor.rs → processor/handlers.rs} +107 -114
  153. package/rust/core/preprocessor/processor/mod.rs +1 -0
  154. package/rust/core/preprocessor/resolver/function.rs +69 -69
  155. package/rust/core/preprocessor/resolver/group.rs +122 -94
  156. package/rust/core/preprocessor/resolver/pattern.rs +14 -2
  157. package/rust/core/store/global.rs +57 -61
  158. package/rust/core/store/mod.rs +1 -5
  159. package/rust/lib.rs +323 -308
  160. package/rust/macros/Cargo.toml +14 -0
  161. package/rust/macros/src/lib.rs +52 -0
  162. package/rust/main.rs +336 -143
  163. package/rust/types/Cargo.toml +1 -1
  164. package/rust/types/src/addons.rs +57 -55
  165. package/rust/types/src/config.rs +82 -74
  166. package/rust/types/src/lib.rs +15 -12
  167. package/rust/types/src/plugin.rs +20 -0
  168. package/rust/types/src/store.rs +139 -0
  169. package/rust/types/src/telemetry.rs +85 -85
  170. package/rust/utils/Cargo.toml +5 -2
  171. package/rust/utils/src/file.rs +477 -94
  172. package/rust/utils/src/first_usage.rs +97 -97
  173. package/rust/utils/src/lib.rs +9 -9
  174. package/rust/utils/src/logger.rs +200 -200
  175. package/rust/utils/src/path.rs +158 -88
  176. package/rust/utils/src/signature.rs +41 -41
  177. package/rust/utils/src/spinner.rs +20 -20
  178. package/rust/utils/src/version.rs +58 -27
  179. package/rust/utils/src/watcher.rs +46 -46
  180. package/rust/web/api.rs +5 -5
  181. package/rust/web/auth.rs +5 -0
  182. package/rust/web/cdn.rs +34 -34
  183. package/rust/web/forge.rs +5 -0
  184. package/rust/web/mod.rs +2 -0
  185. package/tests/integration.rs +21 -21
  186. package/typescript/core/functions/index.ts +11 -0
  187. package/typescript/pkg/devalang_core.ts +20 -4
  188. package/typescript/scripts/version/copy-to-binary.ts +82 -0
  189. package/rust/cli/bank/api.rs +0 -122
  190. package/rust/cli/bank/commands.rs +0 -275
  191. package/rust/cli/bank/mod.rs +0 -29
  192. package/rust/cli/install/bank.rs +0 -53
  193. package/rust/cli/install/commands.rs +0 -35
  194. package/rust/cli/install/mod.rs +0 -4
  195. package/rust/cli/install/plugin.rs +0 -61
  196. package/rust/core/audio/engine/sample.rs +0 -366
  197. package/rust/core/audio/engine/synth.rs +0 -325
  198. package/rust/core/audio/interpreter/arrow_call.rs +0 -311
  199. package/rust/core/audio/renderer.rs +0 -54
  200. package/rust/core/parser/driver.rs +0 -584
  201. package/rust/core/preprocessor/loader.rs +0 -637
  202. package/rust/core/store/export.rs +0 -28
  203. package/rust/core/store/function.rs +0 -40
  204. package/rust/core/store/import.rs +0 -28
  205. package/rust/core/store/variable.rs +0 -51
  206. package/rust/core/utils/mod.rs +0 -1
  207. package/rust/core/utils/path.rs +0 -37
@@ -1,88 +1,158 @@
1
- use std::{
2
- env, fs,
3
- path::{Path, PathBuf},
4
- };
5
-
6
- pub const DEVALANG_CONFIG: &str = ".devalang";
7
- pub const DEVA_DIR: &str = ".deva";
8
-
9
- /// Returns the current working directory.
10
- pub fn get_cwd() -> PathBuf {
11
- // In wasm (and some restricted environments) `env::current_dir()` is unsupported
12
- // and will return an error. Avoid panicking here and fall back to `.` so the
13
- // runtime can still operate in a virtual environment.
14
- env::current_dir().unwrap_or_else(|_| PathBuf::from("."))
15
- }
16
-
17
- /// Returns true if the given directory looks like a devalang project root.
18
- /// Preference is given to the presence of `.devalang` (config file),
19
- /// but falling back to a `.deva` directory is allowed.
20
- pub fn is_project_root(dir: &Path) -> bool {
21
- let config = dir.join(DEVALANG_CONFIG);
22
- if config.is_file() {
23
- return true;
24
- }
25
- let deva = dir.join(DEVA_DIR);
26
- deva.is_dir()
27
- }
28
-
29
- /// Walks upward from `start` to locate the first directory considered a project root.
30
- pub fn find_project_root_from(start: &Path) -> Option<PathBuf> {
31
- for ancestor in start.ancestors() {
32
- if is_project_root(ancestor) {
33
- return Some(ancestor.to_path_buf());
34
- }
35
- }
36
- None
37
- }
38
-
39
- /// Finds the project root from the current working directory.
40
- pub fn find_project_root() -> Option<PathBuf> {
41
- find_project_root_from(&get_cwd())
42
- }
43
-
44
- /// Finds the package root using the `CARGO_MANIFEST_DIR` env var set by Cargo.
45
- pub fn get_package_root() -> Option<PathBuf> {
46
- let cargo_dir = env::var("CARGO_MANIFEST_DIR").ok()?;
47
- Some(PathBuf::from(cargo_dir))
48
- }
49
-
50
- /// Gets the project root or returns a descriptive error if not found.
51
- pub fn get_project_root() -> Result<PathBuf, String> {
52
- find_project_root()
53
- .ok_or_else(|| "Project root not found. Run 'devalang init' in your project.".to_string())
54
- }
55
-
56
- /// Returns the path to `.devalang` in the project root, ensuring it exists.
57
- pub fn get_devalang_config_path() -> Result<PathBuf, String> {
58
- let root = get_project_root()?;
59
- let config_path = root.join(DEVALANG_CONFIG);
60
- if !config_path.exists() {
61
- return Err(format!(
62
- "Config file not found at '{}'. Please run 'devalang init' before continuing.",
63
- config_path.display()
64
- ));
65
- }
66
- Ok(config_path)
67
- }
68
-
69
- /// Returns the `.deva` directory inside the project root (without creating it).
70
- pub fn get_deva_dir() -> Result<PathBuf, String> {
71
- let root = get_project_root()?;
72
- Ok(root.join(DEVA_DIR))
73
- }
74
-
75
- /// Ensures the `.deva` directory exists in the project root and returns its path.
76
- pub fn ensure_deva_dir() -> Result<PathBuf, String> {
77
- let deva = get_deva_dir()?;
78
- if !deva.exists() {
79
- fs::create_dir_all(&deva).map_err(|e| {
80
- format!(
81
- "Failed to create Deva directory '{}': {}",
82
- deva.display(),
83
- e
84
- )
85
- })?;
86
- }
87
- Ok(deva)
88
- }
1
+ use std::{
2
+ env, fs,
3
+ path::{Path, PathBuf},
4
+ };
5
+
6
+ pub const DEVALANG_CONFIG: &str = ".devalang";
7
+ pub const DEVA_DIR: &str = ".deva";
8
+
9
+ /// Returns the current working directory.
10
+ pub fn get_cwd() -> PathBuf {
11
+ // In wasm (and some restricted environments) `env::current_dir()` is unsupported
12
+ // and will return an error. Avoid panicking here and fall back to `.` so the
13
+ // runtime can still operate in a virtual environment.
14
+ env::current_dir().unwrap_or_else(|_| PathBuf::from("."))
15
+ }
16
+
17
+ /// Returns true if the given directory looks like a devalang project root.
18
+ /// Preference is given to the presence of `.devalang` (config file),
19
+ /// but falling back to a `.deva` directory is allowed.
20
+ pub fn is_project_root(dir: &Path) -> bool {
21
+ let config = dir.join(DEVALANG_CONFIG);
22
+ if config.is_file() {
23
+ return true;
24
+ }
25
+ let deva = dir.join(DEVA_DIR);
26
+ deva.is_dir()
27
+ }
28
+
29
+ /// Walks upward from `start` to locate the first directory considered a project root.
30
+ pub fn find_project_root_from(start: &Path) -> Option<PathBuf> {
31
+ for ancestor in start.ancestors() {
32
+ if is_project_root(ancestor) {
33
+ return Some(ancestor.to_path_buf());
34
+ }
35
+ }
36
+ None
37
+ }
38
+
39
+ /// Finds the project root from the current working directory.
40
+ pub fn find_project_root() -> Option<PathBuf> {
41
+ find_project_root_from(&get_cwd())
42
+ }
43
+
44
+ /// Finds the package root using the `CARGO_MANIFEST_DIR` env var set by Cargo.
45
+ pub fn get_package_root() -> Option<PathBuf> {
46
+ // Prefer Cargo-provided manifest dir when available (build-time / cargo run)
47
+ if let Ok(cargo_dir) = env::var("CARGO_MANIFEST_DIR") {
48
+ let p = PathBuf::from(cargo_dir);
49
+ if p.exists() {
50
+ return Some(p);
51
+ }
52
+ }
53
+
54
+ // At runtime (packaged binary) try to infer the package root from the
55
+ // binary location: walk upward from the running executable and look for
56
+ // common markers (package.json, project-version.json, Cargo.toml).
57
+ if let Ok(exe_path) = env::current_exe() {
58
+ if let Some(mut dir) = exe_path.parent().map(|p| p.to_path_buf()) {
59
+ loop {
60
+ if dir.join("package.json").exists()
61
+ || dir.join("project-version.json").exists()
62
+ || dir.join("Cargo.toml").exists()
63
+ {
64
+ return Some(dir);
65
+ }
66
+
67
+ if let Some(parent) = dir.parent() {
68
+ dir = parent.to_path_buf();
69
+ } else {
70
+ break;
71
+ }
72
+ }
73
+ }
74
+ }
75
+
76
+ None
77
+ }
78
+
79
+ /// Gets the project root or returns a descriptive error if not found.
80
+ pub fn get_project_root() -> Result<PathBuf, String> {
81
+ find_project_root()
82
+ .ok_or_else(|| "Project root not found. Run 'devalang init' in your project.".to_string())
83
+ }
84
+
85
+ /// Returns the path to `.devalang` in the project root, ensuring it exists.
86
+ pub fn get_devalang_config_path() -> Result<PathBuf, String> {
87
+ let root = get_project_root()?;
88
+ let config_path = root.join(DEVALANG_CONFIG);
89
+ if !config_path.exists() {
90
+ return Err(format!(
91
+ "Config file not found at '{}'. Please run 'devalang init' before continuing.",
92
+ config_path.display()
93
+ ));
94
+ }
95
+ Ok(config_path)
96
+ }
97
+
98
+ /// Returns the `.deva` directory inside the project root (without creating it).
99
+ pub fn get_deva_dir() -> Result<PathBuf, String> {
100
+ let root = get_project_root()?;
101
+ Ok(root.join(DEVA_DIR))
102
+ }
103
+
104
+ /// Ensures the `.deva` directory exists in the project root and returns its path.
105
+ pub fn ensure_deva_dir() -> Result<PathBuf, String> {
106
+ let deva = get_deva_dir()?;
107
+ if !deva.exists() {
108
+ fs::create_dir_all(&deva).map_err(|e| {
109
+ format!(
110
+ "Failed to create Deva directory '{}': {}",
111
+ deva.display(),
112
+ e
113
+ )
114
+ })?;
115
+ }
116
+ Ok(deva)
117
+ }
118
+
119
+ /// Finds the entry file given a path, returning the normalized path if found.
120
+ /// If the path is a directory, it looks for `index.deva` inside it.
121
+ /// Returns None if no valid entry file is found.
122
+ pub fn find_entry_file(entry: &str) -> Option<String> {
123
+ let path = Path::new(entry);
124
+
125
+ if path.is_file() {
126
+ return Some(normalize_path(entry));
127
+ }
128
+
129
+ if path.is_dir() {
130
+ let candidate = path.join("index.deva");
131
+ if candidate.exists() {
132
+ return Some(normalize_path(&candidate));
133
+ }
134
+ }
135
+
136
+ None
137
+ }
138
+
139
+ /// Normalizes a path to use forward slashes and removes redundant components.
140
+ pub fn normalize_path<P: AsRef<Path>>(path: P) -> String {
141
+ let path_buf = PathBuf::from(path.as_ref());
142
+ path_buf
143
+ .components()
144
+ .collect::<PathBuf>()
145
+ .to_string_lossy()
146
+ .replace('\\', "/")
147
+ }
148
+
149
+ /// Resolves a relative import path against a base path, normalizing the result.
150
+ pub fn resolve_relative_path(base: &str, import: &str) -> String {
151
+ let base_path = Path::new(base).parent().unwrap_or_else(|| Path::new(""));
152
+ let full_path = base_path.join(import);
153
+ full_path
154
+ .components()
155
+ .collect::<PathBuf>()
156
+ .to_string_lossy()
157
+ .replace("\\", "/")
158
+ }
@@ -1,41 +1,41 @@
1
- #[cfg(feature = "cli")]
2
- pub fn get_signature(version: &str) -> String {
3
- let signature = format!(
4
- r#"
5
- /|_/|
6
- / ^ ^(_o 🦊 Devalang
7
- / __.'
8
- / \ A programming language for music and sound.
9
- / _ \_ Part of the Devaloop project.
10
- (_) (_) '._
11
- '.__ '. .-''-'. https://devalang.com
12
- ( '. ('.____.''
13
- _) )'_, ) v{}
14
- (__/ (__/
15
- "#,
16
- version
17
- );
18
-
19
- signature
20
- }
21
-
22
- #[cfg(not(feature = "cli"))]
23
- pub fn get_signature(version: &str) -> String {
24
- let signature = format!(
25
- r#"
26
- /|_/|
27
- / ^ ^(_o 🦊 Devalang
28
- / __.'
29
- / \ A programming language for music and sound.
30
- / _ \_ Part of the Devaloop project.
31
- (_) (_) '._
32
- '.__ '. .-''-'. https://devalang.com
33
- ( '. ('.____.''
34
- _) )'_, ) v{}
35
- (__/ (__/
36
- "#,
37
- version
38
- );
39
-
40
- signature
41
- }
1
+ #[cfg(feature = "cli")]
2
+ pub fn get_signature(version: &str) -> String {
3
+ let signature = format!(
4
+ r#"
5
+ /|_/|
6
+ / ^ ^(_o 🦊 Devalang
7
+ / __.'
8
+ / \ A programming language for music and sound.
9
+ / _ \_ Part of the Devaloop project.
10
+ (_) (_) '._
11
+ '.__ '. .-''-'. https://devalang.com
12
+ ( '. ('.____.''
13
+ _) )'_, ) v{}
14
+ (__/ (__/
15
+ "#,
16
+ version
17
+ );
18
+
19
+ signature
20
+ }
21
+
22
+ #[cfg(not(feature = "cli"))]
23
+ pub fn get_signature(version: &str) -> String {
24
+ let signature = format!(
25
+ r#"
26
+ /|_/|
27
+ / ^ ^(_o 🦊 Devalang
28
+ / __.'
29
+ / \ A programming language for music and sound.
30
+ / _ \_ Part of the Devaloop project.
31
+ (_) (_) '._
32
+ '.__ '. .-''-'. https://devalang.com
33
+ ( '. ('.____.''
34
+ _) )'_, ) v{}
35
+ (__/ (__/
36
+ "#,
37
+ version
38
+ );
39
+
40
+ signature
41
+ }
@@ -1,20 +1,20 @@
1
- #[cfg(feature = "cli")]
2
- use indicatif::{ProgressBar, ProgressStyle};
3
- #[cfg(feature = "cli")]
4
- use std::time::Duration;
5
-
6
- #[cfg(feature = "cli")]
7
- pub fn start_spinner(start_msg: &str) -> ProgressBar {
8
- let spinner = ProgressBar::new_spinner();
9
- spinner.set_style(
10
- ProgressStyle::with_template("{spinner:.green} {msg}")
11
- .unwrap()
12
- .tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]),
13
- );
14
- spinner.set_message(start_msg.to_string());
15
- spinner.enable_steady_tick(Duration::from_millis(80));
16
-
17
- std::thread::sleep(Duration::from_millis(750));
18
-
19
- spinner
20
- }
1
+ #[cfg(feature = "cli")]
2
+ use indicatif::{ProgressBar, ProgressStyle};
3
+ #[cfg(feature = "cli")]
4
+ use std::time::Duration;
5
+
6
+ #[cfg(feature = "cli")]
7
+ pub fn start_spinner(start_msg: &str) -> ProgressBar {
8
+ let spinner = ProgressBar::new_spinner();
9
+ spinner.set_style(
10
+ ProgressStyle::with_template("{spinner:.green} {msg}")
11
+ .unwrap()
12
+ .tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]),
13
+ );
14
+ spinner.set_message(start_msg.to_string());
15
+ spinner.enable_steady_tick(Duration::from_millis(80));
16
+
17
+ std::thread::sleep(Duration::from_millis(750));
18
+
19
+ spinner
20
+ }
@@ -1,27 +1,58 @@
1
- use crate::{path::get_package_root, signature::get_signature};
2
-
3
- pub fn get_version() -> String {
4
- if let Some(root) = get_package_root() {
5
- let project_version_json = root.join("project-version.json");
6
- if let Ok(version) = std::fs::read_to_string(project_version_json) {
7
- if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(&version) {
8
- if let Some(version_val) = parsed.get("version") {
9
- if let Some(s) = version_val.as_str() {
10
- return s.to_string();
11
- }
12
- }
13
- }
14
- }
15
- }
16
-
17
- "0.0.0".to_string()
18
- }
19
-
20
- pub fn get_version_with_signature() -> String {
21
- let version = get_version();
22
- let signature = get_signature(&version);
23
-
24
- println!("{}", signature);
25
-
26
- "(c) 2025 Devaloop. All rights reserved.".to_string()
27
- }
1
+ use crate::{ path::get_package_root, signature::get_signature };
2
+
3
+ /// Returns the CLI version with a runtime-first strategy:
4
+ /// 1. DEVALANG_CLI_VERSION env var
5
+ /// 2. project-version.json located next to the running binary
6
+ /// 3. package.json located in the package root
7
+ /// 4. compile-time env!("CARGO_PKG_VERSION") as a last resort
8
+ pub fn get_version() -> String {
9
+ // 1) env override
10
+ if let Ok(v) = std::env::var("DEVALANG_CLI_VERSION") {
11
+ if !v.trim().is_empty() {
12
+ return v;
13
+ }
14
+ }
15
+
16
+ // 2) project-version.json next to binary
17
+ if let Ok(exe) = std::env::current_exe() {
18
+ if let Some(bin_dir) = exe.parent() {
19
+ let pv = bin_dir.join("project-version.json");
20
+ if pv.exists() {
21
+ if let Ok(contents) = std::fs::read_to_string(pv) {
22
+ if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(&contents) {
23
+ if let Some(v) = parsed.get("version").and_then(|s| s.as_str()) {
24
+ return v.to_string();
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+
32
+ // 3) package.json via package root
33
+ if let Some(root) = get_package_root() {
34
+ let pkg = root.join("package.json");
35
+ if pkg.exists() {
36
+ if let Ok(contents) = std::fs::read_to_string(pkg) {
37
+ if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(&contents) {
38
+ if let Some(v) = parsed.get("version").and_then(|s| s.as_str()) {
39
+ return v.to_string();
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
45
+
46
+ // 4) compile-time fallback
47
+ let compile_time = option_env!("CARGO_PKG_VERSION").unwrap_or("0.0.0");
48
+ compile_time.to_string()
49
+ }
50
+
51
+ pub fn get_version_with_signature() -> String {
52
+ let version = get_version();
53
+ let signature = get_signature(&version);
54
+
55
+ println!("{}", signature);
56
+
57
+ "(c) 2025 Devaloop. All rights reserved.".to_string()
58
+ }
@@ -1,46 +1,46 @@
1
- use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
2
- use std::sync::mpsc::channel;
3
-
4
- use std::time::{Duration, Instant};
5
-
6
- pub fn watch_directory<F>(entry: String, callback: F) -> notify::Result<()>
7
- where
8
- F: Fn() + Send + 'static,
9
- {
10
- let (tx, rx) = channel();
11
-
12
- let mut watcher: RecommendedWatcher = Watcher::new(tx, Config::default())?;
13
- watcher.watch(&entry.as_ref(), RecursiveMode::Recursive)?;
14
-
15
- let mut last_trigger = Instant::now();
16
-
17
- loop {
18
- match rx.recv() {
19
- Ok(_) => {
20
- let now = Instant::now();
21
- if now.duration_since(last_trigger) > Duration::from_millis(200) {
22
- callback();
23
- last_trigger = now;
24
- }
25
- }
26
- Err(e) => {
27
- // Prefer structured logging when available
28
- #[cfg(feature = "cli")]
29
- {
30
- let logger = crate::logger::Logger::new();
31
- logger.log_message(
32
- crate::logger::LogLevel::Error,
33
- &format!("Channel error: {:?}", e),
34
- );
35
- }
36
- #[cfg(not(feature = "cli"))]
37
- {
38
- eprintln!("Channel error: {:?}", e);
39
- }
40
- break;
41
- }
42
- }
43
- }
44
-
45
- Ok(())
46
- }
1
+ use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
2
+ use std::sync::mpsc::channel;
3
+
4
+ use std::time::{Duration, Instant};
5
+
6
+ pub fn watch_directory<F>(entry: String, callback: F) -> notify::Result<()>
7
+ where
8
+ F: Fn() + Send + 'static,
9
+ {
10
+ let (tx, rx) = channel();
11
+
12
+ let mut watcher: RecommendedWatcher = Watcher::new(tx, Config::default())?;
13
+ watcher.watch(&entry.as_ref(), RecursiveMode::Recursive)?;
14
+
15
+ let mut last_trigger = Instant::now();
16
+
17
+ loop {
18
+ match rx.recv() {
19
+ Ok(_) => {
20
+ let now = Instant::now();
21
+ if now.duration_since(last_trigger) > Duration::from_millis(200) {
22
+ callback();
23
+ last_trigger = now;
24
+ }
25
+ }
26
+ Err(e) => {
27
+ // Prefer structured logging when available
28
+ #[cfg(feature = "cli")]
29
+ {
30
+ let logger = crate::logger::Logger::new();
31
+ logger.log_message(
32
+ crate::logger::LogLevel::Error,
33
+ &format!("Channel error: {:?}", e),
34
+ );
35
+ }
36
+ #[cfg(not(feature = "cli"))]
37
+ {
38
+ eprintln!("Channel error: {:?}", e);
39
+ }
40
+ break;
41
+ }
42
+ }
43
+ }
44
+
45
+ Ok(())
46
+ }
package/rust/web/api.rs CHANGED
@@ -1,5 +1,5 @@
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
+ 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
+ }
@@ -0,0 +1,5 @@
1
+ pub fn get_auth_url() -> String {
2
+ let auth_url = "https://auth.devalang.com";
3
+ // let auth_url = "http://127.0.0.1:8787";
4
+ auth_url.to_string()
5
+ }
package/rust/web/cdn.rs CHANGED
@@ -1,34 +1,34 @@
1
- use std::error::Error;
2
- use std::fs::File;
3
- use std::io::{Cursor, copy};
4
- use std::path::Path;
5
-
6
- pub fn get_cdn_url() -> String {
7
- let cdn_url = "https://cdn.devalang.com";
8
- // let cdn_url = "http://127.0.0.1:8888";
9
- cdn_url.to_string()
10
- }
11
-
12
- pub async fn download_from_cdn(url: &str, destination: &Path) -> Result<(), Box<dyn Error>> {
13
- if !url.starts_with(&get_cdn_url()) {
14
- return Err(format!("Invalid CDN URL: {}", url).into());
15
- }
16
-
17
- let response = reqwest::get(url).await?;
18
-
19
- if !response.status().is_success() {
20
- return Err(format!("Failed to download file: HTTP {}", response.status()).into());
21
- }
22
-
23
- if let Some(parent) = destination.parent() {
24
- std::fs::create_dir_all(parent)?;
25
- }
26
-
27
- let bytes = response.bytes().await?;
28
- let mut content = Cursor::new(bytes);
29
- let mut file = File::create(destination)?;
30
-
31
- copy(&mut content, &mut file)?;
32
-
33
- Ok(())
34
- }
1
+ use std::error::Error;
2
+ use std::fs::File;
3
+ use std::io::{Cursor, copy};
4
+ use std::path::Path;
5
+
6
+ pub fn get_cdn_url() -> String {
7
+ let cdn_url = "https://cdn.devalang.com";
8
+ // let cdn_url = "http://127.0.0.1:8888";
9
+ cdn_url.to_string()
10
+ }
11
+
12
+ pub async fn download_from_cdn(url: &str, destination: &Path) -> Result<(), Box<dyn Error>> {
13
+ if !url.starts_with(&get_cdn_url()) {
14
+ return Err(format!("Invalid CDN URL: {}", url).into());
15
+ }
16
+
17
+ let response = reqwest::get(url).await?;
18
+
19
+ if !response.status().is_success() {
20
+ return Err(format!("Failed to download file: HTTP {}", response.status()).into());
21
+ }
22
+
23
+ if let Some(parent) = destination.parent() {
24
+ std::fs::create_dir_all(parent)?;
25
+ }
26
+
27
+ let bytes = response.bytes().await?;
28
+ let mut content = Cursor::new(bytes);
29
+ let mut file = File::create(destination)?;
30
+
31
+ copy(&mut content, &mut file)?;
32
+
33
+ Ok(())
34
+ }
@@ -0,0 +1,5 @@
1
+ pub fn get_forge_api_url() -> String {
2
+ let forge_url = "https://forge.devalang.com";
3
+ // let forge_url = "http://127.0.0.1:9090";
4
+ forge_url.to_string()
5
+ }
package/rust/web/mod.rs CHANGED
@@ -1,3 +1,5 @@
1
1
  pub mod api;
2
+ pub mod auth;
2
3
  pub mod cdn;
4
+ pub mod forge;
3
5
  pub mod sso;