@devaloop/devalang 0.0.1-alpha.9 → 0.0.1-beta.2

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 (322) hide show
  1. package/.cargo/config.toml +2 -0
  2. package/.devalang +6 -1
  3. package/.github/workflows/ci.yml +103 -0
  4. package/Cargo.toml +81 -48
  5. package/README.md +137 -154
  6. package/docs/CHANGELOG.md +428 -1
  7. package/docs/CONTRIBUTING.md +101 -0
  8. package/docs/ROADMAP.md +14 -7
  9. package/docs/TODO.md +16 -15
  10. package/examples/automation.deva +42 -0
  11. package/examples/bank.deva +7 -0
  12. package/examples/bus.deva +10 -0
  13. package/examples/duration.deva +9 -0
  14. package/examples/effect.deva +2 -0
  15. package/examples/events.deva +12 -0
  16. package/examples/filter.deva +11 -0
  17. package/examples/function.deva +15 -0
  18. package/examples/index.deva +57 -12
  19. package/examples/lfo.deva +9 -0
  20. package/examples/loop.deva +5 -12
  21. package/examples/pattern.deva +8 -0
  22. package/examples/plugin.deva +16 -0
  23. package/examples/synth.deva +11 -1
  24. package/examples/synth_types.deva +17 -0
  25. package/examples/variables.deva +1 -1
  26. package/out-tsc/bin/index.d.ts +2 -0
  27. package/out-tsc/bin/index.js +51 -7
  28. package/out-tsc/core/functions/index.d.ts +42 -0
  29. package/out-tsc/core/functions/index.js +87 -0
  30. package/out-tsc/core/index.d.ts +6 -0
  31. package/out-tsc/core/index.js +22 -0
  32. package/out-tsc/core/types/index.d.ts +4 -0
  33. package/out-tsc/core/types/index.js +20 -0
  34. package/out-tsc/core/types/plugin.d.ts +18 -0
  35. package/out-tsc/core/types/plugin.js +2 -0
  36. package/out-tsc/core/types/result.d.ts +27 -0
  37. package/out-tsc/core/types/result.js +2 -0
  38. package/out-tsc/core/types/statement.d.ts +106 -0
  39. package/out-tsc/core/types/statement.js +2 -0
  40. package/out-tsc/core/types/value.d.ts +43 -0
  41. package/out-tsc/core/types/value.js +2 -0
  42. package/out-tsc/index.d.ts +7 -0
  43. package/out-tsc/index.js +42 -1
  44. package/out-tsc/pkg/devalang_core.d.ts +15 -0
  45. package/out-tsc/pkg/devalang_core.js +65 -0
  46. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +34 -0
  47. package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
  48. package/out-tsc/scripts/copy-wasm-dts.js +73 -0
  49. package/out-tsc/scripts/postinstall.d.ts +1 -0
  50. package/out-tsc/scripts/postinstall.js +83 -0
  51. package/out-tsc/scripts/version/bump.d.ts +1 -0
  52. package/out-tsc/scripts/version/fetch.d.ts +1 -0
  53. package/out-tsc/scripts/version/index.d.ts +1 -0
  54. package/out-tsc/scripts/version/sync.d.ts +1 -0
  55. package/package.json +28 -7
  56. package/project-version.json +4 -4
  57. package/rust/cli/bank/api.rs +122 -0
  58. package/rust/cli/bank/commands.rs +306 -0
  59. package/rust/cli/bank/mod.rs +29 -0
  60. package/rust/cli/build/commands.rs +153 -0
  61. package/rust/cli/build/mod.rs +2 -0
  62. package/rust/cli/build/process.rs +165 -0
  63. package/rust/cli/check/mod.rs +208 -0
  64. package/rust/cli/discover/commands.rs +253 -0
  65. package/rust/cli/discover/config.rs +111 -0
  66. package/rust/cli/discover/fs.rs +19 -0
  67. package/rust/cli/discover/install.rs +103 -0
  68. package/rust/cli/discover/metadata.rs +48 -0
  69. package/rust/cli/discover/mod.rs +5 -0
  70. package/rust/cli/{init.rs → init/commands.rs} +32 -23
  71. package/rust/cli/init/mod.rs +1 -0
  72. package/rust/cli/install/addon.rs +118 -0
  73. package/rust/cli/install/bank.rs +72 -0
  74. package/rust/cli/install/commands.rs +35 -0
  75. package/rust/cli/install/mod.rs +4 -0
  76. package/rust/cli/install/plugin.rs +80 -0
  77. package/rust/cli/login/commands.rs +124 -0
  78. package/rust/cli/login/mod.rs +1 -0
  79. package/rust/cli/mod.rs +9 -202
  80. package/rust/cli/parser.rs +359 -0
  81. package/rust/cli/play/commands.rs +375 -0
  82. package/rust/cli/play/io.rs +17 -0
  83. package/rust/cli/play/mod.rs +5 -0
  84. package/rust/cli/play/process.rs +159 -0
  85. package/rust/cli/play/realtime.rs +91 -0
  86. package/rust/cli/play/utils.rs +23 -0
  87. package/rust/cli/telemetry/commands.rs +22 -0
  88. package/rust/cli/telemetry/event_creator.rs +80 -0
  89. package/rust/cli/telemetry/mod.rs +3 -0
  90. package/rust/cli/telemetry/send.rs +51 -0
  91. package/rust/cli/{template.rs → template/commands.rs} +17 -5
  92. package/rust/cli/template/mod.rs +1 -0
  93. package/rust/cli/update/commands.rs +6 -0
  94. package/rust/cli/update/mod.rs +1 -0
  95. package/rust/config/driver.rs +112 -0
  96. package/rust/config/mod.rs +3 -16
  97. package/rust/config/ops.rs +26 -0
  98. package/rust/config/settings.rs +101 -0
  99. package/rust/core/audio/engine/driver.rs +220 -0
  100. package/rust/core/audio/engine/export.rs +169 -0
  101. package/rust/core/audio/engine/helpers.rs +178 -0
  102. package/rust/core/audio/engine/mod.rs +56 -0
  103. package/rust/core/audio/engine/notes/dsp.rs +85 -0
  104. package/rust/core/audio/engine/notes/mod.rs +44 -0
  105. package/rust/core/audio/engine/notes/params.rs +294 -0
  106. package/rust/core/audio/engine/sample/insert.rs +199 -0
  107. package/rust/core/audio/engine/sample/mod.rs +40 -0
  108. package/rust/core/audio/engine/sample/padding.rs +170 -0
  109. package/rust/core/audio/evaluator/condition.rs +61 -0
  110. package/rust/core/audio/evaluator/mod.rs +9 -0
  111. package/rust/core/audio/evaluator/numeric.rs +152 -0
  112. package/rust/core/audio/evaluator/rhs.rs +16 -0
  113. package/rust/core/audio/evaluator/string_expr.rs +94 -0
  114. package/rust/core/audio/interpreter/driver.rs +574 -216
  115. package/rust/core/audio/interpreter/mod.rs +2 -12
  116. package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +175 -0
  117. package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +384 -0
  118. package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +2 -0
  119. package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +316 -0
  120. package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +3 -0
  121. package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +192 -0
  122. package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +24 -0
  123. package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +116 -0
  124. package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +97 -0
  125. package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +100 -0
  126. package/rust/core/audio/interpreter/statements/automate.rs +16 -0
  127. package/rust/core/audio/interpreter/statements/call.rs +295 -0
  128. package/rust/core/audio/interpreter/{condition.rs → statements/condition.rs} +72 -69
  129. package/rust/core/audio/interpreter/statements/function.rs +24 -0
  130. package/rust/core/audio/interpreter/statements/let_.rs +36 -0
  131. package/rust/core/audio/interpreter/statements/load.rs +17 -0
  132. package/rust/core/audio/interpreter/statements/loop_.rs +115 -0
  133. package/rust/core/audio/interpreter/statements/mod.rs +12 -0
  134. package/rust/core/audio/interpreter/statements/sleep.rs +28 -0
  135. package/rust/core/audio/interpreter/statements/spawn.rs +253 -0
  136. package/rust/core/audio/interpreter/statements/tempo.rs +40 -0
  137. package/rust/core/audio/interpreter/statements/trigger.rs +239 -0
  138. package/rust/core/audio/loader/mod.rs +1 -1
  139. package/rust/core/audio/loader/trigger.rs +98 -52
  140. package/rust/core/audio/mod.rs +2 -2
  141. package/rust/core/audio/player.rs +28 -12
  142. package/rust/core/audio/special/easing.rs +189 -0
  143. package/rust/core/audio/special/env.rs +45 -0
  144. package/rust/core/audio/special/math.rs +134 -0
  145. package/rust/core/audio/special/mod.rs +9 -0
  146. package/rust/core/audio/special/modulator.rs +143 -0
  147. package/rust/core/builder/mod.rs +129 -80
  148. package/rust/core/debugger/lexer.rs +4 -4
  149. package/rust/core/debugger/logs.rs +52 -0
  150. package/rust/core/debugger/mod.rs +11 -2
  151. package/rust/core/debugger/preprocessor.rs +4 -4
  152. package/rust/core/debugger/store.rs +38 -25
  153. package/rust/core/error/mod.rs +221 -12
  154. package/rust/core/lexer/driver.rs +59 -0
  155. package/rust/core/lexer/handler/arrow.rs +62 -11
  156. package/rust/core/lexer/handler/at.rs +5 -5
  157. package/rust/core/lexer/handler/brace.rs +11 -11
  158. package/rust/core/lexer/handler/colon.rs +5 -5
  159. package/rust/core/lexer/handler/comment.rs +3 -3
  160. package/rust/core/lexer/handler/dot.rs +6 -6
  161. package/rust/core/lexer/handler/driver.rs +143 -32
  162. package/rust/core/lexer/handler/identifier.rs +11 -5
  163. package/rust/core/lexer/handler/indent.rs +18 -4
  164. package/rust/core/lexer/handler/mod.rs +6 -5
  165. package/rust/core/lexer/handler/newline.rs +3 -3
  166. package/rust/core/lexer/handler/number.rs +5 -5
  167. package/rust/core/lexer/handler/operator.rs +5 -3
  168. package/rust/core/lexer/handler/parenthesis.rs +41 -0
  169. package/rust/core/lexer/handler/slash.rs +21 -0
  170. package/rust/core/lexer/handler/string.rs +3 -3
  171. package/rust/core/lexer/mod.rs +1 -49
  172. package/rust/core/lexer/token.rs +17 -12
  173. package/rust/core/mod.rs +9 -10
  174. package/rust/core/parser/driver/block.rs +111 -0
  175. package/rust/core/parser/driver/cursor.rs +82 -0
  176. package/rust/core/parser/driver/driver_impl.rs +139 -0
  177. package/rust/core/parser/driver/mod.rs +6 -0
  178. package/rust/core/parser/driver/parse_array.rs +120 -0
  179. package/rust/core/parser/driver/parse_map.rs +223 -0
  180. package/rust/core/parser/driver/parser.rs +160 -0
  181. package/rust/core/parser/handler/arrow_call.rs +277 -126
  182. package/rust/core/parser/handler/at.rs +142 -25
  183. package/rust/core/parser/handler/bank.rs +83 -20
  184. package/rust/core/parser/handler/condition.rs +14 -5
  185. package/rust/core/parser/handler/dot.rs +111 -75
  186. package/rust/core/parser/handler/identifier/automate.rs +254 -0
  187. package/rust/core/parser/handler/identifier/call.rs +74 -24
  188. package/rust/core/parser/handler/identifier/emit.rs +70 -0
  189. package/rust/core/parser/handler/identifier/function.rs +113 -0
  190. package/rust/core/parser/handler/identifier/group.rs +28 -14
  191. package/rust/core/parser/handler/identifier/let_.rs +61 -21
  192. package/rust/core/parser/handler/identifier/mod.rs +24 -20
  193. package/rust/core/parser/handler/identifier/on.rs +107 -0
  194. package/rust/core/parser/handler/identifier/print.rs +49 -0
  195. package/rust/core/parser/handler/identifier/sleep.rs +77 -14
  196. package/rust/core/parser/handler/identifier/spawn.rs +81 -31
  197. package/rust/core/parser/handler/identifier/synth.rs +102 -32
  198. package/rust/core/parser/handler/loop_.rs +144 -22
  199. package/rust/core/parser/handler/mod.rs +6 -5
  200. package/rust/core/parser/handler/pattern.rs +74 -0
  201. package/rust/core/parser/handler/tempo.rs +67 -9
  202. package/rust/core/parser/mod.rs +3 -4
  203. package/rust/core/parser/statement.rs +6 -92
  204. package/rust/core/plugin/loader.rs +137 -0
  205. package/rust/core/plugin/mod.rs +2 -0
  206. package/rust/core/plugin/runner/mod.rs +11 -0
  207. package/rust/core/plugin/runner/non_wasm.rs +297 -0
  208. package/rust/core/plugin/runner/wasm32.rs +43 -0
  209. package/rust/core/preprocessor/loader/inject.rs +278 -0
  210. package/rust/core/preprocessor/loader/loader_helpers.rs +110 -0
  211. package/rust/core/preprocessor/loader/mod.rs +235 -0
  212. package/rust/core/preprocessor/mod.rs +4 -4
  213. package/rust/core/preprocessor/module.rs +55 -50
  214. package/rust/core/preprocessor/processor/handlers.rs +107 -0
  215. package/rust/core/preprocessor/processor/mod.rs +1 -0
  216. package/rust/core/preprocessor/resolver/bank.rs +14 -12
  217. package/rust/core/preprocessor/resolver/call.rs +106 -105
  218. package/rust/core/preprocessor/resolver/condition.rs +13 -10
  219. package/rust/core/preprocessor/resolver/driver.rs +145 -48
  220. package/rust/core/preprocessor/resolver/function.rs +69 -0
  221. package/rust/core/preprocessor/resolver/group.rs +122 -61
  222. package/rust/core/preprocessor/resolver/let_.rs +13 -12
  223. package/rust/core/preprocessor/resolver/loop_.rs +240 -13
  224. package/rust/core/preprocessor/resolver/mod.rs +8 -6
  225. package/rust/core/preprocessor/resolver/pattern.rs +83 -0
  226. package/rust/core/preprocessor/resolver/spawn.rs +83 -42
  227. package/rust/core/preprocessor/resolver/synth.rs +15 -11
  228. package/rust/core/preprocessor/resolver/tempo.rs +13 -14
  229. package/rust/core/preprocessor/resolver/trigger.rs +32 -28
  230. package/rust/core/preprocessor/resolver/value.rs +111 -13
  231. package/rust/core/store/global.rs +57 -39
  232. package/rust/core/store/mod.rs +0 -3
  233. package/rust/lib.rs +323 -117
  234. package/rust/main.rs +388 -65
  235. package/rust/types/Cargo.toml +11 -0
  236. package/rust/types/src/addons.rs +55 -0
  237. package/rust/types/src/ast.rs +202 -0
  238. package/rust/types/src/config.rs +84 -0
  239. package/rust/types/src/lib.rs +15 -0
  240. package/rust/types/src/plugin.rs +20 -0
  241. package/rust/types/src/store.rs +139 -0
  242. package/rust/types/src/telemetry.rs +85 -0
  243. package/rust/utils/Cargo.toml +26 -0
  244. package/rust/utils/src/error.rs +186 -0
  245. package/rust/utils/src/file.rs +94 -0
  246. package/rust/utils/src/first_usage.rs +97 -0
  247. package/rust/utils/{mod.rs → src/lib.rs} +6 -3
  248. package/rust/utils/{logger.rs → src/logger.rs} +94 -17
  249. package/rust/utils/src/path.rs +129 -0
  250. package/rust/utils/src/signature.rs +41 -0
  251. package/rust/utils/{spinner.rs → src/spinner.rs} +7 -8
  252. package/rust/utils/src/version.rs +27 -0
  253. package/rust/utils/{watcher.rs → src/watcher.rs} +17 -4
  254. package/rust/web/api.rs +5 -0
  255. package/rust/web/cdn.rs +34 -0
  256. package/rust/web/mod.rs +3 -0
  257. package/rust/web/sso.rs +5 -0
  258. package/templates/minimal/README.md +143 -127
  259. package/templates/welcome/README.md +143 -127
  260. package/templates/welcome/src/index.deva +56 -8
  261. package/templates/welcome/src/variables.deva +2 -4
  262. package/tests/integration.rs +21 -0
  263. package/tests/rust/cli_check_build.rs +21 -0
  264. package/tests/rust/cli_help.rs +12 -0
  265. package/tests/rust/cli_template_list.rs +10 -0
  266. package/tests/rust/cli_version.rs +11 -0
  267. package/tests/typescript/index.spec.ts +136 -0
  268. package/tests/typescript/playhead.spec.ts +36 -0
  269. package/tests/typescript/render_e2e.spec.ts +77 -0
  270. package/tsconfig.json +12 -10
  271. package/typescript/bin/index.ts +19 -5
  272. package/typescript/core/functions/index.ts +94 -0
  273. package/typescript/core/index.ts +6 -0
  274. package/typescript/core/types/index.ts +4 -0
  275. package/typescript/core/types/plugin.ts +19 -0
  276. package/typescript/core/types/result.ts +29 -0
  277. package/typescript/core/types/statement.ts +47 -0
  278. package/typescript/core/types/value.ts +29 -0
  279. package/typescript/index.ts +8 -1
  280. package/typescript/pkg/devalang_core.d.ts +4 -0
  281. package/typescript/pkg/devalang_core.ts +65 -0
  282. package/typescript/scripts/copy-wasm-dts.ts +41 -0
  283. package/typescript/scripts/postinstall.ts +85 -0
  284. package/typescript/scripts/version/bump.ts +0 -1
  285. package/typescript/scripts/version/index.ts +0 -1
  286. package/docs/COMMANDS.md +0 -85
  287. package/docs/CONFIG.md +0 -30
  288. package/docs/SYNTAX.md +0 -210
  289. package/out-tsc/bin/devalang.exe +0 -0
  290. package/out-tsc/scripts/postbuild.js +0 -11
  291. package/rust/cli/build.rs +0 -137
  292. package/rust/cli/check.rs +0 -117
  293. package/rust/cli/play.rs +0 -193
  294. package/rust/config/loader.rs +0 -13
  295. package/rust/core/audio/engine.rs +0 -203
  296. package/rust/core/audio/evaluator.rs +0 -31
  297. package/rust/core/audio/interpreter/arrow_call.rs +0 -129
  298. package/rust/core/audio/interpreter/call.rs +0 -64
  299. package/rust/core/audio/interpreter/let_.rs +0 -19
  300. package/rust/core/audio/interpreter/load.rs +0 -18
  301. package/rust/core/audio/interpreter/loop_.rs +0 -67
  302. package/rust/core/audio/interpreter/sleep.rs +0 -36
  303. package/rust/core/audio/interpreter/spawn.rs +0 -66
  304. package/rust/core/audio/interpreter/tempo.rs +0 -16
  305. package/rust/core/audio/interpreter/trigger.rs +0 -69
  306. package/rust/core/audio/renderer.rs +0 -54
  307. package/rust/core/parser/driver.rs +0 -331
  308. package/rust/core/preprocessor/loader.rs +0 -193
  309. package/rust/core/preprocessor/processor.rs +0 -76
  310. package/rust/core/shared/duration.rs +0 -8
  311. package/rust/core/shared/mod.rs +0 -2
  312. package/rust/core/shared/value.rs +0 -18
  313. package/rust/core/store/export.rs +0 -28
  314. package/rust/core/store/import.rs +0 -28
  315. package/rust/core/store/variable.rs +0 -28
  316. package/rust/core/utils/mod.rs +0 -2
  317. package/rust/core/utils/path.rs +0 -31
  318. package/rust/core/utils/validation.rs +0 -37
  319. package/rust/utils/file.rs +0 -35
  320. package/rust/utils/signature.rs +0 -17
  321. package/rust/utils/version.rs +0 -15
  322. package/typescript/scripts/postbuild.ts +0 -8
@@ -0,0 +1,186 @@
1
+ use super::logger::{LogLevel, Logger};
2
+ use devalang_types::{ErrorResult, Severity, StackFrame, Statement, StatementKind, Value};
3
+ use std::collections::HashMap;
4
+
5
+ pub fn collect_errors_recursively(statements: &[Statement]) -> Vec<ErrorResult> {
6
+ let mut errors: Vec<ErrorResult> = Vec::new();
7
+
8
+ for stmt in statements {
9
+ match &stmt.kind {
10
+ StatementKind::Unknown => {
11
+ errors.push(ErrorResult {
12
+ message: format!("Unknown statement at line {}:{}", stmt.line, stmt.column),
13
+ line: stmt.line,
14
+ column: stmt.column,
15
+ severity: Severity::Warning,
16
+ stack: vec![StackFrame {
17
+ module: None,
18
+ context: Some("Unknown".to_string()),
19
+ line: stmt.line,
20
+ column: stmt.column,
21
+ }],
22
+ });
23
+ }
24
+ StatementKind::Error { message } => {
25
+ errors.push(ErrorResult {
26
+ message: message.clone(),
27
+ line: stmt.line,
28
+ column: stmt.column,
29
+ severity: Severity::Critical,
30
+ stack: vec![StackFrame {
31
+ module: None,
32
+ context: Some("Error".to_string()),
33
+ line: stmt.line,
34
+ column: stmt.column,
35
+ }],
36
+ });
37
+ }
38
+ StatementKind::Loop => {
39
+ if let Some(body_statements) = extract_loop_body_statements(&stmt.value) {
40
+ let nested = collect_errors_recursively(body_statements);
41
+ errors.extend(nested.into_iter().map(|mut e| {
42
+ e.stack.insert(
43
+ 0,
44
+ StackFrame {
45
+ module: None,
46
+ context: Some("loop".to_string()),
47
+ line: stmt.line,
48
+ column: stmt.column,
49
+ },
50
+ );
51
+ e
52
+ }));
53
+ }
54
+ }
55
+ _ => {}
56
+ }
57
+ }
58
+
59
+ errors
60
+ }
61
+
62
+ fn extract_loop_body_statements(value: &Value) -> Option<&[Statement]> {
63
+ if let Value::Map(map) = value {
64
+ if let Some(Value::Block(statements)) = map.get("body") {
65
+ return Some(statements);
66
+ }
67
+ }
68
+ None
69
+ }
70
+
71
+ pub fn partition_errors(errors: Vec<ErrorResult>) -> (Vec<ErrorResult>, Vec<ErrorResult>) {
72
+ let mut warnings = Vec::new();
73
+ let mut criticals = Vec::new();
74
+ for e in errors {
75
+ match e.severity {
76
+ Severity::Warning => warnings.push(e),
77
+ Severity::Critical => criticals.push(e),
78
+ }
79
+ }
80
+ (warnings, criticals)
81
+ }
82
+
83
+ pub fn log_errors_with_stack(prefix: &str, warnings: &[ErrorResult], criticals: &[ErrorResult]) {
84
+ let logger = Logger::new();
85
+ if !warnings.is_empty() {
86
+ logger.log_message(
87
+ LogLevel::Warning,
88
+ &format!("{}: {} warning(s)", prefix, warnings.len()),
89
+ );
90
+ for w in warnings {
91
+ logger.log_message(LogLevel::Warning, &format!("- {}", w.message));
92
+ if let Some(frame) = w.stack.first() {
93
+ let module = frame.module.clone().unwrap_or_default();
94
+ logger.log_message(
95
+ LogLevel::Debug,
96
+ &format!(
97
+ " ↳ {}:{}:{} {}",
98
+ module,
99
+ frame.line,
100
+ frame.column,
101
+ frame.context.clone().unwrap_or_default()
102
+ ),
103
+ );
104
+ }
105
+ if w.stack.len() > 1 {
106
+ for (i, f) in w.stack.iter().enumerate().skip(1) {
107
+ let module = f.module.clone().unwrap_or_default();
108
+ logger.log_message(
109
+ LogLevel::Debug,
110
+ &format!(
111
+ " #{} {}:{}:{} {}",
112
+ i,
113
+ module,
114
+ f.line,
115
+ f.column,
116
+ f.context.clone().unwrap_or_default()
117
+ ),
118
+ );
119
+ }
120
+ }
121
+ }
122
+ }
123
+ if !criticals.is_empty() {
124
+ logger.log_message(
125
+ LogLevel::Error,
126
+ &format!("{}: {} critical error(s)", prefix, criticals.len()),
127
+ );
128
+ for c in criticals {
129
+ logger.log_message(LogLevel::Error, &format!("- {}", c.message));
130
+ if let Some(frame) = c.stack.first() {
131
+ let module = frame.module.clone().unwrap_or_default();
132
+ logger.log_message(
133
+ LogLevel::Error,
134
+ &format!(
135
+ " ↳ {}:{}:{} {}",
136
+ module,
137
+ frame.line,
138
+ frame.column,
139
+ frame.context.clone().unwrap_or_default()
140
+ ),
141
+ );
142
+ }
143
+ if c.stack.len() > 1 {
144
+ for (i, f) in c.stack.iter().enumerate().skip(1) {
145
+ let module = f.module.clone().unwrap_or_default();
146
+ logger.log_message(
147
+ LogLevel::Error,
148
+ &format!(
149
+ " #{} {}:{}:{} {}",
150
+ i,
151
+ module,
152
+ f.line,
153
+ f.column,
154
+ f.context.clone().unwrap_or_default()
155
+ ),
156
+ );
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ pub fn collect_all_errors_with_modules(
164
+ modules: &HashMap<String, Vec<Statement>>,
165
+ ) -> Vec<ErrorResult> {
166
+ let mut all = Vec::new();
167
+ for (module_path, stmts) in modules {
168
+ let mut errs = collect_errors_recursively(stmts);
169
+ for e in errs.iter_mut() {
170
+ if e.stack.is_empty() {
171
+ e.stack.push(StackFrame {
172
+ module: Some(module_path.clone()),
173
+ context: None,
174
+ line: e.line,
175
+ column: e.column,
176
+ });
177
+ } else {
178
+ if e.stack[0].module.is_none() {
179
+ e.stack[0].module = Some(module_path.clone());
180
+ }
181
+ }
182
+ }
183
+ all.extend(errs);
184
+ }
185
+ all
186
+ }
@@ -0,0 +1,94 @@
1
+ use include_dir::{Dir, DirEntry};
2
+ use std::{fs, path::Path};
3
+
4
+ pub fn copy_dir_recursive(dir: &Dir, target_root: &Path, base_path: &Path) {
5
+ for entry in dir.entries() {
6
+ match entry {
7
+ DirEntry::Dir(subdir) => {
8
+ copy_dir_recursive(subdir, target_root, base_path);
9
+ }
10
+ DirEntry::File(file) => {
11
+ // Compute the destination path relative to the provided base.
12
+ let rel_path = match file.path().strip_prefix(base_path) {
13
+ Ok(p) => p.to_owned(),
14
+ Err(_) => {
15
+ eprintln!(
16
+ "Warning: failed to compute relative path for {:?}, skipping",
17
+ file.path()
18
+ );
19
+ continue;
20
+ }
21
+ };
22
+
23
+ let dest_path = target_root.join(rel_path);
24
+
25
+ if let Some(parent) = dest_path.parent() {
26
+ if let Err(e) = fs::create_dir_all(parent) {
27
+ eprintln!(
28
+ "Warning: failed to create directory {}: {}",
29
+ parent.display(),
30
+ e
31
+ );
32
+ continue;
33
+ }
34
+ }
35
+
36
+ if let Err(e) = fs::write(&dest_path, file.contents()) {
37
+ eprintln!("Warning: failed to write {}: {}", dest_path.display(), e);
38
+ continue;
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+ pub fn format_file_size(bytes: u64) -> String {
46
+ const KB: u64 = 1024;
47
+ const MB: u64 = 1024 * 1024;
48
+
49
+ if bytes >= MB {
50
+ format!("{:.2} Mb", (bytes as f64) / (MB as f64))
51
+ } else if bytes >= KB {
52
+ format!("{:.2} Kb", (bytes as f64) / (KB as f64))
53
+ } else {
54
+ format!("{} bytes", bytes)
55
+ }
56
+ }
57
+
58
+ pub fn extract_zip_safely(archive_path: &Path, dest: &Path) -> Result<(), String> {
59
+ let file = std::fs::File::open(archive_path)
60
+ .map_err(|e| format!("Failed to open archive {}: {}", archive_path.display(), e))?;
61
+ let mut archive = zip::ZipArchive::new(file)
62
+ .map_err(|e| format!("Failed to read archive {}: {}", archive_path.display(), e))?;
63
+
64
+ for i in 0..archive.len() {
65
+ let mut file = archive
66
+ .by_index(i)
67
+ .map_err(|e| format!("Failed to access archive entry {}: {}", i, e))?;
68
+
69
+ let enclosed = match file.enclosed_name() {
70
+ Some(path) => path.to_owned(),
71
+ None => {
72
+ continue;
73
+ }
74
+ };
75
+
76
+ let outpath = dest.join(enclosed);
77
+
78
+ if file.name().ends_with('/') || file.is_dir() {
79
+ std::fs::create_dir_all(&outpath)
80
+ .map_err(|e| format!("Failed to create dir {}: {}", outpath.display(), e))?;
81
+ } else {
82
+ if let Some(p) = outpath.parent() {
83
+ std::fs::create_dir_all(p)
84
+ .map_err(|e| format!("Failed to create parent {}: {}", p.display(), e))?;
85
+ }
86
+ let mut outfile = std::fs::File::create(&outpath)
87
+ .map_err(|e| format!("Failed to create file {}: {}", outpath.display(), e))?;
88
+ std::io::copy(&mut file, &mut outfile)
89
+ .map_err(|e| format!("Failed to write file {}: {}", outpath.display(), e))?;
90
+ }
91
+ }
92
+
93
+ Ok(())
94
+ }
@@ -0,0 +1,97 @@
1
+ #[cfg(feature = "cli")]
2
+ use crossterm::style::{Attribute, SetAttribute};
3
+
4
+ #[cfg(feature = "cli")]
5
+ use std::fmt::Write;
6
+
7
+ use crate::logger::{LogLevel, Logger};
8
+ use crate::signature::get_signature;
9
+ use crate::version::get_version;
10
+ use std::env;
11
+ use std::path::PathBuf;
12
+
13
+ fn get_devalang_homedir() -> PathBuf {
14
+ // Prefer explicit env var, then HOME/USERPROFILE, fallback to current dir
15
+ if let Ok(p) = env::var("DEVALANG_HOME") {
16
+ return PathBuf::from(p);
17
+ }
18
+
19
+ if let Ok(p) = env::var("HOME") {
20
+ return PathBuf::from(p).join(".devalang");
21
+ }
22
+
23
+ if let Ok(p) = env::var("USERPROFILE") {
24
+ return PathBuf::from(p).join(".devalang");
25
+ }
26
+
27
+ env::current_dir()
28
+ .unwrap_or_else(|_| PathBuf::from("."))
29
+ .join(".devalang")
30
+ }
31
+
32
+ pub fn check_is_first_usage() -> bool {
33
+ if get_devalang_homedir().exists() == true {
34
+ false
35
+ } else {
36
+ first_usage_welcome();
37
+ true
38
+ }
39
+ }
40
+
41
+ pub fn first_usage_welcome() {
42
+ std::fs::create_dir_all(get_devalang_homedir()).ok();
43
+
44
+ let version = get_version();
45
+ print!("{}", get_signature(&version));
46
+
47
+ let homedir = get_devalang_homedir().display().to_string();
48
+
49
+ let welcome_msg = format!(
50
+ "Welcome to Devalang ! \n\
51
+ It looks like this is your first time using the tool.\n\
52
+ A configuration file will be created in your home directory.\n\
53
+ (location: '{}')",
54
+ homedir
55
+ );
56
+
57
+ #[cfg(feature = "cli")]
58
+ let mut s = String::new();
59
+ #[cfg(feature = "cli")]
60
+ {
61
+ write!(&mut s, "{}", SetAttribute(Attribute::Bold)).unwrap();
62
+ write!(&mut s, "{}", welcome_msg).unwrap();
63
+ write!(&mut s, "{}", SetAttribute(Attribute::Reset)).unwrap();
64
+
65
+ println!("");
66
+ println!("{}", s);
67
+ println!("");
68
+ }
69
+
70
+ #[cfg(not(feature = "cli"))]
71
+ {
72
+ // Fallback: plain output on non-cli (wasm) builds
73
+ println!("");
74
+ println!("{}", welcome_msg);
75
+ println!("");
76
+ }
77
+
78
+ first_usage_ask_for_telemetry();
79
+ }
80
+
81
+ pub fn first_usage_ask_for_telemetry() {
82
+ let telemetry_msg = "Would you like to enable anonymous telemetry ?";
83
+ let telemetry_desc = "This data helps us improve the tool. You can opt-out at any time.";
84
+
85
+ // Non-interactive fallback for first usage: default to telemetry disabled.
86
+ let _ = telemetry_msg;
87
+ let _ = telemetry_desc;
88
+
89
+ let logger = Logger::new();
90
+
91
+ println!("");
92
+ logger.log_message(
93
+ LogLevel::Info,
94
+ "Telemetry disabled by default. You can enable it at any time by using 'devalang telemetry enable'"
95
+ );
96
+ println!("");
97
+ }
@@ -1,6 +1,9 @@
1
- pub mod version;
1
+ pub mod error;
2
+ pub mod file;
3
+ pub mod first_usage;
4
+ pub mod logger;
5
+ pub mod path;
2
6
  pub mod signature;
3
7
  pub mod spinner;
8
+ pub mod version;
4
9
  pub mod watcher;
5
- pub mod file;
6
- pub mod logger;
@@ -1,5 +1,6 @@
1
1
  #[cfg(feature = "cli")]
2
2
  use crossterm::style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor};
3
+ #[cfg(feature = "cli")]
3
4
  use std::fmt::Write;
4
5
 
5
6
  #[derive(Debug, Clone, PartialEq)]
@@ -7,6 +8,7 @@ pub enum LogLevel {
7
8
  Success,
8
9
  Error,
9
10
  Info,
11
+ Print,
10
12
  Warning,
11
13
  Watcher,
12
14
  Debug,
@@ -20,12 +22,25 @@ impl Logger {
20
22
  Logger
21
23
  }
22
24
 
23
- // --- log_message ---
25
+ // Some methods are only used in CLI builds; silence dead_code warnings for non-cli.
26
+ #[cfg(not(feature = "cli"))]
27
+ #[allow(dead_code)]
28
+ fn __wasm_only_allow_dead_code(&self) {}
29
+
30
+ // Additionally allow dead_code for the CLI-only formatting helpers when building without cli
31
+ #[cfg(not(feature = "cli"))]
32
+ #[allow(dead_code)]
33
+ fn __wasm_only_format_helpers(&self) {}
24
34
 
25
35
  #[cfg(feature = "cli")]
26
36
  pub fn log_message(&self, level: LogLevel, message: &str) {
27
37
  let formatted_status = self.format_status(level);
28
- println!("🦊 {} {} {}", self.language_signature(), formatted_status, message);
38
+ println!(
39
+ "🦊 {} {} {}",
40
+ self.language_signature(),
41
+ formatted_status,
42
+ message
43
+ );
29
44
  }
30
45
 
31
46
  #[cfg(not(feature = "cli"))]
@@ -33,12 +48,34 @@ impl Logger {
33
48
  // no-op for WASM
34
49
  }
35
50
 
36
- // --- log_error_with_stacktrace ---
51
+ #[cfg(feature = "cli")]
52
+ pub fn log_message_with_trace(&self, level: LogLevel, message: &str, trace: Vec<&str>) {
53
+ let formatted_status = self.format_status(level);
54
+ println!(
55
+ "🦊 {} {} {}",
56
+ self.language_signature(),
57
+ formatted_status,
58
+ message
59
+ );
60
+ for t in trace {
61
+ println!(" ↳ {}", t);
62
+ }
63
+ }
64
+
65
+ #[cfg(not(feature = "cli"))]
66
+ pub fn log_message_with_trace(&self, _level: LogLevel, _message: &str, _trace: Vec<&str>) {
67
+ // no-op for WASM
68
+ }
37
69
 
38
70
  #[cfg(feature = "cli")]
39
71
  pub fn log_error_with_stacktrace(&self, message: &str, stacktrace: &str) {
40
72
  let formatted_status = self.format_status(LogLevel::Error);
41
- println!("🦊 {} {} {}", self.language_signature(), formatted_status, message);
73
+ println!(
74
+ "🦊 {} {} {}",
75
+ self.language_signature(),
76
+ formatted_status,
77
+ message
78
+ );
42
79
  println!(" ↳ {}", stacktrace);
43
80
  }
44
81
 
@@ -47,16 +84,25 @@ impl Logger {
47
84
  // no-op for WASM
48
85
  }
49
86
 
50
- // --- language_signature ---
51
-
52
87
  #[cfg(feature = "cli")]
88
+ #[allow(dead_code)]
89
+ #[cfg_attr(not(feature = "cli"), allow(dead_code))]
53
90
  fn language_signature(&self) -> String {
54
91
  let mut s = String::new();
55
92
 
56
93
  write!(&mut s, "{}", SetForegroundColor(Color::Grey)).unwrap();
57
94
  s.push('[');
58
95
 
59
- write!(&mut s, "{}", SetForegroundColor(Color::Rgb { r: 29, g: 211, b: 176 })).unwrap();
96
+ write!(
97
+ &mut s,
98
+ "{}",
99
+ SetForegroundColor(Color::Rgb {
100
+ r: 29,
101
+ g: 211,
102
+ b: 176,
103
+ })
104
+ )
105
+ .unwrap();
60
106
  write!(&mut s, "{}", SetAttribute(Attribute::Bold)).unwrap();
61
107
  s.push_str("Devalang");
62
108
  write!(&mut s, "{}", SetAttribute(Attribute::Reset)).unwrap();
@@ -69,23 +115,51 @@ impl Logger {
69
115
  }
70
116
 
71
117
  #[cfg(not(feature = "cli"))]
118
+ #[allow(dead_code)]
72
119
  fn language_signature(&self) -> String {
73
120
  "[Devalang]".to_string()
74
121
  }
75
122
 
76
- // --- format_status ---
77
-
78
123
  #[cfg(feature = "cli")]
79
124
  fn format_status(&self, level: LogLevel) -> String {
80
125
  let mut s = String::new();
81
126
 
82
127
  let color = match level {
83
- LogLevel::Success => Color::Rgb { r: 76, g: 175, b: 80 },
84
- LogLevel::Error => Color::Rgb { r: 244, g: 67, b: 54 },
85
- LogLevel::Info => Color::Rgb { r: 33, g: 150, b: 243 },
86
- LogLevel::Warning => Color::Rgb { r: 255, g: 152, b: 0 },
87
- LogLevel::Watcher => Color::Rgb { r: 156, g: 39, b: 176 },
88
- LogLevel::Debug => Color::Rgb { r: 103, g: 58, b: 183 },
128
+ LogLevel::Success => Color::Rgb {
129
+ r: 76,
130
+ g: 175,
131
+ b: 80,
132
+ },
133
+ LogLevel::Error => Color::Rgb {
134
+ r: 244,
135
+ g: 67,
136
+ b: 54,
137
+ },
138
+ LogLevel::Info => Color::Rgb {
139
+ r: 33,
140
+ g: 150,
141
+ b: 243,
142
+ },
143
+ LogLevel::Warning => Color::Rgb {
144
+ r: 255,
145
+ g: 152,
146
+ b: 0,
147
+ },
148
+ LogLevel::Watcher => Color::Rgb {
149
+ r: 156,
150
+ g: 39,
151
+ b: 176,
152
+ },
153
+ LogLevel::Debug => Color::Rgb {
154
+ r: 103,
155
+ g: 58,
156
+ b: 183,
157
+ },
158
+ LogLevel::Print => Color::Rgb {
159
+ r: 255,
160
+ g: 255,
161
+ b: 255,
162
+ },
89
163
  };
90
164
 
91
165
  let status = match level {
@@ -95,6 +169,7 @@ impl Logger {
95
169
  LogLevel::Warning => "WARNING",
96
170
  LogLevel::Watcher => "WATCHER",
97
171
  LogLevel::Debug => "DEBUG",
172
+ LogLevel::Print => "PRINT",
98
173
  };
99
174
 
100
175
  s.push('[');
@@ -109,15 +184,17 @@ impl Logger {
109
184
  }
110
185
 
111
186
  #[cfg(not(feature = "cli"))]
187
+ #[allow(dead_code)]
112
188
  fn format_status(&self, level: LogLevel) -> String {
113
- match level {
189
+ (match level {
114
190
  LogLevel::Success => "[SUCCESS]",
115
191
  LogLevel::Error => "[ERROR]",
116
192
  LogLevel::Info => "[INFO]",
117
193
  LogLevel::Warning => "[WARNING]",
118
194
  LogLevel::Watcher => "[WATCHER]",
119
195
  LogLevel::Debug => "[DEBUG]",
120
- }
196
+ LogLevel::Print => "[PRINT]",
197
+ })
121
198
  .to_string()
122
199
  }
123
200
  }