@devaloop/devalang 0.0.1-alpha.9 → 0.0.1-beta.1
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 +10 -4
- package/.github/workflows/ci.yml +103 -0
- package/Cargo.toml +80 -48
- package/README.md +135 -154
- package/docs/CHANGELOG.md +386 -1
- package/docs/CONTRIBUTING.md +101 -0
- package/docs/ROADMAP.md +10 -7
- package/docs/TODO.md +21 -9
- package/examples/automation.deva +42 -0
- package/examples/bank.deva +7 -0
- package/examples/duration.deva +9 -0
- package/examples/events.deva +12 -0
- package/examples/function.deva +15 -0
- package/examples/index.deva +57 -12
- package/examples/loop.deva +5 -12
- package/examples/pattern.deva +8 -0
- package/examples/plugin.deva +16 -0
- package/examples/variables.deva +1 -1
- package/out-tsc/bin/index.d.ts +2 -0
- package/out-tsc/bin/index.js +51 -7
- 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 +42 -1
- package/out-tsc/pkg/devalang_core.d.ts +13 -0
- package/out-tsc/pkg/devalang_core.js +50 -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 +83 -0
- 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 +28 -7
- package/project-version.json +4 -4
- 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 +103 -0
- package/rust/cli/build/mod.rs +2 -0
- package/rust/cli/build/process.rs +146 -0
- package/rust/cli/check/mod.rs +208 -0
- 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} +32 -23
- package/rust/cli/init/mod.rs +1 -0
- package/rust/cli/install/addon.rs +118 -0
- package/rust/cli/install/bank.rs +53 -0
- package/rust/cli/install/commands.rs +35 -0
- package/rust/cli/install/mod.rs +4 -0
- package/rust/cli/install/plugin.rs +61 -0
- package/rust/cli/login/commands.rs +124 -0
- package/rust/cli/login/mod.rs +1 -0
- package/rust/cli/mod.rs +12 -205
- package/rust/cli/parser.rs +314 -0
- 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/commands.rs +22 -0
- 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} +69 -57
- package/rust/cli/template/mod.rs +1 -0
- package/rust/cli/update/commands.rs +6 -0
- package/rust/cli/update/mod.rs +1 -0
- package/rust/config/driver.rs +103 -0
- package/rust/config/mod.rs +3 -16
- package/rust/config/ops.rs +26 -0
- package/rust/config/settings.rs +101 -0
- package/rust/core/audio/engine/helpers.rs +170 -0
- package/rust/core/audio/engine/mod.rs +7 -0
- package/rust/core/audio/engine/sample.rs +366 -0
- package/rust/core/audio/engine/synth.rs +325 -0
- package/rust/core/audio/evaluator.rs +310 -31
- package/rust/core/audio/interpreter/arrow_call.rs +311 -129
- package/rust/core/audio/interpreter/automate.rs +18 -0
- package/rust/core/audio/interpreter/call.rs +294 -64
- package/rust/core/audio/interpreter/condition.rs +71 -69
- package/rust/core/audio/interpreter/driver.rs +542 -216
- package/rust/core/audio/interpreter/function.rs +26 -0
- package/rust/core/audio/interpreter/let_.rs +38 -19
- package/rust/core/audio/interpreter/load.rs +19 -18
- package/rust/core/audio/interpreter/loop_.rs +114 -67
- package/rust/core/audio/interpreter/mod.rs +14 -12
- package/rust/core/audio/interpreter/sleep.rs +28 -36
- package/rust/core/audio/interpreter/spawn.rs +252 -66
- package/rust/core/audio/interpreter/tempo.rs +40 -16
- package/rust/core/audio/interpreter/trigger.rs +239 -69
- package/rust/core/audio/loader/mod.rs +1 -1
- package/rust/core/audio/loader/trigger.rs +97 -52
- package/rust/core/audio/mod.rs +7 -6
- package/rust/core/audio/player.rs +70 -54
- package/rust/core/audio/renderer.rs +54 -54
- package/rust/core/audio/special/easing.rs +189 -0
- package/rust/core/audio/special/env.rs +45 -0
- package/rust/core/audio/special/math.rs +134 -0
- package/rust/core/audio/special/mod.rs +9 -0
- package/rust/core/audio/special/modulator.rs +143 -0
- package/rust/core/builder/mod.rs +86 -80
- package/rust/core/debugger/lexer.rs +27 -27
- package/rust/core/debugger/mod.rs +30 -21
- package/rust/core/debugger/module.rs +55 -0
- package/rust/core/debugger/preprocessor.rs +27 -27
- package/rust/core/debugger/store.rs +40 -25
- package/rust/core/error/mod.rs +269 -60
- package/rust/core/lexer/driver.rs +61 -0
- package/rust/core/lexer/handler/arrow.rs +82 -31
- package/rust/core/lexer/handler/at.rs +21 -21
- package/rust/core/lexer/handler/brace.rs +41 -41
- package/rust/core/lexer/handler/colon.rs +21 -21
- package/rust/core/lexer/handler/comment.rs +30 -30
- package/rust/core/lexer/handler/dot.rs +21 -21
- package/rust/core/lexer/handler/driver.rs +337 -226
- package/rust/core/lexer/handler/identifier.rs +47 -41
- package/rust/core/lexer/handler/indent.rs +66 -52
- package/rust/core/lexer/handler/mod.rs +15 -14
- package/rust/core/lexer/handler/newline.rs +23 -23
- package/rust/core/lexer/handler/number.rs +31 -31
- package/rust/core/lexer/handler/operator.rs +46 -44
- package/rust/core/lexer/handler/parenthesis.rs +41 -0
- package/rust/core/lexer/handler/slash.rs +21 -0
- package/rust/core/lexer/handler/string.rs +63 -63
- package/rust/core/lexer/mod.rs +3 -51
- package/rust/core/lexer/token.rs +17 -12
- package/rust/core/mod.rs +10 -10
- package/rust/core/parser/driver.rs +584 -331
- package/rust/core/parser/handler/arrow_call.rs +253 -126
- package/rust/core/parser/handler/at.rs +279 -162
- package/rust/core/parser/handler/bank.rs +104 -41
- package/rust/core/parser/handler/condition.rs +83 -74
- package/rust/core/parser/handler/dot.rs +148 -112
- package/rust/core/parser/handler/identifier/automate.rs +254 -0
- package/rust/core/parser/handler/identifier/call.rs +91 -41
- package/rust/core/parser/handler/identifier/emit.rs +70 -0
- package/rust/core/parser/handler/identifier/function.rs +113 -0
- package/rust/core/parser/handler/identifier/group.rs +89 -75
- package/rust/core/parser/handler/identifier/let_.rs +173 -133
- package/rust/core/parser/handler/identifier/mod.rs +55 -51
- package/rust/core/parser/handler/identifier/on.rs +107 -0
- package/rust/core/parser/handler/identifier/print.rs +49 -0
- package/rust/core/parser/handler/identifier/sleep.rs +43 -33
- package/rust/core/parser/handler/identifier/spawn.rs +91 -41
- package/rust/core/parser/handler/identifier/synth.rs +135 -65
- package/rust/core/parser/handler/loop_.rs +194 -72
- package/rust/core/parser/handler/mod.rs +9 -8
- package/rust/core/parser/handler/pattern.rs +74 -0
- package/rust/core/parser/handler/tempo.rs +57 -47
- package/rust/core/parser/mod.rs +3 -4
- package/rust/core/parser/statement.rs +11 -96
- package/rust/core/plugin/loader.rs +137 -0
- package/rust/core/plugin/mod.rs +2 -0
- package/rust/core/plugin/runner.rs +347 -0
- package/rust/core/preprocessor/loader.rs +637 -193
- package/rust/core/preprocessor/mod.rs +4 -4
- package/rust/core/preprocessor/module.rs +60 -50
- package/rust/core/preprocessor/processor.rs +114 -76
- package/rust/core/preprocessor/resolver/bank.rs +49 -47
- package/rust/core/preprocessor/resolver/call.rs +124 -123
- package/rust/core/preprocessor/resolver/condition.rs +95 -92
- package/rust/core/preprocessor/resolver/driver.rs +324 -227
- package/rust/core/preprocessor/resolver/function.rs +69 -0
- package/rust/core/preprocessor/resolver/group.rs +94 -61
- package/rust/core/preprocessor/resolver/let_.rs +32 -31
- package/rust/core/preprocessor/resolver/loop_.rs +318 -91
- package/rust/core/preprocessor/resolver/mod.rs +16 -14
- package/rust/core/preprocessor/resolver/pattern.rs +83 -0
- package/rust/core/preprocessor/resolver/spawn.rs +99 -58
- package/rust/core/preprocessor/resolver/synth.rs +54 -50
- package/rust/core/preprocessor/resolver/tempo.rs +48 -49
- package/rust/core/preprocessor/resolver/trigger.rs +116 -112
- package/rust/core/preprocessor/resolver/value.rs +176 -78
- package/rust/core/store/export.rs +28 -28
- package/rust/core/store/function.rs +40 -0
- package/rust/core/store/global.rs +61 -39
- package/rust/core/store/import.rs +28 -28
- package/rust/core/store/mod.rs +5 -4
- package/rust/core/store/variable.rs +51 -28
- package/rust/core/utils/mod.rs +1 -2
- package/rust/core/utils/path.rs +37 -31
- package/rust/lib.rs +308 -117
- package/rust/main.rs +364 -65
- package/rust/types/Cargo.toml +11 -0
- package/rust/types/src/addons.rs +55 -0
- package/rust/types/src/ast.rs +202 -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 +26 -0
- package/rust/utils/src/error.rs +186 -0
- 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} +9 -6
- package/rust/utils/{logger.rs → src/logger.rs} +200 -123
- package/rust/utils/src/path.rs +88 -0
- package/rust/utils/src/signature.rs +41 -0
- package/rust/utils/{spinner.rs → src/spinner.rs} +20 -21
- package/rust/utils/src/version.rs +27 -0
- package/rust/utils/{watcher.rs → src/watcher.rs} +46 -33
- package/rust/web/api.rs +5 -0
- package/rust/web/cdn.rs +34 -0
- package/rust/web/mod.rs +3 -0
- package/rust/web/sso.rs +5 -0
- package/templates/minimal/README.md +143 -127
- package/templates/welcome/README.md +143 -127
- package/templates/welcome/src/index.deva +56 -8
- package/templates/welcome/src/variables.deva +2 -4
- package/tests/integration.rs +21 -0
- package/tests/rust/cli_check_build.rs +21 -0
- package/tests/rust/cli_help.rs +12 -0
- package/tests/rust/cli_template_list.rs +10 -0
- package/tests/rust/cli_version.rs +11 -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 +12 -10
- package/typescript/bin/index.ts +19 -5
- 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 +8 -1
- package/typescript/pkg/devalang_core.d.ts +4 -0
- package/typescript/pkg/devalang_core.ts +49 -0
- package/typescript/scripts/copy-wasm-dts.ts +41 -0
- package/typescript/scripts/postinstall.ts +85 -0
- package/typescript/scripts/version/bump.ts +0 -1
- package/typescript/scripts/version/index.ts +0 -1
- package/docs/COMMANDS.md +0 -85
- package/docs/CONFIG.md +0 -30
- package/docs/SYNTAX.md +0 -210
- package/out-tsc/bin/devalang.exe +0 -0
- package/out-tsc/scripts/postbuild.js +0 -11
- package/rust/cli/build.rs +0 -137
- package/rust/cli/check.rs +0 -117
- package/rust/cli/play.rs +0 -193
- package/rust/config/loader.rs +0 -13
- package/rust/core/audio/engine.rs +0 -203
- package/rust/core/shared/duration.rs +0 -8
- package/rust/core/shared/mod.rs +0 -2
- package/rust/core/shared/value.rs +0 -18
- package/rust/core/utils/validation.rs +0 -37
- package/rust/utils/file.rs +0 -35
- package/rust/utils/signature.rs +0 -17
- package/rust/utils/version.rs +0 -15
- package/typescript/scripts/postbuild.ts +0 -8
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { expect } from "chai";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as os from "os";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
|
|
6
|
+
const core: any = require("../../out-tsc");
|
|
7
|
+
|
|
8
|
+
describe("devalang debug_render and render_audio E2E", () => {
|
|
9
|
+
let origCwd: string;
|
|
10
|
+
let tmpDir: string | null = null;
|
|
11
|
+
|
|
12
|
+
before(function () {
|
|
13
|
+
origCwd = process.cwd();
|
|
14
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "devalang-e2e-"));
|
|
15
|
+
fs.writeFileSync(
|
|
16
|
+
path.join(tmpDir, ".devalang"),
|
|
17
|
+
'name = "devalang-test"\n'
|
|
18
|
+
);
|
|
19
|
+
fs.mkdirSync(path.join(tmpDir, ".deva"), { recursive: true });
|
|
20
|
+
process.chdir(tmpDir as string);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
after(function () {
|
|
24
|
+
if (tmpDir) {
|
|
25
|
+
try {
|
|
26
|
+
process.chdir(origCwd);
|
|
27
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
28
|
+
} catch (e) {
|
|
29
|
+
// ignore
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("debug_render should return diagnostics including note_count and global_vars", function () {
|
|
35
|
+
const dbg = core.pkg && core.pkg.debug_render;
|
|
36
|
+
if (typeof dbg !== "function") {
|
|
37
|
+
// skip if wasm binding missing
|
|
38
|
+
// eslint-disable-next-line no-invalid-this
|
|
39
|
+
this.skip();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const sampleProgram = `# sample program\nbpm 120\n\ngroup myLead:\n let mySynth = synth sine\n mySynth -> note(C4, { duration: 400 })\n mySynth -> note(G4, { duration: 400 })\ncall myLead\n`;
|
|
43
|
+
|
|
44
|
+
const out = dbg(sampleProgram);
|
|
45
|
+
expect(out).to.be.an("object");
|
|
46
|
+
expect(out).to.have.property("samples_len");
|
|
47
|
+
expect(out).to.have.property("any_nonzero");
|
|
48
|
+
expect(out).to.have.property("note_count");
|
|
49
|
+
expect(out).to.have.property("global_vars");
|
|
50
|
+
|
|
51
|
+
// Basic assertions: at least one non-zero sample or note_count > 0
|
|
52
|
+
expect(out.note_count).to.be.at.least(0);
|
|
53
|
+
expect(out.global_vars).to.include("myLead");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("render_audio should return a Float32Array and not be completely silent", function () {
|
|
57
|
+
const render = (core.pkg && core.pkg.render_audio) || core.render_audio;
|
|
58
|
+
if (typeof render !== "function") {
|
|
59
|
+
// eslint-disable-next-line no-invalid-this
|
|
60
|
+
this.skip();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const sampleProgram = `# sample program\nbpm 120\n\ngroup myLead:\n let mySynth = synth sine\n mySynth -> note(C4, { duration: 400 })\n mySynth -> note(G4, { duration: 400 })\ncall myLead\n`;
|
|
64
|
+
|
|
65
|
+
const arr = render(sampleProgram);
|
|
66
|
+
// If wasm returns JS typed array wrapper, check constructor name
|
|
67
|
+
expect(arr.constructor && arr.constructor.name).to.match(
|
|
68
|
+
/Float32Array|Float64Array|ArrayBuffer|Uint8Array/
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Convert to plain array if needed
|
|
72
|
+
const samples: number[] = Array.from(arr as any);
|
|
73
|
+
// Expect either note_count > 0 indirectly via nonzero samples
|
|
74
|
+
const anyNonZero = samples.some((s) => s !== 0);
|
|
75
|
+
expect(anyNonZero).to.be.true;
|
|
76
|
+
});
|
|
77
|
+
});
|
package/tsconfig.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
|
12
12
|
|
|
13
13
|
/* Language and Environment */
|
|
14
|
-
"target": "es2016"
|
|
14
|
+
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
|
15
15
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
|
16
16
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
|
17
17
|
// "libReplacement": true, /* Enable lib replacement. */
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
|
27
27
|
|
|
28
28
|
/* Modules */
|
|
29
|
-
"module": "commonjs"
|
|
30
|
-
"rootDir": "./typescript"
|
|
29
|
+
"module": "commonjs" /* Specify what module code is generated. */,
|
|
30
|
+
"rootDir": "./typescript" /* Specify the root folder within your source files. */,
|
|
31
31
|
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
|
32
32
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
|
33
33
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
|
@@ -52,14 +52,14 @@
|
|
|
52
52
|
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
|
53
53
|
|
|
54
54
|
/* Emit */
|
|
55
|
-
|
|
55
|
+
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
|
56
56
|
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
|
57
57
|
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
|
58
58
|
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
|
59
59
|
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
|
60
60
|
// "noEmit": true, /* Disable emitting files from a compilation. */
|
|
61
61
|
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
|
62
|
-
"outDir": "./out-tsc"
|
|
62
|
+
"outDir": "./out-tsc" /* Specify an output folder for all emitted files. */,
|
|
63
63
|
// "removeComments": true, /* Disable emitting comments. */
|
|
64
64
|
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
|
65
65
|
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
|
@@ -80,12 +80,12 @@
|
|
|
80
80
|
// "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
|
|
81
81
|
// "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */
|
|
82
82
|
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
|
83
|
-
"esModuleInterop": true
|
|
83
|
+
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
|
84
84
|
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
|
85
|
-
"forceConsistentCasingInFileNames": true
|
|
85
|
+
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
|
86
86
|
|
|
87
87
|
/* Type Checking */
|
|
88
|
-
"strict": true
|
|
88
|
+
"strict": true /* Enable all strict type-checking options. */,
|
|
89
89
|
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
|
90
90
|
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
|
91
91
|
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
|
@@ -108,6 +108,8 @@
|
|
|
108
108
|
|
|
109
109
|
/* Completeness */
|
|
110
110
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
|
111
|
-
"skipLibCheck": true
|
|
112
|
-
}
|
|
111
|
+
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
|
112
|
+
},
|
|
113
|
+
"include": ["typescript/**/*.ts"],
|
|
114
|
+
"exclude": ["node_modules", "out-tsc", "target", "dist", "**/*.spec.ts"]
|
|
113
115
|
}
|
package/typescript/bin/index.ts
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { spawn } from "child_process";
|
|
4
|
-
import path from "path";
|
|
4
|
+
import * as path from "path";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
let binaryName: string;
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
switch (process.platform) {
|
|
9
|
+
case "win32":
|
|
10
|
+
binaryName = "devalang-x86_64-pc-windows-msvc.exe";
|
|
11
|
+
break;
|
|
12
|
+
case "darwin":
|
|
13
|
+
binaryName = "devalang-x86_64-apple-darwin";
|
|
14
|
+
break;
|
|
15
|
+
case "linux":
|
|
16
|
+
binaryName = "devalang-x86_64-unknown-linux-gnu";
|
|
17
|
+
break;
|
|
18
|
+
default:
|
|
19
|
+
console.error(`Unsupported platform: ${process.platform}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const binaryPath = path.join(__dirname, binaryName);
|
|
9
24
|
|
|
10
25
|
const args = process.argv.slice(2);
|
|
11
26
|
const child = spawn(binaryPath, args, { stdio: "inherit" });
|
|
12
27
|
|
|
13
|
-
|
|
14
|
-
child.on("exit", (code) => process.exit(code));
|
|
28
|
+
child.on("exit", (code) => process.exit(code ?? 1));
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { ParseResult } from "../types/result";
|
|
2
|
+
import { DebugResult } from "../types/result";
|
|
3
|
+
|
|
4
|
+
let wasmPkg: any = undefined;
|
|
5
|
+
try {
|
|
6
|
+
// prefer runtime pkg generated by wasm-pack when available
|
|
7
|
+
// require at runtime so the package can be used even if wasm hasn't been built
|
|
8
|
+
// (this keeps tests and consumers robust).
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
10
|
+
wasmPkg = require("../../pkg/devalang_core");
|
|
11
|
+
} catch (_e) {
|
|
12
|
+
wasmPkg = undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parses the user code.
|
|
17
|
+
* @param entry_path The entry path for the code.
|
|
18
|
+
* @param source The source code to parse.
|
|
19
|
+
* @returns ParseResult | any
|
|
20
|
+
*/
|
|
21
|
+
export function parse(entry_path: string, source: string): ParseResult | any {
|
|
22
|
+
if (wasmPkg && typeof wasmPkg.parse === "function") {
|
|
23
|
+
return wasmPkg.parse(entry_path, source);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
throw new Error(
|
|
27
|
+
"WASM binding 'parse' not available. Build the wasm package or use the JS runtime."
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Renders the debug information for the user code.
|
|
33
|
+
* @param user_code The user-provided code to render debug information for.
|
|
34
|
+
* @returns DebugResult | any
|
|
35
|
+
*/
|
|
36
|
+
export function debug_render(user_code: string): DebugResult | any {
|
|
37
|
+
if (wasmPkg && typeof wasmPkg.debug_render === "function") {
|
|
38
|
+
return wasmPkg.debug_render(user_code);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
throw new Error(
|
|
42
|
+
"WASM binding 'debug_render' not available. Build the wasm package or use the JS runtime."
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Renders audio from the user code.
|
|
48
|
+
* @param user_code The user-provided code to render audio from.
|
|
49
|
+
* @returns Float32Array
|
|
50
|
+
*/
|
|
51
|
+
export function render_audio(user_code: string): Float32Array {
|
|
52
|
+
if (wasmPkg && typeof wasmPkg.render_audio === "function") {
|
|
53
|
+
return wasmPkg.render_audio(user_code);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Fallback: indicate missing wasm with an empty buffer rather than breaking consumers.
|
|
57
|
+
return new Float32Array(0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Register a JS callback to receive playhead events { time, line, column } during playback.
|
|
62
|
+
* The callback will be called with a single object argument.
|
|
63
|
+
* @param cb The callback function to register.
|
|
64
|
+
* @returns void
|
|
65
|
+
*/
|
|
66
|
+
export function register_playhead_callback(cb: (ev: { time: number; line: number; column: number }) => void) {
|
|
67
|
+
if (wasmPkg && typeof wasmPkg.register_playhead_callback === "function") {
|
|
68
|
+
return wasmPkg.register_playhead_callback(cb);
|
|
69
|
+
}
|
|
70
|
+
// no-op fallback
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Unregisters the JS callback for playhead events.
|
|
76
|
+
* @returns void
|
|
77
|
+
*/
|
|
78
|
+
export function unregister_playhead_callback() {
|
|
79
|
+
if (wasmPkg && typeof wasmPkg.unregister_playhead_callback === "function") {
|
|
80
|
+
return wasmPkg.unregister_playhead_callback();
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
@@ -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 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
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,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shim TypeScript source that re-exports the runtime wasm-pack package when
|
|
3
|
+
* available, or provides safe stubs when not present. Compiles to
|
|
4
|
+
* out-tsc/pkg/devalang_core.js so compiled code can require("./pkg/devalang_core").
|
|
5
|
+
*/
|
|
6
|
+
let runtimePkg: any;
|
|
7
|
+
try {
|
|
8
|
+
// prefer runtime pkg generated by wasm-pack when available
|
|
9
|
+
// require at runtime so the package can be used even if wasm hasn't been built
|
|
10
|
+
// (this keeps tests and consumers robust).
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
12
|
+
runtimePkg = require("../../pkg/devalang_core");
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
runtimePkg = undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function parse(...args: any[]) {
|
|
19
|
+
if (runtimePkg && typeof runtimePkg.parse === "function")
|
|
20
|
+
return runtimePkg.parse(...args);
|
|
21
|
+
throw new Error("WASM package not built: pkg/devalang_core not found");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function debug_render(...args: any[]) {
|
|
25
|
+
if (runtimePkg && typeof runtimePkg.debug_render === "function")
|
|
26
|
+
return runtimePkg.debug_render(...args);
|
|
27
|
+
throw new Error("WASM package not built: pkg/devalang_core not found");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function render_audio(...args: any[]) {
|
|
31
|
+
if (runtimePkg && typeof runtimePkg.render_audio === "function")
|
|
32
|
+
return runtimePkg.render_audio(...args);
|
|
33
|
+
return new Float32Array(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function register_playhead_callback(cb?: any) {
|
|
37
|
+
if (runtimePkg && typeof runtimePkg.register_playhead_callback === "function")
|
|
38
|
+
return runtimePkg.register_playhead_callback(cb);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function unregister_playhead_callback() {
|
|
43
|
+
if (runtimePkg && typeof runtimePkg.unregister_playhead_callback === "function")
|
|
44
|
+
return runtimePkg.unregister_playhead_callback();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const pkg = { parse, debug_render, render_audio, register_playhead_callback, unregister_playhead_callback };
|
|
49
|
+
export default pkg;
|
|
@@ -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);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createWriteStream, mkdirSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { https } from "follow-redirects";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
const projectVersionPath = path.join(__dirname, "../../project-version.json");
|
|
8
|
+
let versionString = "";
|
|
9
|
+
try {
|
|
10
|
+
if (!fs.existsSync(projectVersionPath)) {
|
|
11
|
+
console.warn(`⚠️ project-version.json not found at ${projectVersionPath}. Skipping postinstall binary download.`);
|
|
12
|
+
} else {
|
|
13
|
+
const version = fs.readFileSync(projectVersionPath, "utf-8").trim();
|
|
14
|
+
try {
|
|
15
|
+
versionString = JSON.parse(version).version;
|
|
16
|
+
} catch (e: any) {
|
|
17
|
+
console.warn(`⚠️ Failed to parse project-version.json: ${e.message}. Skipping binary download.`);
|
|
18
|
+
versionString = "";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
} catch (e: any) {
|
|
22
|
+
console.warn(`⚠️ Could not read project-version.json: ${e.message}. Skipping binary download.`);
|
|
23
|
+
versionString = "";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const platform = process.platform;
|
|
27
|
+
|
|
28
|
+
let binaryName: string = "";
|
|
29
|
+
|
|
30
|
+
switch (platform) {
|
|
31
|
+
case "win32":
|
|
32
|
+
binaryName = "devalang-x86_64-pc-windows-msvc.exe";
|
|
33
|
+
break;
|
|
34
|
+
case "darwin":
|
|
35
|
+
binaryName = "devalang-x86_64-apple-darwin";
|
|
36
|
+
break;
|
|
37
|
+
case "linux":
|
|
38
|
+
binaryName = "devalang-x86_64-unknown-linux-gnu";
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (binaryName !== "" && versionString) {
|
|
43
|
+
const destDir = join(__dirname, "..", "..", "out-tsc", "bin");
|
|
44
|
+
const dest = join(destDir, binaryName);
|
|
45
|
+
const url = `https://github.com/devaloop-labs/devalang/releases/download/v${versionString}/${binaryName}`;
|
|
46
|
+
|
|
47
|
+
mkdirSync(destDir, { recursive: true });
|
|
48
|
+
|
|
49
|
+
console.log(`⬇️ Downloading ${binaryName} from ${url}`);
|
|
50
|
+
|
|
51
|
+
const req = https.get(url, (res: any) => {
|
|
52
|
+
if (res.statusCode === 404) {
|
|
53
|
+
console.warn(`⚠️ Asset not found (HTTP 404). Skipping binary download.`);
|
|
54
|
+
res.resume();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (res.statusCode !== 200) {
|
|
59
|
+
console.warn(`⚠️ Failed (HTTP ${res.statusCode}). Skipping binary download.`);
|
|
60
|
+
res.resume();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const file = createWriteStream(dest, { mode: 0o755 });
|
|
65
|
+
res.pipe(file);
|
|
66
|
+
file.on("finish", () => {
|
|
67
|
+
file.close();
|
|
68
|
+
console.log(`✅ Downloaded ${binaryName} to ${dest}`);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
req.setTimeout(30000, () => {
|
|
73
|
+
console.warn(`⚠️ Download timed out after 30s. Skipping binary download for ${binaryName}.`);
|
|
74
|
+
try {
|
|
75
|
+
req.destroy();
|
|
76
|
+
} catch (e) {}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
req.on("error", (err: any) => {
|
|
80
|
+
// Network or other errors should not fail CI; log and continue
|
|
81
|
+
console.warn(`⚠️ Error downloading binary: ${err.message}. Skipping binary download.`);
|
|
82
|
+
});
|
|
83
|
+
} else {
|
|
84
|
+
console.warn(`⚠️ Unsupported platform: ${platform}. Skipping binary download.`);
|
|
85
|
+
}
|