@devaloop/devalang 0.0.1-alpha.16-hotfix.3 → 0.0.1-alpha.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cargo/config.toml +2 -0
- package/.devalang +6 -10
- package/.github/workflows/ci.yml +0 -1
- package/Cargo.toml +18 -2
- package/README.md +77 -32
- package/docs/CHANGELOG.md +46 -0
- package/docs/ROADMAP.md +7 -4
- package/examples/index.deva +52 -35
- package/out-tsc/bin/index.d.ts +2 -0
- package/out-tsc/core/functions/index.d.ts +37 -0
- package/out-tsc/core/functions/index.js +76 -0
- package/out-tsc/core/index.d.ts +6 -0
- package/out-tsc/core/index.js +22 -0
- package/out-tsc/core/types/index.d.ts +4 -0
- package/out-tsc/core/types/index.js +20 -0
- package/out-tsc/core/types/plugin.d.ts +18 -0
- package/out-tsc/core/types/plugin.js +2 -0
- package/out-tsc/core/types/result.d.ts +27 -0
- package/out-tsc/core/types/result.js +2 -0
- package/out-tsc/core/types/statement.d.ts +106 -0
- package/out-tsc/core/types/statement.js +2 -0
- package/out-tsc/core/types/value.d.ts +43 -0
- package/out-tsc/core/types/value.js +2 -0
- package/out-tsc/index.d.ts +7 -0
- package/out-tsc/index.js +41 -2
- package/out-tsc/pkg/devalang_core.d.ts +7 -0
- package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +33 -0
- package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
- package/out-tsc/scripts/copy-wasm-dts.js +73 -0
- package/out-tsc/scripts/postinstall.d.ts +1 -0
- package/out-tsc/scripts/postinstall.js +33 -23
- package/out-tsc/scripts/version/bump.d.ts +1 -0
- package/out-tsc/scripts/version/fetch.d.ts +1 -0
- package/out-tsc/scripts/version/index.d.ts +1 -0
- package/out-tsc/scripts/version/sync.d.ts +1 -0
- package/package.json +16 -4
- package/project-version.json +3 -3
- package/rust/cli/bank/api.rs +122 -0
- package/rust/cli/bank/commands.rs +275 -0
- package/rust/cli/bank/mod.rs +29 -0
- package/rust/cli/build/commands.rs +97 -0
- package/rust/cli/build/mod.rs +2 -0
- package/rust/cli/build/process.rs +146 -0
- package/rust/cli/{check.rs → check/mod.rs} +18 -31
- package/rust/cli/discover/commands.rs +253 -0
- package/rust/cli/discover/config.rs +111 -0
- package/rust/cli/discover/fs.rs +19 -0
- package/rust/cli/discover/install.rs +103 -0
- package/rust/cli/discover/metadata.rs +48 -0
- package/rust/cli/discover/mod.rs +5 -0
- package/rust/cli/{init.rs → init/commands.rs} +88 -87
- package/rust/cli/init/mod.rs +1 -0
- package/rust/{installer → cli/install}/addon.rs +5 -9
- package/rust/cli/install/bank.rs +53 -0
- package/rust/cli/{install.rs → install/commands.rs} +9 -9
- package/rust/{installer → cli/install}/mod.rs +2 -3
- package/rust/cli/install/plugin.rs +61 -0
- package/rust/cli/{login.rs → login/commands.rs} +8 -11
- package/rust/cli/login/mod.rs +1 -0
- package/rust/cli/mod.rs +2 -2
- package/rust/cli/{driver.rs → parser.rs} +7 -2
- package/rust/cli/play/commands.rs +324 -0
- package/rust/cli/play/io.rs +17 -0
- package/rust/cli/play/mod.rs +5 -0
- package/rust/cli/play/process.rs +150 -0
- package/rust/cli/play/realtime.rs +91 -0
- package/rust/cli/play/utils.rs +23 -0
- package/rust/cli/{telemetry.rs → telemetry/commands.rs} +4 -4
- package/rust/cli/telemetry/event_creator.rs +80 -0
- package/rust/cli/telemetry/mod.rs +3 -0
- package/rust/cli/telemetry/send.rs +51 -0
- package/rust/cli/{template.rs → template/commands.rs} +1 -1
- package/rust/cli/template/mod.rs +1 -0
- package/rust/cli/{update.rs → update/commands.rs} +6 -6
- package/rust/cli/update/mod.rs +1 -0
- package/rust/config/driver.rs +57 -72
- package/rust/config/mod.rs +1 -2
- package/rust/config/ops.rs +26 -0
- package/rust/config/settings.rs +40 -42
- package/rust/core/audio/engine/helpers.rs +146 -0
- package/rust/core/audio/engine/mod.rs +7 -0
- package/rust/core/audio/engine/sample.rs +298 -0
- package/rust/core/audio/engine/synth.rs +310 -0
- package/rust/core/audio/evaluator.rs +15 -12
- package/rust/core/audio/interpreter/arrow_call.rs +99 -24
- package/rust/core/audio/interpreter/call.rs +81 -60
- package/rust/core/audio/interpreter/condition.rs +3 -2
- package/rust/core/audio/interpreter/driver.rs +206 -151
- package/rust/core/audio/interpreter/let_.rs +1 -1
- package/rust/core/audio/interpreter/load.rs +2 -1
- package/rust/core/audio/interpreter/loop_.rs +7 -6
- package/rust/core/audio/interpreter/sleep.rs +2 -1
- package/rust/core/audio/interpreter/spawn.rs +45 -57
- package/rust/core/audio/interpreter/tempo.rs +31 -10
- package/rust/core/audio/interpreter/trigger.rs +2 -2
- package/rust/core/audio/loader/trigger.rs +4 -7
- package/rust/core/audio/player.rs +6 -0
- package/rust/core/audio/renderer.rs +5 -7
- package/rust/core/audio/special/env.rs +3 -1
- package/rust/core/audio/special/math.rs +4 -4
- package/rust/core/audio/special/modulator.rs +2 -2
- package/rust/core/builder/mod.rs +9 -3
- package/rust/core/debugger/lexer.rs +1 -1
- package/rust/core/debugger/mod.rs +6 -0
- package/rust/core/debugger/module.rs +4 -4
- package/rust/core/debugger/preprocessor.rs +1 -1
- package/rust/core/debugger/store.rs +2 -2
- package/rust/core/error/mod.rs +189 -0
- package/rust/core/lexer/handler/arrow.rs +1 -1
- package/rust/core/lexer/handler/at.rs +1 -1
- package/rust/core/lexer/handler/brace.rs +2 -2
- package/rust/core/lexer/handler/colon.rs +1 -1
- package/rust/core/lexer/handler/comment.rs +1 -1
- package/rust/core/lexer/handler/dot.rs +1 -1
- package/rust/core/lexer/handler/driver.rs +1 -1
- package/rust/core/lexer/handler/identifier.rs +1 -1
- package/rust/core/lexer/handler/mod.rs +1 -2
- package/rust/core/lexer/handler/number.rs +1 -1
- package/rust/core/lexer/handler/operator.rs +1 -1
- package/rust/core/lexer/handler/parenthesis.rs +2 -2
- package/rust/core/lexer/handler/slash.rs +1 -1
- package/rust/core/lexer/handler/string.rs +1 -1
- package/rust/core/lexer/mod.rs +22 -12
- package/rust/core/lexer/token.rs +90 -97
- package/rust/core/mod.rs +0 -1
- package/rust/core/parser/driver.rs +66 -13
- package/rust/core/parser/handler/arrow_call.rs +28 -8
- package/rust/core/parser/handler/at.rs +55 -21
- package/rust/core/parser/handler/bank.rs +14 -4
- package/rust/core/parser/handler/condition.rs +6 -3
- package/rust/core/parser/handler/dot.rs +2 -1
- package/rust/core/parser/handler/identifier/automate.rs +13 -16
- package/rust/core/parser/handler/identifier/call.rs +4 -4
- package/rust/core/parser/handler/identifier/emit.rs +9 -5
- package/rust/core/parser/handler/identifier/function.rs +20 -7
- package/rust/core/parser/handler/identifier/group.rs +11 -7
- package/rust/core/parser/handler/identifier/let_.rs +24 -9
- package/rust/core/parser/handler/identifier/mod.rs +6 -5
- package/rust/core/parser/handler/identifier/on.rs +16 -7
- package/rust/core/parser/handler/identifier/print.rs +6 -9
- package/rust/core/parser/handler/identifier/sleep.rs +12 -5
- package/rust/core/parser/handler/identifier/spawn.rs +4 -4
- package/rust/core/parser/handler/identifier/synth.rs +79 -9
- package/rust/core/parser/handler/loop_.rs +39 -14
- package/rust/core/parser/handler/tempo.rs +9 -5
- package/rust/core/parser/mod.rs +0 -1
- package/rust/core/parser/statement.rs +6 -137
- package/rust/core/plugin/loader.rs +41 -27
- package/rust/core/plugin/runner.rs +68 -17
- package/rust/core/preprocessor/loader.rs +155 -33
- package/rust/core/preprocessor/processor.rs +2 -2
- package/rust/core/preprocessor/resolver/bank.rs +6 -8
- package/rust/core/preprocessor/resolver/call.rs +20 -24
- package/rust/core/preprocessor/resolver/condition.rs +6 -8
- package/rust/core/preprocessor/resolver/driver.rs +14 -16
- package/rust/core/preprocessor/resolver/function.rs +6 -6
- package/rust/core/preprocessor/resolver/group.rs +6 -8
- package/rust/core/preprocessor/resolver/loop_.rs +8 -10
- package/rust/core/preprocessor/resolver/spawn.rs +19 -23
- package/rust/core/preprocessor/resolver/synth.rs +6 -8
- package/rust/core/preprocessor/resolver/tempo.rs +6 -8
- package/rust/core/preprocessor/resolver/trigger.rs +22 -19
- package/rust/core/preprocessor/resolver/value.rs +99 -4
- package/rust/core/store/export.rs +28 -28
- package/rust/core/store/function.rs +6 -0
- package/rust/core/store/global.rs +7 -1
- package/rust/core/store/import.rs +28 -28
- package/rust/core/store/variable.rs +1 -1
- package/rust/core/utils/mod.rs +0 -1
- package/rust/lib.rs +102 -9
- package/rust/main.rs +156 -45
- package/rust/types/Cargo.toml +8 -0
- package/rust/types/src/addons.rs +55 -0
- package/rust/types/src/ast.rs +198 -0
- package/rust/types/src/config.rs +74 -0
- package/rust/types/src/lib.rs +12 -0
- package/rust/types/src/telemetry.rs +85 -0
- package/rust/utils/Cargo.toml +23 -0
- package/rust/utils/{error.rs → src/error.rs} +186 -200
- package/rust/utils/src/file.rs +94 -0
- package/rust/utils/src/first_usage.rs +97 -0
- package/rust/utils/{mod.rs → src/lib.rs} +1 -1
- package/rust/utils/{logger.rs → src/logger.rs} +17 -12
- package/rust/utils/src/path.rs +88 -0
- package/rust/utils/src/signature.rs +41 -0
- package/rust/utils/{spinner.rs → src/spinner.rs} +3 -5
- package/rust/utils/src/version.rs +27 -0
- package/rust/utils/{watcher.rs → src/watcher.rs} +13 -1
- package/rust/web/api.rs +5 -0
- package/rust/web/cdn.rs +34 -0
- package/templates/minimal/README.md +98 -54
- package/templates/welcome/README.md +98 -54
- package/templates/welcome/src/index.deva +56 -8
- package/templates/welcome/src/variables.deva +2 -4
- package/tests/rust/TODO.md +0 -0
- package/tests/typescript/index.spec.ts +136 -0
- package/tests/typescript/playhead.spec.ts +36 -0
- package/tests/typescript/render_e2e.spec.ts +77 -0
- package/tsconfig.json +1 -1
- package/typescript/core/functions/index.ts +83 -0
- package/typescript/core/index.ts +6 -0
- package/typescript/core/types/index.ts +4 -0
- package/typescript/core/types/plugin.ts +19 -0
- package/typescript/core/types/result.ts +29 -0
- package/typescript/core/types/statement.ts +47 -0
- package/typescript/core/types/value.ts +29 -0
- package/typescript/index.ts +7 -2
- package/typescript/pkg/devalang_core.d.ts +4 -0
- package/typescript/scripts/copy-wasm-dts.ts +41 -0
- package/rust/cli/bank.rs +0 -462
- package/rust/cli/build.rs +0 -252
- package/rust/cli/play.rs +0 -1123
- package/rust/common/api.rs +0 -5
- package/rust/common/cdn.rs +0 -5
- package/rust/config/loader.rs +0 -165
- package/rust/config/stats.rs +0 -257
- package/rust/core/audio/engine.rs +0 -696
- package/rust/core/shared/bank.rs +0 -21
- package/rust/core/shared/duration.rs +0 -9
- package/rust/core/shared/mod.rs +0 -3
- package/rust/core/shared/value.rs +0 -35
- package/rust/core/utils/validation.rs +0 -35
- package/rust/installer/bank.rs +0 -62
- package/rust/installer/plugin.rs +0 -54
- package/rust/installer/utils.rs +0 -56
- package/rust/utils/file.rs +0 -38
- package/rust/utils/first_usage.rs +0 -83
- package/rust/utils/signature.rs +0 -19
- package/rust/utils/telemetry.rs +0 -292
- package/rust/utils/version.rs +0 -15
- /package/rust/{common → web}/mod.rs +0 -0
- /package/rust/{common → web}/sso.rs +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a plugin export.
|
|
3
|
+
*/
|
|
4
|
+
export interface PluginExport {
|
|
5
|
+
name: string;
|
|
6
|
+
kind: string;
|
|
7
|
+
default?: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents a plugin.
|
|
12
|
+
*/
|
|
13
|
+
export interface PluginInfo {
|
|
14
|
+
author: string;
|
|
15
|
+
name: string;
|
|
16
|
+
version?: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
exports: PluginExport[];
|
|
19
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents an error that occurred during parsing.
|
|
3
|
+
*/
|
|
4
|
+
export interface ErrorResult {
|
|
5
|
+
message: string;
|
|
6
|
+
line: number;
|
|
7
|
+
column: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents the result of parsing user code.
|
|
12
|
+
*/
|
|
13
|
+
export interface ParseResult {
|
|
14
|
+
ok: boolean;
|
|
15
|
+
ast: string;
|
|
16
|
+
errors: ErrorResult[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Represents the result of debugging user code.
|
|
21
|
+
*/
|
|
22
|
+
export interface DebugResult {
|
|
23
|
+
samples_len: number;
|
|
24
|
+
any_nonzero: boolean;
|
|
25
|
+
ast: string;
|
|
26
|
+
note_count: number;
|
|
27
|
+
global_vars: string[];
|
|
28
|
+
statements_count: number;
|
|
29
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Value, Duration } from "./value";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a statement kind in the code.
|
|
5
|
+
*/
|
|
6
|
+
export type StatementKind =
|
|
7
|
+
| { kind: "Tempo" }
|
|
8
|
+
| { kind: "Bank"; alias?: string }
|
|
9
|
+
| { kind: "Print" }
|
|
10
|
+
| { kind: "Load"; source: string; alias: string }
|
|
11
|
+
| { kind: "Use"; name: string; alias?: string }
|
|
12
|
+
| { kind: "Let"; name: string }
|
|
13
|
+
| { kind: "Automate"; target: string }
|
|
14
|
+
| { kind: "ArrowCall"; target: string; method: string; args: Value[] }
|
|
15
|
+
| { kind: "Function"; name: string; parameters: string[]; body: Statement[] }
|
|
16
|
+
| { kind: "Synth" }
|
|
17
|
+
| { kind: "Trigger"; entity: string; duration: Duration; effects?: Value }
|
|
18
|
+
| { kind: "Sleep" }
|
|
19
|
+
| { kind: "Call"; name: string; args: Value[] }
|
|
20
|
+
| { kind: "Spawn"; name: string; args: Value[] }
|
|
21
|
+
| { kind: "Loop" }
|
|
22
|
+
| { kind: "Group" }
|
|
23
|
+
| { kind: "Include"; path: string }
|
|
24
|
+
| { kind: "Export"; names: string[]; source: string }
|
|
25
|
+
| { kind: "Import"; names: string[]; source: string }
|
|
26
|
+
| { kind: "If" }
|
|
27
|
+
| { kind: "Else" }
|
|
28
|
+
| { kind: "ElseIf" }
|
|
29
|
+
| { kind: "Comment" }
|
|
30
|
+
| { kind: "Indent" }
|
|
31
|
+
| { kind: "Dedent" }
|
|
32
|
+
| { kind: "NewLine" }
|
|
33
|
+
| { kind: "On"; event: string; args?: Value[]; body: Statement[] }
|
|
34
|
+
| { kind: "Emit"; event: string; payload?: Value }
|
|
35
|
+
| { kind: "Unknown" }
|
|
36
|
+
| { kind: "Error"; message: string };
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Represents a statement in the code.
|
|
40
|
+
*/
|
|
41
|
+
export interface Statement {
|
|
42
|
+
kind: StatementKind;
|
|
43
|
+
value: Value;
|
|
44
|
+
indent: number;
|
|
45
|
+
line: number;
|
|
46
|
+
column: number;
|
|
47
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Statement } from "./statement";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a duration in the code.
|
|
5
|
+
*/
|
|
6
|
+
export type Duration =
|
|
7
|
+
| { Number: number }
|
|
8
|
+
| { Identifier: string }
|
|
9
|
+
| { Beat: string }
|
|
10
|
+
| { Auto: null };
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Represents a value in the code.
|
|
14
|
+
*/
|
|
15
|
+
export type Value =
|
|
16
|
+
| { Boolean: boolean }
|
|
17
|
+
| { Number: number }
|
|
18
|
+
| { Duration: Duration }
|
|
19
|
+
| { Identifier: string }
|
|
20
|
+
| { String: string }
|
|
21
|
+
| { Array: Value[] }
|
|
22
|
+
| { Map: Record<string, Value> }
|
|
23
|
+
| { Block: Statement[] }
|
|
24
|
+
| { Sample: string }
|
|
25
|
+
| { Beat: string }
|
|
26
|
+
| { Statement: Statement }
|
|
27
|
+
| { StatementKind: any }
|
|
28
|
+
| { Unknown: null }
|
|
29
|
+
| null;
|
package/typescript/index.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TypeScript
|
|
3
|
-
|
|
2
|
+
* Public TypeScript definitions for Devalang.
|
|
3
|
+
* ————————————————————————————————————————
|
|
4
|
+
* Used to provide TypeScript types for the Devalang WASM package.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export * as pkg from "./pkg/devalang_core";
|
|
8
|
+
export * as core from "./core/index";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
// Copies .d.ts files from pkg/ (wasm-pack output) into out-tsc/pkg/
|
|
5
|
+
const ROOT = path.resolve(__dirname, '..', '..');
|
|
6
|
+
const PKG_DIR = path.join(ROOT, 'pkg');
|
|
7
|
+
const OUT_DIR = path.join(ROOT, 'out-tsc', 'pkg');
|
|
8
|
+
|
|
9
|
+
function ensureDir(p: string): void {
|
|
10
|
+
if (!fs.existsSync(p)) fs.mkdirSync(p, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function copyDir(src: string, dest: string): void {
|
|
14
|
+
ensureDir(dest);
|
|
15
|
+
const items = fs.readdirSync(src, { withFileTypes: true });
|
|
16
|
+
for (const item of items) {
|
|
17
|
+
const srcPath = path.join(src, item.name);
|
|
18
|
+
const destPath = path.join(dest, item.name);
|
|
19
|
+
if (item.isDirectory()) {
|
|
20
|
+
copyDir(srcPath, destPath);
|
|
21
|
+
} else if (item.isFile() && item.name.endsWith('.d.ts')) {
|
|
22
|
+
fs.copyFileSync(srcPath, destPath);
|
|
23
|
+
console.log('copied', srcPath, '->', destPath);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function main(): number {
|
|
29
|
+
if (!fs.existsSync(PKG_DIR)) {
|
|
30
|
+
console.error('pkg directory not found at', PKG_DIR);
|
|
31
|
+
return 1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
ensureDir(OUT_DIR);
|
|
35
|
+
copyDir(PKG_DIR, OUT_DIR);
|
|
36
|
+
console.log('done');
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const exitCode = main();
|
|
41
|
+
if (exitCode !== 0) process.exit(exitCode);
|
package/rust/cli/bank.rs
DELETED
|
@@ -1,462 +0,0 @@
|
|
|
1
|
-
use std::fs;
|
|
2
|
-
|
|
3
|
-
use crate::{
|
|
4
|
-
common::cdn::get_cdn_url,
|
|
5
|
-
config::loader::{load_config, remove_bank_from_config, update_bank_version_in_config},
|
|
6
|
-
core::shared::bank::{BankFile, BankInfo},
|
|
7
|
-
installer::bank::install_bank,
|
|
8
|
-
};
|
|
9
|
-
use serde::Deserialize;
|
|
10
|
-
|
|
11
|
-
#[derive(Debug, Deserialize)]
|
|
12
|
-
pub struct BankList {
|
|
13
|
-
bank: Vec<BankInfo>,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
#[derive(Debug, Deserialize)]
|
|
17
|
-
pub struct BankInfoFetched {
|
|
18
|
-
pub name: String,
|
|
19
|
-
pub version: String,
|
|
20
|
-
pub description: String,
|
|
21
|
-
pub author: String,
|
|
22
|
-
pub latest_version: String,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
#[derive(Debug, Deserialize)]
|
|
26
|
-
pub struct BankVersion {
|
|
27
|
-
pub version: String,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
pub async fn handle_update_bank_command(name: Option<String>) -> Result<(), String> {
|
|
31
|
-
let deva_dir = std::path::Path::new("./.deva");
|
|
32
|
-
let bank_dir = deva_dir.join("bank");
|
|
33
|
-
|
|
34
|
-
if !bank_dir.exists() {
|
|
35
|
-
fs::create_dir_all(bank_dir.clone())
|
|
36
|
-
.map_err(|e| format!("Failed to create bank directory: {}", e))?;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if let Some(name) = name {
|
|
40
|
-
let bank_path = bank_dir.join(&name);
|
|
41
|
-
if !bank_path.exists() {
|
|
42
|
-
return Err(format!("Bank '{}' is not installed", name));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Update specific bank
|
|
46
|
-
let latest_version = match fetch_latest_version(name.clone()).await {
|
|
47
|
-
Ok(version) => version,
|
|
48
|
-
Err(err) => {
|
|
49
|
-
eprintln!("❌ Error fetching latest version for '{}': {}", name, err);
|
|
50
|
-
return Err(format!("Failed to fetch latest version for '{}'", name));
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
let local_bank_info_path = bank_path.join("bank.toml");
|
|
55
|
-
let local_version = match fs::read_to_string(&local_bank_info_path)
|
|
56
|
-
.ok()
|
|
57
|
-
.and_then(|content| toml::from_str::<BankFile>(&content).ok())
|
|
58
|
-
.map(|bf| bf.bank.version)
|
|
59
|
-
{
|
|
60
|
-
Some(version) => version,
|
|
61
|
-
None => {
|
|
62
|
-
eprintln!(
|
|
63
|
-
"⚠️ Unable to read local version for '{}', forcing reinstall...",
|
|
64
|
-
name
|
|
65
|
-
);
|
|
66
|
-
"".to_string() // Force update
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
if local_version != latest_version.version {
|
|
71
|
-
if let Err(e) = update_bank(&name, &latest_version.version).await {
|
|
72
|
-
eprintln!("❌ Error updating bank '{}': {}", name, e);
|
|
73
|
-
} else {
|
|
74
|
-
println!(
|
|
75
|
-
"✅ Bank '{}' updated to version '{}'",
|
|
76
|
-
name, latest_version.version
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
} else {
|
|
80
|
-
println!(
|
|
81
|
-
"Bank '{}' is already up-to-date (version {})",
|
|
82
|
-
name, latest_version.version
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
// Verify if the bank directory exists
|
|
86
|
-
if !bank_path.exists() {
|
|
87
|
-
eprintln!(
|
|
88
|
-
"❌ Bank directory for '{}' does not exist, reinstalling...",
|
|
89
|
-
name
|
|
90
|
-
);
|
|
91
|
-
if let Err(e) = install_bank(&name, deva_dir).await {
|
|
92
|
-
eprintln!("❌ Error reinstalling bank '{}': {}", name, e);
|
|
93
|
-
} else {
|
|
94
|
-
println!("✅ Bank '{}' reinstalled successfully!", name);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
} else {
|
|
99
|
-
// Update all banks
|
|
100
|
-
let root_dir = deva_dir
|
|
101
|
-
.parent()
|
|
102
|
-
.ok_or_else(|| "Failed to determine root directory".to_string())?;
|
|
103
|
-
|
|
104
|
-
let config_path = root_dir.join(".devalang");
|
|
105
|
-
if !config_path.exists() {
|
|
106
|
-
return Err(format!(
|
|
107
|
-
"Config file not found at '{}'. Please run 'devalang init' before adding an addon",
|
|
108
|
-
config_path.display()
|
|
109
|
-
));
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
let config = load_config(Some(&config_path))
|
|
113
|
-
.ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
|
|
114
|
-
|
|
115
|
-
let config_banks = config.banks.clone();
|
|
116
|
-
|
|
117
|
-
// Install or update all banks
|
|
118
|
-
|
|
119
|
-
if let Some(banks) = config_banks {
|
|
120
|
-
for bank in banks {
|
|
121
|
-
let bank_name = bank
|
|
122
|
-
.path
|
|
123
|
-
.strip_prefix("devalang://bank/")
|
|
124
|
-
.unwrap_or(&bank.path)
|
|
125
|
-
.to_string();
|
|
126
|
-
|
|
127
|
-
let latest_version = match fetch_latest_version(bank_name.clone()).await {
|
|
128
|
-
Ok(version) => version,
|
|
129
|
-
Err(err) => {
|
|
130
|
-
eprintln!(
|
|
131
|
-
"❌ Error fetching latest version for '{}': {}",
|
|
132
|
-
bank_name, err
|
|
133
|
-
);
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
if let Some(local_bank_version) = bank.version {
|
|
139
|
-
if latest_version.version != local_bank_version {
|
|
140
|
-
if let Err(e) = update_bank(&bank_name, &latest_version.version).await {
|
|
141
|
-
eprintln!("❌ Error updating bank '{}': {}", bank_name, e);
|
|
142
|
-
} else {
|
|
143
|
-
println!(
|
|
144
|
-
"✅ Bank '{}' updated to version '{}'",
|
|
145
|
-
bank_name, latest_version.version
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
} else {
|
|
149
|
-
println!(
|
|
150
|
-
"Bank '{}' is already up-to-date (version {})",
|
|
151
|
-
bank_name, local_bank_version
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
// Verify if the bank directory exists
|
|
155
|
-
let bank_path = bank_dir.join(&bank_name);
|
|
156
|
-
|
|
157
|
-
if !bank_path.exists() {
|
|
158
|
-
eprintln!(
|
|
159
|
-
"❌ Bank directory for '{}' does not exist, reinstalling...",
|
|
160
|
-
bank_name
|
|
161
|
-
);
|
|
162
|
-
if let Err(e) = install_bank(&bank_name, deva_dir).await {
|
|
163
|
-
eprintln!("❌ Error reinstalling bank '{}': {}", bank_name, e);
|
|
164
|
-
} else {
|
|
165
|
-
println!("✅ Bank '{}' reinstalled successfully!", bank_name);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
} else {
|
|
170
|
-
// If the bank version is not specified in the config, install it
|
|
171
|
-
if let Err(e) = install_bank(&bank_name, deva_dir).await {
|
|
172
|
-
eprintln!("❌ Error installing bank '{}': {}", bank_name, e);
|
|
173
|
-
} else {
|
|
174
|
-
println!("✅ Bank '{}' installed successfully!", bank_name);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
Ok(())
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
async fn update_bank(bank_name: &str, latest_version: &str) -> Result<(), String> {
|
|
185
|
-
let deva_dir = std::path::Path::new("./.deva");
|
|
186
|
-
|
|
187
|
-
// First, delete the existing bank directory
|
|
188
|
-
let bank_dir = deva_dir.join("bank").join(bank_name);
|
|
189
|
-
|
|
190
|
-
if bank_dir.exists() {
|
|
191
|
-
std::fs::remove_dir_all(&bank_dir).unwrap_or_else(|_| {
|
|
192
|
-
eprintln!(
|
|
193
|
-
"⚠️ Failed to remove old bank directory for '{}', aborting !",
|
|
194
|
-
bank_name
|
|
195
|
-
);
|
|
196
|
-
std::process::exit(1);
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Now, install the new version
|
|
201
|
-
if let Err(e) = install_bank(bank_name, deva_dir).await {
|
|
202
|
-
eprintln!("❌ Error installing bank '{}': {}", bank_name, e);
|
|
203
|
-
} else {
|
|
204
|
-
println!("✅ Bank '{}' installed successfully!", bank_name);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
let root_dir = deva_dir
|
|
208
|
-
.parent()
|
|
209
|
-
.ok_or_else(|| "Failed to determine root directory".to_string())?;
|
|
210
|
-
|
|
211
|
-
let config_path = root_dir.join(".devalang");
|
|
212
|
-
if !config_path.exists() {
|
|
213
|
-
return Err(format!(
|
|
214
|
-
"Config file not found at '{}'. Please run 'devalang init' before adding an addon",
|
|
215
|
-
config_path.display()
|
|
216
|
-
));
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
let mut config = load_config(Some(&config_path))
|
|
220
|
-
.ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
|
|
221
|
-
|
|
222
|
-
// Update the bank version in the config
|
|
223
|
-
update_bank_version_in_config(&mut config, bank_name, latest_version);
|
|
224
|
-
|
|
225
|
-
Ok(())
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
pub async fn handle_remove_bank_command(name: String) -> Result<(), String> {
|
|
229
|
-
let deva_dir = std::path::Path::new("./.deva");
|
|
230
|
-
let bank_dir = deva_dir.join("bank");
|
|
231
|
-
|
|
232
|
-
let bank_path = bank_dir.join(&name);
|
|
233
|
-
|
|
234
|
-
if !bank_path.exists() {
|
|
235
|
-
return Err(format!("Bank '{}' is not installed", name));
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
std::fs::remove_dir_all(&bank_path).map_err(|e| format!("Failed to remove bank: {}", e))?;
|
|
239
|
-
|
|
240
|
-
// Remove the bank from the config
|
|
241
|
-
let root_dir = deva_dir
|
|
242
|
-
.parent()
|
|
243
|
-
.ok_or_else(|| "Failed to determine root directory".to_string())?;
|
|
244
|
-
|
|
245
|
-
let config_path = root_dir.join(".devalang");
|
|
246
|
-
if !config_path.exists() {
|
|
247
|
-
return Err(format!(
|
|
248
|
-
"Config file not found at '{}'. Please run 'devalang init' before adding an addon",
|
|
249
|
-
config_path.display()
|
|
250
|
-
));
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
let mut config = load_config(Some(&config_path))
|
|
254
|
-
.ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
|
|
255
|
-
|
|
256
|
-
remove_bank_from_config(&mut config, &name);
|
|
257
|
-
|
|
258
|
-
println!("✅ Bank '{}' removed successfully", name);
|
|
259
|
-
|
|
260
|
-
Ok(())
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
pub async fn handle_bank_available_command() -> Result<(), String> {
|
|
264
|
-
let bank_list = match list_external_banks().await {
|
|
265
|
-
Ok(list) => list,
|
|
266
|
-
Err(_err) => {
|
|
267
|
-
eprintln!("❌ Error fetching bank list");
|
|
268
|
-
return Err("Failed to fetch bank list".into());
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
println!("Available banks for current project :");
|
|
273
|
-
println!(" ");
|
|
274
|
-
|
|
275
|
-
for bank in bank_list {
|
|
276
|
-
println!("📦 {}", bank.name);
|
|
277
|
-
println!(" - Version: {}", bank.version);
|
|
278
|
-
println!(" - Description: {}", bank.description);
|
|
279
|
-
println!(" - Author: {}", bank.author);
|
|
280
|
-
println!(" ");
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
Ok(())
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
pub async fn handle_bank_info_command(
|
|
287
|
-
name: String,
|
|
288
|
-
) -> Result<BankInfo, Box<dyn std::error::Error>> {
|
|
289
|
-
let cdn_url = get_cdn_url();
|
|
290
|
-
let url = format!("{}/bank/{}/info", cdn_url, name);
|
|
291
|
-
|
|
292
|
-
let response = match reqwest::get(&url).await {
|
|
293
|
-
Ok(resp) => resp,
|
|
294
|
-
Err(_err) => {
|
|
295
|
-
return Err("Failed to fetch bank info".into());
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
if !response.status().is_success() {
|
|
300
|
-
return Err(format!("Failed to fetch bank info: HTTP {}", response.status()).into());
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
let bytes = match response.bytes().await {
|
|
304
|
-
Ok(b) => b,
|
|
305
|
-
Err(_err) => {
|
|
306
|
-
eprintln!("❌ Error reading response body");
|
|
307
|
-
return Err("Failed to read response body".into());
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
let parsed: BankInfo = serde_json::from_slice(&bytes)?;
|
|
312
|
-
|
|
313
|
-
println!("📦 Bank Info for '{}':", name);
|
|
314
|
-
println!(" - Name: {}", parsed.name);
|
|
315
|
-
println!(" - Version: {}", parsed.version);
|
|
316
|
-
println!(" - Description: {}", parsed.description);
|
|
317
|
-
println!(" - Author: {}", parsed.author);
|
|
318
|
-
|
|
319
|
-
Ok(parsed)
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
pub async fn handle_bank_list_command() -> Result<(), String> {
|
|
323
|
-
let bank_list = match list_installed_banks().await {
|
|
324
|
-
Ok(list) => list,
|
|
325
|
-
Err(_err) => {
|
|
326
|
-
eprintln!("❌ Error fetching bank list");
|
|
327
|
-
return Err("Failed to fetch bank list".into());
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
println!("Installed banks for current project :");
|
|
332
|
-
|
|
333
|
-
for bank_toml in bank_list {
|
|
334
|
-
let latest_version = match fetch_latest_version(bank_toml.bank.name.clone()).await {
|
|
335
|
-
Ok(version) => version,
|
|
336
|
-
Err(_err) => {
|
|
337
|
-
eprintln!(
|
|
338
|
-
"❌ Error fetching latest version for '{}'",
|
|
339
|
-
bank_toml.bank.name
|
|
340
|
-
);
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
let is_latest = if latest_version.version == bank_toml.bank.version {
|
|
346
|
-
"✅"
|
|
347
|
-
} else {
|
|
348
|
-
"❗"
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
println!(" ");
|
|
352
|
-
println!("📦 {}", bank_toml.bank.name);
|
|
353
|
-
println!(
|
|
354
|
-
" - Version: v{} {} (latest: v{})",
|
|
355
|
-
bank_toml.bank.version, is_latest, latest_version.version
|
|
356
|
-
);
|
|
357
|
-
println!(" - Description: {}", bank_toml.bank.description);
|
|
358
|
-
println!(" - Author: {}", bank_toml.bank.author);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
Ok(())
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
async fn fetch_latest_version(
|
|
365
|
-
bank_name: String,
|
|
366
|
-
) -> Result<BankVersion, Box<dyn std::error::Error>> {
|
|
367
|
-
let cdn_url = get_cdn_url();
|
|
368
|
-
let url = format!("{}/bank/{}/version", cdn_url, bank_name);
|
|
369
|
-
|
|
370
|
-
let response = reqwest::get(url).await?;
|
|
371
|
-
|
|
372
|
-
if !response.status().is_success() {
|
|
373
|
-
return Err(format!("❌ Failed to fetch version: HTTP {}", response.status()).into());
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
let bytes = response.bytes().await?;
|
|
377
|
-
|
|
378
|
-
let version: BankVersion = serde_json::from_slice(&bytes)?;
|
|
379
|
-
|
|
380
|
-
Ok(version)
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
async fn list_external_banks() -> Result<Vec<BankInfo>, Box<dyn std::error::Error>> {
|
|
384
|
-
let cdn_url = get_cdn_url();
|
|
385
|
-
let url = format!("{}/bank/list", cdn_url);
|
|
386
|
-
|
|
387
|
-
let response = reqwest::get(url).await?;
|
|
388
|
-
|
|
389
|
-
if !response.status().is_success() {
|
|
390
|
-
return Err(format!("❌ Failed to fetch bank list: HTTP {}", response.status()).into());
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
let bytes = response.bytes().await?;
|
|
394
|
-
|
|
395
|
-
let parsed: BankList = serde_json::from_slice(&bytes)?;
|
|
396
|
-
|
|
397
|
-
Ok(parsed.bank)
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
async fn list_installed_banks() -> Result<Vec<BankFile>, String> {
|
|
401
|
-
let deva_dir = std::path::Path::new("./.deva");
|
|
402
|
-
let bank_dir = deva_dir.join("bank");
|
|
403
|
-
|
|
404
|
-
let mut banks = Vec::new();
|
|
405
|
-
|
|
406
|
-
if !bank_dir.exists() {
|
|
407
|
-
return Ok(banks); // No banks installed
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// TODO: Verify installed banks in files
|
|
411
|
-
// let installed_banks = std::fs
|
|
412
|
-
// ::read_dir(bank_dir)
|
|
413
|
-
// .map_err(|e| format!("Failed to read bank directory: {}", e))?;
|
|
414
|
-
|
|
415
|
-
let root_dir = deva_dir
|
|
416
|
-
.parent()
|
|
417
|
-
.ok_or_else(|| "Failed to determine root directory".to_string())?;
|
|
418
|
-
|
|
419
|
-
let config_path = root_dir.join(".devalang");
|
|
420
|
-
if !config_path.exists() {
|
|
421
|
-
return Err(format!(
|
|
422
|
-
"Config file not found at '{}'. Please run 'devalang init' before adding an addon",
|
|
423
|
-
config_path.display()
|
|
424
|
-
));
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
let config = load_config(Some(&config_path))
|
|
428
|
-
.ok_or_else(|| format!("Failed to load config from '{}'", config_path.display()))?;
|
|
429
|
-
|
|
430
|
-
let config_banks = config.banks.clone();
|
|
431
|
-
|
|
432
|
-
if let Some(banks_in_toml) = config_banks {
|
|
433
|
-
for bank in banks_in_toml {
|
|
434
|
-
let bank_name = bank
|
|
435
|
-
.path
|
|
436
|
-
.strip_prefix("devalang://bank/")
|
|
437
|
-
.unwrap_or(&bank.path)
|
|
438
|
-
.to_string();
|
|
439
|
-
|
|
440
|
-
let bank_path = bank_dir.join(&bank_name);
|
|
441
|
-
if bank_path.exists() {
|
|
442
|
-
let bank_info_path = bank_path.join("bank.toml");
|
|
443
|
-
|
|
444
|
-
if bank_info_path.exists() {
|
|
445
|
-
let content = std::fs::read_to_string(&bank_info_path)
|
|
446
|
-
.map_err(|e| format!("Failed to read bank info: {}", e))?;
|
|
447
|
-
|
|
448
|
-
match toml::from_str::<BankFile>(&content) {
|
|
449
|
-
Ok(bank_info) => banks.push(bank_info),
|
|
450
|
-
Err(_err) => {
|
|
451
|
-
eprintln!("❌ Error parsing bank info for '{}'", bank_name);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
} else {
|
|
455
|
-
eprintln!("❌ Bank info file not found for '{}'", bank_name);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
Ok(banks)
|
|
462
|
-
}
|