1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
|
# JavaScript Interop
This document covers Baba Yaga's JavaScript interoperability features, which allow safe and controlled access to JavaScript functionality while maintaining Baba Yaga's functional programming guarantees.
## Table of Contents
1. [Overview](#overview)
2. [Core Functions](#core-functions)
3. [Type Conversion](#type-conversion)
4. [Security Model](#security-model)
5. [Common Patterns](#common-patterns)
6. [Error Handling](#error-handling)
7. [Configuration](#configuration)
8. [Best Practices](#best-practices)
9. [Examples](#examples)
## Overview
Baba Yaga's JavaScript interop system provides a safe bridge between Baba Yaga's functional, immutable world and JavaScript's imperative, mutable one. All JavaScript operations return `Result` types to maintain explicit error handling.
### Key Principles
- **Safety First**: All JS operations are sandboxed and return `Result` types
- **Explicit Boundaries**: Clear separation between Baba Yaga and JavaScript
- **Type Safety**: Automatic conversion between type systems
- **Error Isolation**: JavaScript errors become Baba Yaga `Err` values
## Core Functions
All JavaScript interop functions are available in the `io.*` namespace.
### Function Calls
#### `io.callJS`
Call a JavaScript function synchronously.
```baba
io.callJS : (functionName: String, args: [Any]) -> Result
// Examples
absResult : io.callJS "Math.abs" [-42];
// Returns: Ok (JSValue 42)
parseResult : io.callJS "JSON.parse" ["{\"x\": 10}"];
// Returns: Ok (JSValue {x: 10})
// Note: io.callJS returns a Result whose Ok value is a JSValue wrapper
// around the raw JavaScript value. You can pass this JSValue directly to
// io.getProperty, io.setProperty, io.hasProperty, io.jsArrayToList,
// io.objectToTable, etc. without manual unwrapping.
```
#### `io.callJSAsync`
Call a JavaScript function asynchronously (if async operations are enabled).
```baba
io.callJSAsync : (functionName: String, args: [Any]) -> Result
// Example (requires enableAsyncOps: true)
fetchResult : io.callJSAsync "fetch" ["https://api.example.com/data"];
```
### Property Access
#### `io.getProperty`
Get a property from a JavaScript object.
```baba
io.getProperty : (obj: Any, propName: String) -> Result
// Example
obj : io.callJS "JSON.parse" ["{\"name\": \"Alice\"}"];
nameResult : when obj is
Ok parsed then io.getProperty parsed "name"
Err msg then Err msg;
// Returns: Ok "Alice" (direct Baba Yaga string)
```
#### `io.setProperty`
Set a property on a JavaScript object (mutates the object).
```baba
io.setProperty : (obj: Any, propName: String, value: Any) -> Result
// Example
obj : io.callJS "JSON.parse" ["{}"];
result : when obj is
Ok parsed then io.setProperty parsed "newProp" 42
Err msg then Err msg;
```
#### `io.hasProperty`
Check if a property exists on a JavaScript object.
```baba
io.hasProperty : (obj: Any, propName: String) -> Bool
// Example
obj : io.callJS "JSON.parse" ["{\"x\": 10}"];
hasX : when obj is
Ok parsed then io.hasProperty parsed "x"
Err _ then false;
// Returns: true
```
### Type Conversion
#### `io.jsArrayToList`
Convert a JavaScript array to a Baba Yaga list.
```baba
io.jsArrayToList : (jsArray: Any) -> Result
// Example
jsArray : io.callJS "JSON.parse" ["[1, 2, 3]"];
listResult : when jsArray is
Ok arr then io.jsArrayToList arr
Err msg then Err msg;
// Returns: Ok [1, 2, 3] (direct Baba Yaga list)
```
#### `io.listToJSArray`
Convert a Baba Yaga list to a JavaScript array.
```baba
io.listToJSArray : (list: [Any]) -> Any
// Example
babaList : [1, 2, 3, 4, 5];
jsArray : io.listToJSArray babaList;
jsonResult : io.callJS "JSON.stringify" [jsArray];
// Returns: Ok (JSValue "[1,2,3,4,5]")
```
#### `io.objectToTable`
Convert a JavaScript object to a Baba Yaga table.
```baba
io.objectToTable : (obj: Any) -> Result
// Example
jsObj : io.callJS "JSON.parse" ["{\"name\": \"Bob\", \"age\": 25}"];
tableResult : when jsObj is
Ok obj then io.objectToTable obj
Err msg then Err msg;
// Returns: Ok {name: "Bob", age: 25} (direct Baba Yaga table)
```
#### `io.tableToObject`
Convert a Baba Yaga table to a JavaScript object.
```baba
io.tableToObject : (table: Table) -> Any
// Example
babaTable : {x: 100, y: 200};
jsObj : io.tableToObject babaTable;
jsonResult : io.callJS "JSON.stringify" [jsObj];
// Returns: Ok (JSValue "{\"x\":100,\"y\":200}")
```
### Error Management
#### `io.getLastJSError`
Get the last JavaScript error that occurred.
Note: depending on language syntax rules for zero-argument functions, direct invocation may not be available in all contexts. Prefer handling errors from `io.callJS` directly via the returned `Result`.
#### `io.clearJSError`
Clear the last JavaScript error.
Note: same invocation caveat as above applies.
## Type Conversion
### Automatic Conversions
The JavaScript bridge automatically converts between Baba Yaga and JavaScript types:
| Baba Yaga Type | JavaScript Type | Notes |
|----------------|-----------------|-------------------------------------|
| `Number` | `number` | Preserves integer/float distinction |
| `String` | `string` | Direct conversion |
| `Bool` | `boolean` | Direct conversion |
| `List` | `Array` | Recursive conversion of elements |
| `Table` | `Object` | Converts Map to plain object |
| `Result` | N/A | Handled at boundary |
### Manual Conversions
For more control, use explicit conversion functions:
```baba
// Safe JSON parsing with error handling
parseJSON : jsonString ->
when (validate.type "String" jsonString) is
false then Err "Input must be a string"
true then when (io.callJS "JSON.parse" [jsonString]) is
Ok parsed then Ok (io.objectToTable parsed)
Err msg then Err ("JSON parse error: " .. msg);
// Usage
result : parseJSON "{\"user\": \"Alice\", \"score\": 95}";
```
## Security Model
The JavaScript interop system uses a configurable security model:
### Sandboxed Execution
All JavaScript code runs in a controlled sandbox with:
- **Limited Global Access**: Only allowed globals are available
- **Function Whitelist**: Only explicitly allowed functions can be called
- **Timeout Protection**: Operations have configurable time limits
- **Memory Limits**: Configurable memory usage constraints
### Default Allowed Functions
By default, these JavaScript functions are available:
```javascript
// JSON operations
'JSON.parse', 'JSON.stringify',
// Math operations
'Math.abs', 'Math.floor', 'Math.ceil', 'Math.round',
'Math.min', 'Math.max', 'Math.random',
// Console operations
'console.log', 'console.warn', 'console.error',
// Time operations
'Date.now', 'performance.now'
```
### Configuration
Configure the JavaScript bridge through the host configuration:
```javascript
const host = {
jsBridgeConfig: {
allowedFunctions: new Set(['Math.abs', 'JSON.parse']),
maxExecutionTime: 5000, // 5 seconds
enableAsyncOps: false, // Disable async operations
enableFileSystem: false, // Disable file system access
enableNetwork: false // Disable network access
}
};
```
## Common Patterns
### Safe JSON Operations
```baba
// Safe JSON parsing
safeParseJSON : jsonStr ->
when (io.callJS "JSON.parse" [jsonStr]) is
Ok obj then when (io.objectToTable obj) is
Ok table then Ok table
Err msg then Err ("Conversion error: " .. msg)
Err msg then Err ("Parse error: " .. msg);
// Safe JSON stringification
safeStringifyJSON : table ->
jsObj : io.tableToObject table;
io.callJS "JSON.stringify" [jsObj];
```
### Mathematical Operations
```baba
// Safe mathematical operations with validation
safeMath : operation args ->
when (validate.notEmpty args) is
false then Err "No arguments provided"
true then when operation is
"abs" then io.callJS "Math.abs" [head args]
"min" then io.callJS "Math.min" args
"max" then io.callJS "Math.max" args
"round" then io.callJS "Math.round" [head args]
_ then Err ("Unknown operation: " .. operation);
// Usage
result : safeMath "abs" [-42]; // Ok 42
minResult : safeMath "min" [10, 5, 8]; // Ok 5
```
### Working with JavaScript APIs
```baba
// Date operations
getCurrentTimestamp : () ->
io.callJS "Date.now" [];
formatDate : timestamp ->
when (io.callJS "Date" [timestamp]) is
Ok dateObj then io.callJS "Date.prototype.toISOString" [dateObj]
Err msg then Err msg;
// Performance monitoring
measurePerformance : operation ->
startTime : io.callJS "performance.now" [];
result : operation;
endTime : io.callJS "performance.now" [];
duration : when (startTime, endTime) is
(Ok start, Ok end) then Ok (end - start)
_ then Err "Could not measure performance";
{result: result, duration: duration};
```
## Error Handling
### JavaScript Error Types
JavaScript errors are automatically converted to Baba Yaga `Err` values:
```baba
// This will return an Err
result : io.callJS "JSON.parse" ["invalid json"];
// Returns: Err "Unexpected token i in JSON at position 0"
// Handle different error types
handleJSError : result ->
when result is
Ok value then processValue value
Err msg then when (text.contains msg "JSON") is
true then handleJSONError msg
false then handleGenericError msg;
```
### Error Recovery Patterns
```baba
// Retry pattern
retryOperation : operation maxAttempts ->
attempt : 1;
tryOperation : currentAttempt ->
when (currentAttempt > maxAttempts) is
true then Err "Max attempts exceeded"
false then when (operation) is
Ok result then Ok result
Err _ then tryOperation (currentAttempt + 1);
tryOperation attempt;
// Fallback pattern
withFallback : primaryOp fallbackOp ->
when primaryOp is
Ok result then Ok result
Err _ then fallbackOp;
```
## Best Practices
### 1. Always Use Result Types
Never assume JavaScript operations will succeed:
```baba
// Good
result : when (io.callJS "Math.abs" [value]) is
Ok abs then processValue abs
Err msg then handleError msg;
// Bad - assumes success
abs : io.callJS "Math.abs" [value]; // This returns Result, not number
```
### 2. Validate Inputs
Always validate data before sending to JavaScript:
```baba
// Good
safeCall : value ->
when (validate.type "Number" value) is
false then Err "Value must be a number"
true then io.callJS "Math.abs" [value];
// Bad - no validation
unsafeCall : value ->
io.callJS "Math.abs" [value];
```
### 3. Handle Type Conversions Explicitly
Be explicit about type conversions:
```baba
// Good
processJSData : jsData ->
when (io.objectToTable jsData) is
Ok table then processTable table
Err msg then Err ("Conversion failed: " .. msg);
// Bad - assumes conversion works
processJSData : jsData ->
table : io.objectToTable jsData;
processTable table;
```
### 4. Use Composition for Complex Operations
Break complex JavaScript interactions into smaller, composable functions:
```baba
// Composed operations
parseAndValidate : jsonStr schema ->
parsed : safeParseJSON jsonStr;
when parsed is
Ok data then validateAgainstSchema data schema
Err msg then Err msg;
transformAndStringify : data transformer ->
transformed : transformer data;
safeStringifyJSON transformed;
```
## Examples
### Complete JSON Processing Pipeline
```baba
// Complete JSON processing with error handling
processJSONData : jsonString ->
// Parse JSON
parseResult : io.callJS "JSON.parse" [jsonString];
when parseResult is
Err msg then Err ("Parse failed: " .. msg)
Ok jsObj then
// Convert to Baba Yaga table
when (io.objectToTable jsObj) is
Err msg then Err ("Conversion failed: " .. msg)
Ok table then
// Process the data
processedTable : processData table;
// Convert back to JS object
jsResult : io.tableToObject processedTable;
// Stringify result
io.callJS "JSON.stringify" [jsResult];
// Helper function
processData : table ->
// Add timestamp
withTimestamp : table .. {timestamp: getCurrentTimestamp};
// Validate required fields
when (hasRequiredFields withTimestamp) is
false then table .. {error: "Missing required fields"}
true then withTimestamp;
// Usage
input : "{\"name\": \"Alice\", \"score\": 95}";
result : processJSONData input;
// Returns: Ok (JSValue "{\"name\":\"Alice\",\"score\":95,\"timestamp\":1640995200000}")
```
### Working with JavaScript Arrays
```baba
// Process JavaScript arrays
processJSArray : jsArrayString ->
// Parse array
arrayResult : io.callJS "JSON.parse" [jsArrayString];
when arrayResult is
Err msg then Err msg
Ok jsArray then
// Convert to Baba Yaga list
when (io.jsArrayToList jsArray) is
Err msg then Err msg
Ok babaList then
// Process with Baba Yaga functions
processed : map (x -> x * 2) babaList;
filtered : filter (x -> x > 10) processed;
// Convert back to JS array
jsResult : io.listToJSArray filtered;
// Return as JSON
io.callJS "JSON.stringify" [jsResult];
// Usage
input : "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]";
result : processJSArray input;
// Returns: Ok (JSValue "[4,6,8,10,12,14,16,18,20]")
```
This JavaScript interop system provides a safe, controlled way to leverage JavaScript's ecosystem while maintaining Baba Yaga's functional programming principles and explicit error handling.
|