@onda-lang/wasm-compiler 0.6.0 → 0.7.0
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/README.md +52 -3
- package/bin/onda-wasm.js +1 -1
- package/dist/backend/constants.js +1 -1
- package/dist/backend/index.js +2427 -342
- package/dist/build.json +3 -3
- package/dist/frontend/README.md +12 -3
- package/dist/frontend/onda_compiler_web.d.ts +94 -5
- package/dist/frontend/onda_compiler_web.js +442 -4
- package/dist/frontend/onda_compiler_web_bg.wasm +0 -0
- package/dist/frontend/onda_compiler_web_bg.wasm.d.ts +34 -3
- package/dist/frontend/package.json +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/src/index.d.ts +106 -3
- package/src/index.js +400 -19
- package/src/worker.js +58 -3
package/src/index.d.ts
CHANGED
|
@@ -50,15 +50,90 @@ export interface OndaCompileOptions {
|
|
|
50
50
|
codegen?: OndaCodegenOptions;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export interface
|
|
53
|
+
export interface OndaSourceWorkspace {
|
|
54
54
|
entry: string;
|
|
55
55
|
sources: Record<string, string>;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
export type OndaSourceReferenceKind = "include" | "import";
|
|
59
|
+
|
|
60
|
+
export interface OndaSourceDocument {
|
|
61
|
+
path: string;
|
|
62
|
+
contents: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface OndaSourceResolution {
|
|
66
|
+
source: string;
|
|
67
|
+
kind: OndaSourceReferenceKind;
|
|
68
|
+
specifier: string;
|
|
69
|
+
target: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface OndaSourceGraph {
|
|
73
|
+
entry: string;
|
|
74
|
+
stdlibDigest: string;
|
|
75
|
+
documents: OndaSourceDocument[];
|
|
76
|
+
resolutions: OndaSourceResolution[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type OndaBufferElement = "bool" | "i32" | "i64" | "f32" | "f64";
|
|
80
|
+
export type OndaBufferData =
|
|
81
|
+
| Uint8Array
|
|
82
|
+
| Int32Array
|
|
83
|
+
| BigInt64Array
|
|
84
|
+
| Float32Array
|
|
85
|
+
| Float64Array;
|
|
86
|
+
|
|
87
|
+
export interface OndaBufferAssetBinding {
|
|
88
|
+
element: OndaBufferElement;
|
|
89
|
+
frames: number;
|
|
90
|
+
channels: number;
|
|
91
|
+
sampleRate: number;
|
|
92
|
+
data: OndaBufferData;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface OndaProjectBufferInfo {
|
|
96
|
+
name: string;
|
|
97
|
+
assetId: string;
|
|
98
|
+
element: OndaBufferElement;
|
|
99
|
+
frames: number;
|
|
100
|
+
channels: number;
|
|
101
|
+
sampleRate: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface OndaProjectImageInfo {
|
|
105
|
+
formatVersion: number;
|
|
106
|
+
contentDigest: string;
|
|
107
|
+
sourceGraph: OndaSourceGraph;
|
|
108
|
+
buffers: OndaProjectBufferInfo[];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface OndaSerializedProjectImage extends OndaProjectImageInfo {
|
|
112
|
+
bytes: Uint8Array;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface OndaMaterializedProjectFile {
|
|
116
|
+
path: string;
|
|
117
|
+
bytes: Uint8Array;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface OndaProjectMaterialization {
|
|
121
|
+
directories: string[];
|
|
122
|
+
files: OndaMaterializedProjectFile[];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface OndaProjectCapabilities {
|
|
126
|
+
imageFormatVersion: number;
|
|
127
|
+
bufferAssetFormatVersion: number;
|
|
128
|
+
stdlibDigest: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
58
131
|
export interface OndaCompilationResult {
|
|
59
132
|
artifact: OndaProcessorArtifact;
|
|
60
133
|
/** Entry first, then transitive non-stdlib imports/includes in discovery order. */
|
|
61
134
|
sourceFiles: string[];
|
|
135
|
+
/** Exact resolved graph for successful multi-file/project-image compilation. */
|
|
136
|
+
sourceGraph: OndaSourceGraph | null;
|
|
62
137
|
}
|
|
63
138
|
|
|
64
139
|
export interface OndaCompilerInstance {
|
|
@@ -66,10 +141,38 @@ export interface OndaCompilerInstance {
|
|
|
66
141
|
source: string,
|
|
67
142
|
options?: OndaCompileOptions,
|
|
68
143
|
): Promise<OndaCompilationResult>;
|
|
69
|
-
|
|
70
|
-
|
|
144
|
+
compileWorkspace(
|
|
145
|
+
workspace: OndaSourceWorkspace,
|
|
146
|
+
options?: OndaCompileOptions,
|
|
147
|
+
): Promise<OndaCompilationResult>;
|
|
148
|
+
compileProjectImage(
|
|
149
|
+
imageBytes: ArrayBuffer | ArrayBufferView,
|
|
71
150
|
options?: OndaCompileOptions,
|
|
72
151
|
): Promise<OndaCompilationResult>;
|
|
152
|
+
createProjectImage(
|
|
153
|
+
sourceGraph: OndaSourceGraph,
|
|
154
|
+
buffers?: Map<string, ArrayBuffer | ArrayBufferView>
|
|
155
|
+
| Record<string, ArrayBuffer | ArrayBufferView>,
|
|
156
|
+
): Promise<OndaSerializedProjectImage>;
|
|
157
|
+
inspectProjectImage(
|
|
158
|
+
imageBytes: ArrayBuffer | ArrayBufferView,
|
|
159
|
+
): Promise<OndaProjectImageInfo>;
|
|
160
|
+
loadProjectFiles(
|
|
161
|
+
files: Map<string, ArrayBuffer | ArrayBufferView>
|
|
162
|
+
| Record<string, ArrayBuffer | ArrayBufferView>,
|
|
163
|
+
projectFilePath?: string | null,
|
|
164
|
+
): Promise<OndaSerializedProjectImage>;
|
|
165
|
+
materializeProjectImage(
|
|
166
|
+
imageBytes: ArrayBuffer | ArrayBufferView,
|
|
167
|
+
assetFileNames?: Map<string, string> | Record<string, string>,
|
|
168
|
+
): Promise<OndaProjectMaterialization>;
|
|
169
|
+
encodeBufferAsset(binding: OndaBufferAssetBinding): Promise<Uint8Array>;
|
|
170
|
+
decodeBufferAsset(bytes: ArrayBuffer | ArrayBufferView): Promise<OndaBufferAssetBinding>;
|
|
171
|
+
decodeBufferFile(
|
|
172
|
+
bytes: ArrayBuffer | ArrayBufferView,
|
|
173
|
+
path?: string,
|
|
174
|
+
): Promise<OndaBufferAssetBinding>;
|
|
175
|
+
projectCapabilities(): Promise<OndaProjectCapabilities>;
|
|
73
176
|
sendLspMessage(message: OndaLspMessage): Promise<OndaLspMessage[]>;
|
|
74
177
|
setLspAnalysisOptions(options?: OndaCompileOptions): Promise<void>;
|
|
75
178
|
dispose(): Promise<void>;
|
package/src/index.js
CHANGED
|
@@ -91,52 +91,204 @@ class OndaCompiler {
|
|
|
91
91
|
} catch (error) {
|
|
92
92
|
throw diagnosticsFromFrontend(error);
|
|
93
93
|
}
|
|
94
|
-
const { mir, sourceFiles } = consumeFrontendCompilation(frontendCompilation);
|
|
94
|
+
const { mir, sourceFiles, sourceGraph } = consumeFrontendCompilation(frontendCompilation);
|
|
95
95
|
const artifact = compileMirTransport(
|
|
96
96
|
mir,
|
|
97
97
|
compile.codegen,
|
|
98
98
|
this.compileTrustedMir,
|
|
99
99
|
sourceFiles,
|
|
100
100
|
);
|
|
101
|
-
return { artifact, sourceFiles };
|
|
101
|
+
return { artifact, sourceFiles, sourceGraph };
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
async
|
|
105
|
-
if (!
|
|
106
|
-
throw configurationError("
|
|
104
|
+
async compileWorkspace(workspace, options = {}) {
|
|
105
|
+
if (!workspace || typeof workspace !== "object" || Array.isArray(workspace)) {
|
|
106
|
+
throw configurationError("workspace must contain an entry and source map");
|
|
107
107
|
}
|
|
108
|
-
if (typeof
|
|
109
|
-
throw configurationError("
|
|
108
|
+
if (typeof workspace.entry !== "string" || workspace.entry.length === 0) {
|
|
109
|
+
throw configurationError("workspace.entry must be a non-empty string");
|
|
110
110
|
}
|
|
111
|
-
if (!
|
|
112
|
-
throw configurationError("
|
|
111
|
+
if (!workspace.sources || typeof workspace.sources !== "object" || Array.isArray(workspace.sources)) {
|
|
112
|
+
throw configurationError("workspace.sources must be an object of paths to source strings");
|
|
113
113
|
}
|
|
114
|
-
for (const [path, source] of Object.entries(
|
|
114
|
+
for (const [path, source] of Object.entries(workspace.sources)) {
|
|
115
115
|
if (typeof source !== "string") {
|
|
116
|
-
throw configurationError(`
|
|
116
|
+
throw configurationError(`workspace source '${path}' must be a string`);
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
const compile = normalizeCompileOptions(options);
|
|
121
121
|
let frontendCompilation;
|
|
122
122
|
try {
|
|
123
|
-
frontendCompilation = this.frontend.
|
|
124
|
-
|
|
125
|
-
JSON.stringify(
|
|
123
|
+
frontendCompilation = this.frontend.compile_source_workspace_to_mir_messagepack(
|
|
124
|
+
workspace.entry,
|
|
125
|
+
JSON.stringify(workspace.sources),
|
|
126
126
|
compile.sampleRate,
|
|
127
127
|
compile.blockSize,
|
|
128
128
|
);
|
|
129
129
|
} catch (error) {
|
|
130
130
|
throw diagnosticsFromFrontend(error);
|
|
131
131
|
}
|
|
132
|
-
const { mir, sourceFiles } = consumeFrontendCompilation(frontendCompilation);
|
|
132
|
+
const { mir, sourceFiles, sourceGraph } = consumeFrontendCompilation(frontendCompilation);
|
|
133
133
|
const artifact = compileMirTransport(
|
|
134
134
|
mir,
|
|
135
135
|
compile.codegen,
|
|
136
136
|
this.compileTrustedMir,
|
|
137
137
|
sourceFiles,
|
|
138
138
|
);
|
|
139
|
-
return { artifact, sourceFiles };
|
|
139
|
+
return { artifact, sourceFiles, sourceGraph };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async compileProjectImage(imageBytes, options = {}) {
|
|
143
|
+
const bytes = normalizeBytes(imageBytes, "project image");
|
|
144
|
+
const compile = normalizeCompileOptions(options);
|
|
145
|
+
let frontendCompilation;
|
|
146
|
+
try {
|
|
147
|
+
frontendCompilation = this.frontend.compile_project_image_to_mir_messagepack(
|
|
148
|
+
bytes,
|
|
149
|
+
compile.sampleRate,
|
|
150
|
+
compile.blockSize,
|
|
151
|
+
);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
throw diagnosticsFromFrontend(error);
|
|
154
|
+
}
|
|
155
|
+
const { mir, sourceFiles, sourceGraph } = consumeFrontendCompilation(frontendCompilation);
|
|
156
|
+
const artifact = compileMirTransport(
|
|
157
|
+
mir,
|
|
158
|
+
compile.codegen,
|
|
159
|
+
this.compileTrustedMir,
|
|
160
|
+
sourceFiles,
|
|
161
|
+
);
|
|
162
|
+
return { artifact, sourceFiles, sourceGraph };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async createProjectImage(sourceGraph, buffers = new Map()) {
|
|
166
|
+
const graph = normalizeSourceGraph(sourceGraph);
|
|
167
|
+
const builder = new this.frontend.WebProjectImageBuilder(JSON.stringify(graph));
|
|
168
|
+
try {
|
|
169
|
+
for (const [name, bytes] of normalizeBufferAssetEntries(buffers)) {
|
|
170
|
+
builder.add_buffer(name, bytes);
|
|
171
|
+
}
|
|
172
|
+
const bytes = builder.serialize();
|
|
173
|
+
return {
|
|
174
|
+
bytes,
|
|
175
|
+
...normalizeProjectImageInfo(JSON.parse(this.frontend.inspect_project_image(bytes))),
|
|
176
|
+
};
|
|
177
|
+
} catch (cause) {
|
|
178
|
+
throw new OndaCompilerError("failed to create Onda project image", { cause });
|
|
179
|
+
} finally {
|
|
180
|
+
builder.free();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async inspectProjectImage(imageBytes) {
|
|
185
|
+
try {
|
|
186
|
+
return normalizeProjectImageInfo(JSON.parse(this.frontend.inspect_project_image(
|
|
187
|
+
normalizeBytes(imageBytes, "project image"),
|
|
188
|
+
)));
|
|
189
|
+
} catch (cause) {
|
|
190
|
+
throw new OndaCompilerError("failed to inspect Onda project image", { cause });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async loadProjectFiles(files, projectFilePath = null) {
|
|
195
|
+
const builder = new this.frontend.WebMaterializedProjectBuilder();
|
|
196
|
+
try {
|
|
197
|
+
if (projectFilePath !== null) {
|
|
198
|
+
builder.select_project(normalizeProjectFilePath(projectFilePath));
|
|
199
|
+
}
|
|
200
|
+
for (const [path, bytes] of normalizeProjectFileEntries(files)) {
|
|
201
|
+
builder.add_file(path, bytes);
|
|
202
|
+
}
|
|
203
|
+
const bytes = builder.serialize();
|
|
204
|
+
return {
|
|
205
|
+
bytes,
|
|
206
|
+
...normalizeProjectImageInfo(JSON.parse(this.frontend.inspect_project_image(bytes))),
|
|
207
|
+
};
|
|
208
|
+
} catch (cause) {
|
|
209
|
+
throw new OndaCompilerError("failed to load Onda project files", { cause });
|
|
210
|
+
} finally {
|
|
211
|
+
builder.free();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async materializeProjectImage(imageBytes, assetFileNames = new Map()) {
|
|
216
|
+
let plan;
|
|
217
|
+
try {
|
|
218
|
+
plan = this.frontend.materialize_project_image(
|
|
219
|
+
normalizeBytes(imageBytes, "project image"),
|
|
220
|
+
JSON.stringify(Object.fromEntries(normalizeAssetFileNameEntries(assetFileNames))),
|
|
221
|
+
);
|
|
222
|
+
const files = [];
|
|
223
|
+
for (let index = 0; index < plan.file_count(); index += 1) {
|
|
224
|
+
files.push({ path: plan.file_path(index), bytes: plan.file_bytes(index) });
|
|
225
|
+
}
|
|
226
|
+
return { directories: JSON.parse(plan.directories_json()), files };
|
|
227
|
+
} catch (cause) {
|
|
228
|
+
throw new OndaCompilerError("failed to materialize Onda project image", { cause });
|
|
229
|
+
} finally {
|
|
230
|
+
plan?.free();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async encodeBufferAsset(binding) {
|
|
235
|
+
const normalized = normalizeBufferBinding(binding);
|
|
236
|
+
try {
|
|
237
|
+
return this.frontend.encode_buffer_asset(
|
|
238
|
+
normalized.element,
|
|
239
|
+
normalized.frames,
|
|
240
|
+
normalized.channels,
|
|
241
|
+
normalized.sampleRate,
|
|
242
|
+
encodeCanonicalPayload(normalized.element, normalized.data),
|
|
243
|
+
);
|
|
244
|
+
} catch (cause) {
|
|
245
|
+
throw new OndaCompilerError("failed to encode Onda buffer asset", { cause });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async decodeBufferAsset(bytes) {
|
|
250
|
+
return this.#decodeBuffer(
|
|
251
|
+
() => this.frontend.decode_buffer_asset(normalizeBytes(bytes, "buffer asset")),
|
|
252
|
+
"failed to decode Onda buffer asset",
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async decodeBufferFile(bytes, path = "buffer") {
|
|
257
|
+
return this.#decodeBuffer(
|
|
258
|
+
() => this.frontend.decode_buffer_file(
|
|
259
|
+
normalizeBytes(bytes, "buffer file"),
|
|
260
|
+
String(path),
|
|
261
|
+
),
|
|
262
|
+
"failed to decode buffer file",
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async #decodeBuffer(decode, message) {
|
|
267
|
+
let decoded;
|
|
268
|
+
try {
|
|
269
|
+
decoded = decode();
|
|
270
|
+
const element = decoded.element();
|
|
271
|
+
const payload = decoded.canonical_payload();
|
|
272
|
+
return {
|
|
273
|
+
element,
|
|
274
|
+
frames: decoded.frames(),
|
|
275
|
+
channels: decoded.channels(),
|
|
276
|
+
sampleRate: decoded.sample_rate(),
|
|
277
|
+
data: decodeCanonicalPayload(element, payload),
|
|
278
|
+
};
|
|
279
|
+
} catch (cause) {
|
|
280
|
+
throw new OndaCompilerError(message, { cause });
|
|
281
|
+
} finally {
|
|
282
|
+
decoded?.free();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async projectCapabilities() {
|
|
287
|
+
return {
|
|
288
|
+
imageFormatVersion: this.frontend.project_image_format_version(),
|
|
289
|
+
bufferAssetFormatVersion: this.frontend.buffer_asset_format_version(),
|
|
290
|
+
stdlibDigest: this.frontend.current_stdlib_digest(),
|
|
291
|
+
};
|
|
140
292
|
}
|
|
141
293
|
|
|
142
294
|
async sendLspMessage(message) {
|
|
@@ -190,8 +342,44 @@ class WorkerOndaCompiler {
|
|
|
190
342
|
return this.request("compileSource", { source, options });
|
|
191
343
|
}
|
|
192
344
|
|
|
193
|
-
|
|
194
|
-
return this.request("
|
|
345
|
+
compileWorkspace(workspace, options = {}) {
|
|
346
|
+
return this.request("compileWorkspace", { workspace, options });
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
compileProjectImage(imageBytes, options = {}) {
|
|
350
|
+
return this.request("compileProjectImage", { imageBytes, options });
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
createProjectImage(sourceGraph, buffers = new Map()) {
|
|
354
|
+
return this.request("createProjectImage", { sourceGraph, buffers });
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
inspectProjectImage(imageBytes) {
|
|
358
|
+
return this.request("inspectProjectImage", { imageBytes });
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
loadProjectFiles(files, projectFilePath = null) {
|
|
362
|
+
return this.request("loadProjectFiles", { files, projectFilePath });
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
materializeProjectImage(imageBytes, assetFileNames = new Map()) {
|
|
366
|
+
return this.request("materializeProjectImage", { imageBytes, assetFileNames });
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
encodeBufferAsset(binding) {
|
|
370
|
+
return this.request("encodeBufferAsset", { binding });
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
decodeBufferAsset(bytes) {
|
|
374
|
+
return this.request("decodeBufferAsset", { bytes });
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
decodeBufferFile(bytes, path = "buffer") {
|
|
378
|
+
return this.request("decodeBufferFile", { bytes, path });
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
projectCapabilities() {
|
|
382
|
+
return this.request("projectCapabilities");
|
|
195
383
|
}
|
|
196
384
|
|
|
197
385
|
sendLspMessage(message) {
|
|
@@ -340,7 +528,10 @@ function consumeFrontendCompilation(compilation) {
|
|
|
340
528
|
try {
|
|
341
529
|
const mir = compilation.take_mir();
|
|
342
530
|
const sourceFiles = normalizeSourceFiles(JSON.parse(compilation.source_files_json()));
|
|
343
|
-
|
|
531
|
+
const sourceGraph = normalizeReturnedSourceGraph(
|
|
532
|
+
JSON.parse(compilation.source_image_json()),
|
|
533
|
+
);
|
|
534
|
+
return { mir, sourceFiles, sourceGraph };
|
|
344
535
|
} finally {
|
|
345
536
|
compilation.free();
|
|
346
537
|
}
|
|
@@ -430,3 +621,193 @@ function normalizeSourceFiles(sourceFiles) {
|
|
|
430
621
|
if (!Array.isArray(sourceFiles)) return [];
|
|
431
622
|
return sourceFiles.map((path) => String(path));
|
|
432
623
|
}
|
|
624
|
+
|
|
625
|
+
function normalizeBytes(value, context) {
|
|
626
|
+
if (value instanceof Uint8Array) return value;
|
|
627
|
+
if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
628
|
+
if (ArrayBuffer.isView(value)) {
|
|
629
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
630
|
+
}
|
|
631
|
+
throw new OndaCompilerError(`${context} must be an ArrayBuffer or typed-array view`);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function normalizeSourceGraph(graph) {
|
|
635
|
+
if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
|
|
636
|
+
throw new OndaCompilerError("source graph must be an object");
|
|
637
|
+
}
|
|
638
|
+
const entry = String(graph.entry ?? "");
|
|
639
|
+
const stdlibDigest = String(graph.stdlibDigest ?? graph.stdlib_digest ?? "");
|
|
640
|
+
if (!entry || !stdlibDigest) {
|
|
641
|
+
throw new OndaCompilerError("source graph requires entry and stdlibDigest");
|
|
642
|
+
}
|
|
643
|
+
const documents = Array.isArray(graph.documents) ? graph.documents.map((document) => ({
|
|
644
|
+
path: String(document?.path ?? ""),
|
|
645
|
+
contents: String(document?.contents ?? ""),
|
|
646
|
+
})) : [];
|
|
647
|
+
const resolutions = Array.isArray(graph.resolutions) ? graph.resolutions.map((resolution) => ({
|
|
648
|
+
source: String(resolution?.source ?? ""),
|
|
649
|
+
kind: String(resolution?.kind ?? ""),
|
|
650
|
+
specifier: String(resolution?.specifier ?? ""),
|
|
651
|
+
target: String(resolution?.target ?? ""),
|
|
652
|
+
})) : [];
|
|
653
|
+
return {
|
|
654
|
+
entry,
|
|
655
|
+
stdlib_digest: stdlibDigest,
|
|
656
|
+
documents,
|
|
657
|
+
resolutions,
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function normalizeReturnedSourceGraph(graph) {
|
|
662
|
+
if (!graph) return null;
|
|
663
|
+
return {
|
|
664
|
+
entry: String(graph.entry),
|
|
665
|
+
stdlibDigest: String(graph.stdlib_digest),
|
|
666
|
+
documents: graph.documents.map((document) => ({
|
|
667
|
+
path: String(document.path),
|
|
668
|
+
contents: String(document.contents),
|
|
669
|
+
})),
|
|
670
|
+
resolutions: graph.resolutions.map((resolution) => ({
|
|
671
|
+
source: String(resolution.source),
|
|
672
|
+
kind: String(resolution.kind),
|
|
673
|
+
specifier: String(resolution.specifier),
|
|
674
|
+
target: String(resolution.target),
|
|
675
|
+
})),
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function normalizeProjectImageInfo(info) {
|
|
680
|
+
return {
|
|
681
|
+
formatVersion: Number(info.format_version),
|
|
682
|
+
contentDigest: String(info.content_digest),
|
|
683
|
+
sourceGraph: normalizeReturnedSourceGraph(info.sources),
|
|
684
|
+
buffers: info.buffers.map((buffer) => ({
|
|
685
|
+
name: String(buffer.name),
|
|
686
|
+
assetId: String(buffer.asset_id),
|
|
687
|
+
element: String(buffer.element),
|
|
688
|
+
frames: Number(buffer.frames),
|
|
689
|
+
channels: Number(buffer.channels),
|
|
690
|
+
sampleRate: Number(buffer.sample_rate),
|
|
691
|
+
})),
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function normalizeBufferAssetEntries(buffers) {
|
|
696
|
+
const entries = buffers instanceof Map
|
|
697
|
+
? [...buffers]
|
|
698
|
+
: buffers && typeof buffers === "object" && !Array.isArray(buffers)
|
|
699
|
+
? Object.entries(buffers)
|
|
700
|
+
: null;
|
|
701
|
+
if (!entries) throw new OndaCompilerError("project buffers must be a Map or object");
|
|
702
|
+
return entries.map(([name, bytes]) => {
|
|
703
|
+
if (typeof name !== "string" || !name) {
|
|
704
|
+
throw new OndaCompilerError("project buffer names must be non-empty strings");
|
|
705
|
+
}
|
|
706
|
+
return [name, normalizeBytes(bytes, `project buffer '${name}'`)];
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function normalizeAssetFileNameEntries(fileNames) {
|
|
711
|
+
const entries = fileNames instanceof Map
|
|
712
|
+
? [...fileNames]
|
|
713
|
+
: fileNames && typeof fileNames === "object" && !Array.isArray(fileNames)
|
|
714
|
+
? Object.entries(fileNames)
|
|
715
|
+
: null;
|
|
716
|
+
if (!entries) throw new OndaCompilerError("asset filenames must be a Map or object");
|
|
717
|
+
return entries.map(([name, fileName]) => {
|
|
718
|
+
if (typeof name !== "string" || !name || typeof fileName !== "string" || !fileName) {
|
|
719
|
+
throw new OndaCompilerError("asset filenames require non-empty buffer names and filenames");
|
|
720
|
+
}
|
|
721
|
+
return [name, fileName];
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
function normalizeProjectFilePath(path) {
|
|
726
|
+
if (typeof path !== "string" || !path) {
|
|
727
|
+
throw new OndaCompilerError("selected project manifest must be a non-empty string");
|
|
728
|
+
}
|
|
729
|
+
return path;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
function normalizeProjectFileEntries(files) {
|
|
733
|
+
const entries = files instanceof Map
|
|
734
|
+
? [...files]
|
|
735
|
+
: files && typeof files === "object" && !Array.isArray(files)
|
|
736
|
+
? Object.entries(files)
|
|
737
|
+
: null;
|
|
738
|
+
if (!entries) throw new OndaCompilerError("project files must be a Map or object");
|
|
739
|
+
return entries.map(([path, bytes]) => {
|
|
740
|
+
if (typeof path !== "string" || !path) {
|
|
741
|
+
throw new OndaCompilerError("project file paths must be non-empty strings");
|
|
742
|
+
}
|
|
743
|
+
return [path, normalizeBytes(bytes, `project file '${path}'`)];
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
function normalizeBufferBinding(binding) {
|
|
748
|
+
if (!binding || typeof binding !== "object" || Array.isArray(binding)) {
|
|
749
|
+
throw new OndaCompilerError("buffer binding must be an object");
|
|
750
|
+
}
|
|
751
|
+
const element = String(binding.element ?? binding.scalar ?? "");
|
|
752
|
+
const frames = Number(binding.frames);
|
|
753
|
+
const channels = Number(binding.channels);
|
|
754
|
+
const sampleRate = Number(binding.sampleRate);
|
|
755
|
+
const data = binding.data;
|
|
756
|
+
const expectedConstructor = {
|
|
757
|
+
bool: Uint8Array,
|
|
758
|
+
i32: Int32Array,
|
|
759
|
+
i64: BigInt64Array,
|
|
760
|
+
f32: Float32Array,
|
|
761
|
+
f64: Float64Array,
|
|
762
|
+
}[element];
|
|
763
|
+
if (!expectedConstructor || !(data instanceof expectedConstructor)) {
|
|
764
|
+
throw new OndaCompilerError(`buffer element '${element}' requires ${expectedConstructor?.name ?? "a supported typed array"}`);
|
|
765
|
+
}
|
|
766
|
+
if (
|
|
767
|
+
!Number.isInteger(frames) || frames <= 0
|
|
768
|
+
|| !Number.isInteger(channels) || channels <= 0
|
|
769
|
+
|| !Number.isFinite(sampleRate) || sampleRate <= 0
|
|
770
|
+
|| data.length !== frames * channels
|
|
771
|
+
) {
|
|
772
|
+
throw new OndaCompilerError("buffer binding has an invalid shape or sample rate");
|
|
773
|
+
}
|
|
774
|
+
return { element, frames, channels, sampleRate, data };
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
function encodeCanonicalPayload(element, data) {
|
|
778
|
+
if (element === "bool") {
|
|
779
|
+
if (data.some((value) => value > 1)) {
|
|
780
|
+
throw new OndaCompilerError("bool buffer values must be 0 or 1");
|
|
781
|
+
}
|
|
782
|
+
return data.slice();
|
|
783
|
+
}
|
|
784
|
+
const bytes = new Uint8Array(data.length * data.BYTES_PER_ELEMENT);
|
|
785
|
+
const view = new DataView(bytes.buffer);
|
|
786
|
+
for (let index = 0; index < data.length; index += 1) {
|
|
787
|
+
const offset = index * data.BYTES_PER_ELEMENT;
|
|
788
|
+
if (element === "i32") view.setInt32(offset, data[index], true);
|
|
789
|
+
else if (element === "i64") view.setBigInt64(offset, data[index], true);
|
|
790
|
+
else if (element === "f32") view.setFloat32(offset, data[index], true);
|
|
791
|
+
else view.setFloat64(offset, data[index], true);
|
|
792
|
+
}
|
|
793
|
+
return bytes;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
function decodeCanonicalPayload(element, payload) {
|
|
797
|
+
if (element === "bool") return payload.slice();
|
|
798
|
+
const elementBytes = element === "i32" || element === "f32" ? 4 : 8;
|
|
799
|
+
const length = payload.byteLength / elementBytes;
|
|
800
|
+
const output = element === "i32" ? new Int32Array(length)
|
|
801
|
+
: element === "i64" ? new BigInt64Array(length)
|
|
802
|
+
: element === "f32" ? new Float32Array(length)
|
|
803
|
+
: new Float64Array(length);
|
|
804
|
+
const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);
|
|
805
|
+
for (let index = 0; index < length; index += 1) {
|
|
806
|
+
const offset = index * elementBytes;
|
|
807
|
+
output[index] = element === "i32" ? view.getInt32(offset, true)
|
|
808
|
+
: element === "i64" ? view.getBigInt64(offset, true)
|
|
809
|
+
: element === "f32" ? view.getFloat32(offset, true)
|
|
810
|
+
: view.getFloat64(offset, true);
|
|
811
|
+
}
|
|
812
|
+
return output;
|
|
813
|
+
}
|
package/src/worker.js
CHANGED
|
@@ -19,14 +19,69 @@ globalThis.addEventListener("message", async (event) => {
|
|
|
19
19
|
respond(requestId, result, [result.artifact.wasm.buffer]);
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
|
-
if (message.type === "
|
|
23
|
-
const result = await (await compiler()).
|
|
24
|
-
message.
|
|
22
|
+
if (message.type === "compileWorkspace") {
|
|
23
|
+
const result = await (await compiler()).compileWorkspace(
|
|
24
|
+
message.workspace,
|
|
25
25
|
message.options,
|
|
26
26
|
);
|
|
27
27
|
respond(requestId, result, [result.artifact.wasm.buffer]);
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
+
if (message.type === "compileProjectImage") {
|
|
31
|
+
const result = await (await compiler()).compileProjectImage(
|
|
32
|
+
message.imageBytes,
|
|
33
|
+
message.options,
|
|
34
|
+
);
|
|
35
|
+
respond(requestId, result, [result.artifact.wasm.buffer]);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (message.type === "createProjectImage") {
|
|
39
|
+
const result = await (await compiler()).createProjectImage(
|
|
40
|
+
message.sourceGraph,
|
|
41
|
+
message.buffers,
|
|
42
|
+
);
|
|
43
|
+
respond(requestId, result, [result.bytes.buffer]);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (message.type === "inspectProjectImage") {
|
|
47
|
+
respond(requestId, await (await compiler()).inspectProjectImage(message.imageBytes));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (message.type === "loadProjectFiles") {
|
|
51
|
+
const result = await (await compiler()).loadProjectFiles(
|
|
52
|
+
message.files,
|
|
53
|
+
message.projectFilePath,
|
|
54
|
+
);
|
|
55
|
+
respond(requestId, result, [result.bytes.buffer]);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (message.type === "materializeProjectImage") {
|
|
59
|
+
const result = await (await compiler()).materializeProjectImage(
|
|
60
|
+
message.imageBytes,
|
|
61
|
+
message.assetFileNames,
|
|
62
|
+
);
|
|
63
|
+
respond(requestId, result, result.files.map((file) => file.bytes.buffer));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (message.type === "encodeBufferAsset") {
|
|
67
|
+
const result = await (await compiler()).encodeBufferAsset(message.binding);
|
|
68
|
+
respond(requestId, result, [result.buffer]);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (message.type === "decodeBufferAsset") {
|
|
72
|
+
const result = await (await compiler()).decodeBufferAsset(message.bytes);
|
|
73
|
+
respond(requestId, result, [result.data.buffer]);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (message.type === "decodeBufferFile") {
|
|
77
|
+
const result = await (await compiler()).decodeBufferFile(message.bytes, message.path);
|
|
78
|
+
respond(requestId, result, [result.data.buffer]);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (message.type === "projectCapabilities") {
|
|
82
|
+
respond(requestId, await (await compiler()).projectCapabilities());
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
30
85
|
if (message.type === "lspMessage") {
|
|
31
86
|
const responses = await (await compiler()).sendLspMessage(message.message);
|
|
32
87
|
respond(requestId, responses);
|