@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.
- package/.devalang +9 -10
- package/Cargo.toml +84 -80
- package/README.md +10 -7
- package/docs/CHANGELOG.md +83 -0
- package/docs/ROADMAP.md +6 -2
- package/docs/TODO.md +3 -14
- package/examples/bus.deva +10 -0
- package/examples/chain.deva +19 -0
- package/examples/effect.deva +2 -0
- package/examples/filter.deva +11 -0
- package/examples/lfo.deva +9 -0
- package/examples/plugin.deva +10 -10
- package/examples/routing.deva +23 -0
- package/examples/synth.deva +11 -1
- package/examples/synth_types.deva +17 -0
- package/out-tsc/bin/project-version.json +6 -0
- package/out-tsc/core/functions/index.d.ts +5 -0
- package/out-tsc/core/functions/index.js +11 -0
- package/out-tsc/pkg/devalang_core.d.ts +2 -0
- package/out-tsc/pkg/devalang_core.js +17 -2
- package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +1 -0
- package/out-tsc/scripts/version/copy-to-binary.d.ts +1 -0
- package/out-tsc/scripts/version/copy-to-binary.js +79 -0
- package/package.json +23 -10
- package/project-version.json +3 -3
- package/rust/bindings/Cargo.toml +9 -0
- package/rust/bindings/src/lib.rs +86 -0
- package/rust/cli/addon/commands.rs +35 -0
- package/rust/cli/addon/download.rs +234 -0
- package/rust/cli/addon/install.rs +33 -0
- package/rust/cli/addon/list.rs +224 -0
- package/rust/cli/addon/metadata.rs +124 -0
- package/rust/cli/addon/mod.rs +8 -0
- package/rust/cli/addon/remove.rs +271 -0
- package/rust/cli/addon/update.rs +305 -0
- package/rust/cli/{install/addon.rs → addon/utils.rs} +34 -43
- package/rust/cli/build/commands.rs +153 -103
- package/rust/cli/build/mod.rs +2 -2
- package/rust/cli/build/process.rs +165 -146
- package/rust/cli/check/mod.rs +208 -208
- package/rust/cli/discover/commands.rs +53 -31
- package/rust/cli/discover/config.rs +2 -4
- package/rust/cli/discover/install.rs +139 -28
- package/rust/cli/discover/metadata.rs +3 -3
- package/rust/cli/login/commands.rs +124 -124
- package/rust/cli/me/commands.rs +52 -0
- package/rust/cli/me/mod.rs +1 -0
- package/rust/cli/mod.rs +2 -2
- package/rust/cli/parser.rs +76 -70
- package/rust/cli/play/commands.rs +375 -324
- package/rust/cli/play/mod.rs +5 -5
- package/rust/cli/play/process.rs +159 -150
- package/rust/cli/play/realtime.rs +91 -91
- package/rust/cli/telemetry/commands.rs +22 -22
- package/rust/cli/telemetry/event_creator.rs +80 -80
- package/rust/cli/telemetry/mod.rs +3 -3
- package/rust/cli/telemetry/send.rs +51 -51
- package/rust/cli/template/commands.rs +69 -69
- package/rust/config/driver.rs +112 -103
- package/rust/config/mod.rs +3 -3
- package/rust/config/ops.rs +26 -26
- package/rust/config/settings.rs +101 -101
- package/rust/core/audio/engine/driver.rs +237 -0
- package/rust/core/audio/engine/export.rs +169 -0
- package/rust/core/audio/engine/helpers.rs +178 -170
- package/rust/core/audio/engine/mod.rs +56 -7
- package/rust/core/audio/engine/notes/dsp.rs +88 -0
- package/rust/core/audio/engine/notes/mod.rs +53 -0
- package/rust/core/audio/engine/notes/params.rs +294 -0
- package/rust/core/audio/engine/sample/insert.rs +300 -0
- package/rust/core/audio/engine/sample/mod.rs +40 -0
- package/rust/core/audio/engine/sample/padding.rs +170 -0
- package/rust/core/audio/evaluator/condition.rs +61 -0
- package/rust/core/audio/evaluator/mod.rs +9 -0
- package/rust/core/audio/{evaluator.rs → evaluator/numeric.rs} +152 -310
- package/rust/core/audio/evaluator/rhs.rs +16 -0
- package/rust/core/audio/evaluator/string_expr.rs +94 -0
- package/rust/core/audio/interpreter/driver.rs +574 -542
- package/rust/core/audio/interpreter/mod.rs +2 -14
- package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +179 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +398 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/effects.rs +323 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +3 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +371 -0
- package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +3 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +192 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +24 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +116 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +97 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +100 -0
- package/rust/core/audio/interpreter/{automate.rs → statements/automate.rs} +2 -4
- package/rust/core/audio/interpreter/{call.rs → statements/call.rs} +36 -5
- package/rust/core/audio/interpreter/{condition.rs → statements/condition.rs} +72 -71
- package/rust/core/audio/interpreter/{function.rs → statements/function.rs} +24 -26
- package/rust/core/audio/interpreter/{let_.rs → statements/let_.rs} +36 -38
- package/rust/core/audio/interpreter/{load.rs → statements/load.rs} +17 -19
- package/rust/core/audio/interpreter/{loop_.rs → statements/loop_.rs} +115 -114
- package/rust/core/audio/interpreter/statements/mod.rs +12 -0
- package/rust/core/audio/interpreter/{sleep.rs → statements/sleep.rs} +28 -28
- package/rust/core/audio/interpreter/{spawn.rs → statements/spawn.rs} +54 -4
- package/rust/core/audio/interpreter/{tempo.rs → statements/tempo.rs} +40 -40
- package/rust/core/audio/interpreter/{trigger.rs → statements/trigger.rs} +242 -239
- package/rust/core/audio/loader/trigger.rs +98 -97
- package/rust/core/audio/mod.rs +6 -7
- package/rust/core/audio/special/easing.rs +189 -189
- package/rust/core/audio/special/env.rs +45 -45
- package/rust/core/audio/special/math.rs +134 -134
- package/rust/core/audio/special/modulator.rs +143 -143
- package/rust/core/builder/mod.rs +129 -86
- package/rust/core/debugger/{module.rs → logs.rs} +52 -55
- package/rust/core/debugger/mod.rs +30 -30
- package/rust/core/debugger/store.rs +38 -40
- package/rust/core/error/mod.rs +269 -269
- package/rust/core/lexer/driver.rs +2 -4
- package/rust/core/mod.rs +9 -10
- package/rust/core/parser/driver/block.rs +111 -0
- package/rust/core/parser/driver/cursor.rs +82 -0
- package/rust/core/parser/driver/driver_impl.rs +159 -0
- package/rust/core/parser/driver/mod.rs +6 -0
- package/rust/core/parser/driver/parse_array.rs +120 -0
- package/rust/core/parser/driver/parse_map.rs +247 -0
- package/rust/core/parser/driver/parser.rs +160 -0
- package/rust/core/parser/handler/arrow_call.rs +90 -15
- package/rust/core/parser/handler/at.rs +279 -279
- package/rust/core/parser/handler/bank.rs +104 -104
- package/rust/core/parser/handler/condition.rs +83 -83
- package/rust/core/parser/handler/dot.rs +148 -148
- package/rust/core/parser/handler/identifier/automate.rs +254 -254
- package/rust/core/parser/handler/identifier/call.rs +91 -91
- package/rust/core/parser/handler/identifier/emit.rs +70 -70
- package/rust/core/parser/handler/identifier/function.rs +113 -113
- package/rust/core/parser/handler/identifier/group.rs +89 -89
- package/rust/core/parser/handler/identifier/let_.rs +173 -173
- package/rust/core/parser/handler/identifier/mod.rs +55 -55
- package/rust/core/parser/handler/identifier/on.rs +107 -107
- package/rust/core/parser/handler/identifier/print.rs +49 -49
- package/rust/core/parser/handler/identifier/sleep.rs +96 -43
- package/rust/core/parser/handler/identifier/spawn.rs +91 -91
- package/rust/core/parser/handler/identifier/synth.rs +39 -3
- package/rust/core/parser/handler/loop_.rs +194 -194
- package/rust/core/parser/handler/pattern.rs +25 -2
- package/rust/core/parser/handler/tempo.rs +105 -57
- package/rust/core/parser/statement.rs +10 -11
- package/rust/core/plugin/loader.rs +137 -137
- package/rust/core/plugin/runner/mod.rs +11 -0
- package/rust/core/plugin/{runner.rs → runner/non_wasm.rs} +206 -72
- package/rust/core/plugin/runner/wasm32.rs +44 -0
- package/rust/core/preprocessor/loader/inject.rs +313 -0
- package/rust/core/preprocessor/loader/loader_helpers.rs +110 -0
- package/rust/core/preprocessor/loader/mod.rs +235 -0
- package/rust/core/preprocessor/module.rs +55 -60
- package/rust/core/preprocessor/{processor.rs → processor/handlers.rs} +107 -114
- package/rust/core/preprocessor/processor/mod.rs +1 -0
- package/rust/core/preprocessor/resolver/function.rs +69 -69
- package/rust/core/preprocessor/resolver/group.rs +122 -94
- package/rust/core/preprocessor/resolver/pattern.rs +14 -2
- package/rust/core/store/global.rs +57 -61
- package/rust/core/store/mod.rs +1 -5
- package/rust/lib.rs +323 -308
- package/rust/macros/Cargo.toml +14 -0
- package/rust/macros/src/lib.rs +52 -0
- package/rust/main.rs +336 -143
- package/rust/types/Cargo.toml +1 -1
- package/rust/types/src/addons.rs +57 -55
- package/rust/types/src/config.rs +82 -74
- package/rust/types/src/lib.rs +15 -12
- package/rust/types/src/plugin.rs +20 -0
- package/rust/types/src/store.rs +139 -0
- package/rust/types/src/telemetry.rs +85 -85
- package/rust/utils/Cargo.toml +5 -2
- package/rust/utils/src/file.rs +477 -94
- package/rust/utils/src/first_usage.rs +97 -97
- package/rust/utils/src/lib.rs +9 -9
- package/rust/utils/src/logger.rs +200 -200
- package/rust/utils/src/path.rs +158 -88
- package/rust/utils/src/signature.rs +41 -41
- package/rust/utils/src/spinner.rs +20 -20
- package/rust/utils/src/version.rs +58 -27
- package/rust/utils/src/watcher.rs +46 -46
- package/rust/web/api.rs +5 -5
- package/rust/web/auth.rs +5 -0
- package/rust/web/cdn.rs +34 -34
- package/rust/web/forge.rs +5 -0
- package/rust/web/mod.rs +2 -0
- package/tests/integration.rs +21 -21
- package/typescript/core/functions/index.ts +11 -0
- package/typescript/pkg/devalang_core.ts +20 -4
- package/typescript/scripts/version/copy-to-binary.ts +82 -0
- package/rust/cli/bank/api.rs +0 -122
- package/rust/cli/bank/commands.rs +0 -275
- package/rust/cli/bank/mod.rs +0 -29
- package/rust/cli/install/bank.rs +0 -53
- package/rust/cli/install/commands.rs +0 -35
- package/rust/cli/install/mod.rs +0 -4
- package/rust/cli/install/plugin.rs +0 -61
- package/rust/core/audio/engine/sample.rs +0 -366
- package/rust/core/audio/engine/synth.rs +0 -325
- package/rust/core/audio/interpreter/arrow_call.rs +0 -311
- package/rust/core/audio/renderer.rs +0 -54
- package/rust/core/parser/driver.rs +0 -584
- package/rust/core/preprocessor/loader.rs +0 -637
- package/rust/core/store/export.rs +0 -28
- package/rust/core/store/function.rs +0 -40
- package/rust/core/store/import.rs +0 -28
- package/rust/core/store/variable.rs +0 -51
- package/rust/core/utils/mod.rs +0 -1
- package/rust/core/utils/path.rs +0 -37
package/rust/cli/check/mod.rs
CHANGED
|
@@ -1,208 +1,208 @@
|
|
|
1
|
-
use crate::{
|
|
2
|
-
config::driver::ProjectConfig,
|
|
3
|
-
core::{
|
|
4
|
-
debugger::{
|
|
5
|
-
lexer::write_lexer_log_file,
|
|
6
|
-
|
|
7
|
-
preprocessor::write_preprocessor_log_file,
|
|
8
|
-
store::{write_function_log_file, write_variables_log_file},
|
|
9
|
-
},
|
|
10
|
-
preprocessor::loader::ModuleLoader,
|
|
11
|
-
store::global::GlobalStore,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
use devalang_utils::{
|
|
17
|
-
logger::{LogLevel, Logger},
|
|
18
|
-
spinner::start_spinner,
|
|
19
|
-
watcher::watch_directory,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
#[cfg(feature = "cli")]
|
|
23
|
-
pub fn handle_check_command(
|
|
24
|
-
config: Option<ProjectConfig>,
|
|
25
|
-
entry: Option<String>,
|
|
26
|
-
output: Option<String>,
|
|
27
|
-
watch: bool,
|
|
28
|
-
debug: bool,
|
|
29
|
-
) -> Result<(), String> {
|
|
30
|
-
let fetched_entry = if entry.is_none() {
|
|
31
|
-
config
|
|
32
|
-
.as_ref()
|
|
33
|
-
.and_then(|c| c.defaults.entry.clone())
|
|
34
|
-
.unwrap_or_default()
|
|
35
|
-
} else {
|
|
36
|
-
entry.clone().unwrap_or_default()
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
let fetched_output = if output.is_none() {
|
|
40
|
-
config
|
|
41
|
-
.as_ref()
|
|
42
|
-
.and_then(|c| c.defaults.output.clone())
|
|
43
|
-
.unwrap_or_default()
|
|
44
|
-
} else {
|
|
45
|
-
output.clone().unwrap_or_default()
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
let fetched_watch = if watch {
|
|
49
|
-
watch
|
|
50
|
-
} else {
|
|
51
|
-
config
|
|
52
|
-
.as_ref()
|
|
53
|
-
.and_then(|c| c.defaults.watch)
|
|
54
|
-
.unwrap_or(false)
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
let logger = Logger::new();
|
|
58
|
-
|
|
59
|
-
if fetched_entry.is_empty() {
|
|
60
|
-
logger.log_message(
|
|
61
|
-
LogLevel::Error,
|
|
62
|
-
"Entry path is not specified. Please provide a valid entry path.",
|
|
63
|
-
);
|
|
64
|
-
return Err("missing entry path".to_string());
|
|
65
|
-
}
|
|
66
|
-
if fetched_output.is_empty() {
|
|
67
|
-
logger.log_message(
|
|
68
|
-
LogLevel::Error,
|
|
69
|
-
"Output directory is not specified. Please provide a valid output directory.",
|
|
70
|
-
);
|
|
71
|
-
return Err("missing output directory".to_string());
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
let entry_file = match find_entry_file(&fetched_entry) {
|
|
75
|
-
Some(p) => p,
|
|
76
|
-
None => {
|
|
77
|
-
logger.log_message(
|
|
78
|
-
LogLevel::Error,
|
|
79
|
-
&format!("❌ index.deva not found in directory: {}", fetched_entry),
|
|
80
|
-
);
|
|
81
|
-
return Err("index.deva not found".to_string());
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// SECTION Begin check
|
|
86
|
-
if fetched_watch {
|
|
87
|
-
let _ = begin_check(
|
|
88
|
-
entry_file.clone(),
|
|
89
|
-
fetched_output.clone(),
|
|
90
|
-
debug,
|
|
91
|
-
config.clone(),
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
logger.log_message(
|
|
95
|
-
LogLevel::Watcher,
|
|
96
|
-
&format!("Watching for changes in '{}'...", fetched_entry),
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
let cfg_for_watch = config.clone();
|
|
100
|
-
watch_directory(entry_file.clone(), move || {
|
|
101
|
-
logger.log_message(LogLevel::Watcher, "Detected changes, re-checking...");
|
|
102
|
-
if let Err(e) = begin_check(
|
|
103
|
-
entry_file.clone(),
|
|
104
|
-
fetched_output.clone(),
|
|
105
|
-
debug,
|
|
106
|
-
cfg_for_watch.clone(),
|
|
107
|
-
) {
|
|
108
|
-
eprintln!("[check] failed: {}", e);
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
.unwrap();
|
|
112
|
-
} else {
|
|
113
|
-
begin_check(
|
|
114
|
-
entry_file.clone(),
|
|
115
|
-
fetched_output.clone(),
|
|
116
|
-
debug,
|
|
117
|
-
config.clone(),
|
|
118
|
-
)?;
|
|
119
|
-
}
|
|
120
|
-
Ok(())
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
fn begin_check(
|
|
124
|
-
entry: String,
|
|
125
|
-
output: String,
|
|
126
|
-
debug: bool,
|
|
127
|
-
_config: Option<ProjectConfig>,
|
|
128
|
-
) -> Result<(), String> {
|
|
129
|
-
let spinner = start_spinner("Checking...");
|
|
130
|
-
|
|
131
|
-
let duration = std::time::Instant::now();
|
|
132
|
-
|
|
133
|
-
let normalized_entry_file = normalize_path(&entry);
|
|
134
|
-
let normalized_output_dir = normalize_path(&output);
|
|
135
|
-
|
|
136
|
-
let mut global_store = GlobalStore::new();
|
|
137
|
-
let module_loader = ModuleLoader::new(&normalized_entry_file, &normalized_output_dir);
|
|
138
|
-
|
|
139
|
-
// SECTION Load
|
|
140
|
-
// NOTE: We don't use modules in the check command, but we still need to load them
|
|
141
|
-
let modules = module_loader.load_all_modules(&mut global_store);
|
|
142
|
-
|
|
143
|
-
// Debugging: Log loaded modules and errors
|
|
144
|
-
let logger = Logger::new();
|
|
145
|
-
logger.log_message(LogLevel::Info, "Loaded modules:");
|
|
146
|
-
for module_name in modules.0.keys() {
|
|
147
|
-
logger.log_message(LogLevel::Info, &format!("- {}", module_name));
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if debug {
|
|
151
|
-
for (module_path, module) in global_store.modules.clone() {
|
|
152
|
-
write_module_variable_log_file(
|
|
153
|
-
&normalized_output_dir,
|
|
154
|
-
&module_path,
|
|
155
|
-
&module.variable_table,
|
|
156
|
-
);
|
|
157
|
-
write_module_function_log_file(
|
|
158
|
-
&normalized_output_dir,
|
|
159
|
-
&module_path,
|
|
160
|
-
&module.function_table,
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
write_lexer_log_file(
|
|
165
|
-
&normalized_output_dir,
|
|
166
|
-
"lexer_tokens.log",
|
|
167
|
-
modules.0.clone(),
|
|
168
|
-
);
|
|
169
|
-
write_preprocessor_log_file(
|
|
170
|
-
&normalized_output_dir,
|
|
171
|
-
"resolved_statements.log",
|
|
172
|
-
modules.1.clone(),
|
|
173
|
-
);
|
|
174
|
-
write_variables_log_file(
|
|
175
|
-
&normalized_output_dir,
|
|
176
|
-
"global_variables.log",
|
|
177
|
-
global_store.variables.clone(),
|
|
178
|
-
);
|
|
179
|
-
write_function_log_file(
|
|
180
|
-
&normalized_output_dir,
|
|
181
|
-
"global_functions.log",
|
|
182
|
-
global_store.functions.clone(),
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
let all_errors = crate::core::error::collect_all_errors_with_modules(&modules.1);
|
|
187
|
-
|
|
188
|
-
let (warnings, criticals) = crate::core::error::partition_errors(all_errors);
|
|
189
|
-
crate::core::error::log_errors_with_stack("Check", &warnings, &criticals);
|
|
190
|
-
|
|
191
|
-
if !criticals.is_empty() {
|
|
192
|
-
spinner.finish_and_clear();
|
|
193
|
-
return Err("check failed with critical errors".to_string());
|
|
194
|
-
} else {
|
|
195
|
-
logger.log_message(LogLevel::Success, "No errors detected.");
|
|
196
|
-
|
|
197
|
-
let success_message = format!(
|
|
198
|
-
"Check completed successfully in {:.2?}. Output files written to: '{}'",
|
|
199
|
-
duration.elapsed(),
|
|
200
|
-
normalized_output_dir
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
spinner.finish_and_clear();
|
|
204
|
-
logger.log_message(LogLevel::Success, &success_message);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
Ok(())
|
|
208
|
-
}
|
|
1
|
+
use crate::{
|
|
2
|
+
config::driver::ProjectConfig,
|
|
3
|
+
core::{
|
|
4
|
+
debugger::{
|
|
5
|
+
lexer::write_lexer_log_file,
|
|
6
|
+
logs::{write_module_function_log_file, write_module_variable_log_file},
|
|
7
|
+
preprocessor::write_preprocessor_log_file,
|
|
8
|
+
store::{write_function_log_file, write_variables_log_file},
|
|
9
|
+
},
|
|
10
|
+
preprocessor::loader::ModuleLoader,
|
|
11
|
+
store::global::GlobalStore,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
use devalang_utils::path::{find_entry_file, normalize_path};
|
|
15
|
+
|
|
16
|
+
use devalang_utils::{
|
|
17
|
+
logger::{LogLevel, Logger},
|
|
18
|
+
spinner::start_spinner,
|
|
19
|
+
watcher::watch_directory,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
#[cfg(feature = "cli")]
|
|
23
|
+
pub fn handle_check_command(
|
|
24
|
+
config: Option<ProjectConfig>,
|
|
25
|
+
entry: Option<String>,
|
|
26
|
+
output: Option<String>,
|
|
27
|
+
watch: bool,
|
|
28
|
+
debug: bool,
|
|
29
|
+
) -> Result<(), String> {
|
|
30
|
+
let fetched_entry = if entry.is_none() {
|
|
31
|
+
config
|
|
32
|
+
.as_ref()
|
|
33
|
+
.and_then(|c| c.defaults.entry.clone())
|
|
34
|
+
.unwrap_or_default()
|
|
35
|
+
} else {
|
|
36
|
+
entry.clone().unwrap_or_default()
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
let fetched_output = if output.is_none() {
|
|
40
|
+
config
|
|
41
|
+
.as_ref()
|
|
42
|
+
.and_then(|c| c.defaults.output.clone())
|
|
43
|
+
.unwrap_or_default()
|
|
44
|
+
} else {
|
|
45
|
+
output.clone().unwrap_or_default()
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
let fetched_watch = if watch {
|
|
49
|
+
watch
|
|
50
|
+
} else {
|
|
51
|
+
config
|
|
52
|
+
.as_ref()
|
|
53
|
+
.and_then(|c| c.defaults.watch)
|
|
54
|
+
.unwrap_or(false)
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
let logger = Logger::new();
|
|
58
|
+
|
|
59
|
+
if fetched_entry.is_empty() {
|
|
60
|
+
logger.log_message(
|
|
61
|
+
LogLevel::Error,
|
|
62
|
+
"Entry path is not specified. Please provide a valid entry path.",
|
|
63
|
+
);
|
|
64
|
+
return Err("missing entry path".to_string());
|
|
65
|
+
}
|
|
66
|
+
if fetched_output.is_empty() {
|
|
67
|
+
logger.log_message(
|
|
68
|
+
LogLevel::Error,
|
|
69
|
+
"Output directory is not specified. Please provide a valid output directory.",
|
|
70
|
+
);
|
|
71
|
+
return Err("missing output directory".to_string());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let entry_file = match find_entry_file(&fetched_entry) {
|
|
75
|
+
Some(p) => p,
|
|
76
|
+
None => {
|
|
77
|
+
logger.log_message(
|
|
78
|
+
LogLevel::Error,
|
|
79
|
+
&format!("❌ index.deva not found in directory: {}", fetched_entry),
|
|
80
|
+
);
|
|
81
|
+
return Err("index.deva not found".to_string());
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// SECTION Begin check
|
|
86
|
+
if fetched_watch {
|
|
87
|
+
let _ = begin_check(
|
|
88
|
+
entry_file.clone(),
|
|
89
|
+
fetched_output.clone(),
|
|
90
|
+
debug,
|
|
91
|
+
config.clone(),
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
logger.log_message(
|
|
95
|
+
LogLevel::Watcher,
|
|
96
|
+
&format!("Watching for changes in '{}'...", fetched_entry),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
let cfg_for_watch = config.clone();
|
|
100
|
+
watch_directory(entry_file.clone(), move || {
|
|
101
|
+
logger.log_message(LogLevel::Watcher, "Detected changes, re-checking...");
|
|
102
|
+
if let Err(e) = begin_check(
|
|
103
|
+
entry_file.clone(),
|
|
104
|
+
fetched_output.clone(),
|
|
105
|
+
debug,
|
|
106
|
+
cfg_for_watch.clone(),
|
|
107
|
+
) {
|
|
108
|
+
eprintln!("[check] failed: {}", e);
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
.unwrap();
|
|
112
|
+
} else {
|
|
113
|
+
begin_check(
|
|
114
|
+
entry_file.clone(),
|
|
115
|
+
fetched_output.clone(),
|
|
116
|
+
debug,
|
|
117
|
+
config.clone(),
|
|
118
|
+
)?;
|
|
119
|
+
}
|
|
120
|
+
Ok(())
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
fn begin_check(
|
|
124
|
+
entry: String,
|
|
125
|
+
output: String,
|
|
126
|
+
debug: bool,
|
|
127
|
+
_config: Option<ProjectConfig>,
|
|
128
|
+
) -> Result<(), String> {
|
|
129
|
+
let spinner = start_spinner("Checking...");
|
|
130
|
+
|
|
131
|
+
let duration = std::time::Instant::now();
|
|
132
|
+
|
|
133
|
+
let normalized_entry_file = normalize_path(&entry);
|
|
134
|
+
let normalized_output_dir = normalize_path(&output);
|
|
135
|
+
|
|
136
|
+
let mut global_store = GlobalStore::new();
|
|
137
|
+
let module_loader = ModuleLoader::new(&normalized_entry_file, &normalized_output_dir);
|
|
138
|
+
|
|
139
|
+
// SECTION Load
|
|
140
|
+
// NOTE: We don't use modules in the check command, but we still need to load them
|
|
141
|
+
let modules = module_loader.load_all_modules(&mut global_store);
|
|
142
|
+
|
|
143
|
+
// Debugging: Log loaded modules and errors
|
|
144
|
+
let logger = Logger::new();
|
|
145
|
+
logger.log_message(LogLevel::Info, "Loaded modules:");
|
|
146
|
+
for module_name in modules.0.keys() {
|
|
147
|
+
logger.log_message(LogLevel::Info, &format!("- {}", module_name));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if debug {
|
|
151
|
+
for (module_path, module) in global_store.modules.clone() {
|
|
152
|
+
write_module_variable_log_file(
|
|
153
|
+
&normalized_output_dir,
|
|
154
|
+
&module_path,
|
|
155
|
+
&module.variable_table,
|
|
156
|
+
);
|
|
157
|
+
write_module_function_log_file(
|
|
158
|
+
&normalized_output_dir,
|
|
159
|
+
&module_path,
|
|
160
|
+
&module.function_table,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
write_lexer_log_file(
|
|
165
|
+
&normalized_output_dir,
|
|
166
|
+
"lexer_tokens.log",
|
|
167
|
+
modules.0.clone(),
|
|
168
|
+
);
|
|
169
|
+
write_preprocessor_log_file(
|
|
170
|
+
&normalized_output_dir,
|
|
171
|
+
"resolved_statements.log",
|
|
172
|
+
modules.1.clone(),
|
|
173
|
+
);
|
|
174
|
+
write_variables_log_file(
|
|
175
|
+
&normalized_output_dir,
|
|
176
|
+
"global_variables.log",
|
|
177
|
+
global_store.variables.clone(),
|
|
178
|
+
);
|
|
179
|
+
write_function_log_file(
|
|
180
|
+
&normalized_output_dir,
|
|
181
|
+
"global_functions.log",
|
|
182
|
+
global_store.functions.clone(),
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let all_errors = crate::core::error::collect_all_errors_with_modules(&modules.1);
|
|
187
|
+
|
|
188
|
+
let (warnings, criticals) = crate::core::error::partition_errors(all_errors);
|
|
189
|
+
crate::core::error::log_errors_with_stack("Check", &warnings, &criticals);
|
|
190
|
+
|
|
191
|
+
if !criticals.is_empty() {
|
|
192
|
+
spinner.finish_and_clear();
|
|
193
|
+
return Err("check failed with critical errors".to_string());
|
|
194
|
+
} else {
|
|
195
|
+
logger.log_message(LogLevel::Success, "No errors detected.");
|
|
196
|
+
|
|
197
|
+
let success_message = format!(
|
|
198
|
+
"Check completed successfully in {:.2?}. Output files written to: '{}'",
|
|
199
|
+
duration.elapsed(),
|
|
200
|
+
normalized_output_dir
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
spinner.finish_and_clear();
|
|
204
|
+
logger.log_message(LogLevel::Success, &success_message);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
Ok(())
|
|
208
|
+
}
|
|
@@ -1,57 +1,69 @@
|
|
|
1
1
|
use crate::cli::discover::config::add_addons_to_config;
|
|
2
2
|
use crate::cli::discover::install::install_selected_addons;
|
|
3
3
|
use devalang_types::DiscoveredAddon;
|
|
4
|
+
use devalang_utils::spinner::start_spinner;
|
|
4
5
|
use devalang_utils::{
|
|
5
6
|
logger::{LogLevel, Logger},
|
|
6
7
|
path as path_utils,
|
|
7
|
-
spinner::start_spinner,
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
pub async fn handle_discover_command() -> Result<(), String> {
|
|
10
|
+
pub async fn handle_discover_command(no_clear_tmp: bool) -> Result<(), String> {
|
|
11
11
|
let deva_dir = path_utils::ensure_deva_dir()?;
|
|
12
12
|
|
|
13
|
-
// Search for
|
|
14
|
-
|
|
13
|
+
// Search for compiled addon archives in the .deva directory
|
|
14
|
+
// New norm: archives are packaged as `.tar.gz`. We recursively find all
|
|
15
|
+
// files ending with `.tar.gz` and propose them for installation. The
|
|
16
|
+
// install flow will inspect the extracted content to determine the exact
|
|
17
|
+
// addon type (bank/plugin/preset/template) when possible.
|
|
15
18
|
|
|
16
19
|
let mut addons_found = Vec::new();
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
// the known addon extensions. This allows discovery in nested folders.
|
|
20
|
-
fn walk_dir_collect(base: &std::path::Path, exts: &[&str], out: &mut Vec<DiscoveredAddon>) {
|
|
21
|
+
fn walk_dir_collect_tar_gz(base: &std::path::Path, out: &mut Vec<DiscoveredAddon>) {
|
|
21
22
|
if let Ok(entries) = std::fs::read_dir(base) {
|
|
22
23
|
for entry in entries.filter_map(|e| e.ok()) {
|
|
23
24
|
let p = entry.path();
|
|
24
25
|
if p.is_dir() {
|
|
25
|
-
|
|
26
|
+
walk_dir_collect_tar_gz(&p, out);
|
|
26
27
|
} else if p.is_file() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
28
|
+
let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("");
|
|
29
|
+
if name.ends_with(".tar.gz") || name.ends_with(".tgz") {
|
|
30
|
+
// derive a friendly name (strip extensions)
|
|
31
|
+
let stem = if name.ends_with(".tar.gz") {
|
|
32
|
+
name.trim_end_matches(".tar.gz").to_string()
|
|
33
|
+
} else {
|
|
34
|
+
name.trim_end_matches(".tgz").to_string()
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
let publisher = p
|
|
38
|
+
.parent()
|
|
39
|
+
.and_then(|parent| parent.file_name())
|
|
40
|
+
.and_then(|s| s.to_str())
|
|
41
|
+
.unwrap_or("unknown")
|
|
42
|
+
.to_string();
|
|
43
|
+
|
|
44
|
+
out.push(DiscoveredAddon {
|
|
45
|
+
name: stem,
|
|
46
|
+
path: p.clone(),
|
|
47
|
+
publisher: publisher.clone(),
|
|
48
|
+
extension: "tar.gz".to_string(),
|
|
49
|
+
addon_type: "unknown".to_string(),
|
|
50
|
+
});
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
|
|
57
|
+
walk_dir_collect_tar_gz(&deva_dir, &mut addons_found);
|
|
58
|
+
|
|
59
|
+
// Pre-classify discovered archives by inspecting their contents for metadata
|
|
60
|
+
for addon in addons_found.iter_mut() {
|
|
61
|
+
if let Ok(t) = devalang_utils::file::detect_addon_type_in_archive(&addon.path) {
|
|
62
|
+
if t != "unknown" {
|
|
63
|
+
addon.addon_type = t;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
55
67
|
|
|
56
68
|
let logger = Logger::new();
|
|
57
69
|
|
|
@@ -79,6 +91,10 @@ pub async fn handle_discover_command() -> Result<(), String> {
|
|
|
79
91
|
.cloned()
|
|
80
92
|
.collect::<Vec<_>>();
|
|
81
93
|
|
|
94
|
+
// Combine discovered known-type addons. If nothing was classified (all
|
|
95
|
+
// entries have `addon_type == "unknown"`), fall back to the raw
|
|
96
|
+
// `addons_found` so users can still install archives discovered in
|
|
97
|
+
// `.deva`.
|
|
82
98
|
let mut all_addons = Vec::with_capacity(
|
|
83
99
|
banks_found.len() + plugins_found.len() + presets_found.len() + templates_found.len(),
|
|
84
100
|
);
|
|
@@ -87,6 +103,11 @@ pub async fn handle_discover_command() -> Result<(), String> {
|
|
|
87
103
|
all_addons.extend(presets_found.iter().cloned());
|
|
88
104
|
all_addons.extend(templates_found.iter().cloned());
|
|
89
105
|
|
|
106
|
+
if all_addons.is_empty() {
|
|
107
|
+
// No known types detected — include everything we discovered.
|
|
108
|
+
all_addons = addons_found.clone();
|
|
109
|
+
}
|
|
110
|
+
|
|
90
111
|
println!();
|
|
91
112
|
|
|
92
113
|
if all_addons.is_empty() {
|
|
@@ -220,7 +241,8 @@ pub async fn handle_discover_command() -> Result<(), String> {
|
|
|
220
241
|
.cloned()
|
|
221
242
|
.collect::<Vec<_>>();
|
|
222
243
|
|
|
223
|
-
let install_selected_addons_result =
|
|
244
|
+
let install_selected_addons_result =
|
|
245
|
+
install_selected_addons(addons_to_install, no_clear_tmp).await;
|
|
224
246
|
match install_selected_addons_result {
|
|
225
247
|
Ok(addons_enriched) => {
|
|
226
248
|
if let Err(e) = add_addons_to_config(addons_enriched).await {
|
|
@@ -9,8 +9,8 @@ pub async fn add_addons_to_config(addons: Vec<AddonWithMetadata>) -> Result<(),
|
|
|
9
9
|
|
|
10
10
|
for addon in addons {
|
|
11
11
|
let addon_path_as_devalang_protocol = format!(
|
|
12
|
-
"devalang://{}/{}
|
|
13
|
-
addon.addon_type, addon.metadata.
|
|
12
|
+
"devalang://{}/{}/{}",
|
|
13
|
+
addon.addon_type, addon.metadata.publisher, addon.metadata.name
|
|
14
14
|
);
|
|
15
15
|
|
|
16
16
|
match addon.addon_type.as_str() {
|
|
@@ -31,7 +31,6 @@ pub async fn add_addons_to_config(addons: Vec<AddonWithMetadata>) -> Result<(),
|
|
|
31
31
|
|
|
32
32
|
banks.push(ProjectConfigBankEntry {
|
|
33
33
|
path: addon_path_as_devalang_protocol,
|
|
34
|
-
version: Some(addon.metadata.version.clone()),
|
|
35
34
|
});
|
|
36
35
|
}
|
|
37
36
|
|
|
@@ -52,7 +51,6 @@ pub async fn add_addons_to_config(addons: Vec<AddonWithMetadata>) -> Result<(),
|
|
|
52
51
|
|
|
53
52
|
plugins.push(ProjectConfigPluginEntry {
|
|
54
53
|
path: addon_path_as_devalang_protocol,
|
|
55
|
-
version: Some(addon.metadata.version.clone()),
|
|
56
54
|
});
|
|
57
55
|
}
|
|
58
56
|
|