@mojir/lits 2.1.35 → 2.1.36

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 CHANGED
@@ -68,7 +68,7 @@ let squares = [1, 2, 3, 4, 5] map square;
68
68
  // => [1, 4, 9, 16, 25]
69
69
 
70
70
  // Using operator as a function
71
- let sum = +([1, 2, 3, 4, 5]);
71
+ let sum = +(1, 2, 3, 4, 5);
72
72
  // => 15
73
73
  ```
74
74
 
@@ -153,18 +153,14 @@ let y = {
153
153
 
154
154
  #### Destructuring
155
155
 
156
+ ##### Basic Object Destructuring
157
+
156
158
  ```lits
157
159
  // Object destructuring
158
160
  let { name, age } = { name: "John", age: 30 };
159
161
  // name => "John", age => 30
160
162
  ```
161
163
 
162
- ```lits
163
- // Array destructuring
164
- let [a, b] = [1, 2, 3, 4];
165
- // a => 1, b => 2
166
- ```
167
-
168
164
  ```lits
169
165
  // With default values
170
166
  let { name = "Unknown", age = 0 } = { name: "John" };
@@ -172,18 +168,101 @@ let { name = "Unknown", age = 0 } = { name: "John" };
172
168
  ```
173
169
 
174
170
  ```lits
175
- // Rest patterns
171
+ // Renaming with 'as'
172
+ let { name as userName } = { name: "Dave" };
173
+ // userName => "Dave"
174
+ ```
175
+
176
+ ```lits
177
+ // Multiple renames
178
+ let { firstName as name, age as years } = { firstName: "Eve", age: 28 };
179
+ // name => "Eve", years => 28
180
+ ```
181
+
182
+ ##### Advanced Destructuring Patterns
183
+
184
+ ```lits
185
+ // Complex nested destructuring with defaults and renaming
186
+ let {
187
+ name as userName = "Guest",
188
+ profile: {
189
+ age = 0,
190
+ contact: { email as userEmail = "none" }
191
+ },
192
+ settings = { theme: "light" },
193
+ scores as userScores = [],
194
+ ...others
195
+ } = { name: "Sam", profile: { contact: {} }};
196
+ // userName => "Sam", age => 0, userEmail => "none", etc.
197
+ ```
198
+
199
+ ```lits
200
+ // Combining array and object destructuring
201
+ let [{ name }, { age }] = [{ name: "Tina" }, { age: 33 }];
202
+ // name => "Tina", age => 33
203
+ ```
204
+
205
+ ```lits
206
+ // Object with array property destructuring
207
+ let { name, scores: [one, two] } = { name: "Uma", scores: [85, 92] };
208
+ // name => "Uma", one => 85, two => 92
209
+ ```
210
+
211
+ ##### Array Destructuring
212
+
213
+ ```lits
214
+ // Array destructuring
215
+ let [, , a, b] = [1, 2, 3, 4];
216
+ // a => 3, b => 4
217
+
218
+ // Array destructuring with defaults
219
+ let [one, two = 2] = [1];
220
+ // one => 1, two => 2
221
+
222
+ // Skipping elements
223
+ let [x, , z] = [1, 2, 3];
224
+ // x => 1, z => 3
225
+ ```
226
+
227
+ ##### Rest Patterns
228
+
229
+ ```lits
230
+ // Array rest pattern
176
231
  let [head, ...tail] = [1, 2, 3, 4];
177
232
  // head => 1, tail => [2, 3, 4]
233
+
234
+ // Object rest pattern
235
+ let { name, ...otherProps } = { name: "John", age: 30, city: "NYC" };
236
+ // name => "John", otherProps => { age: 30, city: "NYC" }
237
+
238
+ // Empty rest patterns
239
+ let [only, ...empty] = [1];
240
+ // only => 1, empty => []
178
241
  ```
179
242
 
243
+ ##### Function Parameter Destructuring
244
+
180
245
  ```lits
181
- // Destructuring in function parameters
182
- let displayPerson = ({name, age}) ->
183
- name ++ " is " ++ str(age) ++ " years old";
246
+ // Basic parameter destructuring
247
+ let greet = ({ name }) -> "Hello, " ++ name;
248
+ greet({ name: "Pat" });
249
+ // => "Hello, Pat"
250
+
251
+ // With defaults in parameters
252
+ let greet2 = ({ name = "friend" }) -> "Hello, " ++ name;
253
+ greet2({});
254
+ // => "Hello, friend"
255
+
256
+ // Nested parameter destructuring
257
+ let processUser = ({ profile: { name, age }}) ->
258
+ name ++ " is " ++ str(age);
259
+ processUser({ profile: { name: "Quinn", age: 29 }});
260
+ // => "Quinn is 29"
184
261
 
185
- displayPerson({ name: "John", age: 30 });
186
- // => "John is 30 years old"
262
+ // Array parameter destructuring
263
+ let processCoords = ([x, y]) -> x + y;
264
+ processCoords([3, 4]);
265
+ // => 7
187
266
  ```
188
267
 
189
268
  ### Functions
@@ -220,7 +299,6 @@ let factorial = n ->
220
299
  #### If/Unless
221
300
 
222
301
  ```lits
223
- // If expression
224
302
  let x = !:random-int(0, 20); // Random number between 0 and 19
225
303
 
226
304
  if x > 10 then
@@ -235,12 +313,13 @@ if false then "never" end;
235
313
  // => null
236
314
 
237
315
  // Unless (inverted if)
238
- unless x > 10 then
316
+ let y = !:random-int(0, 20);
317
+ unless y > 10 then
239
318
  "small"
240
319
  else
241
320
  "large"
242
321
  end;
243
- // => "small" (if x <= 10) or "large" (if x > 10)
322
+ // => "small" (if y <= 10) or "large" (if y > 10)
244
323
  ```
245
324
 
246
325
  #### Cond
@@ -253,8 +332,17 @@ cond
253
332
  case x < 5 then "small"
254
333
  case x < 10 then "medium"
255
334
  case x < 15 then "large"
256
- end ?? "extra large"
335
+ end ?? "extra large";
257
336
  // Tests conditions sequentially, returns first truthy match
337
+
338
+ // Cond with complex conditions
339
+ let urgent = !:random-int(0, 2) == 1;
340
+ let important = !:random-int(0, 2) == 1;
341
+ let priority = cond
342
+ case urgent && important then "critical"
343
+ case urgent then "high"
344
+ case important then "medium"
345
+ end ?? "low";
258
346
  ```
259
347
 
260
348
  #### Switch
@@ -267,8 +355,20 @@ switch x
267
355
  case 0 then "zero"
268
356
  case 1 then "one"
269
357
  case 2 then "two"
270
- end
358
+ end;
271
359
  // => "zero" (if x = 0), "one" (if x = 1), etc., or null if no match
360
+
361
+ // Switch with multiple cases
362
+ let userInput = "help";
363
+ let exit = -> "exiting";
364
+ let showHelp = -> "showing help";
365
+ let saveData = -> "saving data";
366
+
367
+ switch userInput
368
+ case "quit" then exit()
369
+ case "help" then showHelp()
370
+ case "save" then saveData()
371
+ end;
272
372
  ```
273
373
 
274
374
  ### Loops and Iteration
@@ -280,15 +380,15 @@ end
280
380
  for (x in [1, 2, 3, 4]) -> x * 2;
281
381
  // => [2, 4, 6, 8]
282
382
 
283
- // With filtering
383
+ // With filtering (when clause)
284
384
  for (x in [1, 2, 3, 4] when odd?(x)) -> x * 2;
285
385
  // => [2, 6]
286
386
 
287
- // With while condition
387
+ // With early termination (while clause)
288
388
  for (x in [1, 2, 3, 4] while x < 3) -> x * 2;
289
389
  // => [2, 4]
290
390
 
291
- // With let bindings
391
+ // With let bindings for intermediate calculations
292
392
  for (x in [1, 2, 3] let doubled = x * 2) -> doubled + 1;
293
393
  // => [3, 5, 7]
294
394
 
@@ -296,6 +396,20 @@ for (x in [1, 2, 3] let doubled = x * 2) -> doubled + 1;
296
396
  for (x in [1, 2], y in [10, 20]) -> x + y;
297
397
  // => [11, 21, 12, 22]
298
398
 
399
+ // Complex for comprehensions with multiple conditions
400
+ for (
401
+ i in range(10)
402
+ let ii = i ^ 2
403
+ while ii < 40
404
+ when ii % 3 == 0,
405
+ j in range(10)
406
+ when j % 2 == 1
407
+ ) -> ii + j;
408
+
409
+ // Using previous bindings in subsequent iterations
410
+ for (x in [1, 2], y in [x, 2 * x]) -> x * y;
411
+ // => [1, 2, 4, 8]
412
+
299
413
  // Object iteration
300
414
  for (entry in { a: 1, b: 2 } let [key, value] = entry) -> key ++ ":" ++ str(value);
301
415
  // => ["a:1", "b:2"]
@@ -319,8 +433,41 @@ loop (n = 5, acc = 1) -> {
319
433
  else
320
434
  recur(n - 1, acc * n)
321
435
  end
322
- }
436
+ };
323
437
  // => 120 (factorial of 5)
438
+
439
+ // Complex loop with multiple variables
440
+ loop (items = [1, 2, 3, 4, 5], sum = 0, cnt = 0) -> {
441
+ if empty?(items) then
442
+ { sum: sum, average: sum / cnt }
443
+ else
444
+ recur(rest(items), sum + first(items), cnt + 1)
445
+ end
446
+ };
447
+ ```
448
+
449
+ ### Recursion with Recur
450
+
451
+ #### Function Recursion
452
+
453
+ ```lits
454
+ // Simple recursive function with recur
455
+ let factorial = (n) -> {
456
+ if n <= 1 then
457
+ 1
458
+ else
459
+ n * recur(n - 1)
460
+ end
461
+ };
462
+
463
+ // Tail-recursive function
464
+ let sumToN = (n, acc = 0) -> {
465
+ if zero?(n) then
466
+ acc
467
+ else
468
+ recur(n - 1, acc + n)
469
+ end
470
+ };
324
471
  ```
325
472
 
326
473
  ### Error Handling
@@ -329,6 +476,7 @@ loop (n = 5, acc = 1) -> {
329
476
 
330
477
  ```lits
331
478
  // Basic try/catch
479
+ let riskyOperation = () -> throw("Something went wrong");
332
480
  try
333
481
  riskyOperation()
334
482
  catch
@@ -341,6 +489,16 @@ try
341
489
  catch (error)
342
490
  "Error: " ++ error.message
343
491
  end;
492
+
493
+ // Try-catch for graceful degradation
494
+ let parseData = () -> { value: 42 };
495
+ let process = (val) -> val * 2;
496
+ try
497
+ let { value } = parseData();
498
+ process(value);
499
+ catch
500
+ "Using default value"
501
+ end;
344
502
  ```
345
503
 
346
504
  #### Throw
@@ -348,202 +506,177 @@ end;
348
506
  ```lits
349
507
  // Throwing errors
350
508
  try
351
- throw("Custom error message");
509
+ throw("Custom error message")
352
510
  catch
353
511
  "Caught an error"
354
512
  end;
355
513
 
356
- // In context
514
+ // Custom error messages in functions
357
515
  let divide = (a, b) ->
358
516
  if zero?(b) then
359
- throw("Division by zero")
517
+ throw("Cannot divide by zero")
360
518
  else
361
519
  a / b
362
520
  end;
363
- ```
364
-
365
- ### Logical Operators
366
-
367
- #### And/Or
368
-
369
- ```lits
370
- // Logical AND (short-circuit)
371
- true && "second value"; // => "second value"
372
- false && "never reached"; // => false
373
-
374
- // Logical OR (short-circuit)
375
- false || "default value"; // => "default value"
376
- true || "never reached"; // => true
377
521
 
378
- // Multiple arguments
379
- &&(true, true, "all true"); // => "all true"
380
- ||(false, false, "found"); // => "found"
522
+ // Conditional error throwing
523
+ let validateAge = (age) ->
524
+ cond
525
+ case age < 0 then throw("Age cannot be negative")
526
+ case age > 150 then throw("Age seems unrealistic")
527
+ case true then age
528
+ end;
381
529
  ```
382
530
 
383
- #### Null Coalescing
531
+ ### Block Expressions
384
532
 
385
533
  ```lits
386
- // Null coalescing operator
387
- null ?? "default"; // => "default"
388
- undefined ?? "default"; // => "default"
389
- 0 ?? "default"; // => 0 (only null/undefined are coalesced)
390
- false ?? "default"; // => false
391
- "" ?? "default"; // => ""
392
- ```
534
+ // Block for grouping expressions
535
+ let computeX = () -> 5;
536
+ let computeY = () -> 10;
537
+ let processResult = (z) -> z * 2;
393
538
 
394
- ### Blocks
539
+ let result = {
540
+ let x = computeX();
541
+ let y = computeY();
542
+ let z = x * y;
543
+ processResult(z)
544
+ };
545
+
546
+ // Block with side effects
547
+ let loadData = () -> [1, 2, 3];
548
+ let processData = (data) -> data map -> $ * 2;
395
549
 
396
- ```lits
397
- // Block expressions
398
550
  {
399
- let a = 1 + 2 + 3;
400
- let b = x -> x * x;
401
- b(a)
402
- }
403
- // => 36 (returns value of last expression)
551
+ write!("Starting process...");
552
+ let data = loadData();
553
+ let processed = processData(data);
554
+ write!("Process completed");
555
+ processed
556
+ };
404
557
  ```
405
558
 
406
- ### Arrays and Objects
559
+ ### Array and Object Spread
407
560
 
408
- #### Array Construction
561
+ #### Array Spread
409
562
 
410
563
  ```lits
411
- // Array literal
412
- [1, 2, 3, 4];
564
+ // Spread in array literals
565
+ let combined = [1, 2, ...[3, 4, 5], 6];
566
+ // => [1, 2, 3, 4, 5, 6]
413
567
 
414
- // Array function
415
- array(1, 2, 3, 4);
416
-
417
- // With spread
418
- let small-set = [3, 4, 5];
419
- [1, 2, ...small-set, 6];
420
- // => [1, 2, 3, 4, 5, 6];
568
+ // Multiple spreads
569
+ let start = [1, 2];
570
+ let middle = [3, 4];
571
+ let stop = [5, 6];
572
+ let result = [...start, ...middle, ...stop];
421
573
  ```
422
574
 
423
- #### Object Construction
575
+ #### Object Spread
424
576
 
425
577
  ```lits
426
- // Object literal
427
- { name: "John", age: 30 };
428
-
429
- // Object function
430
- object("name", "John", "age", 30);
431
-
432
- // With spread
433
- let defaults = { type: "Person", active: true };
434
- {
435
- ...defaults,
578
+ // Object spread for merging
579
+ let person = {
436
580
  name: "John",
437
581
  age: 30
438
582
  };
439
- // => { type: "Person", active: true, name: "John", age: 30 }
440
- ```
441
-
442
- ### Recursion
443
583
 
444
- #### Recur
584
+ let employee = {
585
+ ...person,
586
+ id: "E123",
587
+ department: "Engineering"
588
+ };
589
+ // => { name: "John", age: 30, id: "E123", department: "Engineering" }
445
590
 
446
- ```lits
447
- // Tail recursion with recur
448
- let countdown = n -> {
449
- write!(n);
450
- if pos?(n) then
451
- recur(n - 1)
452
- end
591
+ // Spread with override
592
+ let defaults = {
593
+ name: "Default Name",
594
+ theme: "light",
595
+ active: true
453
596
  };
454
597
 
455
- countdown(3)
456
- // Prints: 3 2 1 0
598
+ let updated = {
599
+ ...defaults,
600
+ name: "Custom Name" // Override defaults.name
601
+ };
457
602
  ```
458
603
 
459
- ## Operators and Functions
460
-
461
- ### Algebraic Notation
604
+ ### Logical Operators
462
605
 
463
- All functions that take two parameters can be used as operators:
606
+ #### And/Or
464
607
 
465
608
  ```lits
466
- // As a function
467
- max(5, 10); // => 10
609
+ // Logical AND (short-circuit)
610
+ true && "second value"; // => "second value"
611
+ false && "never reached"; // => false
468
612
 
469
- // As an operator
470
- 5 max 10; // => 10
613
+ // Logical OR (short-circuit)
614
+ false || "default value"; // => "default value"
615
+ true || "never reached"; // => true
616
+
617
+ // Multiple arguments
618
+ &&(true, true, "all true"); // => "all true"
619
+ ||(false, false, "found"); // => "found"
471
620
  ```
472
621
 
473
- All operators can be used as functions:
622
+ #### Null Coalescing
474
623
 
475
624
  ```lits
476
- // As an operator
477
- 5 + 3; // => 8
478
-
479
- // As a function
480
- +(5, 3); // => 8
625
+ // Null coalescing operator
626
+ null ?? "default"; // => "default"
627
+ undefined-var ?? "default"; // => "default"
628
+ 0 ?? "default"; // => 0 (only null/undefined are coalesced)
629
+ false ?? "default"; // => false
630
+ "" ?? "default"; // => ""
631
+ ```
481
632
 
482
- // Partial application with underscore placeholder
483
- let add5 = +(5, _);
484
- add5(3); // => 8
633
+ ### Ternary Operator
485
634
 
486
- // Multiple placeholders
487
- let subtractTwoValues = -(100, _, _);
488
- subtractTwoValues(4, 3); // => 93
635
+ ```lits
636
+ // Conditional expression
637
+ let age = !:random-int(10, 60);
638
+ let result = age >= 18 ? "adult" : "minor";
489
639
 
490
- // Single placeholder in different positions
491
- let subtract = -(_, 2);
492
- subtract(10); // => 8
640
+ // Nested ternary
641
+ let score = !:random-int(0, 100);
642
+ let category = score >= 90 ? "A" : score >= 80 ? "B" : "C";
493
643
 
494
- let divide = /(10, _);
495
- divide(2); // => 5
644
+ // With complex expressions
645
+ let isLoggedIn = () -> true;
646
+ let hasPermission = () -> true;
647
+ let status = isLoggedIn() && hasPermission() ? "authorized" : "unauthorized";
496
648
  ```
497
649
 
498
- ### Parameter Order
650
+ ## Operators and Precedence
499
651
 
500
- Lits favors subject-first parameter order for better operator chaining:
652
+ Lits follows a clear operator precedence hierarchy. Understanding precedence helps you write expressions that behave as expected:
501
653
 
502
- ```lits
503
- // Function style
504
- filter([1, 2, 3, 4], odd?); // => [1, 3]
505
-
506
- // Operator style (more readable)
507
- [1, 2, 3, 4] filter odd?; // => [1, 3]
508
- ```
654
+ ### Precedence Table (Highest to Lowest)
509
655
 
510
- ### Pipe Operator
656
+ 1. **Function calls** - `fn(args)`
657
+ 2. **Array/Object access** - `arr[index]`, `obj.property`
658
+ 3. **Unary operators** - `not`, `!`, `-` (negation)
659
+ 4. **Exponentiation** - `^` (right-associative)
660
+ 5. **Multiplication, Division, Modulo** - `*`, `/`, `%`
661
+ 6. **Addition, Subtraction** - `+`, `-`
662
+ 7. **String concatenation** - `++`
663
+ 8. **Comparison operators** - `<`, `>`, `<=`, `>=`
664
+ 9. **Equality operators** - `==`, `!=`, `identical?`
665
+ 10. **Logical AND** - `&&`
666
+ 11. **Logical OR** - `||`
667
+ 12. **Null coalescing** - `??`
668
+ 13. **Ternary conditional** - `condition ? true-value : false-value`
511
669
 
512
- The pipe operator `|>` passes the result of the left expression as the first argument to the right function:
670
+ ### Examples
513
671
 
514
672
  ```lits
515
- // Without pipe operator
516
- reduce(map(filter([1, 2, 3, 4, 5, 6], odd?), -> $ + $), +, 0);
673
+ // Comparison and logical operators
674
+ 5 > 3 && 2 < 4; // => true
675
+ 5 > 3 || 2 > 4; // => true
517
676
 
518
- // With pipe operator (much more readable)
519
- [1, 2, 3, 4, 5, 6]
520
- |> filter(_, odd?)
521
- |> map(_, -> $ * $)
522
- |> reduce(_, +, 0);
523
- // => 35
524
-
525
- // Simple transformations
526
- "hello world"
527
- |> upper-case
528
- |> split(_, " ")
529
- |> reverse
530
- |> join(_, "-");
531
- // => "WORLD-HELLO"
532
-
533
- // Mathematical operations
534
- 10
535
- |> +(_, 5)
536
- |> *(_, 2)
537
- |> /(_, 3);
538
- // => 10 (10 + 5 = 15, 15 * 2 = 30, 30 / 3 = 10)
539
-
540
- // Data processing pipeline
541
- { numbers: [1, 2, 3, 4, 5], multiplier: 3 }
542
- |> get(_, "numbers")
543
- |> filter(_, even?)
544
- |> map(_, *(_, 3))
545
- |> reduce(_, +, 0);
546
- // => 18 (even numbers [2, 4] -> [6, 12] -> sum = 18)
677
+ // Ternary has low precedence
678
+ let x = !:random-int(0, 10);
679
+ x + 3 > 4 ? 1 : 0; // => (x + 3) > 4 ? 1 : 0
547
680
  ```
548
681
 
549
682
  ## Built-in Functions
@@ -577,12 +710,7 @@ export let square = x -> x * x;
577
710
  ### Factorial
578
711
 
579
712
  ```lits
580
- let factorial = n ->
581
- if n <= 1 then
582
- 1
583
- else
584
- n * self(n - 1)
585
- end;
713
+ let factorial = n -> n <= 1 ? 1 : n * self(n - 1);
586
714
 
587
715
  factorial(5) // => 120
588
716
  ```
@@ -605,99 +733,67 @@ let oddSum = numbers
605
733
  // => 25
606
734
  ```
607
735
 
608
- ### Object Manipulation
736
+ ### String Processing
609
737
 
610
738
  ```lits
611
- let person = { name: "John", age: 30, city: "New York" };
612
-
613
- // Update age
614
- let older = assoc(person, "age", 31);
739
+ let text = "Hello, World! How are you today?";
615
740
 
616
- // Add new field
617
- let withJob = assoc(older, "job", "Developer");
741
+ // Word count
742
+ let wordCount = text
743
+ |> split(_, #"\s+")
744
+ |> count(_);
745
+ // => 6
618
746
 
619
- // Using pipe operator for chaining
620
- let updated = person
621
- |> assoc(_, "age", 31)
622
- |> assoc(_, "job", "Developer");
747
+ // Uppercase words longer than 4 characters
748
+ let longWords = text
749
+ |> split(_, #"\s+")
750
+ |> filter(_, -> count($) > 4)
751
+ |> map(_, upper-case);
752
+ // => ["HELLO,", "WORLD!", "TODAY?"]
623
753
  ```
624
754
 
625
- ### Pattern Matching Examples
626
-
627
- #### Switch (for matching against a single value)
755
+ ### Data Transformation
628
756
 
629
757
  ```lits
630
- let gradeToLetter = grade ->
631
- switch grade
632
- case 90 then "A"
633
- case 80 then "B"
634
- case 70 then "C"
635
- case 60 then "D"
636
- end ?? "F";
758
+ let users = [
759
+ { name: "Alice", age: 30, department: "Engineering" },
760
+ { name: "Bob", age: 25, department: "Marketing" },
761
+ { name: "Charlie", age: 35, department: "Engineering" }
762
+ ];
637
763
 
638
- gradeToLetter(80); // => "B"
639
- gradeToLetter(55); // => "F"
640
-
641
- // HTTP status code handling
642
- let statusMessage = code ->
643
- switch code
644
- case 200 then "OK"
645
- case 404 then "Not Found"
646
- case 500 then "Internal Server Error"
647
- end ?? "Unknown Status";
648
- ```
649
-
650
- #### Cond (for testing different conditions)
651
-
652
- ```lits
653
- let describe = x ->
654
- cond
655
- case null?(x) then "nothing"
656
- case number?(x) then "a number: " ++ str(x)
657
- case string?(x) then "text: " ++ x
658
- case array?(x) then "list of " ++ str(count(x)) ++ " items"
659
- end ?? "unknown type";
660
-
661
- describe(42); // => "a number: 42"
662
- describe([1,2,3]); // => "list of 3 items"
663
-
664
- // Grade ranges
665
- let gradeToLetter = score ->
666
- cond
667
- case score >= 90 then "A"
668
- case score >= 80 then "B"
669
- case score >= 70 then "C"
670
- case score >= 60 then "D"
671
- end ?? "F";
672
-
673
- gradeToLetter(85); // => "B"
674
- gradeToLetter(55); // => "F"
764
+ // Group by department and get average age
765
+ let grouped = users |> group-by(_, "department");
766
+ let departmentAges = grouped
767
+ |> entries(_)
768
+ |> map(_, ([dept, people]) -> {
769
+ let ages = people |> map(_, "age");
770
+ let total = ages |> reduce(_, +, 0);
771
+ [dept, total / count(ages)]
772
+ })
773
+ |> (pairs -> zipmap(map(pairs, 0), map(pairs, 1)));
774
+ // => { "Engineering": 32.5, "Marketing": 25 }
675
775
  ```
676
776
 
677
777
  ## JavaScript Interoperability
678
778
 
679
- Lits provides a comprehensive JavaScript API for embedding and integration:
779
+ ### Using Lits in JavaScript
680
780
 
681
781
  ```javascript
682
- import { Lits } from 'lits';
782
+ import { Lits } from '@mojir/lits';
683
783
 
684
- // Create a Lits instance
685
784
  const lits = new Lits();
686
785
 
687
- // Run Lits code
688
- const result = lits.run('+(5, 3)');
689
- console.log(result); // 8
786
+ // Basic usage
787
+ const result1 = lits.run('+(1, 2, 3)');
788
+ console.log(result1); // 6
690
789
 
691
- // Pass JavaScript values to Lits
790
+ // Provide JavaScript values
692
791
  const result2 = lits.run('name ++ " is " ++ str(age)', {
693
- values: {
694
- name: "John",
695
- age: 30
696
- }
792
+ values: { name: 'John', age: 30 }
697
793
  });
698
794
  console.log(result2); // "John is 30"
699
795
 
700
- // Expose JavaScript functions to Lits
796
+ // Expose JavaScript functions
701
797
  const result3 = lits.run('myAlert("Hello from Lits!")', {
702
798
  jsFunctions: {
703
799
  myAlert: {