starlight-cli 1.1.15 → 1.1.17

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
@@ -10213,7 +10213,6 @@ const fs = __nccwpck_require__(896);
10213
10213
  const Lexer = __nccwpck_require__(211);
10214
10214
  const Parser = __nccwpck_require__(222);
10215
10215
  const path = __nccwpck_require__(928);
10216
-
10217
10216
  class ReturnValue {
10218
10217
  constructor(value) { this.value = value; }
10219
10218
  }
@@ -10414,7 +10413,51 @@ formatValue(value, seen = new Set()) {
10414
10413
  if (arg && typeof arg === 'object') return Object.keys(arg).length;
10415
10414
  return 0;
10416
10415
  });
10416
+ this.global.define('lower', arg => {
10417
+ if (typeof arg !== 'string') return String(arg).toLowerCase();
10418
+ return arg.toLowerCase();
10419
+ });
10420
+ this.global.define('toStr', arg => String(arg));
10421
+
10422
+ this.global.define('upper', arg => {
10423
+ if (typeof arg !== 'string') return String(arg).toUpperCase();
10424
+ return arg.toUpperCase();
10425
+ });
10426
+
10427
+ this.global.define('trim', arg => {
10428
+ if (typeof arg !== 'string') return String(arg).trim();
10429
+ return arg.trim();
10430
+ });
10431
+
10432
+ this.global.define('startsWith', (str, prefix) => {
10433
+ if (typeof str !== 'string') str = String(str);
10434
+ if (typeof prefix !== 'string') prefix = String(prefix);
10435
+ return str.startsWith(prefix);
10436
+ });
10437
+
10438
+ this.global.define('endsWith', (str, suffix) => {
10439
+ if (typeof str !== 'string') str = String(str);
10440
+ if (typeof suffix !== 'string') suffix = String(suffix);
10441
+ return str.endsWith(suffix);
10442
+ });
10443
+
10444
+ this.global.define('includes', (str, substr) => {
10445
+ if (typeof str !== 'string') str = String(str);
10446
+ if (typeof substr !== 'string') substr = String(substr);
10447
+ return str.includes(substr);
10448
+ });
10449
+
10450
+ this.global.define('repeat', (str, times) => {
10451
+ if (typeof str !== 'string') str = String(str);
10452
+ return str.repeat(Number(times) || 0);
10453
+ });
10417
10454
 
10455
+ this.global.define('replace', (str, search, replacement) => {
10456
+ if (typeof str !== 'string') str = String(str);
10457
+ if (typeof search !== 'string') search = String(search);
10458
+ if (typeof replacement !== 'string') replacement = String(replacement);
10459
+ return str.split(search).join(replacement);
10460
+ });
10418
10461
  this.global.define('print', arg => { console.log(arg); return null; });
10419
10462
  this.global.define('type', arg => {
10420
10463
  if (Array.isArray(arg)) return 'array';
@@ -10563,6 +10606,72 @@ this.global.define('range', (...args) => {
10563
10606
 
10564
10607
  return result;
10565
10608
  });
10609
+ this.global.define('floor', arg => Math.floor(Number(arg)));
10610
+ this.global.define('ceil', arg => Math.ceil(Number(arg)));
10611
+ this.global.define('round', arg => Math.round(Number(arg)));
10612
+ this.global.define('abs', arg => Math.abs(Number(arg)));
10613
+ this.global.define('pow', (base, exp) => Math.pow(Number(base), Number(exp)));
10614
+ this.global.define('sqrt', arg => Math.sqrt(Number(arg)));
10615
+ this.global.define('min', (...args) => Math.min(...args.map(Number)));
10616
+ this.global.define('max', (...args) => Math.max(...args.map(Number)));
10617
+ this.global.define('randomFloat', (min, max) => {
10618
+ min = Number(min); max = Number(max);
10619
+ if (isNaN(min) || isNaN(max)) return 0;
10620
+ return Math.random() * (max - min) + min;
10621
+ });
10622
+
10623
+ this.global.define('push', (arr, val) => {
10624
+ if (!Array.isArray(arr)) throw new RuntimeError('push() expects an array', null, this.source);
10625
+ arr.push(val); return arr.length;
10626
+ });
10627
+ this.global.define('pop', arr => {
10628
+ if (!Array.isArray(arr)) throw new RuntimeError('pop() expects an array', null, this.source);
10629
+ return arr.pop();
10630
+ });
10631
+ this.global.define('shift', arr => {
10632
+ if (!Array.isArray(arr)) throw new RuntimeError('shift() expects an array', null, this.source);
10633
+ return arr.shift();
10634
+ });
10635
+ this.global.define('unshift', (arr, val) => {
10636
+ if (!Array.isArray(arr)) throw new RuntimeError('unshift() expects an array', null, this.source);
10637
+ arr.unshift(val); return arr.length;
10638
+ });
10639
+ this.global.define('sort', (arr, fn) => {
10640
+ if (!Array.isArray(arr)) throw new RuntimeError('sort() expects an array', null, this.source);
10641
+ if (fn && typeof fn === 'function') return arr.sort(fn);
10642
+ return arr.sort();
10643
+ });
10644
+ this.global.define('reverse', arr => {
10645
+ if (!Array.isArray(arr)) throw new RuntimeError('reverse() expects an array', null, this.source);
10646
+ return arr.reverse();
10647
+ });
10648
+
10649
+ this.global.define('has', (obj, key) => obj && typeof obj === 'object' ? obj.hasOwnProperty(key) : false);
10650
+ this.global.define('merge', (obj1, obj2) => {
10651
+ if (!obj1 || typeof obj1 !== 'object') obj1 = {};
10652
+ if (!obj2 || typeof obj2 !== 'object') obj2 = {};
10653
+ return { ...obj1, ...obj2 };
10654
+ });
10655
+
10656
+ this.global.define('uuid', () => {
10657
+ // simple random UUID v4
10658
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
10659
+ const r = Math.random() * 16 | 0;
10660
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
10661
+ return v.toString(16);
10662
+ });
10663
+ });
10664
+ this.global.define('timestamp', () => Date.now());
10665
+ this.global.define('clone', arg => {
10666
+ if (Array.isArray(arg)) return [...arg];
10667
+ if (arg && typeof arg === 'object') return { ...arg };
10668
+ return arg; // primitive types
10669
+ });
10670
+ this.global.define('typeOf', arg => {
10671
+ if (arg === null) return 'null';
10672
+ if (Array.isArray(arg)) return 'array';
10673
+ return typeof arg;
10674
+ });
10566
10675
 
10567
10676
  this.global.define('ask', prompt => {
10568
10677
  const readlineSync = __nccwpck_require__(552);
@@ -10619,6 +10728,271 @@ this.global.define('sleep', async (ms) => {
10619
10728
  this.global.define('str', arg => {
10620
10729
  return String(arg);
10621
10730
  });
10731
+ this.global.define('now', () => Date.now());
10732
+ this.global.define('formatDate', (timestamp, locale = 'en-US', options = {}) => {
10733
+ if (timestamp === null || timestamp === undefined) timestamp = Date.now();
10734
+ const t = typeof timestamp === 'number' ? timestamp : Number(timestamp);
10735
+ if (isNaN(t)) t = Date.now();
10736
+ return new Date(t).toLocaleString(locale, options);
10737
+ });
10738
+
10739
+ this.global.define('readFile', path => {
10740
+ if (typeof path !== 'string') path = String(path);
10741
+ try {
10742
+ return fs.readFileSync(path, 'utf-8');
10743
+ } catch (e) {
10744
+ throw new RuntimeError('readFile error: ' + e.message, null, this.source);
10745
+ }
10746
+ });
10747
+ this.global.define('writeFile', (path, content) => {
10748
+ if (typeof path !== 'string') path = String(path);
10749
+ if (typeof content !== 'string') content = String(content);
10750
+ try {
10751
+ fs.writeFileSync(path, content, 'utf-8');
10752
+ return true;
10753
+ } catch (e) {
10754
+ throw new RuntimeError('writeFile error: ' + e.message, null, this.source);
10755
+ }
10756
+ });
10757
+
10758
+ this.global.define('split', (str, separator) => {
10759
+ if (typeof str !== 'string') str = String(str);
10760
+ if (separator === undefined) separator = '';
10761
+ return str.split(separator);
10762
+ });
10763
+
10764
+ this.global.define('join', (arr, separator = '') => {
10765
+ if (!Array.isArray(arr)) throw new RuntimeError('join() expects an array', null, this.source);
10766
+ return arr.join(separator);
10767
+ });
10768
+
10769
+ this.global.define('substring', (str, start, end) => {
10770
+ if (typeof str !== 'string') str = String(str);
10771
+ start = Number(start) || 0;
10772
+ end = end !== undefined ? Number(end) : undefined;
10773
+ return str.substring(start, end);
10774
+ });
10775
+
10776
+ this.global.define('padStart', (str, targetLength, padString = ' ') => {
10777
+ if (typeof str !== 'string') str = String(str);
10778
+ targetLength = Number(targetLength) || 0;
10779
+ return str.padStart(targetLength, padString);
10780
+ });
10781
+
10782
+ this.global.define('padEnd', (str, targetLength, padString = ' ') => {
10783
+ if (typeof str !== 'string') str = String(str);
10784
+ targetLength = Number(targetLength) || 0;
10785
+ return str.padEnd(targetLength, padString);
10786
+ });
10787
+ this.global.define('unique', arr => {
10788
+ if (!Array.isArray(arr)) throw new RuntimeError('unique() expects an array', null, this.source);
10789
+ return [...new Set(arr)];
10790
+ });
10791
+
10792
+ this.global.define('indexOf', (arr, val) => {
10793
+ if (!Array.isArray(arr)) throw new RuntimeError('indexOf() expects an array', null, this.source);
10794
+ return arr.indexOf(val);
10795
+ });
10796
+
10797
+ this.global.define('includesArr', (arr, val) => {
10798
+ if (!Array.isArray(arr)) throw new RuntimeError('includesArr() expects an array', null, this.source);
10799
+ return arr.includes(val);
10800
+ });
10801
+
10802
+ this.global.define('flatten', arr => {
10803
+ if (!Array.isArray(arr)) throw new RuntimeError('flatten() expects an array', null, this.source);
10804
+ return arr.flat(Infinity);
10805
+ });
10806
+
10807
+ this.global.define('randomChoice', arr => {
10808
+ if (!Array.isArray(arr)) throw new RuntimeError('randomChoice() expects an array', null, this.source);
10809
+ return arr[Math.floor(Math.random() * arr.length)];
10810
+ });
10811
+
10812
+ this.global.define('entries', obj => {
10813
+ if (!obj || typeof obj !== 'object') throw new RuntimeError('entries() expects an object', null, this.source);
10814
+ return Object.entries(obj);
10815
+ });
10816
+
10817
+ this.global.define('invert', obj => {
10818
+ if (!obj || typeof obj !== 'object') throw new RuntimeError('invert() expects an object', null, this.source);
10819
+ const result = {};
10820
+ for (const key in obj) result[obj[key]] = key;
10821
+ return result;
10822
+ });
10823
+
10824
+ this.global.define('isEmpty', arg => {
10825
+ if (arg == null) return true;
10826
+ if (Array.isArray(arg) || typeof arg === 'string') return arg.length === 0;
10827
+ if (typeof arg === 'object') return Object.keys(arg).length === 0;
10828
+ return false;
10829
+ });
10830
+
10831
+ this.global.define('deepClone', arg => {
10832
+ return JSON.parse(JSON.stringify(arg));
10833
+ });
10834
+
10835
+ this.global.define('capitalize', str => {
10836
+ if (typeof str !== 'string') str = String(str);
10837
+ if (str.length === 0) return '';
10838
+ return str[0].toUpperCase() + str.slice(1);
10839
+ });
10840
+
10841
+ this.global.define('reverseStr', str => {
10842
+ if (typeof str !== 'string') str = String(str);
10843
+ return str.split('').reverse().join('');
10844
+ });
10845
+
10846
+ this.global.define('trimStart', str => {
10847
+ if (typeof str !== 'string') str = String(str);
10848
+ return str.trimStart();
10849
+ });
10850
+
10851
+ this.global.define('trimEnd', str => {
10852
+ if (typeof str !== 'string') str = String(str);
10853
+ return str.trimEnd();
10854
+ });
10855
+
10856
+ this.global.define('clamp', (value, min, max) => {
10857
+ value = Number(value); min = Number(min); max = Number(max);
10858
+ return Math.min(Math.max(value, min), max);
10859
+ });
10860
+
10861
+ this.global.define('sign', value => {
10862
+ value = Number(value);
10863
+ return Math.sign(value);
10864
+ });
10865
+
10866
+ this.global.define('appendFile', (path, content) => {
10867
+ if (typeof path !== 'string') path = String(path);
10868
+ if (typeof content !== 'string') content = String(content);
10869
+ try {
10870
+ fs.appendFileSync(path, content, 'utf-8');
10871
+ return true;
10872
+ } catch (e) {
10873
+ throw new RuntimeError('appendFile error: ' + e.message, null, this.source);
10874
+ }
10875
+ });
10876
+
10877
+ this.global.define('exists', path => {
10878
+ if (typeof path !== 'string') path = String(path);
10879
+ return fs.existsSync(path);
10880
+ });
10881
+
10882
+ this.global.define('mkdir', path => {
10883
+ if (typeof path !== 'string') path = String(path);
10884
+ if (!fs.existsSync(path)) fs.mkdirSync(path, { recursive: true });
10885
+ return true;
10886
+ });
10887
+ this.global.define('count', (arr, value) => {
10888
+ if (!Array.isArray(arr)) throw new RuntimeError('count() expects an array', null, this.source);
10889
+ return arr.filter(x => x === value).length;
10890
+ });
10891
+
10892
+ this.global.define('uniqueBy', (arr, fn) => {
10893
+ if (!Array.isArray(arr)) throw new RuntimeError('uniqueBy() expects an array', null, this.source);
10894
+ const seen = new Set();
10895
+ const result = [];
10896
+ for (const item of arr) {
10897
+ const key = fn ? fn(item) : item;
10898
+ if (!seen.has(key)) {
10899
+ seen.add(key);
10900
+ result.push(item);
10901
+ }
10902
+ }
10903
+ return result;
10904
+ });
10905
+ this.global.define('getProp', (obj, key, defaultValue = null) => {
10906
+ if (!obj || typeof obj !== 'object') return defaultValue;
10907
+ const keys = key.split('.');
10908
+ let current = obj;
10909
+ for (const k of keys) {
10910
+ if (current[k] === undefined) return defaultValue;
10911
+ current = current[k];
10912
+ }
10913
+ return current;
10914
+ });
10915
+
10916
+ this.global.define('setProp', (obj, key, value) => {
10917
+ if (!obj || typeof obj !== 'object') throw new RuntimeError('setProp() expects an object', null, this.source);
10918
+ const keys = key.split('.');
10919
+ let current = obj;
10920
+ for (let i = 0; i < keys.length - 1; i++) {
10921
+ if (!current[keys[i]] || typeof current[keys[i]] !== 'object') current[keys[i]] = {};
10922
+ current = current[keys[i]];
10923
+ }
10924
+ current[keys[keys.length - 1]] = value;
10925
+ return obj;
10926
+ });
10927
+
10928
+ this.global.define('mergeDeep', (obj1, obj2) => {
10929
+ const isObject = val => val && typeof val === 'object';
10930
+ const result = {...obj1};
10931
+ for (const key in obj2) {
10932
+ if (isObject(obj2[key]) && isObject(result[key])) {
10933
+ result[key] = this.global.get('mergeDeep')(result[key], obj2[key]);
10934
+ } else {
10935
+ result[key] = obj2[key];
10936
+ }
10937
+ }
10938
+ return result;
10939
+ });
10940
+ this.global.define('camelCase', str => {
10941
+ if (typeof str !== 'string') str = String(str);
10942
+ return str
10943
+ .replace(/[-_ ]+./g, s => s.charAt(s.length - 1).toUpperCase())
10944
+ .replace(/^[A-Z]/, s => s.toLowerCase());
10945
+ });
10946
+
10947
+ this.global.define('kebabCase', str => {
10948
+ if (typeof str !== 'string') str = String(str);
10949
+ return str
10950
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
10951
+ .replace(/\s+/g, '-')
10952
+ .replace(/_+/g, '-')
10953
+ .toLowerCase();
10954
+ });
10955
+
10956
+ this.global.define('repeatStr', (str, times) => {
10957
+ if (typeof str !== 'string') str = String(str);
10958
+ return str.repeat(Number(times) || 0);
10959
+ });
10960
+ this.global.define('randomInt', (min, max) => {
10961
+ min = Number(min); max = Number(max);
10962
+ if (isNaN(min) || isNaN(max)) return 0;
10963
+ return Math.floor(Math.random() * (max - min + 1)) + min;
10964
+ });
10965
+
10966
+ this.global.define('lerp', (a, b, t) => {
10967
+ a = Number(a); b = Number(b); t = Number(t);
10968
+ return a + (b - a) * t;
10969
+ });
10970
+
10971
+ this.global.define('degToRad', deg => Number(deg) * (Math.PI / 180));
10972
+ this.global.define('radToDeg', rad => Number(rad) * (180 / Math.PI));
10973
+ this.global.define('readJSON', path => {
10974
+ const content = this.global.get('readFile')(path);
10975
+ return JSON.parse(content);
10976
+ });
10977
+
10978
+ this.global.define('writeJSON', (path, obj) => {
10979
+ const content = JSON.stringify(obj, null, 2);
10980
+ return this.global.get('writeFile')(path, content);
10981
+ });
10982
+
10983
+ this.global.define('deleteFile', path => {
10984
+ if (typeof path !== 'string') path = String(path);
10985
+ if (!fs.existsSync(path)) return false;
10986
+ fs.unlinkSync(path);
10987
+ return true;
10988
+ });
10989
+
10990
+ this.global.define('rmdir', path => {
10991
+ if (typeof path !== 'string') path = String(path);
10992
+ if (!fs.existsSync(path)) return false;
10993
+ fs.rmSync(path, { recursive: true, force: true });
10994
+ return true;
10995
+ });
10622
10996
 
10623
10997
  }
10624
10998
 
@@ -10632,10 +11006,17 @@ async evaluate(node, env = this.global) {
10632
11006
  case 'SldeployStatement': return await this.evalSldeploy(node, env);
10633
11007
  case 'AskStatement': return await this.evalAsk(node, env);
10634
11008
  case 'DefineStatement': return await this.evalDefine(node, env);
11009
+ case 'FunctionExpression':
11010
+ return this.evalFunctionExpression(node, env);
11011
+ case 'SliceExpression':
11012
+ return await this.evalSlice(node, env);
11013
+
10635
11014
  case 'ExpressionStatement': return await this.evaluate(node.expression, env);
10636
11015
  case 'BinaryExpression': return await this.evalBinary(node, env);
10637
11016
  case 'LogicalExpression': return await this.evalLogical(node, env);
10638
11017
  case 'UnaryExpression': return await this.evalUnary(node, env);
11018
+ case 'ConditionalExpression':
11019
+ return await this.evalConditional(node, env);
10639
11020
  case 'Literal': return node.value;
10640
11021
  case 'Identifier': return env.get(node.name, node, this.source);
10641
11022
  case 'IfStatement': return await this.evalIf(node, env);
@@ -10738,6 +11119,36 @@ async evalProgram(node, env) {
10738
11119
  }
10739
11120
  return result;
10740
11121
  }
11122
+ async evalSlice(node, env) {
11123
+ try {
11124
+ const arr = await this.evaluate(node.object, env);
11125
+ const start = node.start ? await this.evaluate(node.start, env) : 0;
11126
+ const end = node.end ? await this.evaluate(node.end, env) : arr.length;
11127
+
11128
+ if (!Array.isArray(arr)) {
11129
+ throw new RuntimeError(
11130
+ 'Slice target must be an array',
11131
+ node,
11132
+ this.source,
11133
+ env
11134
+ );
11135
+ }
11136
+
11137
+ const s = start < 0 ? Math.max(arr.length + start, 0) : Math.min(start, arr.length);
11138
+ const e = end < 0 ? Math.max(arr.length + end, 0) : Math.min(end, arr.length);
11139
+
11140
+ return arr.slice(s, e);
11141
+
11142
+ } catch (err) {
11143
+ if (err instanceof RuntimeError) throw err;
11144
+ throw new RuntimeError(
11145
+ err.message || 'Error evaluating slice expression',
11146
+ node,
11147
+ this.source,
11148
+ env
11149
+ );
11150
+ }
11151
+ }
10741
11152
 
10742
11153
  async evalStartStatement(node, env) {
10743
11154
  try {
@@ -10786,6 +11197,24 @@ async evalStartStatement(node, env) {
10786
11197
  );
10787
11198
  }
10788
11199
  }
11200
+ async evalConditional(node, env) {
11201
+ try {
11202
+ const test = await this.evaluate(node.test, env);
11203
+ if (test) {
11204
+ return await this.evaluate(node.consequent, env);
11205
+ } else {
11206
+ return await this.evaluate(node.alternate, env);
11207
+ }
11208
+ } catch (e) {
11209
+ if (e instanceof RuntimeError) throw e;
11210
+ throw new RuntimeError(
11211
+ e.message || 'Error evaluating conditional expression',
11212
+ node,
11213
+ this.source,
11214
+ env
11215
+ );
11216
+ }
11217
+ }
10789
11218
 
10790
11219
  async evalRaceClause(node, env) {
10791
11220
  try {
@@ -11396,6 +11825,41 @@ async evalFor(node, env) {
11396
11825
  );
11397
11826
  }
11398
11827
  }
11828
+ evalFunctionExpression(node, env) {
11829
+ if (!node.body || !Array.isArray(node.params)) {
11830
+ throw new RuntimeError(
11831
+ 'Invalid function expression',
11832
+ node,
11833
+ this.source,
11834
+ env
11835
+ );
11836
+ }
11837
+
11838
+ const evaluator = this;
11839
+
11840
+ const fn = async function (...args) {
11841
+ const localEnv = new Environment(env);
11842
+
11843
+ for (let i = 0; i < node.params.length; i++) {
11844
+ const param = node.params[i];
11845
+ const paramName = typeof param === 'string' ? param : param.name;
11846
+ localEnv.define(paramName, args[i]);
11847
+ }
11848
+
11849
+ try {
11850
+ const result = await evaluator.evaluate(node.body, localEnv);
11851
+ return result === undefined ? null : result;
11852
+ } catch (e) {
11853
+ if (e instanceof ReturnValue) return e.value === undefined ? null : e.value;
11854
+ throw e;
11855
+ }
11856
+ };
11857
+ fn.params = node.params;
11858
+ fn.body = node.body;
11859
+ fn.env = env;
11860
+
11861
+ return fn;
11862
+ }
11399
11863
 
11400
11864
  evalFunctionDeclaration(node, env) {
11401
11865
  try {
@@ -11483,7 +11947,6 @@ async evalCall(node, env) {
11483
11947
  );
11484
11948
  }
11485
11949
  }
11486
-
11487
11950
  async evalIndex(node, env) {
11488
11951
  try {
11489
11952
  const obj = await this.evaluate(node.object, env);
@@ -11516,7 +11979,6 @@ async evalIndex(node, env) {
11516
11979
  );
11517
11980
  }
11518
11981
  }
11519
-
11520
11982
  async evalObject(node, env) {
11521
11983
  try {
11522
11984
  const out = {};
@@ -13161,33 +13623,100 @@ postfix() {
13161
13623
  while (true) {
13162
13624
  const t = this.current;
13163
13625
 
13164
- if (t.type === 'LBRACKET') {
13165
- const startLine = t.line;
13166
- const startCol = t.column;
13167
- this.eat('LBRACKET');
13626
+ if (t.type === 'LBRACKET') {
13627
+ const startLine = t.line;
13628
+ const startCol = t.column;
13629
+ this.eat('LBRACKET');
13630
+
13631
+ let start = null;
13632
+ let end = null;
13633
+ let step = null;
13634
+
13635
+ if (this.current.type === 'COLON') {
13636
+ this.eat('COLON');
13637
+
13638
+ if (this.current.type !== 'RBRACKET' && this.current.type !== 'COLON') {
13639
+ end = this.expression();
13640
+ }
13641
+
13642
+ if (this.current.type === 'COLON') {
13643
+ this.eat('COLON');
13644
+ if (this.current.type !== 'RBRACKET') {
13645
+ step = this.expression();
13646
+ }
13647
+ }
13648
+
13649
+ if (this.current.type !== 'RBRACKET') {
13650
+ throw new ParseError(
13651
+ "Expected ']' after slice",
13652
+ this.current,
13653
+ this.source
13654
+ );
13655
+ }
13656
+
13657
+ this.eat('RBRACKET');
13658
+
13659
+ node = {
13660
+ type: 'SliceExpression',
13661
+ object: node,
13662
+ start,
13663
+ end,
13664
+ step,
13665
+ line: startLine,
13666
+ column: startCol
13667
+ };
13668
+
13669
+ } else {
13670
+ start = this.expression();
13671
+
13672
+ if (this.current.type === 'COLON') {
13673
+ this.eat('COLON');
13168
13674
 
13169
- const index = this.expression();
13675
+ if (this.current.type !== 'RBRACKET' && this.current.type !== 'COLON') {
13676
+ end = this.expression();
13677
+ }
13678
+
13679
+ if (this.current.type === 'COLON') {
13680
+ this.eat('COLON');
13681
+ if (this.current.type !== 'RBRACKET') {
13682
+ step = this.expression();
13683
+ }
13684
+ }
13170
13685
 
13171
13686
  if (this.current.type !== 'RBRACKET') {
13172
13687
  throw new ParseError(
13173
- "Expected ']' after index expression",
13688
+ "Expected ']' after slice",
13174
13689
  this.current,
13175
- this.source,
13176
- "Index access must be closed, e.g. arr[0]"
13690
+ this.source
13177
13691
  );
13178
13692
  }
13179
13693
 
13180
13694
  this.eat('RBRACKET');
13181
13695
 
13696
+ node = {
13697
+ type: 'SliceExpression',
13698
+ object: node,
13699
+ start,
13700
+ end,
13701
+ step,
13702
+ line: startLine,
13703
+ column: startCol
13704
+ };
13705
+
13706
+ } else {
13707
+ this.eat('RBRACKET');
13182
13708
  node = {
13183
13709
  type: 'IndexExpression',
13184
13710
  object: node,
13185
- indexer: index,
13711
+ indexer: start,
13186
13712
  line: startLine,
13187
13713
  column: startCol
13188
13714
  };
13189
- continue;
13190
13715
  }
13716
+ }
13717
+ }
13718
+
13719
+
13191
13720
 
13192
13721
  if (t.type === 'LPAREN') {
13193
13722
  const startLine = t.line;
@@ -13319,6 +13848,7 @@ arrowFunction(params) {
13319
13848
  };
13320
13849
  }
13321
13850
 
13851
+
13322
13852
  primary() {
13323
13853
  const t = this.current;
13324
13854
 
@@ -13390,7 +13920,6 @@ primary() {
13390
13920
  return { type: 'NewExpression', callee, arguments: args, line: t.line, column: t.column };
13391
13921
  }
13392
13922
 
13393
- // ---- ask(...) function call ----
13394
13923
  if (t.type === 'ASK') {
13395
13924
  this.eat('ASK');
13396
13925
 
@@ -13431,6 +13960,69 @@ primary() {
13431
13960
  column: t.column
13432
13961
  };
13433
13962
  }
13963
+ if (t.type === 'FUNC') {
13964
+ const funcToken = t;
13965
+ this.eat('FUNC');
13966
+
13967
+ let params = [];
13968
+ if (this.current.type === 'LPAREN') {
13969
+ this.eat('LPAREN');
13970
+
13971
+ if (this.current.type !== 'RPAREN') {
13972
+ if (this.current.type !== 'IDENTIFIER') {
13973
+ throw new ParseError(
13974
+ "Expected parameter name",
13975
+ this.current,
13976
+ this.source
13977
+ );
13978
+ }
13979
+
13980
+ params.push(this.current.value);
13981
+ this.eat('IDENTIFIER');
13982
+
13983
+ while (this.current.type === 'COMMA') {
13984
+ this.eat('COMMA');
13985
+ if (this.current.type !== 'IDENTIFIER') {
13986
+ throw new ParseError(
13987
+ "Expected parameter name",
13988
+ this.current,
13989
+ this.source
13990
+ );
13991
+ }
13992
+ params.push(this.current.value);
13993
+ this.eat('IDENTIFIER');
13994
+ }
13995
+ }
13996
+
13997
+ if (this.current.type !== 'RPAREN') {
13998
+ throw new ParseError(
13999
+ "Expected ')' after function parameters",
14000
+ this.current,
14001
+ this.source
14002
+ );
14003
+ }
14004
+
14005
+ this.eat('RPAREN');
14006
+ }
14007
+
14008
+ if (this.current.type !== 'LBRACE') {
14009
+ throw new ParseError(
14010
+ "Expected '{' to start function body",
14011
+ this.current,
14012
+ this.source
14013
+ );
14014
+ }
14015
+
14016
+ const body = this.block();
14017
+
14018
+ return {
14019
+ type: 'FunctionExpression',
14020
+ params,
14021
+ body,
14022
+ line: funcToken.line,
14023
+ column: funcToken.column
14024
+ };
14025
+ }
13434
14026
 
13435
14027
  if (t.type === 'IDENTIFIER') {
13436
14028
  const name = t.value;
@@ -13567,7 +14159,7 @@ primary() {
13567
14159
  t,
13568
14160
  this.source
13569
14161
  );
13570
- }
14162
+ }
13571
14163
 
13572
14164
  }
13573
14165
 
@@ -13751,7 +14343,7 @@ const Lexer = __nccwpck_require__(211);
13751
14343
  const Parser = __nccwpck_require__(222);
13752
14344
  const Evaluator = __nccwpck_require__(112);
13753
14345
 
13754
- const VERSION = '1.1.15';
14346
+ const VERSION = '1.1.17';
13755
14347
 
13756
14348
  const COLOR = {
13757
14349
  reset: '\x1b[0m',