starlight-cli 1.1.2 → 1.1.4

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/dist/index.js CHANGED
@@ -1392,7 +1392,6 @@ class Environment {
1392
1392
  if (name in this.store) return this.store[name];
1393
1393
  if (this.parent) return this.parent.get(name, node, source);
1394
1394
 
1395
- // Only suggest for top-level variable/function names
1396
1395
  let suggestion = null;
1397
1396
  if (node && source) {
1398
1397
  suggestion = this.suggest?.(name, this) || null;
@@ -1427,7 +1426,6 @@ class Evaluator {
1427
1426
  this.setupBuiltins();
1428
1427
  }
1429
1428
  suggest(name, env) {
1430
- // Collect all variable/function names from the environment chain
1431
1429
  const names = new Set();
1432
1430
  let current = env;
1433
1431
  while (current) {
@@ -1441,11 +1439,10 @@ suggest(name, env) {
1441
1439
  let bestScore = Infinity;
1442
1440
 
1443
1441
  for (const item of names) {
1444
- // simple edit distance approximation
1445
1442
  const dist = Math.abs(item.length - name.length) +
1446
1443
  [...name].filter((c, i) => c !== item[i]).length;
1447
1444
 
1448
- if (dist < bestScore && dist <= 2) { // max distance 2
1445
+ if (dist < bestScore && dist <= 2) {
1449
1446
  bestScore = dist;
1450
1447
  best = item;
1451
1448
  }
@@ -1457,39 +1454,31 @@ suggest(name, env) {
1457
1454
  formatValue(value, seen = new Set()) {
1458
1455
  const color = __nccwpck_require__(55);
1459
1456
 
1460
- // Handle circular references
1461
1457
  if (typeof value === 'object' && value !== null) {
1462
1458
  if (seen.has(value)) return color.red('[Circular]');
1463
1459
  seen.add(value);
1464
1460
  }
1465
1461
 
1466
- // Python-style null / undefined
1467
1462
  if (value === null) return color.yellow('None');
1468
1463
  if (value === undefined) return color.yellow('undefined');
1469
1464
 
1470
1465
  const t = typeof value;
1471
1466
 
1472
- // Strings (no quotes)
1473
1467
  if (t === 'string') return color.cyan(value);
1474
1468
 
1475
- // Numbers
1476
1469
  if (t === 'number') return color.green(String(value));
1477
1470
 
1478
- // Booleans
1479
1471
  if (t === 'boolean') return color.yellow(value ? 'true' : 'false');
1480
1472
 
1481
- // Native JS functions
1482
1473
  if (t === 'function') {
1483
1474
  return color.magenta(value.name ? `<function ${value.name}>` : '<function>');
1484
1475
  }
1485
1476
 
1486
- // Arrays
1487
1477
  if (Array.isArray(value)) {
1488
1478
  const items = value.map(v => this.formatValue(v, seen));
1489
1479
  return color.white('[ ' + items.join(', ') + ' ]');
1490
1480
  }
1491
1481
 
1492
- // Objects (including user-defined functions)
1493
1482
  if (t === 'object') {
1494
1483
  if (value.params && value.body) {
1495
1484
  return color.magenta(value.name ? `<function ${value.name}>` : '<function>');
@@ -1501,7 +1490,6 @@ formatValue(value, seen = new Set()) {
1501
1490
  return color.magenta('{ ') + entries.join(color.magenta(', ')) + color.magenta(' }');
1502
1491
  }
1503
1492
 
1504
- // Fallback
1505
1493
  try {
1506
1494
  return String(value);
1507
1495
  } catch {
@@ -1581,7 +1569,6 @@ this.global.define('fetch', async (url, options = {}) => {
1581
1569
  };
1582
1570
  });
1583
1571
 
1584
- // GET request
1585
1572
  this.global.define('get', async (url) => {
1586
1573
  const res = await fetch(url);
1587
1574
  return await res.json();
@@ -1628,6 +1615,11 @@ case 'ForInStatement':
1628
1615
  return await this.evalFor(node, env);
1629
1616
  case 'DoTrackStatement':
1630
1617
  return await this.evalDoTrack(node, env);
1618
+ case 'StartStatement':
1619
+ return await this.evalStartStatement(node, env);
1620
+
1621
+ case 'RaceClause':
1622
+ return await this.evalRaceClause(node, env);
1631
1623
 
1632
1624
  case 'BreakStatement': throw new BreakSignal();
1633
1625
  case 'ContinueStatement': throw new ContinueSignal();
@@ -1656,14 +1648,14 @@ case 'DoTrackStatement':
1656
1648
  const callee = await this.evaluate(node.callee, env);
1657
1649
 
1658
1650
  if (typeof callee === 'object' && callee.body) {
1659
- const evaluator = this; // <- capture the current evaluator
1651
+ const evaluator = this;
1660
1652
  const Constructor = function(...args) {
1661
1653
  const newEnv = new Environment(callee.env);
1662
1654
  newEnv.define('this', this);
1663
1655
  for (let i = 0; i < callee.params.length; i++) {
1664
1656
  newEnv.define(callee.params[i], args[i]);
1665
1657
  }
1666
- return evaluator.evaluate(callee.body, newEnv); // use captured evaluator
1658
+ return evaluator.evaluate(callee.body, newEnv);
1667
1659
  };
1668
1660
 
1669
1661
  const args = [];
@@ -1701,13 +1693,78 @@ async evalProgram(node, env) {
1701
1693
  return result;
1702
1694
  }
1703
1695
 
1696
+ async evalStartStatement(node, env) {
1697
+ try {
1698
+ const value = await this.evaluate(node.discriminant, env);
1699
+ let executing = false;
1700
+ for (const c of node.cases) {
1701
+ try {
1702
+ if (!executing) {
1703
+ const testValue = await this.evaluate(c.test, env);
1704
+ if (testValue === value) executing = true;
1705
+ }
1706
+
1707
+ if (executing) {
1708
+ await this.evaluate(c.consequent, new Environment(env));
1709
+ }
1710
+ } catch (caseErr) {
1711
+ if (caseErr instanceof BreakSignal) break;
1712
+ if (caseErr instanceof RuntimeError ||
1713
+ caseErr instanceof ReturnValue ||
1714
+ caseErr instanceof ContinueSignal) {
1715
+ throw caseErr; // propagate signals
1716
+ }
1717
+
1718
+ throw new RuntimeError(
1719
+ caseErr.message || 'Error evaluating case in start statement',
1720
+ c,
1721
+ this.source
1722
+ );
1723
+ }
1724
+ }
1725
+
1726
+ return null;
1727
+ } catch (err) {
1728
+ if (err instanceof RuntimeError ||
1729
+ err instanceof ReturnValue ||
1730
+ err instanceof BreakSignal ||
1731
+ err instanceof ContinueSignal) {
1732
+ throw err;
1733
+ }
1734
+ throw new RuntimeError(
1735
+ err.message || 'Error evaluating start statement',
1736
+ node,
1737
+ this.source
1738
+ );
1739
+ }
1740
+ }
1741
+
1742
+
1743
+ async evalRaceClause(node, env) {
1744
+ try {
1745
+ const testValue = await this.evaluate(node.test, env);
1746
+ const result = await this.evaluate(node.consequent, new Environment(env));
1747
+ return { testValue, result };
1748
+ } catch (err) {
1749
+ if (err instanceof RuntimeError ||
1750
+ err instanceof ReturnValue ||
1751
+ err instanceof BreakSignal ||
1752
+ err instanceof ContinueSignal) {
1753
+ throw err;
1754
+ }
1755
+ throw new RuntimeError(
1756
+ err.message || 'Error evaluating race clause',
1757
+ node,
1758
+ this.source
1759
+ );
1760
+ }
1761
+ }
1704
1762
 
1705
1763
  async evalDoTrack(node, env) {
1706
1764
  try {
1707
1765
  return await this.evaluate(node.body, env);
1708
1766
  } catch (err) {
1709
1767
  if (!node.handler) {
1710
- // Wrap any raw error into RuntimeError with line info
1711
1768
  if (err instanceof RuntimeError) throw err;
1712
1769
  throw new RuntimeError(err.message || 'Error in doTrack body', node.body, this.source);
1713
1770
  }
@@ -1718,7 +1775,6 @@ async evalDoTrack(node, env) {
1718
1775
  try {
1719
1776
  return await this.evaluate(node.handler, trackEnv);
1720
1777
  } catch (handlerErr) {
1721
- // Wrap handler errors as well
1722
1778
  if (handlerErr instanceof RuntimeError) throw handlerErr;
1723
1779
  throw new RuntimeError(handlerErr.message || 'Error in doTrack handler', node.handler, this.source);
1724
1780
  }
@@ -1818,16 +1874,33 @@ evalArrowFunction(node, env) {
1818
1874
  if (!node.body) {
1819
1875
  throw new RuntimeError('Arrow function missing body', node, this.source);
1820
1876
  }
1877
+
1821
1878
  if (!Array.isArray(node.params)) {
1822
1879
  throw new RuntimeError('Invalid arrow function parameters', node, this.source);
1823
1880
  }
1824
1881
 
1825
- return {
1826
- params: node.params,
1827
- body: node.body,
1828
- env: env,
1829
- arrow: true,
1830
- async: node.async || false
1882
+ const evaluator = this;
1883
+
1884
+ return async function (...args) {
1885
+ const localEnv = new Environment(env);
1886
+
1887
+ node.params.forEach((p, i) => {
1888
+ localEnv.define(p.name, args[i]);
1889
+ });
1890
+
1891
+ try {
1892
+ if (node.isBlock) {
1893
+ const result = await evaluator.evaluate(node.body, localEnv);
1894
+ return result ?? null;
1895
+ } else {
1896
+ return await evaluator.evaluate(node.body, localEnv);
1897
+ }
1898
+ } catch (err) {
1899
+ if (err instanceof ReturnValue) {
1900
+ return err.value;
1901
+ }
1902
+ throw err;
1903
+ }
1831
1904
  };
1832
1905
  }
1833
1906
 
@@ -2002,7 +2075,6 @@ async evalWhile(node, env) {
2002
2075
  return null;
2003
2076
  }
2004
2077
  async evalFor(node, env) {
2005
- // Python-style: for x in iterable (with optional 'let')
2006
2078
  if (node.type === 'ForInStatement') {
2007
2079
  const iterable = await this.evaluate(node.iterable, env);
2008
2080
 
@@ -2012,8 +2084,6 @@ async evalFor(node, env) {
2012
2084
 
2013
2085
  const loopVar = node.variable; // string name of the loop variable
2014
2086
  const createLoopEnv = () => node.letKeyword ? new Environment(env) : env;
2015
-
2016
- // Arrays: iterate over elements
2017
2087
  if (Array.isArray(iterable)) {
2018
2088
  for (const value of iterable) {
2019
2089
  const loopEnv = createLoopEnv();
@@ -2028,7 +2098,6 @@ async evalFor(node, env) {
2028
2098
  }
2029
2099
  }
2030
2100
  }
2031
- // Objects: iterate over keys
2032
2101
  else {
2033
2102
  for (const key of Object.keys(iterable)) {
2034
2103
  const loopEnv = createLoopEnv();
@@ -2047,7 +2116,6 @@ async evalFor(node, env) {
2047
2116
  return null;
2048
2117
  }
2049
2118
 
2050
- // C-style for loop (classic JS style)
2051
2119
  const local = new Environment(env);
2052
2120
 
2053
2121
  if (node.init) await this.evaluate(node.init, local);
@@ -2133,19 +2201,14 @@ async evalIndex(node, env) {
2133
2201
  const idx = await this.evaluate(node.indexer, env);
2134
2202
 
2135
2203
  if (obj == null) throw new RuntimeError('Cannot index null or undefined', node, this.source);
2136
-
2137
- // Array access: return undefined if out of bounds
2138
2204
  if (Array.isArray(obj)) {
2139
2205
  if (idx < 0 || idx >= obj.length) return undefined;
2140
2206
  return obj[idx];
2141
2207
  }
2142
-
2143
- // Object access: return undefined if property missing
2144
2208
  if (typeof obj === 'object') {
2145
2209
  return obj[idx]; // undefined if missing
2146
2210
  }
2147
2211
 
2148
- // Fallback for non-object non-array
2149
2212
  return undefined;
2150
2213
  }
2151
2214
  async evalObject(node, env) {
@@ -2239,7 +2302,7 @@ class Lexer {
2239
2302
  'break', 'continue', 'func', 'return',
2240
2303
  'true', 'false', 'null',
2241
2304
  'ask', 'define', 'import', 'from', 'as',
2242
- 'async', 'await', 'new', 'in', 'do', 'track'
2305
+ 'async', 'await', 'new', 'in', 'do', 'track', 'start', 'race'
2243
2306
  ];
2244
2307
  }
2245
2308
 
@@ -2502,6 +2565,7 @@ class Parser {
2502
2565
  case 'WHILE': return this.whileStatement();
2503
2566
  case 'FOR': return this.forStatement();
2504
2567
  case 'DO': return this.doTrackStatement();
2568
+ case 'START': return this.startStatement();
2505
2569
  case 'BREAK': return this.breakStatement();
2506
2570
  case 'CONTINUE': return this.continueStatement();
2507
2571
  case 'FUNC': return this.funcDeclaration();
@@ -2513,9 +2577,9 @@ class Parser {
2513
2577
  }
2514
2578
  }
2515
2579
  varDeclaration() {
2516
- const t = this.current; // LET token
2580
+ const t = this.current;
2517
2581
  this.eat('LET');
2518
- const idToken = this.current; // identifier token
2582
+ const idToken = this.current;
2519
2583
  const id = idToken.value;
2520
2584
  this.eat('IDENTIFIER');
2521
2585
 
@@ -2525,7 +2589,6 @@ varDeclaration() {
2525
2589
  expr = this.expression();
2526
2590
  }
2527
2591
 
2528
- // semicolon optional
2529
2592
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
2530
2593
 
2531
2594
  return {
@@ -2536,9 +2599,49 @@ varDeclaration() {
2536
2599
  column: t.column
2537
2600
  };
2538
2601
  }
2602
+ startStatement() {
2603
+ const t = this.current;
2604
+ this.eat('START');
2605
+
2606
+ const discriminant = this.expression();
2607
+
2608
+ this.eat('LBRACE');
2609
+
2610
+ const cases = [];
2611
+
2612
+ while (this.current.type === 'RACE') {
2613
+ cases.push(this.raceClause());
2614
+ }
2615
+
2616
+ this.eat('RBRACE');
2617
+
2618
+ return {
2619
+ type: 'StartStatement',
2620
+ discriminant,
2621
+ cases,
2622
+ line: t.line,
2623
+ column: t.column
2624
+ };
2625
+ }
2626
+ raceClause() {
2627
+ const t = this.current;
2628
+ this.eat('RACE');
2629
+
2630
+ const test = this.expression();
2631
+
2632
+ const consequent = this.block();
2633
+
2634
+ return {
2635
+ type: 'RaceClause',
2636
+ test,
2637
+ consequent,
2638
+ line: t.line,
2639
+ column: t.column
2640
+ };
2641
+ }
2539
2642
 
2540
2643
  sldeployStatement() {
2541
- const t = this.current; // SLDEPLOY token
2644
+ const t = this.current;
2542
2645
  this.eat('SLDEPLOY');
2543
2646
  const expr = this.expression();
2544
2647
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
@@ -2551,7 +2654,7 @@ sldeployStatement() {
2551
2654
  }
2552
2655
 
2553
2656
  doTrackStatement() {
2554
- const t = this.current; // DO token
2657
+ const t = this.current;
2555
2658
  this.eat('DO');
2556
2659
 
2557
2660
  const body = this.block();
@@ -2572,9 +2675,9 @@ doTrackStatement() {
2572
2675
  }
2573
2676
 
2574
2677
  defineStatement() {
2575
- const t = this.current; // DEFINE token
2678
+ const t = this.current;
2576
2679
  this.eat('DEFINE');
2577
- const idToken = this.current; // identifier token
2680
+ const idToken = this.current;
2578
2681
  const id = idToken.value;
2579
2682
  this.eat('IDENTIFIER');
2580
2683
 
@@ -2596,7 +2699,7 @@ defineStatement() {
2596
2699
  }
2597
2700
 
2598
2701
  asyncFuncDeclaration() {
2599
- const t = this.current; // first token of function (identifier)
2702
+ const t = this.current;
2600
2703
  const name = this.current.value;
2601
2704
  this.eat('IDENTIFIER');
2602
2705
 
@@ -2614,7 +2717,6 @@ asyncFuncDeclaration() {
2614
2717
  }
2615
2718
  this.eat('RPAREN');
2616
2719
  } else {
2617
- // no parentheses: single param as Python style
2618
2720
  if (this.current.type === 'IDENTIFIER') {
2619
2721
  params.push(this.current.value);
2620
2722
  this.eat('IDENTIFIER');
@@ -2634,7 +2736,7 @@ asyncFuncDeclaration() {
2634
2736
  }
2635
2737
 
2636
2738
  ifStatement() {
2637
- const t = this.current; // IF token
2739
+ const t = this.current;
2638
2740
  this.eat('IF');
2639
2741
 
2640
2742
  let test;
@@ -2643,7 +2745,6 @@ ifStatement() {
2643
2745
  test = this.expression();
2644
2746
  this.eat('RPAREN');
2645
2747
  } else {
2646
- // Python style: no parentheses
2647
2748
  test = this.expression();
2648
2749
  }
2649
2750
 
@@ -2667,7 +2768,7 @@ ifStatement() {
2667
2768
  }
2668
2769
 
2669
2770
  whileStatement() {
2670
- const t = this.current; // WHILE token
2771
+ const t = this.current;
2671
2772
  this.eat('WHILE');
2672
2773
 
2673
2774
  let test;
@@ -2690,7 +2791,7 @@ whileStatement() {
2690
2791
  }
2691
2792
 
2692
2793
  importStatement() {
2693
- const t = this.current; // IMPORT token
2794
+ const t = this.current;
2694
2795
  this.eat('IMPORT');
2695
2796
 
2696
2797
  let specifiers = [];
@@ -2749,7 +2850,6 @@ forStatement() {
2749
2850
  const t = this.current; // FOR token
2750
2851
  this.eat('FOR');
2751
2852
 
2752
- // --- Python-style: for variable in iterable (supports optional 'let') ---
2753
2853
  if ((this.current.type === 'LET' && this.peekType() === 'IDENTIFIER' && this.peekType(2) === 'IN') ||
2754
2854
  (this.current.type === 'IDENTIFIER' && this.peekType() === 'IN')) {
2755
2855
 
@@ -2790,7 +2890,6 @@ forStatement() {
2790
2890
  };
2791
2891
  }
2792
2892
 
2793
- // --- C-style: for(init; test; update) ---
2794
2893
  let init = null;
2795
2894
  let test = null;
2796
2895
  let update = null;
@@ -2798,22 +2897,18 @@ forStatement() {
2798
2897
  if (this.current.type === 'LPAREN') {
2799
2898
  this.eat('LPAREN');
2800
2899
 
2801
- // init
2802
2900
  if (this.current.type !== 'SEMICOLON') {
2803
2901
  init = this.current.type === 'LET' ? this.varDeclaration() : this.expressionStatement();
2804
2902
  } else {
2805
2903
  this.eat('SEMICOLON');
2806
2904
  }
2807
2905
 
2808
- // test
2809
2906
  if (this.current.type !== 'SEMICOLON') test = this.expression();
2810
2907
  this.eat('SEMICOLON');
2811
2908
 
2812
- // update
2813
2909
  if (this.current.type !== 'RPAREN') update = this.expression();
2814
2910
  this.eat('RPAREN');
2815
2911
  } else {
2816
- // fallback: single expression (rare, mostly handled above)
2817
2912
  init = this.expression();
2818
2913
  if (this.current.type === 'IN') {
2819
2914
  this.eat('IN');
@@ -2836,21 +2931,19 @@ forStatement() {
2836
2931
  breakStatement() {
2837
2932
  const t = this.current; // BREAK token
2838
2933
  this.eat('BREAK');
2839
- // Python-style: no semicolon needed, ignore if present
2840
2934
  if (this.current.type === 'SEMICOLON') this.advance();
2841
2935
  return { type: 'BreakStatement', line: t.line, column: t.column };
2842
2936
  }
2843
2937
 
2844
2938
  continueStatement() {
2845
- const t = this.current; // CONTINUE token
2939
+ const t = this.current;
2846
2940
  this.eat('CONTINUE');
2847
- // Python-style: no semicolon needed, ignore if present
2848
2941
  if (this.current.type === 'SEMICOLON') this.advance();
2849
2942
  return { type: 'ContinueStatement', line: t.line, column: t.column };
2850
2943
  }
2851
2944
 
2852
2945
  funcDeclaration() {
2853
- const t = this.current; // FUNC token
2946
+ const t = this.current;
2854
2947
  this.eat('FUNC');
2855
2948
  const nameToken = this.current;
2856
2949
  const name = nameToken.value;
@@ -2872,7 +2965,6 @@ funcDeclaration() {
2872
2965
  }
2873
2966
  this.eat('RPAREN');
2874
2967
  } else {
2875
- // Python-style: single param without parentheses
2876
2968
  if (this.current.type === 'IDENTIFIER') {
2877
2969
  const paramToken = this.current;
2878
2970
  params.push({ name: paramToken.value, line: paramToken.line, column: paramToken.column });
@@ -2893,7 +2985,6 @@ returnStatement() {
2893
2985
  argument = this.expression();
2894
2986
  }
2895
2987
 
2896
- // semicolon optional
2897
2988
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
2898
2989
 
2899
2990
  return { type: 'ReturnStatement', argument, line: t.line, column: t.column };
@@ -2911,9 +3002,8 @@ block() {
2911
3002
  }
2912
3003
 
2913
3004
  expressionStatement() {
2914
- const exprToken = this.current; // first token of the expression
3005
+ const exprToken = this.current;
2915
3006
  const expr = this.expression();
2916
- // semicolon optional
2917
3007
  if (this.current.type === 'SEMICOLON') this.eat('SEMICOLON');
2918
3008
  return { type: 'ExpressionStatement', expression: expr, line: exprToken.line, column: exprToken.column };
2919
3009
  }
@@ -3026,7 +3116,6 @@ unary() {
3026
3116
  };
3027
3117
  }
3028
3118
 
3029
- // Python-like: ignore ++ and -- if not used
3030
3119
  if (t.type === 'PLUSPLUS' || t.type === 'MINUSMINUS') {
3031
3120
  const op = t.type;
3032
3121
  this.eat(op);
@@ -3066,7 +3155,7 @@ postfix() {
3066
3155
  const args = [];
3067
3156
  while (this.current.type !== 'RPAREN' && this.current.type !== 'EOF') {
3068
3157
  args.push(this.expression());
3069
- if (this.current.type === 'COMMA') this.eat('COMMA'); // optional comma
3158
+ if (this.current.type === 'COMMA') this.eat('COMMA');
3070
3159
  }
3071
3160
  if (this.current.type === 'RPAREN') this.eat('RPAREN');
3072
3161
  node = { type: 'CallExpression', callee: node, arguments: args, line: startLine, column: startCol };
@@ -3103,15 +3192,26 @@ postfix() {
3103
3192
 
3104
3193
  arrowFunction(params) {
3105
3194
  const t = this.current;
3106
- if (t.type === 'ARROW') this.eat('ARROW');
3107
- const body = this.expression();
3195
+ this.eat('ARROW');
3196
+
3197
+ let body;
3198
+ let isBlock = false;
3199
+
3200
+ if (this.current.type === 'LBRACE') {
3201
+ body = this.block();
3202
+ isBlock = true;
3203
+ } else {
3204
+ body = this.expression();
3205
+ }
3206
+
3108
3207
  const startLine = params.length > 0 ? params[0].line : t.line;
3109
- const startCol = params.length > 0 ? params[0].column : t.column;
3208
+ const startCol = params.length > 0 ? params[0].column : t.column;
3110
3209
 
3111
3210
  return {
3112
3211
  type: 'ArrowFunctionExpression',
3113
3212
  params,
3114
3213
  body,
3214
+ isBlock,
3115
3215
  line: startLine,
3116
3216
  column: startCol
3117
3217
  };
@@ -3243,11 +3343,11 @@ arrowFunction(params) {
3243
3343
  this.eat('LBRACE');
3244
3344
  const props = [];
3245
3345
  while (this.current.type !== 'RBRACE') {
3246
- const key = this.expression(); // Flexible key: can be any expression
3346
+ const key = this.expression();
3247
3347
  this.eat('COLON');
3248
3348
  const value = this.expression();
3249
3349
  props.push({ key, value });
3250
- if (this.current.type === 'COMMA') this.eat('COMMA'); // optional trailing comma
3350
+ if (this.current.type === 'COMMA') this.eat('COMMA');
3251
3351
  }
3252
3352
  this.eat('RBRACE');
3253
3353
  return { type: 'ObjectExpression', props, line: startLine, column: startCol };
@@ -3440,7 +3540,7 @@ const Lexer = __nccwpck_require__(211);
3440
3540
  const Parser = __nccwpck_require__(222);
3441
3541
  const Evaluator = __nccwpck_require__(112);
3442
3542
 
3443
- const VERSION = '1.1.2';
3543
+ const VERSION = '1.1.4';
3444
3544
 
3445
3545
  const COLOR = {
3446
3546
  reset: '\x1b[0m',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starlight-cli",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "Starlight Programming Language CLI",
5
5
  "bin": {
6
6
  "starlight": "index.js"