@gabrielbryk/jq-ts 1.3.5 → 1.4.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/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/errors.ts
3
3
  var BaseError = class extends Error {
4
4
  kind;
@@ -42,7 +42,6 @@ var RuntimeError = class extends BaseError {
42
42
  super("runtime", message, span);
43
43
  }
44
44
  };
45
-
46
45
  //#endregion
47
46
  //#region src/tokens.ts
48
47
  const keywordKinds = {
@@ -66,7 +65,6 @@ const keywordKinds = {
66
65
  label: "Label",
67
66
  break: "Break"
68
67
  };
69
-
70
68
  //#endregion
71
69
  //#region src/lexer.ts
72
70
  /**
@@ -279,7 +277,7 @@ const lex = (text) => {
279
277
  const raw = text.slice(start, pos);
280
278
  const keyword = keywordKinds[raw];
281
279
  if (keyword === "Null" || keyword === "True" || keyword === "False") pushToken(keyword, start, pos);
282
- else if (keyword) pushToken(keyword, start, pos);
280
+ else if (keyword) pushToken(keyword, start, pos, raw);
283
281
  else pushToken("Identifier", start, pos, raw);
284
282
  continue;
285
283
  }
@@ -380,7 +378,6 @@ const lex = (text) => {
380
378
  }
381
379
  };
382
380
  const isHexDigit = (ch) => !!ch && (ch >= "0" && ch <= "9" || ch >= "a" && ch <= "f" || ch >= "A" && ch <= "F");
383
-
384
381
  //#endregion
385
382
  //#region src/parser.ts
386
383
  /**
@@ -447,19 +444,93 @@ var Parser = class {
447
444
  }
448
445
  let expr = this.parsePipe(allowComma);
449
446
  while (this.match("As")) {
450
- const varToken = this.consume("Variable", "Expected variable name after \"as\"");
451
- this.consume("Pipe", "Expected \"|\" after variable binding");
447
+ const pattern = this.parseBindingPattern();
448
+ this.consume("Pipe", "Expected \"|\" after binding pattern");
452
449
  const body = this.parseBinding(allowComma);
453
450
  expr = {
454
451
  kind: "As",
455
452
  bind: expr,
456
- name: String(varToken.value),
453
+ pattern,
457
454
  body,
458
455
  span: spanBetween(expr.span, body.span)
459
456
  };
460
457
  }
461
458
  return expr;
462
459
  }
460
+ parseBindingPattern() {
461
+ if (this.match("Variable")) {
462
+ const token = this.previous();
463
+ return {
464
+ kind: "VariablePattern",
465
+ name: String(token.value),
466
+ span: token.span
467
+ };
468
+ }
469
+ if (this.match("LBracket")) {
470
+ const start = this.previous();
471
+ const items = [];
472
+ if (!this.match("RBracket")) {
473
+ do
474
+ items.push(this.parseBindingPattern());
475
+ while (this.match("Comma"));
476
+ this.consume("RBracket", "Expected \"]\" after array binding pattern");
477
+ }
478
+ return {
479
+ kind: "ArrayPattern",
480
+ items,
481
+ span: spanBetween(start.span, this.previous().span)
482
+ };
483
+ }
484
+ if (this.match("LBrace")) {
485
+ const start = this.previous();
486
+ const entries = [];
487
+ if (!this.match("RBrace")) {
488
+ do
489
+ entries.push(this.parseObjectBindingPatternEntry());
490
+ while (this.match("Comma"));
491
+ this.consume("RBrace", "Expected \"}\" after object binding pattern");
492
+ }
493
+ return {
494
+ kind: "ObjectPattern",
495
+ entries,
496
+ span: spanBetween(start.span, this.previous().span)
497
+ };
498
+ }
499
+ throw this.error(this.peek(), "Expected variable or destructuring pattern after \"as\"");
500
+ }
501
+ parseObjectBindingPatternEntry() {
502
+ if (this.match("Variable")) {
503
+ const token = this.previous();
504
+ const name = String(token.value);
505
+ return {
506
+ key: name,
507
+ pattern: {
508
+ kind: "VariablePattern",
509
+ name,
510
+ span: token.span
511
+ },
512
+ span: token.span
513
+ };
514
+ }
515
+ let key;
516
+ let keySpan;
517
+ if (this.match("Identifier")) {
518
+ const token = this.previous();
519
+ key = String(token.value);
520
+ keySpan = token.span;
521
+ } else if (this.match("String")) {
522
+ const token = this.previous();
523
+ key = String(token.value);
524
+ keySpan = token.span;
525
+ } else throw this.error(this.peek(), "Expected identifier, string, or variable shorthand in object binding pattern");
526
+ this.consume("Colon", "Expected \":\" after object binding pattern key");
527
+ const pattern = this.parseBindingPattern();
528
+ return {
529
+ key,
530
+ pattern,
531
+ span: spanBetween(keySpan, pattern.span)
532
+ };
533
+ }
463
534
  parsePipe(allowComma = true) {
464
535
  let expr = this.parseComma(allowComma);
465
536
  while (this.match("Pipe")) {
@@ -623,16 +694,6 @@ var Parser = class {
623
694
  return expr;
624
695
  }
625
696
  parseUnary() {
626
- if (this.match("Not")) {
627
- const op = this.previous();
628
- const expr = this.parseUnary();
629
- return {
630
- kind: "Unary",
631
- op: "Not",
632
- expr,
633
- span: spanBetween(op.span, expr.span)
634
- };
635
- }
636
697
  if (this.match("Minus")) {
637
698
  const op = this.previous();
638
699
  const expr = this.parseUnary();
@@ -703,10 +764,7 @@ var Parser = class {
703
764
  expr = {
704
765
  kind: "Try",
705
766
  body: expr,
706
- handler: {
707
- kind: "Identity",
708
- span: op.span
709
- },
767
+ handler: void 0,
710
768
  span: spanBetween(expr.span, op.span)
711
769
  };
712
770
  continue;
@@ -749,11 +807,8 @@ var Parser = class {
749
807
  kind: "Recurse",
750
808
  span: this.previous().span
751
809
  };
752
- if (this.match("DotDot")) return {
753
- kind: "Recurse",
754
- span: this.previous().span
755
- };
756
810
  if (this.match("Break")) return this.parseBreak(this.previous());
811
+ if (this.match("Not")) return this.finishIdentifier(this.previous());
757
812
  throw this.error(this.peek(), "Unexpected token");
758
813
  }
759
814
  parseBreak(start) {
@@ -767,8 +822,8 @@ var Parser = class {
767
822
  parseReduce(start) {
768
823
  const source = this.parsePipe();
769
824
  this.consume("As", "Expected \"as\" after reduce source");
770
- const varToken = this.consume("Variable", "Expected variable after \"as\"");
771
- this.consume("LParen", "Expected \"(\" after variable");
825
+ const pattern = this.parseBindingPattern();
826
+ this.consume("LParen", "Expected \"(\" after binding pattern");
772
827
  const init = this.parseComma();
773
828
  this.consume("Semicolon", "Expected \";\" after init");
774
829
  const update = this.parseComma();
@@ -776,7 +831,7 @@ var Parser = class {
776
831
  return {
777
832
  kind: "Reduce",
778
833
  source,
779
- var: String(varToken.value),
834
+ pattern,
780
835
  init,
781
836
  update,
782
837
  span: spanBetween(start.span, end.span)
@@ -785,8 +840,8 @@ var Parser = class {
785
840
  parseForeach(start) {
786
841
  const source = this.parsePipe();
787
842
  this.consume("As", "Expected \"as\" after foreach source");
788
- const varToken = this.consume("Variable", "Expected variable after \"as\"");
789
- this.consume("LParen", "Expected \"(\" after variable");
843
+ const pattern = this.parseBindingPattern();
844
+ this.consume("LParen", "Expected \"(\" after binding pattern");
790
845
  const init = this.parseComma();
791
846
  this.consume("Semicolon", "Expected \";\" after init");
792
847
  const update = this.parseComma();
@@ -796,7 +851,7 @@ var Parser = class {
796
851
  return {
797
852
  kind: "Foreach",
798
853
  source,
799
- var: String(varToken.value),
854
+ pattern,
800
855
  init,
801
856
  update,
802
857
  extract,
@@ -1018,10 +1073,7 @@ var Parser = class {
1018
1073
  expr = {
1019
1074
  kind: "Try",
1020
1075
  body: expr,
1021
- handler: {
1022
- kind: "Identity",
1023
- span: op.span
1024
- },
1076
+ handler: void 0,
1025
1077
  span: spanBetween(expr.span, op.span)
1026
1078
  };
1027
1079
  continue;
@@ -1167,7 +1219,6 @@ const spanBetween = (a, b) => ({
1167
1219
  start: Math.min(a.start, b.start),
1168
1220
  end: Math.max(a.end, b.end)
1169
1221
  });
1170
-
1171
1222
  //#endregion
1172
1223
  //#region src/builtins/registry.ts
1173
1224
  const builtins = {};
@@ -1178,7 +1229,6 @@ const registerBuiltin = (spec) => {
1178
1229
  const registerBuiltins = (specs) => {
1179
1230
  for (const spec of specs) registerBuiltin(spec);
1180
1231
  };
1181
-
1182
1232
  //#endregion
1183
1233
  //#region src/value.ts
1184
1234
  /**
@@ -1205,7 +1255,7 @@ const valueEquals = (a, b) => {
1205
1255
  for (let i = 0; i < a.length; i += 1) if (!valueEquals(a[i], b[i])) return false;
1206
1256
  return true;
1207
1257
  }
1208
- if (isPlainObject(a) && isPlainObject(b)) {
1258
+ if (isPlainObject$1(a) && isPlainObject$1(b)) {
1209
1259
  const aKeys = Object.keys(a).sort();
1210
1260
  const bKeys = Object.keys(b).sort();
1211
1261
  if (aKeys.length !== bKeys.length) return false;
@@ -1242,7 +1292,7 @@ const compareValues = (a, b) => {
1242
1292
  }
1243
1293
  return a.length < b.length ? -1 : 1;
1244
1294
  }
1245
- if (isPlainObject(a) && isPlainObject(b)) {
1295
+ if (isPlainObject$1(a) && isPlainObject$1(b)) {
1246
1296
  const aKeys = Object.keys(a).sort();
1247
1297
  const bKeys = Object.keys(b).sort();
1248
1298
  const len = Math.min(aKeys.length, bKeys.length);
@@ -1276,7 +1326,7 @@ const typeRank = (value) => {
1276
1326
  * @param value - The value to check.
1277
1327
  * @returns `true` if `value` is a non-null object (and not an array).
1278
1328
  */
1279
- const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1329
+ const isPlainObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1280
1330
  /**
1281
1331
  * Checks if a value is a JSON array.
1282
1332
  *
@@ -1299,7 +1349,6 @@ const describeType = (value) => {
1299
1349
  if (Array.isArray(value)) return "array";
1300
1350
  return "object";
1301
1351
  };
1302
-
1303
1352
  //#endregion
1304
1353
  //#region src/builtins/utils.ts
1305
1354
  const emit$1 = (value, span, tracker) => {
@@ -1307,7 +1356,10 @@ const emit$1 = (value, span, tracker) => {
1307
1356
  return value;
1308
1357
  };
1309
1358
  const ensureIndex = (val) => {
1310
- if (typeof val === "number" && Number.isInteger(val)) return val;
1359
+ if (typeof val === "number") {
1360
+ if (!Number.isFinite(val)) return void 0;
1361
+ return Math.trunc(val);
1362
+ }
1311
1363
  if (typeof val === "string" && /^-?\d+$/.test(val)) return parseInt(val, 10);
1312
1364
  };
1313
1365
  const stableStringify = (value) => {
@@ -1318,7 +1370,6 @@ const stableStringify = (value) => {
1318
1370
  if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
1319
1371
  return `{${Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(",")}}`;
1320
1372
  };
1321
-
1322
1373
  //#endregion
1323
1374
  //#region src/builtins/std.ts
1324
1375
  const toJqString = (value) => {
@@ -1364,9 +1415,87 @@ const stdBuiltins = [
1364
1415
  if (typeof input === "string") yield emit$1(Array.from(input).length, span, tracker);
1365
1416
  else if (Array.isArray(input)) yield emit$1(input.length, span, tracker);
1366
1417
  else if (input !== null && typeof input === "object") yield emit$1(Object.keys(input).length, span, tracker);
1418
+ else if (typeof input === "number") yield emit$1(Math.abs(input), span, tracker);
1367
1419
  else throw new RuntimeError(`Cannot take length of ${describeType(input)}`, span);
1368
1420
  }
1369
1421
  },
1422
+ {
1423
+ name: "arrays",
1424
+ arity: 0,
1425
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1426
+ if (Array.isArray(input)) yield emit$1(input, span, tracker);
1427
+ }
1428
+ },
1429
+ {
1430
+ name: "objects",
1431
+ arity: 0,
1432
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1433
+ if (isPlainObject$1(input)) yield emit$1(input, span, tracker);
1434
+ }
1435
+ },
1436
+ {
1437
+ name: "iterables",
1438
+ arity: 0,
1439
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1440
+ if (Array.isArray(input) || isPlainObject$1(input)) yield emit$1(input, span, tracker);
1441
+ }
1442
+ },
1443
+ {
1444
+ name: "booleans",
1445
+ arity: 0,
1446
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1447
+ if (typeof input === "boolean") yield emit$1(input, span, tracker);
1448
+ }
1449
+ },
1450
+ {
1451
+ name: "numbers",
1452
+ arity: 0,
1453
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1454
+ if (typeof input === "number") yield emit$1(input, span, tracker);
1455
+ }
1456
+ },
1457
+ {
1458
+ name: "strings",
1459
+ arity: 0,
1460
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1461
+ if (typeof input === "string") yield emit$1(input, span, tracker);
1462
+ }
1463
+ },
1464
+ {
1465
+ name: "nulls",
1466
+ arity: 0,
1467
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1468
+ if (input === null) yield emit$1(input, span, tracker);
1469
+ }
1470
+ },
1471
+ {
1472
+ name: "values",
1473
+ arity: 0,
1474
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1475
+ if (input !== null) yield emit$1(input, span, tracker);
1476
+ }
1477
+ },
1478
+ {
1479
+ name: "scalars",
1480
+ arity: 0,
1481
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1482
+ if (input === null || typeof input !== "object") yield emit$1(input, span, tracker);
1483
+ }
1484
+ },
1485
+ {
1486
+ name: "finites",
1487
+ arity: 0,
1488
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1489
+ if (typeof input === "number" && Number.isFinite(input)) yield emit$1(input, span, tracker);
1490
+ }
1491
+ },
1492
+ {
1493
+ name: "normals",
1494
+ arity: 0,
1495
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1496
+ if (typeof input === "number" && Number.isFinite(input) && input !== 0) yield emit$1(input, span, tracker);
1497
+ }
1498
+ },
1370
1499
  {
1371
1500
  name: "empty",
1372
1501
  arity: 0,
@@ -1379,10 +1508,17 @@ const stdBuiltins = [
1379
1508
  yield emit$1(isTruthy(input), span, tracker);
1380
1509
  }
1381
1510
  },
1511
+ {
1512
+ name: "not",
1513
+ arity: 0,
1514
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1515
+ yield emit$1(!isTruthy(input), span, tracker);
1516
+ }
1517
+ },
1382
1518
  {
1383
1519
  name: "walk",
1384
1520
  arity: 1,
1385
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1521
+ apply: function* (input, args, env, tracker, evaluate, span) {
1386
1522
  const f = args[0];
1387
1523
  const walkRec = function* (curr) {
1388
1524
  tracker.step(span);
@@ -1391,7 +1527,7 @@ const stdBuiltins = [
1391
1527
  const newArr = [];
1392
1528
  for (const item of curr) for (const walkedItem of walkRec(item)) newArr.push(walkedItem);
1393
1529
  newStruct = newArr;
1394
- } else if (isPlainObject(curr)) {
1530
+ } else if (isPlainObject$1(curr)) {
1395
1531
  const newObj = {};
1396
1532
  const keys = Object.keys(curr).sort();
1397
1533
  let objValid = true;
@@ -1412,23 +1548,27 @@ const stdBuiltins = [
1412
1548
  if (!objValid) return;
1413
1549
  newStruct = newObj;
1414
1550
  }
1415
- yield* evaluate$1(f, newStruct, env, tracker);
1551
+ yield* evaluate(f, newStruct, env, tracker);
1416
1552
  };
1417
1553
  yield* walkRec(input);
1418
1554
  }
1419
1555
  }
1420
1556
  ];
1421
-
1422
1557
  //#endregion
1423
1558
  //#region src/builtins/errors.ts
1424
1559
  const errorBuiltins = [{
1560
+ name: "error",
1561
+ arity: 0,
1562
+ apply: function* (_input, _args, _env, _tracker, _eval, span) {
1563
+ throw new RuntimeError("null", span);
1564
+ }
1565
+ }, {
1425
1566
  name: "error",
1426
1567
  arity: 1,
1427
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1428
- for (const msg of evaluate$1(args[0], input, env, tracker)) throw new RuntimeError(typeof msg === "string" ? msg : stableStringify(msg), span);
1568
+ apply: function* (input, args, env, tracker, evaluate, span) {
1569
+ for (const msg of evaluate(args[0], input, env, tracker)) throw new RuntimeError(typeof msg === "string" ? msg : stableStringify(msg), span);
1429
1570
  }
1430
1571
  }];
1431
-
1432
1572
  //#endregion
1433
1573
  //#region src/builtins/strings.ts
1434
1574
  const checkContains = (a, b) => {
@@ -1436,7 +1576,7 @@ const checkContains = (a, b) => {
1436
1576
  if (typeof a !== typeof b) return false;
1437
1577
  if (typeof a === "string" && typeof b === "string") return a.includes(b);
1438
1578
  if (Array.isArray(a) && Array.isArray(b)) return b.every((bItem) => a.some((aItem) => checkContains(aItem, bItem)));
1439
- if (isPlainObject(a) && isPlainObject(b)) {
1579
+ if (isPlainObject$1(a) && isPlainObject$1(b)) {
1440
1580
  const keys = Object.keys(b);
1441
1581
  for (const key of keys) {
1442
1582
  if (!Object.prototype.hasOwnProperty.call(a, key)) return false;
@@ -1452,9 +1592,9 @@ const stringBuiltins = [
1452
1592
  {
1453
1593
  name: "split",
1454
1594
  arity: 1,
1455
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1595
+ apply: function* (input, args, env, tracker, evaluate, span) {
1456
1596
  if (typeof input !== "string") throw new RuntimeError("split input must be a string", span);
1457
- const sepGen = evaluate$1(args[0], input, env, tracker);
1597
+ const sepGen = evaluate(args[0], input, env, tracker);
1458
1598
  for (const sep of sepGen) {
1459
1599
  if (typeof sep !== "string") throw new RuntimeError("split separator must be a string", span);
1460
1600
  yield emit$1(input.split(sep), span, tracker);
@@ -1464,16 +1604,15 @@ const stringBuiltins = [
1464
1604
  {
1465
1605
  name: "join",
1466
1606
  arity: 1,
1467
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1607
+ apply: function* (input, args, env, tracker, evaluate, span) {
1468
1608
  if (!Array.isArray(input)) throw new RuntimeError("join input must be an array", span);
1469
- const sepGen = evaluate$1(args[0], input, env, tracker);
1609
+ const sepGen = evaluate(args[0], input, env, tracker);
1470
1610
  for (const sep of sepGen) {
1471
1611
  if (typeof sep !== "string") throw new RuntimeError("join separator must be a string", span);
1472
1612
  const parts = [];
1473
- for (const item of input) {
1474
- if (typeof item !== "string") throw new RuntimeError(`join expects strings, but got ${describeType(item)}`, span);
1475
- parts.push(item);
1476
- }
1613
+ for (const item of input) if (item === null) parts.push("");
1614
+ else if (typeof item === "string" || typeof item === "number" || typeof item === "boolean") parts.push(String(item));
1615
+ else throw new RuntimeError(`join cannot join ${describeType(item)}`, span);
1477
1616
  yield emit$1(parts.join(sep), span, tracker);
1478
1617
  }
1479
1618
  }
@@ -1481,9 +1620,9 @@ const stringBuiltins = [
1481
1620
  {
1482
1621
  name: "startswith",
1483
1622
  arity: 1,
1484
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1623
+ apply: function* (input, args, env, tracker, evaluate, span) {
1485
1624
  if (typeof input !== "string") throw new RuntimeError("startswith input must be a string", span);
1486
- const prefixGen = evaluate$1(args[0], input, env, tracker);
1625
+ const prefixGen = evaluate(args[0], input, env, tracker);
1487
1626
  for (const prefix of prefixGen) {
1488
1627
  if (typeof prefix !== "string") throw new RuntimeError("startswith prefix must be a string", span);
1489
1628
  yield emit$1(input.startsWith(prefix), span, tracker);
@@ -1493,9 +1632,9 @@ const stringBuiltins = [
1493
1632
  {
1494
1633
  name: "endswith",
1495
1634
  arity: 1,
1496
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1635
+ apply: function* (input, args, env, tracker, evaluate, span) {
1497
1636
  if (typeof input !== "string") throw new RuntimeError("endswith input must be a string", span);
1498
- const suffixGen = evaluate$1(args[0], input, env, tracker);
1637
+ const suffixGen = evaluate(args[0], input, env, tracker);
1499
1638
  for (const suffix of suffixGen) {
1500
1639
  if (typeof suffix !== "string") throw new RuntimeError("endswith suffix must be a string", span);
1501
1640
  yield emit$1(input.endsWith(suffix), span, tracker);
@@ -1505,16 +1644,16 @@ const stringBuiltins = [
1505
1644
  {
1506
1645
  name: "contains",
1507
1646
  arity: 1,
1508
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1509
- const bGen = evaluate$1(args[0], input, env, tracker);
1647
+ apply: function* (input, args, env, tracker, evaluate, span) {
1648
+ const bGen = evaluate(args[0], input, env, tracker);
1510
1649
  for (const b of bGen) yield emit$1(checkContains(input, b), span, tracker);
1511
1650
  }
1512
1651
  },
1513
1652
  {
1514
1653
  name: "index",
1515
1654
  arity: 1,
1516
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1517
- const searchGen = evaluate$1(args[0], input, env, tracker);
1655
+ apply: function* (input, args, env, tracker, evaluate, span) {
1656
+ const searchGen = evaluate(args[0], input, env, tracker);
1518
1657
  for (const search of searchGen) if (Array.isArray(input)) {
1519
1658
  let foundIndex = null;
1520
1659
  for (let i = 0; i < input.length; i++) {
@@ -1536,8 +1675,8 @@ const stringBuiltins = [
1536
1675
  {
1537
1676
  name: "rindex",
1538
1677
  arity: 1,
1539
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1540
- const searchGen = evaluate$1(args[0], input, env, tracker);
1678
+ apply: function* (input, args, env, tracker, evaluate, span) {
1679
+ const searchGen = evaluate(args[0], input, env, tracker);
1541
1680
  for (const search of searchGen) if (Array.isArray(input)) {
1542
1681
  let foundIndex = null;
1543
1682
  for (let i = input.length - 1; i >= 0; i--) {
@@ -1559,8 +1698,8 @@ const stringBuiltins = [
1559
1698
  {
1560
1699
  name: "indices",
1561
1700
  arity: 1,
1562
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1563
- const searchGen = evaluate$1(args[0], input, env, tracker);
1701
+ apply: function* (input, args, env, tracker, evaluate, span) {
1702
+ const searchGen = evaluate(args[0], input, env, tracker);
1564
1703
  for (const search of searchGen) {
1565
1704
  const indices = [];
1566
1705
  if (Array.isArray(input)) for (let i = 0; i < input.length; i++) {
@@ -1598,6 +1737,14 @@ const stringBuiltins = [
1598
1737
  yield emit$1(Array.from(input).map((c) => c.codePointAt(0)), span, tracker);
1599
1738
  }
1600
1739
  },
1740
+ {
1741
+ name: "utf8bytelength",
1742
+ arity: 0,
1743
+ apply: function* (input, _args, _env, tracker, _eval, span) {
1744
+ if (typeof input !== "string") throw new RuntimeError("utf8bytelength expects string", span);
1745
+ yield emit$1(utf8ByteLength(input), span, tracker);
1746
+ }
1747
+ },
1601
1748
  {
1602
1749
  name: "implode",
1603
1750
  arity: 0,
@@ -1614,9 +1761,9 @@ const stringBuiltins = [
1614
1761
  {
1615
1762
  name: "ltrimstr",
1616
1763
  arity: 1,
1617
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1764
+ apply: function* (input, args, env, tracker, evaluate, span) {
1618
1765
  if (typeof input !== "string") throw new RuntimeError("ltrimstr expects string", span);
1619
- const prefixGen = evaluate$1(args[0], input, env, tracker);
1766
+ const prefixGen = evaluate(args[0], input, env, tracker);
1620
1767
  for (const prefix of prefixGen) {
1621
1768
  if (typeof prefix !== "string") throw new RuntimeError("ltrimstr prefix must be a string", span);
1622
1769
  if (input.startsWith(prefix)) yield emit$1(input.slice(prefix.length), span, tracker);
@@ -1625,435 +1772,103 @@ const stringBuiltins = [
1625
1772
  }
1626
1773
  },
1627
1774
  {
1628
- name: "rtrimstr",
1775
+ name: "trimstr",
1629
1776
  arity: 1,
1630
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1631
- if (typeof input !== "string") throw new RuntimeError("rtrimstr expects string", span);
1632
- const suffixGen = evaluate$1(args[0], input, env, tracker);
1633
- for (const suffix of suffixGen) {
1634
- if (typeof suffix !== "string") throw new RuntimeError("rtrimstr suffix must be a string", span);
1635
- if (input.endsWith(suffix)) yield emit$1(input.slice(0, input.length - suffix.length), span, tracker);
1636
- else yield emit$1(input, span, tracker);
1777
+ apply: function* (input, args, env, tracker, evaluate, span) {
1778
+ if (typeof input !== "string") throw new RuntimeError("trimstr expects string", span);
1779
+ for (const trim of evaluate(args[0], input, env, tracker)) {
1780
+ if (typeof trim !== "string") throw new RuntimeError("trimstr argument must be string", span);
1781
+ let result = input;
1782
+ if (result.startsWith(trim)) result = result.slice(trim.length);
1783
+ if (result.endsWith(trim)) result = result.slice(0, result.length - trim.length);
1784
+ yield emit$1(result, span, tracker);
1637
1785
  }
1638
1786
  }
1639
1787
  },
1640
1788
  {
1641
- name: "ascii_downcase",
1789
+ name: "trim",
1642
1790
  arity: 0,
1643
1791
  apply: function* (input, _args, _env, tracker, _eval, span) {
1644
- if (typeof input !== "string") throw new RuntimeError("ascii_downcase expects string", span);
1645
- yield emit$1(input.toLowerCase(), span, tracker);
1792
+ if (typeof input !== "string") throw new RuntimeError("trim expects string", span);
1793
+ yield emit$1(input.trim(), span, tracker);
1646
1794
  }
1647
1795
  },
1648
1796
  {
1649
- name: "ascii_upcase",
1797
+ name: "ltrim",
1650
1798
  arity: 0,
1651
1799
  apply: function* (input, _args, _env, tracker, _eval, span) {
1652
- if (typeof input !== "string") throw new RuntimeError("ascii_upcase expects string", span);
1653
- yield emit$1(input.toUpperCase(), span, tracker);
1800
+ if (typeof input !== "string") throw new RuntimeError("ltrim expects string", span);
1801
+ yield emit$1(input.trimStart(), span, tracker);
1654
1802
  }
1655
- }
1656
- ];
1657
-
1658
- //#endregion
1659
- //#region src/builtins/collections.ts
1660
- function sortStable(arr, compare$1) {
1661
- return arr.map((item, index) => ({
1662
- item,
1663
- index
1664
- })).sort((a, b) => {
1665
- const cmp = compare$1(a.item, b.item);
1666
- return cmp !== 0 ? cmp : a.index - b.index;
1667
- }).map((p) => p.item);
1668
- }
1669
- const collectionBuiltins = [
1803
+ },
1670
1804
  {
1671
- name: "keys",
1805
+ name: "rtrim",
1672
1806
  arity: 0,
1673
1807
  apply: function* (input, _args, _env, tracker, _eval, span) {
1674
- if (Array.isArray(input)) yield emit$1(Array.from({ length: input.length }, (_, i) => i), span, tracker);
1675
- else if (input !== null && typeof input === "object") yield emit$1(Object.keys(input).sort(), span, tracker);
1676
- else throw new RuntimeError(`keys expects an array or object`, span);
1677
- }
1678
- },
1679
- {
1680
- name: "has",
1681
- arity: 1,
1682
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1683
- const keyFilter = args[0];
1684
- for (const key of evaluate$1(keyFilter, input, env, tracker)) if (Array.isArray(input)) {
1685
- const idx = ensureIndex(key);
1686
- yield emit$1(idx !== void 0 && idx >= 0 && idx < input.length, span, tracker);
1687
- } else if (input !== null && typeof input === "object") {
1688
- let keyStr;
1689
- if (typeof key === "string") keyStr = key;
1690
- else if (typeof key === "number") keyStr = key.toString();
1691
- else throw new RuntimeError(`has() key must be string or number for object input`, span);
1692
- yield emit$1(Object.prototype.hasOwnProperty.call(input, keyStr), span, tracker);
1693
- } else throw new RuntimeError(`has() expects an array or object input`, span);
1694
- }
1695
- },
1696
- {
1697
- name: "map",
1698
- arity: 1,
1699
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1700
- if (!Array.isArray(input)) throw new RuntimeError("map expects an array", span);
1701
- const result = [];
1702
- const filter = args[0];
1703
- for (const item of input) {
1704
- tracker.step(span);
1705
- for (const output of evaluate$1(filter, item, env, tracker)) result.push(output);
1706
- }
1707
- yield emit$1(result, span, tracker);
1808
+ if (typeof input !== "string") throw new RuntimeError("rtrim expects string", span);
1809
+ yield emit$1(input.trimEnd(), span, tracker);
1708
1810
  }
1709
1811
  },
1710
1812
  {
1711
- name: "select",
1813
+ name: "rtrimstr",
1712
1814
  arity: 1,
1713
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1714
- const filter = args[0];
1715
- for (const res of evaluate$1(filter, input, env, tracker)) if (isTruthy(res)) {
1716
- yield emit$1(input, span, tracker);
1717
- return;
1815
+ apply: function* (input, args, env, tracker, evaluate, span) {
1816
+ if (typeof input !== "string") throw new RuntimeError("rtrimstr expects string", span);
1817
+ const suffixGen = evaluate(args[0], input, env, tracker);
1818
+ for (const suffix of suffixGen) {
1819
+ if (typeof suffix !== "string") throw new RuntimeError("rtrimstr suffix must be a string", span);
1820
+ if (input.endsWith(suffix)) yield emit$1(input.slice(0, input.length - suffix.length), span, tracker);
1821
+ else yield emit$1(input, span, tracker);
1718
1822
  }
1719
1823
  }
1720
1824
  },
1721
1825
  {
1722
- name: "sort",
1826
+ name: "ascii_downcase",
1723
1827
  arity: 0,
1724
1828
  apply: function* (input, _args, _env, tracker, _eval, span) {
1725
- if (!Array.isArray(input)) throw new RuntimeError("sort expects an array", span);
1726
- const sorted = sortStable(input, (a, b) => compareValues(a, b));
1727
- tracker.step(span);
1728
- yield emit$1(sorted, span, tracker);
1729
- }
1730
- },
1731
- {
1732
- name: "sort_by",
1733
- arity: 1,
1734
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1735
- if (!Array.isArray(input)) throw new RuntimeError("sort_by expects an array", span);
1736
- const filter = args[0];
1737
- const pairs = [];
1738
- for (const item of input) {
1739
- tracker.step(span);
1740
- const keys = Array.from(evaluate$1(filter, item, env, tracker));
1741
- if (keys.length !== 1) throw new RuntimeError("sort_by key expression must return exactly one value", span);
1742
- pairs.push({
1743
- val: item,
1744
- key: keys[0]
1745
- });
1746
- }
1747
- yield emit$1(sortStable(pairs, (a, b) => compareValues(a.key, b.key)).map((p) => p.val), span, tracker);
1829
+ if (typeof input !== "string") throw new RuntimeError("ascii_downcase expects string", span);
1830
+ yield emit$1(input.replace(/[A-Z]/g, (char) => char.toLowerCase()), span, tracker);
1748
1831
  }
1749
1832
  },
1750
1833
  {
1751
- name: "unique",
1834
+ name: "ascii_upcase",
1752
1835
  arity: 0,
1753
1836
  apply: function* (input, _args, _env, tracker, _eval, span) {
1754
- if (!Array.isArray(input)) throw new RuntimeError("unique expects an array", span);
1755
- const seen = [];
1756
- const result = [];
1757
- for (const item of input) {
1758
- tracker.step(span);
1759
- if (!seen.some((s) => valueEquals(s, item))) {
1760
- seen.push(item);
1761
- result.push(item);
1762
- }
1763
- }
1764
- yield emit$1(result, span, tracker);
1765
- }
1766
- },
1767
- {
1768
- name: "unique_by",
1769
- arity: 1,
1770
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1771
- if (!Array.isArray(input)) throw new RuntimeError("unique_by expects an array", span);
1772
- const filter = args[0];
1773
- const seenKeys = [];
1774
- const result = [];
1775
- for (const item of input) {
1776
- tracker.step(span);
1777
- const keys = Array.from(evaluate$1(filter, item, env, tracker));
1778
- if (keys.length !== 1) throw new RuntimeError("unique_by key expression must return exactly one value", span);
1779
- const key = keys[0];
1780
- if (!seenKeys.some((s) => valueEquals(s, key))) {
1781
- seenKeys.push(key);
1782
- result.push(item);
1783
- }
1784
- }
1785
- yield emit$1(result, span, tracker);
1837
+ if (typeof input !== "string") throw new RuntimeError("ascii_upcase expects string", span);
1838
+ yield emit$1(input.replace(/[a-z]/g, (char) => char.toUpperCase()), span, tracker);
1786
1839
  }
1787
1840
  },
1788
1841
  {
1789
- name: "to_entries",
1842
+ name: "tojson",
1790
1843
  arity: 0,
1791
1844
  apply: function* (input, _args, _env, tracker, _eval, span) {
1792
- if (Array.isArray(input)) yield emit$1(input.map((v, i) => ({
1793
- key: i,
1794
- value: v
1795
- })), span, tracker);
1796
- else if (input !== null && typeof input === "object") yield emit$1(Object.keys(input).sort().map((k) => ({
1797
- key: k,
1798
- value: input[k]
1799
- })), span, tracker);
1800
- else throw new RuntimeError("to_entries expects array or object", span);
1845
+ yield emit$1(stableStringify(input), span, tracker);
1801
1846
  }
1802
1847
  },
1803
1848
  {
1804
- name: "from_entries",
1805
- arity: 0,
1806
- apply: function* (input, _args, _env, tracker, _eval, span) {
1807
- if (!Array.isArray(input)) throw new RuntimeError("from_entries expects an array", span);
1808
- const result = {};
1809
- for (const item of input) {
1810
- tracker.step(span);
1811
- if (item === null || typeof item !== "object" || Array.isArray(item)) throw new RuntimeError("from_entries expects array of objects", span);
1812
- const obj = item;
1813
- if (!("key" in obj) || !("value" in obj)) throw new RuntimeError("from_entries items must have \"key\" and \"value\"", span);
1814
- const key = obj["key"];
1815
- if (typeof key !== "string") throw new RuntimeError("from_entries object keys must be strings", span);
1816
- result[key] = obj["value"];
1817
- }
1818
- yield emit$1(result, span, tracker);
1819
- }
1820
- },
1821
- {
1822
- name: "with_entries",
1823
- arity: 1,
1824
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1825
- let entries;
1826
- if (Array.isArray(input)) entries = input.map((v, i) => ({
1827
- key: i,
1828
- value: v
1829
- }));
1830
- else if (input !== null && typeof input === "object") entries = Object.keys(input).sort().map((k) => ({
1831
- key: k,
1832
- value: input[k]
1833
- }));
1834
- else throw new RuntimeError("with_entries expects array or object", span);
1835
- const transformed = [];
1836
- const filter = args[0];
1837
- for (const entry of entries) {
1838
- tracker.step(span);
1839
- for (const outVar of evaluate$1(filter, entry, env, tracker)) transformed.push(outVar);
1840
- }
1841
- const result = {};
1842
- for (const item of transformed) {
1843
- if (item === null || typeof item !== "object" || Array.isArray(item)) throw new RuntimeError("with_entries filter must produce objects", span);
1844
- const obj = item;
1845
- if (!("key" in obj) || !("value" in obj)) throw new RuntimeError("with_entries items must have \"key\" and \"value\"", span);
1846
- const key = obj["key"];
1847
- if (typeof key !== "string") throw new RuntimeError("with_entries keys must be strings", span);
1848
- result[key] = obj["value"];
1849
- }
1850
- yield emit$1(result, span, tracker);
1851
- }
1852
- },
1853
- {
1854
- name: "group_by",
1855
- arity: 1,
1856
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1857
- if (!Array.isArray(input)) throw new RuntimeError("group_by expects an array", span);
1858
- const pairs = [];
1859
- const filter = args[0];
1860
- for (const item of input) {
1861
- tracker.step(span);
1862
- const keys = Array.from(evaluate$1(filter, item, env, tracker));
1863
- if (keys.length !== 1) throw new RuntimeError("group_by key expression must return exactly one value", span);
1864
- pairs.push({
1865
- val: item,
1866
- key: keys[0]
1867
- });
1868
- }
1869
- const sorted = sortStable(pairs, (a, b) => compareValues(a.key, b.key));
1870
- const groups = [];
1871
- if (sorted.length > 0) {
1872
- let currentGroup = [sorted[0].val];
1873
- let currentKey = sorted[0].key;
1874
- for (let i = 1; i < sorted.length; i++) {
1875
- const pair = sorted[i];
1876
- if (compareValues(pair.key, currentKey) === 0) currentGroup.push(pair.val);
1877
- else {
1878
- groups.push(currentGroup);
1879
- currentGroup = [pair.val];
1880
- currentKey = pair.key;
1881
- }
1882
- }
1883
- groups.push(currentGroup);
1884
- }
1885
- yield emit$1(groups, span, tracker);
1886
- }
1887
- },
1888
- {
1889
- name: "reverse",
1890
- arity: 0,
1891
- apply: function* (input, _args, _env, tracker, _eval, span) {
1892
- if (!Array.isArray(input)) throw new RuntimeError("reverse expects an array", span);
1893
- yield emit$1([...input].reverse(), span, tracker);
1894
- }
1895
- },
1896
- {
1897
- name: "flatten",
1898
- arity: 0,
1899
- apply: function* (input, _args, _env, tracker, _eval, span) {
1900
- if (!Array.isArray(input)) throw new RuntimeError("flatten expects an array", span);
1901
- const flattenRec = (arr) => {
1902
- let res = [];
1903
- for (const item of arr) if (Array.isArray(item)) res = res.concat(flattenRec(item));
1904
- else res.push(item);
1905
- return res;
1906
- };
1907
- yield emit$1(flattenRec(input), span, tracker);
1908
- }
1909
- },
1910
- {
1911
- name: "flatten",
1912
- arity: 1,
1913
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1914
- if (!Array.isArray(input)) throw new RuntimeError("flatten expects an array", span);
1915
- const depths = evaluate$1(args[0], input, env, tracker);
1916
- for (const depthVal of depths) {
1917
- if (typeof depthVal !== "number") throw new RuntimeError("flatten depth must be a number", span);
1918
- const flattenDepth = (arr, d) => {
1919
- if (d <= 0) return arr;
1920
- let res = [];
1921
- for (const item of arr) if (Array.isArray(item)) res = res.concat(flattenDepth(item, d - 1));
1922
- else res.push(item);
1923
- return res;
1924
- };
1925
- yield emit$1(flattenDepth(input, depthVal), span, tracker);
1926
- }
1927
- }
1928
- },
1929
- {
1930
- name: "keys_unsorted",
1931
- arity: 0,
1932
- apply: function* (input, _args, _env, tracker, _eval, span) {
1933
- if (Array.isArray(input)) yield emit$1(Array.from({ length: input.length }, (_, i) => i), span, tracker);
1934
- else if (input !== null && typeof input === "object") yield emit$1(Object.keys(input), span, tracker);
1935
- else throw new RuntimeError(`keys_unsorted expects an array or object`, span);
1936
- }
1937
- },
1938
- {
1939
- name: "transpose",
1940
- arity: 0,
1941
- apply: function* (input, _args, _env, tracker, _eval, span) {
1942
- if (!Array.isArray(input)) throw new RuntimeError("transpose expects an array", span);
1943
- const arr = input;
1944
- if (arr.length === 0) {
1945
- yield emit$1([], span, tracker);
1946
- return;
1947
- }
1948
- let maxLen = 0;
1949
- for (const row of arr) {
1950
- if (!Array.isArray(row)) throw new RuntimeError("transpose input must be array of arrays", span);
1951
- if (row.length > maxLen) maxLen = row.length;
1952
- }
1953
- const result = [];
1954
- for (let j = 0; j < maxLen; j++) {
1955
- const newRow = [];
1956
- for (let i = 0; i < arr.length; i++) {
1957
- const row = arr[i];
1958
- const val = j < row.length ? row[j] : null;
1959
- newRow.push(val);
1960
- }
1961
- result.push(newRow);
1962
- }
1963
- yield emit$1(result, span, tracker);
1964
- }
1965
- },
1966
- {
1967
- name: "bsearch",
1968
- arity: 1,
1969
- apply: function* (input, args, env, tracker, evaluate$1, span) {
1970
- if (!Array.isArray(input)) throw new RuntimeError("bsearch expects an array", span);
1971
- const targetGen = evaluate$1(args[0], input, env, tracker);
1972
- for (const target of targetGen) {
1973
- let low = 0;
1974
- let high = input.length - 1;
1975
- let idx = -1;
1976
- while (low <= high) {
1977
- const mid = Math.floor((low + high) / 2);
1978
- const cmp = compareValues(input[mid], target);
1979
- if (cmp === 0) {
1980
- idx = mid;
1981
- break;
1982
- } else if (cmp < 0) low = mid + 1;
1983
- else high = mid - 1;
1984
- }
1985
- if (idx !== -1) yield emit$1(idx, span, tracker);
1986
- else yield emit$1(-low - 1, span, tracker);
1987
- }
1988
- }
1989
- },
1990
- {
1991
- name: "combinations",
1849
+ name: "fromjson",
1992
1850
  arity: 0,
1993
1851
  apply: function* (input, _args, _env, tracker, _eval, span) {
1994
- if (!Array.isArray(input)) throw new RuntimeError("combinations expects an array", span);
1995
- if (input.some((x) => !Array.isArray(x))) throw new RuntimeError("combinations input must be array of arrays", span);
1996
- const arrays = input;
1997
- if (arrays.length === 0) {
1998
- yield emit$1([], span, tracker);
1999
- return;
2000
- }
2001
- const helper = function* (idx, current) {
2002
- if (idx === arrays.length) {
2003
- yield [...current];
2004
- return;
2005
- }
2006
- const arr = arrays[idx];
2007
- if (arr.length === 0) return;
2008
- for (const item of arr) {
2009
- current.push(item);
2010
- yield* helper(idx + 1, current);
2011
- current.pop();
2012
- }
2013
- };
2014
- for (const combo of helper(0, [])) yield emit$1(combo, span, tracker);
2015
- }
2016
- },
2017
- {
2018
- name: "combinations",
2019
- arity: 1,
2020
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2021
- if (!Array.isArray(input)) throw new RuntimeError("combinations expects an array", span);
2022
- const nGen = evaluate$1(args[0], input, env, tracker);
2023
- for (const nVal of nGen) {
2024
- if (typeof nVal !== "number") throw new RuntimeError("combinations(n) expects n to be number", span);
2025
- if (nVal === 0) {
2026
- yield emit$1([], span, tracker);
2027
- continue;
2028
- }
2029
- const arrays = [];
2030
- for (let i = 0; i < nVal; i++) arrays.push(input);
2031
- const helper = function* (idx, current) {
2032
- if (idx === arrays.length) {
2033
- yield [...current];
2034
- return;
2035
- }
2036
- const arr = arrays[idx];
2037
- for (const item of arr) {
2038
- current.push(item);
2039
- yield* helper(idx + 1, current);
2040
- current.pop();
2041
- }
2042
- };
2043
- if (input.length === 0 && nVal > 0) {} else for (const combo of helper(0, [])) yield emit$1(combo, span, tracker);
1852
+ if (typeof input !== "string") throw new RuntimeError("fromjson expects string", span);
1853
+ try {
1854
+ yield emit$1(JSON.parse(input), span, tracker);
1855
+ } catch {
1856
+ throw new RuntimeError("fromjson could not parse JSON", span);
2044
1857
  }
2045
1858
  }
2046
- },
2047
- {
2048
- name: "inside",
2049
- arity: 1,
2050
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2051
- const bGen = evaluate$1(args[0], input, env, tracker);
2052
- for (const b of bGen) yield emit$1(checkContains(b, input), span, tracker);
2053
- }
2054
1859
  }
2055
1860
  ];
2056
-
1861
+ const utf8ByteLength = (input) => {
1862
+ let length = 0;
1863
+ for (const char of input) {
1864
+ const codePoint = char.codePointAt(0);
1865
+ if (codePoint <= 127) length += 1;
1866
+ else if (codePoint <= 2047) length += 2;
1867
+ else if (codePoint <= 65535) length += 3;
1868
+ else length += 4;
1869
+ }
1870
+ return length;
1871
+ };
2057
1872
  //#endregion
2058
1873
  //#region src/eval/path_eval.ts
2059
1874
  /**
@@ -2066,17 +1881,17 @@ const collectionBuiltins = [
2066
1881
  * @param tracker - Limits tracker.
2067
1882
  * @param evaluate - Recursive evaluator.
2068
1883
  */
2069
- const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
1884
+ const evaluatePath = function* (node, input, env, tracker, evaluate) {
2070
1885
  switch (node.kind) {
2071
1886
  case "Identity":
2072
1887
  yield [];
2073
1888
  return;
2074
1889
  case "FieldAccess":
2075
- for (const parent of evaluatePath(node.target, input, env, tracker, evaluate$1)) yield [...parent, node.field];
1890
+ for (const parent of evaluatePath(node.target, input, env, tracker, evaluate)) yield [...parent, node.field];
2076
1891
  return;
2077
1892
  case "IndexAccess": {
2078
- const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate$1));
2079
- const output = evaluate$1(node.index, input, env, tracker);
1893
+ const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate));
1894
+ const output = evaluate(node.index, input, env, tracker);
2080
1895
  for (const keyVal of output) {
2081
1896
  let key;
2082
1897
  if (typeof keyVal === "string") key = keyVal;
@@ -2087,19 +1902,19 @@ const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
2087
1902
  return;
2088
1903
  }
2089
1904
  case "Pipe": {
2090
- const leftPaths = Array.from(evaluatePath(node.left, input, env, tracker, evaluate$1));
1905
+ const leftPaths = Array.from(evaluatePath(node.left, input, env, tracker, evaluate));
2091
1906
  for (const p of leftPaths) {
2092
1907
  const val = getPath(input, p) ?? null;
2093
- for (const q of evaluatePath(node.right, val, env, tracker, evaluate$1)) yield [...p, ...q];
1908
+ for (const q of evaluatePath(node.right, val, env, tracker, evaluate)) yield [...p, ...q];
2094
1909
  }
2095
1910
  return;
2096
1911
  }
2097
1912
  case "Comma":
2098
- yield* evaluatePath(node.left, input, env, tracker, evaluate$1);
2099
- yield* evaluatePath(node.right, input, env, tracker, evaluate$1);
1913
+ yield* evaluatePath(node.left, input, env, tracker, evaluate);
1914
+ yield* evaluatePath(node.right, input, env, tracker, evaluate);
2100
1915
  return;
2101
1916
  case "Iterate": {
2102
- const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate$1));
1917
+ const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate));
2103
1918
  for (const p of parentPaths) {
2104
1919
  const val = getPath(input, p);
2105
1920
  if (Array.isArray(val)) for (let i = 0; i < val.length; i++) yield [...p, i];
@@ -2113,7 +1928,7 @@ const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
2113
1928
  }
2114
1929
  case "Call":
2115
1930
  if (node.name === "select") {
2116
- const conds = evaluate$1(node.args[0], input, env, tracker);
1931
+ const conds = evaluate(node.args[0], input, env, tracker);
2117
1932
  let matched = false;
2118
1933
  for (const c of conds) if (c !== null && c !== false) matched = true;
2119
1934
  if (matched) yield [];
@@ -2121,9 +1936,9 @@ const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
2121
1936
  }
2122
1937
  throw new RuntimeError(`Function ${node.name} not supported in path expression`, node.span);
2123
1938
  case "Slice": {
2124
- const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate$1));
2125
- const startRes = node.start ? Array.from(evaluate$1(node.start, input, env, tracker)) : [null];
2126
- const endRes = node.end ? Array.from(evaluate$1(node.end, input, env, tracker)) : [null];
1939
+ const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate));
1940
+ const startRes = node.start ? Array.from(evaluate(node.start, input, env, tracker)) : [null];
1941
+ const endRes = node.end ? Array.from(evaluate(node.end, input, env, tracker)) : [null];
2127
1942
  for (const startVal of startRes) for (const endVal of endRes) {
2128
1943
  const sliceSpec = {
2129
1944
  start: typeof startVal === "number" ? startVal : null,
@@ -2135,7 +1950,7 @@ const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
2135
1950
  }
2136
1951
  case "Try":
2137
1952
  try {
2138
- yield* evaluatePath(node.body, input, env, tracker, evaluate$1);
1953
+ yield* evaluatePath(node.body, input, env, tracker, evaluate);
2139
1954
  } catch (e) {
2140
1955
  if (!(e instanceof RuntimeError)) throw e;
2141
1956
  }
@@ -2146,24 +1961,27 @@ const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
2146
1961
  default: throw new RuntimeError("Invalid path expression", node.span);
2147
1962
  }
2148
1963
  };
2149
-
2150
1964
  //#endregion
2151
1965
  //#region src/builtins/paths.ts
2152
1966
  function* traversePaths(root, currentPath, span, tracker) {
2153
1967
  tracker.step(span);
2154
- if (root === null || typeof root !== "object" || Array.isArray(root) && root.length === 0 || isPlainObject(root) && Object.keys(root).length === 0) {
2155
- yield emit$1([...currentPath], span, tracker);
2156
- return;
1968
+ if (Array.isArray(root)) for (let i = 0; i < root.length; i++) {
1969
+ const path = [...currentPath, i];
1970
+ yield emit$1(path, span, tracker);
1971
+ yield* traversePaths(root[i], path, span, tracker);
2157
1972
  }
2158
- if (Array.isArray(root)) for (let i = 0; i < root.length; i++) yield* traversePaths(root[i], [...currentPath, i], span, tracker);
2159
- else if (isPlainObject(root)) {
1973
+ else if (isPlainObject$1(root)) {
2160
1974
  const keys = Object.keys(root).sort();
2161
- for (const key of keys) yield* traversePaths(root[key], [...currentPath, key], span, tracker);
1975
+ for (const key of keys) {
1976
+ const path = [...currentPath, key];
1977
+ yield emit$1(path, span, tracker);
1978
+ yield* traversePaths(root[key], path, span, tracker);
1979
+ }
2162
1980
  }
2163
1981
  }
2164
1982
  const isPath = (val) => {
2165
1983
  if (!Array.isArray(val)) return false;
2166
- return val.every((p) => typeof p === "string" || typeof p === "number" && Number.isInteger(p) || isPlainObject(p) && ("start" in p || "end" in p));
1984
+ return val.every((p) => typeof p === "string" || typeof p === "number" && Number.isInteger(p) || isPlainObject$1(p) && ("start" in p || "end" in p));
2167
1985
  };
2168
1986
  const ensurePath = (val, span) => {
2169
1987
  if (isPath(val)) return val;
@@ -2173,7 +1991,7 @@ const getPath = (root, path) => {
2173
1991
  let curr = root;
2174
1992
  for (const part of path) {
2175
1993
  if (curr === null) return void 0;
2176
- if (typeof part === "string" && isPlainObject(curr)) {
1994
+ if (typeof part === "string" && isPlainObject$1(curr)) {
2177
1995
  if (!Object.prototype.hasOwnProperty.call(curr, part)) return void 0;
2178
1996
  curr = curr[part];
2179
1997
  } else if (typeof part === "number" && Array.isArray(curr)) {
@@ -2188,7 +2006,7 @@ const updatePath = (root, path, updateFn, span, depth = 0) => {
2188
2006
  const [head, ...tail] = path;
2189
2007
  if (typeof head === "string") {
2190
2008
  let obj = {};
2191
- if (isPlainObject(root)) obj = { ...root };
2009
+ if (isPlainObject$1(root)) obj = { ...root };
2192
2010
  else if (root === null) obj = {};
2193
2011
  else throw new RuntimeError(`Cannot index ${describeType(root)} with string "${head}"`, span);
2194
2012
  const newVal = updatePath((Object.prototype.hasOwnProperty.call(obj, head) ? obj[head] : void 0) ?? null, tail, updateFn, span, depth + 1);
@@ -2228,7 +2046,7 @@ const updatePath = (root, path, updateFn, span, depth = 0) => {
2228
2046
  };
2229
2047
  const deletePaths = (root, paths, span) => {
2230
2048
  if (paths.some((p) => p.length === 0)) return null;
2231
- if (isPlainObject(root)) {
2049
+ if (isPlainObject$1(root)) {
2232
2050
  const result = { ...root };
2233
2051
  const relevantPaths = paths.filter((p) => p.length > 0 && typeof p[0] === "string");
2234
2052
  const byKey = {};
@@ -2273,19 +2091,35 @@ const pathBuiltins = [
2273
2091
  yield* traversePaths(input, [], span, tracker);
2274
2092
  }
2275
2093
  },
2094
+ {
2095
+ name: "paths",
2096
+ arity: 1,
2097
+ apply: function* (input, args, env, tracker, evaluate, span) {
2098
+ for (const pathVal of traversePaths(input, [], span, tracker)) {
2099
+ const path = ensurePath(pathVal, span);
2100
+ const value = getPath(input, path) ?? null;
2101
+ let matched = false;
2102
+ for (const result of evaluate(args[0], value, env, tracker)) if (result !== null && result !== false) {
2103
+ matched = true;
2104
+ break;
2105
+ }
2106
+ if (matched) yield emit$1(path, span, tracker);
2107
+ }
2108
+ }
2109
+ },
2276
2110
  {
2277
2111
  name: "getpath",
2278
2112
  arity: 1,
2279
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2280
- for (const pathVal of evaluate$1(args[0], input, env, tracker)) yield emit$1(getPath(input, ensurePath(pathVal, span)) ?? null, span, tracker);
2113
+ apply: function* (input, args, env, tracker, evaluate, span) {
2114
+ for (const pathVal of evaluate(args[0], input, env, tracker)) yield emit$1(getPath(input, ensurePath(pathVal, span)) ?? null, span, tracker);
2281
2115
  }
2282
2116
  },
2283
2117
  {
2284
2118
  name: "setpath",
2285
2119
  arity: 2,
2286
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2287
- const paths = Array.from(evaluate$1(args[0], input, env, tracker));
2288
- const values = Array.from(evaluate$1(args[1], input, env, tracker));
2120
+ apply: function* (input, args, env, tracker, evaluate, span) {
2121
+ const paths = Array.from(evaluate(args[0], input, env, tracker));
2122
+ const values = Array.from(evaluate(args[1], input, env, tracker));
2289
2123
  for (const pathVal of paths) {
2290
2124
  const path = ensurePath(pathVal, span);
2291
2125
  for (const val of values) yield emit$1(updatePath(input, path, () => val, span) ?? null, span, tracker);
@@ -2295,30 +2129,508 @@ const pathBuiltins = [
2295
2129
  {
2296
2130
  name: "delpaths",
2297
2131
  arity: 1,
2298
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2299
- for (const pathsVal of evaluate$1(args[0], input, env, tracker)) {
2132
+ apply: function* (input, args, env, tracker, evaluate, span) {
2133
+ for (const pathsVal of evaluate(args[0], input, env, tracker)) {
2300
2134
  if (!Array.isArray(pathsVal)) throw new RuntimeError("delpaths expects an array of paths", span);
2301
2135
  yield emit$1(deletePaths(input, pathsVal.map((p) => ensurePath(p, span)), span), span, tracker);
2302
2136
  }
2303
2137
  }
2304
2138
  },
2305
2139
  {
2306
- name: "path",
2140
+ name: "path",
2141
+ arity: 1,
2142
+ apply: function* (input, args, env, tracker, evaluate, span) {
2143
+ for (const p of evaluatePath(args[0], input, env, tracker, evaluate)) yield emit$1(p, span, tracker);
2144
+ }
2145
+ }
2146
+ ];
2147
+ //#endregion
2148
+ //#region src/builtins/collections.ts
2149
+ function sortStable(arr, compare) {
2150
+ return arr.map((item, index) => ({
2151
+ item,
2152
+ index
2153
+ })).sort((a, b) => {
2154
+ const cmp = compare(a.item, b.item);
2155
+ return cmp !== 0 ? cmp : a.index - b.index;
2156
+ }).map((p) => p.item);
2157
+ }
2158
+ const collectionBuiltins = [
2159
+ {
2160
+ name: "keys",
2161
+ arity: 0,
2162
+ apply: function* (input, _args, _env, tracker, _eval, span) {
2163
+ if (Array.isArray(input)) yield emit$1(Array.from({ length: input.length }, (_, i) => i), span, tracker);
2164
+ else if (input !== null && typeof input === "object") yield emit$1(Object.keys(input).sort(), span, tracker);
2165
+ else throw new RuntimeError(`keys expects an array or object`, span);
2166
+ }
2167
+ },
2168
+ {
2169
+ name: "has",
2170
+ arity: 1,
2171
+ apply: function* (input, args, env, tracker, evaluate, span) {
2172
+ const keyFilter = args[0];
2173
+ for (const key of evaluate(keyFilter, input, env, tracker)) if (Array.isArray(input)) {
2174
+ const idx = ensureIndex(key);
2175
+ yield emit$1(idx !== void 0 && idx >= 0 && idx < input.length, span, tracker);
2176
+ } else if (input !== null && typeof input === "object") {
2177
+ let keyStr;
2178
+ if (typeof key === "string") keyStr = key;
2179
+ else if (typeof key === "number") keyStr = key.toString();
2180
+ else throw new RuntimeError(`has() key must be string or number for object input`, span);
2181
+ yield emit$1(Object.prototype.hasOwnProperty.call(input, keyStr), span, tracker);
2182
+ } else throw new RuntimeError(`has() expects an array or object input`, span);
2183
+ }
2184
+ },
2185
+ {
2186
+ name: "map",
2187
+ arity: 1,
2188
+ apply: function* (input, args, env, tracker, evaluate, span) {
2189
+ if (!Array.isArray(input)) throw new RuntimeError("map expects an array", span);
2190
+ const result = [];
2191
+ const filter = args[0];
2192
+ for (const item of input) {
2193
+ tracker.step(span);
2194
+ for (const output of evaluate(filter, item, env, tracker)) result.push(output);
2195
+ }
2196
+ yield emit$1(result, span, tracker);
2197
+ }
2198
+ },
2199
+ {
2200
+ name: "map_values",
2201
+ arity: 1,
2202
+ apply: function* (input, args, env, tracker, evaluate, span) {
2203
+ const filter = args[0];
2204
+ if (Array.isArray(input)) {
2205
+ const result = [];
2206
+ for (const item of input) {
2207
+ tracker.step(span);
2208
+ for (const output of evaluate(filter, item, env, tracker)) result.push(output);
2209
+ }
2210
+ yield emit$1(result, span, tracker);
2211
+ return;
2212
+ }
2213
+ if (input !== null && typeof input === "object") {
2214
+ const result = {};
2215
+ for (const key of Object.keys(input)) {
2216
+ tracker.step(span);
2217
+ let last;
2218
+ let found = false;
2219
+ for (const output of evaluate(filter, input[key], env, tracker)) {
2220
+ last = output;
2221
+ found = true;
2222
+ }
2223
+ if (found) result[key] = last;
2224
+ }
2225
+ yield emit$1(result, span, tracker);
2226
+ return;
2227
+ }
2228
+ throw new RuntimeError("map_values expects an array or object", span);
2229
+ }
2230
+ },
2231
+ {
2232
+ name: "select",
2233
+ arity: 1,
2234
+ apply: function* (input, args, env, tracker, evaluate, span) {
2235
+ const filter = args[0];
2236
+ for (const res of evaluate(filter, input, env, tracker)) if (isTruthy(res)) {
2237
+ yield emit$1(input, span, tracker);
2238
+ return;
2239
+ }
2240
+ }
2241
+ },
2242
+ {
2243
+ name: "sort",
2244
+ arity: 0,
2245
+ apply: function* (input, _args, _env, tracker, _eval, span) {
2246
+ if (!Array.isArray(input)) throw new RuntimeError("sort expects an array", span);
2247
+ const sorted = sortStable(input, (a, b) => compareValues(a, b));
2248
+ tracker.step(span);
2249
+ yield emit$1(sorted, span, tracker);
2250
+ }
2251
+ },
2252
+ {
2253
+ name: "sort_by",
2254
+ arity: 1,
2255
+ apply: function* (input, args, env, tracker, evaluate, span) {
2256
+ if (!Array.isArray(input)) throw new RuntimeError("sort_by expects an array", span);
2257
+ const filter = args[0];
2258
+ const pairs = [];
2259
+ for (const item of input) {
2260
+ tracker.step(span);
2261
+ const keys = Array.from(evaluate(filter, item, env, tracker));
2262
+ if (keys.length !== 1) throw new RuntimeError("sort_by key expression must return exactly one value", span);
2263
+ pairs.push({
2264
+ val: item,
2265
+ key: keys[0]
2266
+ });
2267
+ }
2268
+ yield emit$1(sortStable(pairs, (a, b) => compareValues(a.key, b.key)).map((p) => p.val), span, tracker);
2269
+ }
2270
+ },
2271
+ {
2272
+ name: "unique",
2273
+ arity: 0,
2274
+ apply: function* (input, _args, _env, tracker, _eval, span) {
2275
+ if (!Array.isArray(input)) throw new RuntimeError("unique expects an array", span);
2276
+ const seen = [];
2277
+ const result = [];
2278
+ for (const item of input) {
2279
+ tracker.step(span);
2280
+ if (!seen.some((s) => valueEquals(s, item))) {
2281
+ seen.push(item);
2282
+ result.push(item);
2283
+ }
2284
+ }
2285
+ yield emit$1(result, span, tracker);
2286
+ }
2287
+ },
2288
+ {
2289
+ name: "unique_by",
2290
+ arity: 1,
2291
+ apply: function* (input, args, env, tracker, evaluate, span) {
2292
+ if (!Array.isArray(input)) throw new RuntimeError("unique_by expects an array", span);
2293
+ const filter = args[0];
2294
+ const seenKeys = [];
2295
+ const result = [];
2296
+ for (const item of input) {
2297
+ tracker.step(span);
2298
+ const keys = Array.from(evaluate(filter, item, env, tracker));
2299
+ if (keys.length !== 1) throw new RuntimeError("unique_by key expression must return exactly one value", span);
2300
+ const key = keys[0];
2301
+ if (!seenKeys.some((s) => valueEquals(s, key))) {
2302
+ seenKeys.push(key);
2303
+ result.push(item);
2304
+ }
2305
+ }
2306
+ yield emit$1(result, span, tracker);
2307
+ }
2308
+ },
2309
+ {
2310
+ name: "to_entries",
2311
+ arity: 0,
2312
+ apply: function* (input, _args, _env, tracker, _eval, span) {
2313
+ if (Array.isArray(input)) yield emit$1(input.map((v, i) => ({
2314
+ key: i,
2315
+ value: v
2316
+ })), span, tracker);
2317
+ else if (input !== null && typeof input === "object") yield emit$1(Object.keys(input).sort().map((k) => ({
2318
+ key: k,
2319
+ value: input[k]
2320
+ })), span, tracker);
2321
+ else throw new RuntimeError("to_entries expects array or object", span);
2322
+ }
2323
+ },
2324
+ {
2325
+ name: "from_entries",
2326
+ arity: 0,
2327
+ apply: function* (input, _args, _env, tracker, _eval, span) {
2328
+ if (!Array.isArray(input)) throw new RuntimeError("from_entries expects an array", span);
2329
+ const result = {};
2330
+ for (const item of input) {
2331
+ tracker.step(span);
2332
+ if (item === null || typeof item !== "object" || Array.isArray(item)) throw new RuntimeError("from_entries expects array of objects", span);
2333
+ const obj = item;
2334
+ const key = getEntryField(obj, [
2335
+ "key",
2336
+ "Key",
2337
+ "name",
2338
+ "Name"
2339
+ ]);
2340
+ const value = getEntryField(obj, ["value", "Value"]);
2341
+ if (key === void 0 || value === void 0) throw new RuntimeError("from_entries items must have key/name and value fields", span);
2342
+ if (typeof key !== "string") throw new RuntimeError("from_entries object keys must be strings", span);
2343
+ result[key] = value;
2344
+ }
2345
+ yield emit$1(result, span, tracker);
2346
+ }
2347
+ },
2348
+ {
2349
+ name: "with_entries",
2350
+ arity: 1,
2351
+ apply: function* (input, args, env, tracker, evaluate, span) {
2352
+ let entries;
2353
+ if (Array.isArray(input)) entries = input.map((v, i) => ({
2354
+ key: i,
2355
+ value: v
2356
+ }));
2357
+ else if (input !== null && typeof input === "object") entries = Object.keys(input).sort().map((k) => ({
2358
+ key: k,
2359
+ value: input[k]
2360
+ }));
2361
+ else throw new RuntimeError("with_entries expects array or object", span);
2362
+ const transformed = [];
2363
+ const filter = args[0];
2364
+ for (const entry of entries) {
2365
+ tracker.step(span);
2366
+ for (const outVar of evaluate(filter, entry, env, tracker)) transformed.push(outVar);
2367
+ }
2368
+ const result = {};
2369
+ for (const item of transformed) {
2370
+ if (item === null || typeof item !== "object" || Array.isArray(item)) throw new RuntimeError("with_entries filter must produce objects", span);
2371
+ const obj = item;
2372
+ if (!("key" in obj) || !("value" in obj)) throw new RuntimeError("with_entries items must have \"key\" and \"value\"", span);
2373
+ const key = obj["key"];
2374
+ if (typeof key !== "string") throw new RuntimeError("with_entries keys must be strings", span);
2375
+ result[key] = obj["value"];
2376
+ }
2377
+ yield emit$1(result, span, tracker);
2378
+ }
2379
+ },
2380
+ {
2381
+ name: "group_by",
2382
+ arity: 1,
2383
+ apply: function* (input, args, env, tracker, evaluate, span) {
2384
+ if (!Array.isArray(input)) throw new RuntimeError("group_by expects an array", span);
2385
+ const pairs = [];
2386
+ const filter = args[0];
2387
+ for (const item of input) {
2388
+ tracker.step(span);
2389
+ const keys = Array.from(evaluate(filter, item, env, tracker));
2390
+ if (keys.length !== 1) throw new RuntimeError("group_by key expression must return exactly one value", span);
2391
+ pairs.push({
2392
+ val: item,
2393
+ key: keys[0]
2394
+ });
2395
+ }
2396
+ const sorted = sortStable(pairs, (a, b) => compareValues(a.key, b.key));
2397
+ const groups = [];
2398
+ if (sorted.length > 0) {
2399
+ let currentGroup = [sorted[0].val];
2400
+ let currentKey = sorted[0].key;
2401
+ for (let i = 1; i < sorted.length; i++) {
2402
+ const pair = sorted[i];
2403
+ if (compareValues(pair.key, currentKey) === 0) currentGroup.push(pair.val);
2404
+ else {
2405
+ groups.push(currentGroup);
2406
+ currentGroup = [pair.val];
2407
+ currentKey = pair.key;
2408
+ }
2409
+ }
2410
+ groups.push(currentGroup);
2411
+ }
2412
+ yield emit$1(groups, span, tracker);
2413
+ }
2414
+ },
2415
+ {
2416
+ name: "reverse",
2417
+ arity: 0,
2418
+ apply: function* (input, _args, _env, tracker, _eval, span) {
2419
+ if (!Array.isArray(input)) throw new RuntimeError("reverse expects an array", span);
2420
+ yield emit$1([...input].reverse(), span, tracker);
2421
+ }
2422
+ },
2423
+ {
2424
+ name: "in",
2425
+ arity: 1,
2426
+ apply: function* (input, args, env, tracker, evaluate, span) {
2427
+ for (const container of evaluate(args[0], input, env, tracker)) {
2428
+ if (Array.isArray(container)) {
2429
+ if (typeof input !== "number") throw new RuntimeError(`Cannot check whether array has a ${typeof input} key`, span);
2430
+ const idx = ensureIndex(input);
2431
+ yield emit$1(idx !== void 0 && idx >= 0 && idx < container.length, span, tracker);
2432
+ continue;
2433
+ }
2434
+ if (container !== null && typeof container === "object") {
2435
+ if (typeof input !== "string") throw new RuntimeError(`Cannot check whether object has a ${typeof input} key`, span);
2436
+ yield emit$1(Object.prototype.hasOwnProperty.call(container, input), span, tracker);
2437
+ continue;
2438
+ }
2439
+ throw new RuntimeError("in expects an array or object argument", span);
2440
+ }
2441
+ }
2442
+ },
2443
+ {
2444
+ name: "del",
2445
+ arity: 1,
2446
+ apply: function* (input, args, env, tracker, evaluate, span) {
2447
+ yield emit$1(deletePaths(input, Array.from(evaluatePath(args[0], input, env, tracker, evaluate)), span), span, tracker);
2448
+ }
2449
+ },
2450
+ {
2451
+ name: "pick",
2452
+ arity: 1,
2453
+ apply: function* (input, args, env, tracker, evaluate, span) {
2454
+ const paths = Array.from(evaluatePath(args[0], input, env, tracker, evaluate));
2455
+ let result = null;
2456
+ for (const path of paths) {
2457
+ const value = getPath(input, path);
2458
+ result = updatePath(result, path, () => value ?? null, span) ?? null;
2459
+ }
2460
+ yield emit$1(result, span, tracker);
2461
+ }
2462
+ },
2463
+ {
2464
+ name: "flatten",
2465
+ arity: 0,
2466
+ apply: function* (input, _args, _env, tracker, _eval, span) {
2467
+ if (!Array.isArray(input)) throw new RuntimeError("flatten expects an array", span);
2468
+ const flattenRec = (arr) => {
2469
+ let res = [];
2470
+ for (const item of arr) if (Array.isArray(item)) res = res.concat(flattenRec(item));
2471
+ else res.push(item);
2472
+ return res;
2473
+ };
2474
+ yield emit$1(flattenRec(input), span, tracker);
2475
+ }
2476
+ },
2477
+ {
2478
+ name: "flatten",
2479
+ arity: 1,
2480
+ apply: function* (input, args, env, tracker, evaluate, span) {
2481
+ if (!Array.isArray(input)) throw new RuntimeError("flatten expects an array", span);
2482
+ const depths = evaluate(args[0], input, env, tracker);
2483
+ for (const depthVal of depths) {
2484
+ if (typeof depthVal !== "number") throw new RuntimeError("flatten depth must be a number", span);
2485
+ const flattenDepth = (arr, d) => {
2486
+ if (d <= 0) return arr;
2487
+ let res = [];
2488
+ for (const item of arr) if (Array.isArray(item)) res = res.concat(flattenDepth(item, d - 1));
2489
+ else res.push(item);
2490
+ return res;
2491
+ };
2492
+ yield emit$1(flattenDepth(input, depthVal), span, tracker);
2493
+ }
2494
+ }
2495
+ },
2496
+ {
2497
+ name: "keys_unsorted",
2498
+ arity: 0,
2499
+ apply: function* (input, _args, _env, tracker, _eval, span) {
2500
+ if (Array.isArray(input)) yield emit$1(Array.from({ length: input.length }, (_, i) => i), span, tracker);
2501
+ else if (input !== null && typeof input === "object") yield emit$1(Object.keys(input), span, tracker);
2502
+ else throw new RuntimeError(`keys_unsorted expects an array or object`, span);
2503
+ }
2504
+ },
2505
+ {
2506
+ name: "transpose",
2507
+ arity: 0,
2508
+ apply: function* (input, _args, _env, tracker, _eval, span) {
2509
+ if (!Array.isArray(input)) throw new RuntimeError("transpose expects an array", span);
2510
+ const arr = input;
2511
+ if (arr.length === 0) {
2512
+ yield emit$1([], span, tracker);
2513
+ return;
2514
+ }
2515
+ let maxLen = 0;
2516
+ for (const row of arr) {
2517
+ if (!Array.isArray(row)) throw new RuntimeError("transpose input must be array of arrays", span);
2518
+ if (row.length > maxLen) maxLen = row.length;
2519
+ }
2520
+ const result = [];
2521
+ for (let j = 0; j < maxLen; j++) {
2522
+ const newRow = [];
2523
+ for (let i = 0; i < arr.length; i++) {
2524
+ const row = arr[i];
2525
+ const val = j < row.length ? row[j] : null;
2526
+ newRow.push(val);
2527
+ }
2528
+ result.push(newRow);
2529
+ }
2530
+ yield emit$1(result, span, tracker);
2531
+ }
2532
+ },
2533
+ {
2534
+ name: "bsearch",
2535
+ arity: 1,
2536
+ apply: function* (input, args, env, tracker, evaluate, span) {
2537
+ if (!Array.isArray(input)) throw new RuntimeError("bsearch expects an array", span);
2538
+ const targetGen = evaluate(args[0], input, env, tracker);
2539
+ for (const target of targetGen) {
2540
+ let low = 0;
2541
+ let high = input.length - 1;
2542
+ let idx = -1;
2543
+ while (low <= high) {
2544
+ const mid = Math.floor((low + high) / 2);
2545
+ const cmp = compareValues(input[mid], target);
2546
+ if (cmp === 0) {
2547
+ idx = mid;
2548
+ break;
2549
+ } else if (cmp < 0) low = mid + 1;
2550
+ else high = mid - 1;
2551
+ }
2552
+ if (idx !== -1) yield emit$1(idx, span, tracker);
2553
+ else yield emit$1(-low - 1, span, tracker);
2554
+ }
2555
+ }
2556
+ },
2557
+ {
2558
+ name: "combinations",
2559
+ arity: 0,
2560
+ apply: function* (input, _args, _env, tracker, _eval, span) {
2561
+ if (!Array.isArray(input)) throw new RuntimeError("combinations expects an array", span);
2562
+ if (input.some((x) => !Array.isArray(x))) throw new RuntimeError("combinations input must be array of arrays", span);
2563
+ const arrays = input;
2564
+ if (arrays.length === 0) {
2565
+ yield emit$1([], span, tracker);
2566
+ return;
2567
+ }
2568
+ const helper = function* (idx, current) {
2569
+ if (idx === arrays.length) {
2570
+ yield [...current];
2571
+ return;
2572
+ }
2573
+ const arr = arrays[idx];
2574
+ if (arr.length === 0) return;
2575
+ for (const item of arr) {
2576
+ current.push(item);
2577
+ yield* helper(idx + 1, current);
2578
+ current.pop();
2579
+ }
2580
+ };
2581
+ for (const combo of helper(0, [])) yield emit$1(combo, span, tracker);
2582
+ }
2583
+ },
2584
+ {
2585
+ name: "combinations",
2586
+ arity: 1,
2587
+ apply: function* (input, args, env, tracker, evaluate, span) {
2588
+ if (!Array.isArray(input)) throw new RuntimeError("combinations expects an array", span);
2589
+ const nGen = evaluate(args[0], input, env, tracker);
2590
+ for (const nVal of nGen) {
2591
+ if (typeof nVal !== "number") throw new RuntimeError("combinations(n) expects n to be number", span);
2592
+ if (nVal === 0) {
2593
+ yield emit$1([], span, tracker);
2594
+ continue;
2595
+ }
2596
+ const arrays = [];
2597
+ for (let i = 0; i < nVal; i++) arrays.push(input);
2598
+ const helper = function* (idx, current) {
2599
+ if (idx === arrays.length) {
2600
+ yield [...current];
2601
+ return;
2602
+ }
2603
+ const arr = arrays[idx];
2604
+ for (const item of arr) {
2605
+ current.push(item);
2606
+ yield* helper(idx + 1, current);
2607
+ current.pop();
2608
+ }
2609
+ };
2610
+ if (input.length === 0 && nVal > 0) {} else for (const combo of helper(0, [])) yield emit$1(combo, span, tracker);
2611
+ }
2612
+ }
2613
+ },
2614
+ {
2615
+ name: "inside",
2307
2616
  arity: 1,
2308
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2309
- for (const p of evaluatePath(args[0], input, env, tracker, evaluate$1)) yield emit$1(p, span, tracker);
2617
+ apply: function* (input, args, env, tracker, evaluate, span) {
2618
+ const bGen = evaluate(args[0], input, env, tracker);
2619
+ for (const b of bGen) yield emit$1(checkContains(b, input), span, tracker);
2310
2620
  }
2311
2621
  }
2312
2622
  ];
2313
-
2623
+ const getEntryField = (obj, names) => {
2624
+ for (const name of names) if (Object.prototype.hasOwnProperty.call(obj, name)) return obj[name];
2625
+ };
2314
2626
  //#endregion
2315
2627
  //#region src/builtins/iterators.ts
2316
2628
  const iteratorBuiltins = [
2317
2629
  {
2318
2630
  name: "range",
2319
2631
  arity: 1,
2320
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2321
- const ends = evaluate$1(args[0], input, env, tracker);
2632
+ apply: function* (input, args, env, tracker, evaluate, span) {
2633
+ const ends = evaluate(args[0], input, env, tracker);
2322
2634
  for (const end of ends) {
2323
2635
  if (typeof end !== "number") throw new RuntimeError("range expects numbers", span);
2324
2636
  for (let i = 0; i < end; i++) yield emit$1(i, span, tracker);
@@ -2328,9 +2640,9 @@ const iteratorBuiltins = [
2328
2640
  {
2329
2641
  name: "range",
2330
2642
  arity: 2,
2331
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2332
- const starts = Array.from(evaluate$1(args[0], input, env, tracker));
2333
- const ends = Array.from(evaluate$1(args[1], input, env, tracker));
2643
+ apply: function* (input, args, env, tracker, evaluate, span) {
2644
+ const starts = Array.from(evaluate(args[0], input, env, tracker));
2645
+ const ends = Array.from(evaluate(args[1], input, env, tracker));
2334
2646
  for (const start of starts) for (const end of ends) {
2335
2647
  if (typeof start !== "number" || typeof end !== "number") throw new RuntimeError("range expects numbers", span);
2336
2648
  if (start < end) for (let i = start; i < end; i++) yield emit$1(i, span, tracker);
@@ -2340,10 +2652,10 @@ const iteratorBuiltins = [
2340
2652
  {
2341
2653
  name: "range",
2342
2654
  arity: 3,
2343
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2344
- const starts = Array.from(evaluate$1(args[0], input, env, tracker));
2345
- const ends = Array.from(evaluate$1(args[1], input, env, tracker));
2346
- const steps = Array.from(evaluate$1(args[2], input, env, tracker));
2655
+ apply: function* (input, args, env, tracker, evaluate, span) {
2656
+ const starts = Array.from(evaluate(args[0], input, env, tracker));
2657
+ const ends = Array.from(evaluate(args[1], input, env, tracker));
2658
+ const steps = Array.from(evaluate(args[2], input, env, tracker));
2347
2659
  for (const start of starts) for (const end of ends) for (const step of steps) {
2348
2660
  if (typeof start !== "number" || typeof end !== "number" || typeof step !== "number") throw new RuntimeError("range expects numbers", span);
2349
2661
  if (step === 0) throw new RuntimeError("range step cannot be zero", span);
@@ -2355,12 +2667,12 @@ const iteratorBuiltins = [
2355
2667
  {
2356
2668
  name: "limit",
2357
2669
  arity: 2,
2358
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2359
- const limits = evaluate$1(args[0], input, env, tracker);
2670
+ apply: function* (input, args, env, tracker, evaluate, span) {
2671
+ const limits = evaluate(args[0], input, env, tracker);
2360
2672
  for (const n of limits) {
2361
2673
  if (typeof n !== "number") throw new RuntimeError("limit expects number", span);
2362
2674
  let count = 0;
2363
- if (n > 0) for (const val of evaluate$1(args[1], input, env, tracker)) {
2675
+ if (n > 0) for (const val of evaluate(args[1], input, env, tracker)) {
2364
2676
  yield val;
2365
2677
  count++;
2366
2678
  if (count >= n) break;
@@ -2368,38 +2680,78 @@ const iteratorBuiltins = [
2368
2680
  }
2369
2681
  }
2370
2682
  },
2683
+ {
2684
+ name: "skip",
2685
+ arity: 2,
2686
+ apply: function* (input, args, env, tracker, evaluate, span) {
2687
+ for (const n of evaluate(args[0], input, env, tracker)) {
2688
+ if (typeof n !== "number") throw new RuntimeError("skip expects number", span);
2689
+ let count = 0;
2690
+ for (const val of evaluate(args[1], input, env, tracker)) {
2691
+ if (count >= n) yield val;
2692
+ count++;
2693
+ }
2694
+ }
2695
+ }
2696
+ },
2697
+ {
2698
+ name: "first",
2699
+ arity: 0,
2700
+ apply: function* (input) {
2701
+ if (Array.isArray(input) && input.length > 0) yield input[0];
2702
+ }
2703
+ },
2371
2704
  {
2372
2705
  name: "first",
2373
2706
  arity: 1,
2374
- apply: function* (input, args, env, tracker, evaluate$1) {
2375
- for (const val of evaluate$1(args[0], input, env, tracker)) {
2707
+ apply: function* (input, args, env, tracker, evaluate) {
2708
+ for (const val of evaluate(args[0], input, env, tracker)) {
2376
2709
  yield val;
2377
2710
  break;
2378
2711
  }
2379
2712
  }
2380
2713
  },
2714
+ {
2715
+ name: "last",
2716
+ arity: 0,
2717
+ apply: function* (input) {
2718
+ if (Array.isArray(input) && input.length > 0) yield input[input.length - 1];
2719
+ }
2720
+ },
2381
2721
  {
2382
2722
  name: "last",
2383
2723
  arity: 1,
2384
- apply: function* (input, args, env, tracker, evaluate$1) {
2724
+ apply: function* (input, args, env, tracker, evaluate) {
2385
2725
  let lastVal;
2386
2726
  let found = false;
2387
- for (const val of evaluate$1(args[0], input, env, tracker)) {
2727
+ for (const val of evaluate(args[0], input, env, tracker)) {
2388
2728
  lastVal = val;
2389
2729
  found = true;
2390
2730
  }
2391
2731
  if (found) yield lastVal;
2392
2732
  }
2393
2733
  },
2734
+ {
2735
+ name: "nth",
2736
+ arity: 1,
2737
+ apply: function* (input, args, env, tracker, evaluate, span) {
2738
+ if (!Array.isArray(input)) throw new RuntimeError("nth expects array input", span);
2739
+ for (const n of evaluate(args[0], input, env, tracker)) {
2740
+ if (typeof n !== "number") throw new RuntimeError("nth expects number", span);
2741
+ const idx = Math.trunc(n);
2742
+ if (idx >= 0 && idx < input.length) yield input[idx];
2743
+ }
2744
+ }
2745
+ },
2394
2746
  {
2395
2747
  name: "nth",
2396
2748
  arity: 2,
2397
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2398
- const indices = evaluate$1(args[0], input, env, tracker);
2749
+ apply: function* (input, args, env, tracker, evaluate, span) {
2750
+ const indices = evaluate(args[0], input, env, tracker);
2399
2751
  for (const n of indices) {
2400
2752
  if (typeof n !== "number") throw new RuntimeError("nth expects number", span);
2401
2753
  let count = 0;
2402
- for (const val of evaluate$1(args[1], input, env, tracker)) {
2754
+ for (const val of evaluate(args[1], input, env, tracker)) {
2403
2755
  if (count === n) {
2404
2756
  yield val;
2405
2757
  break;
@@ -2412,67 +2764,161 @@ const iteratorBuiltins = [
2412
2764
  {
2413
2765
  name: "isempty",
2414
2766
  arity: 1,
2415
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2767
+ apply: function* (input, args, env, tracker, evaluate, span) {
2416
2768
  let empty = true;
2417
- for (const _ of evaluate$1(args[0], input, env, tracker)) {
2769
+ for (const _ of evaluate(args[0], input, env, tracker)) {
2418
2770
  empty = false;
2419
2771
  break;
2420
2772
  }
2421
2773
  yield emit$1(empty, span, tracker);
2422
2774
  }
2423
2775
  },
2776
+ {
2777
+ name: "all",
2778
+ arity: 0,
2779
+ apply: function* (input, _args, _env, tracker, _evaluate, span) {
2780
+ if (!Array.isArray(input)) throw new RuntimeError("all expects an array", span);
2781
+ yield emit$1(input.every(isTruthy), span, tracker);
2782
+ }
2783
+ },
2424
2784
  {
2425
2785
  name: "all",
2426
2786
  arity: 1,
2427
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2787
+ apply: function* (input, args, env, tracker, evaluate, span) {
2788
+ if (!Array.isArray(input)) throw new RuntimeError("all expects an array", span);
2428
2789
  let result = true;
2429
- for (const val of evaluate$1(args[0], input, env, tracker)) if (!isTruthy(val)) {
2430
- result = false;
2431
- break;
2790
+ for (const item of input) {
2791
+ let itemResult = false;
2792
+ for (const val of evaluate(args[0], item, env, tracker)) if (isTruthy(val)) {
2793
+ itemResult = true;
2794
+ break;
2795
+ }
2796
+ if (!itemResult) {
2797
+ result = false;
2798
+ break;
2799
+ }
2800
+ }
2801
+ yield emit$1(result, span, tracker);
2802
+ }
2803
+ },
2804
+ {
2805
+ name: "all",
2806
+ arity: 2,
2807
+ apply: function* (input, args, env, tracker, evaluate, span) {
2808
+ let result = true;
2809
+ for (const item of evaluate(args[0], input, env, tracker)) {
2810
+ let itemResult = false;
2811
+ for (const condition of evaluate(args[1], item, env, tracker)) if (isTruthy(condition)) {
2812
+ itemResult = true;
2813
+ break;
2814
+ }
2815
+ if (!itemResult) {
2816
+ result = false;
2817
+ break;
2818
+ }
2432
2819
  }
2433
2820
  yield emit$1(result, span, tracker);
2434
2821
  }
2435
2822
  },
2823
+ {
2824
+ name: "any",
2825
+ arity: 0,
2826
+ apply: function* (input, _args, _env, tracker, _evaluate, span) {
2827
+ if (!Array.isArray(input)) throw new RuntimeError("any expects an array", span);
2828
+ yield emit$1(input.some(isTruthy), span, tracker);
2829
+ }
2830
+ },
2436
2831
  {
2437
2832
  name: "any",
2438
2833
  arity: 1,
2439
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2834
+ apply: function* (input, args, env, tracker, evaluate, span) {
2835
+ if (!Array.isArray(input)) throw new RuntimeError("any expects an array", span);
2440
2836
  let result = false;
2441
- for (const val of evaluate$1(args[0], input, env, tracker)) if (isTruthy(val)) {
2442
- result = true;
2443
- break;
2837
+ for (const item of input) {
2838
+ for (const val of evaluate(args[0], item, env, tracker)) if (isTruthy(val)) {
2839
+ result = true;
2840
+ break;
2841
+ }
2842
+ if (result) break;
2843
+ }
2844
+ yield emit$1(result, span, tracker);
2845
+ }
2846
+ },
2847
+ {
2848
+ name: "any",
2849
+ arity: 2,
2850
+ apply: function* (input, args, env, tracker, evaluate, span) {
2851
+ let result = false;
2852
+ for (const item of evaluate(args[0], input, env, tracker)) {
2853
+ for (const condition of evaluate(args[1], item, env, tracker)) if (isTruthy(condition)) {
2854
+ result = true;
2855
+ break;
2856
+ }
2857
+ if (result) break;
2444
2858
  }
2445
2859
  yield emit$1(result, span, tracker);
2446
2860
  }
2447
2861
  },
2862
+ {
2863
+ name: "recurse",
2864
+ arity: 0,
2865
+ apply: function* (input, _args, _env, tracker, _evaluate, span) {
2866
+ const rec = function* (curr) {
2867
+ yield emit$1(curr, span, tracker);
2868
+ if (Array.isArray(curr)) for (const item of curr) yield* rec(item);
2869
+ else if (curr !== null && typeof curr === "object") {
2870
+ const keys = Object.keys(curr).sort();
2871
+ for (const key of keys) yield* rec(curr[key]);
2872
+ }
2873
+ };
2874
+ yield* rec(input);
2875
+ }
2876
+ },
2448
2877
  {
2449
2878
  name: "recurse",
2450
2879
  arity: 1,
2451
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2880
+ apply: function* (input, args, env, tracker, evaluate, span) {
2452
2881
  const rec = function* (curr) {
2453
2882
  yield emit$1(curr, span, tracker);
2454
- const nexts = evaluate$1(args[0], curr, env, tracker);
2883
+ const nexts = evaluate(args[0], curr, env, tracker);
2455
2884
  for (const next of nexts) yield* rec(next);
2456
2885
  };
2457
2886
  yield* rec(input);
2458
2887
  }
2459
2888
  },
2889
+ {
2890
+ name: "recurse",
2891
+ arity: 2,
2892
+ apply: function* (input, args, env, tracker, evaluate, span) {
2893
+ const stepExpr = args[0];
2894
+ const conditionExpr = args[1];
2895
+ const rec = function* (curr) {
2896
+ yield emit$1(curr, span, tracker);
2897
+ for (const condition of evaluate(conditionExpr, curr, env, tracker)) {
2898
+ if (!isTruthy(condition)) return;
2899
+ break;
2900
+ }
2901
+ for (const next of evaluate(stepExpr, curr, env, tracker)) yield* rec(next);
2902
+ };
2903
+ yield* rec(input);
2904
+ }
2905
+ },
2460
2906
  {
2461
2907
  name: "while",
2462
2908
  arity: 2,
2463
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2909
+ apply: function* (input, args, env, tracker, evaluate, span) {
2464
2910
  const condExpr = args[0];
2465
2911
  const updateExpr = args[1];
2466
2912
  const rec = function* (curr) {
2467
2913
  tracker.step(span);
2468
2914
  let condMatches = false;
2469
- for (const c of evaluate$1(condExpr, curr, env, tracker)) if (isTruthy(c)) {
2915
+ for (const c of evaluate(condExpr, curr, env, tracker)) if (isTruthy(c)) {
2470
2916
  condMatches = true;
2471
2917
  break;
2472
2918
  }
2473
2919
  if (condMatches) {
2474
2920
  yield emit$1(curr, span, tracker);
2475
- for (const next of evaluate$1(updateExpr, curr, env, tracker)) yield* rec(next);
2921
+ for (const next of evaluate(updateExpr, curr, env, tracker)) yield* rec(next);
2476
2922
  }
2477
2923
  };
2478
2924
  yield* rec(input);
@@ -2481,18 +2927,18 @@ const iteratorBuiltins = [
2481
2927
  {
2482
2928
  name: "until",
2483
2929
  arity: 2,
2484
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2930
+ apply: function* (input, args, env, tracker, evaluate, span) {
2485
2931
  const condExpr = args[0];
2486
2932
  const updateExpr = args[1];
2487
2933
  const rec = function* (curr) {
2488
2934
  tracker.step(span);
2489
2935
  let condMatches = false;
2490
- for (const c of evaluate$1(condExpr, curr, env, tracker)) if (isTruthy(c)) {
2936
+ for (const c of evaluate(condExpr, curr, env, tracker)) if (isTruthy(c)) {
2491
2937
  condMatches = true;
2492
2938
  break;
2493
2939
  }
2494
2940
  if (condMatches) yield emit$1(curr, span, tracker);
2495
- else for (const next of evaluate$1(updateExpr, curr, env, tracker)) yield* rec(next);
2941
+ else for (const next of evaluate(updateExpr, curr, env, tracker)) yield* rec(next);
2496
2942
  };
2497
2943
  yield* rec(input);
2498
2944
  }
@@ -2500,15 +2946,14 @@ const iteratorBuiltins = [
2500
2946
  {
2501
2947
  name: "repeat",
2502
2948
  arity: 1,
2503
- apply: function* (input, args, env, tracker, evaluate$1, span) {
2949
+ apply: function* (input, args, env, tracker, evaluate, span) {
2504
2950
  while (true) {
2505
2951
  tracker.step(span);
2506
- yield* evaluate$1(args[0], input, env, tracker);
2952
+ yield* evaluate(args[0], input, env, tracker);
2507
2953
  }
2508
2954
  }
2509
2955
  }
2510
2956
  ];
2511
-
2512
2957
  //#endregion
2513
2958
  //#region src/eval/ops.ts
2514
2959
  /**
@@ -2557,7 +3002,7 @@ function isEqual(a, b) {
2557
3002
  if (a.length !== b.length) return false;
2558
3003
  return a.every((v, i) => isEqual(v, b[i]));
2559
3004
  }
2560
- if (isPlainObject$1(a) && isPlainObject$1(b)) {
3005
+ if (isPlainObject(a) && isPlainObject(b)) {
2561
3006
  const ka = Object.keys(a).sort();
2562
3007
  const kb = Object.keys(b).sort();
2563
3008
  if (ka.length !== kb.length) return false;
@@ -2574,7 +3019,7 @@ function compare(a, b) {
2574
3019
  if (typeof v === "number") return 2;
2575
3020
  if (typeof v === "string") return 3;
2576
3021
  if (Array.isArray(v)) return 4;
2577
- if (isPlainObject$1(v)) return 5;
3022
+ if (isPlainObject(v)) return 5;
2578
3023
  return 6;
2579
3024
  };
2580
3025
  const ta = typeOrder(a);
@@ -2590,7 +3035,7 @@ function compare(a, b) {
2590
3035
  }
2591
3036
  return a.length - b.length;
2592
3037
  }
2593
- if (isPlainObject$1(a) && isPlainObject$1(b)) {
3038
+ if (isPlainObject(a) && isPlainObject(b)) {
2594
3039
  const keysA = Object.keys(a).sort();
2595
3040
  const keysB = Object.keys(b).sort();
2596
3041
  for (let i = 0; i < Math.min(keysA.length, keysB.length); i++) {
@@ -2610,7 +3055,7 @@ function add(left, right, span) {
2610
3055
  if (typeof left === "number" && typeof right === "number") return left + right;
2611
3056
  if (typeof left === "string" && typeof right === "string") return left + right;
2612
3057
  if (Array.isArray(left) && Array.isArray(right)) return [...left, ...right];
2613
- if (isPlainObject$1(left) && isPlainObject$1(right)) return {
3058
+ if (isPlainObject(left) && isPlainObject(right)) return {
2614
3059
  ...left,
2615
3060
  ...right
2616
3061
  };
@@ -2628,7 +3073,7 @@ function mul(left, right, span) {
2628
3073
  if (typeof left === "number" && typeof right === "number") return left * right;
2629
3074
  if (typeof left === "string" && typeof right === "number") return repeatString(left, right);
2630
3075
  if (typeof left === "number" && typeof right === "string") return repeatString(right, left);
2631
- if (isPlainObject$1(left) && isPlainObject$1(right)) return mergeDeep(left, right);
3076
+ if (isPlainObject(left) && isPlainObject(right)) return mergeDeep(left, right);
2632
3077
  throw new RuntimeError(`Cannot multiply ${describeType(left)} by ${describeType(right)}`, span);
2633
3078
  }
2634
3079
  function div(left, right, span) {
@@ -2657,15 +3102,14 @@ function mergeDeep(target, source) {
2657
3102
  for (const key of Object.keys(source)) {
2658
3103
  const sVal = source[key];
2659
3104
  const tVal = result[key];
2660
- if (isPlainObject$1(sVal) && tVal !== void 0 && isPlainObject$1(tVal)) result[key] = mergeDeep(tVal, sVal);
3105
+ if (isPlainObject(sVal) && tVal !== void 0 && isPlainObject(tVal)) result[key] = mergeDeep(tVal, sVal);
2661
3106
  else result[key] = sVal;
2662
3107
  }
2663
3108
  return result;
2664
3109
  }
2665
- function isPlainObject$1(v) {
3110
+ function isPlainObject(v) {
2666
3111
  return typeof v === "object" && v !== null && !Array.isArray(v);
2667
3112
  }
2668
-
2669
3113
  //#endregion
2670
3114
  //#region src/builtins/math.ts
2671
3115
  const mathBuiltins = [
@@ -2723,12 +3167,22 @@ const mathBuiltins = [
2723
3167
  {
2724
3168
  name: "infinite",
2725
3169
  arity: 0,
3170
+ apply: function* (_input, _args, _env, tracker, _eval, span) {
3171
+ yield emit$1(Infinity, span, tracker);
3172
+ }
3173
+ },
3174
+ {
3175
+ name: "nan",
3176
+ arity: 0,
3177
+ apply: function* (_input, _args, _env, tracker, _eval, span) {
3178
+ yield emit$1(NaN, span, tracker);
3179
+ }
3180
+ },
3181
+ {
3182
+ name: "isinfinite",
3183
+ arity: 0,
2726
3184
  apply: function* (input, _args, _env, tracker, _eval, span) {
2727
- if (typeof input !== "number") {
2728
- yield emit$1(false, span, tracker);
2729
- return;
2730
- }
2731
- yield emit$1(!Number.isFinite(input) && !Number.isNaN(input), span, tracker);
3185
+ yield emit$1(typeof input === "number" && !Number.isFinite(input) && !Number.isNaN(input), span, tracker);
2732
3186
  }
2733
3187
  },
2734
3188
  {
@@ -2757,6 +3211,13 @@ const mathBuiltins = [
2757
3211
  yield emit$1(true, span, tracker);
2758
3212
  }
2759
3213
  },
3214
+ {
3215
+ name: "isnormal",
3216
+ arity: 0,
3217
+ apply: function* (input, _args, _env, tracker, _eval, span) {
3218
+ yield emit$1(typeof input === "number" && Number.isFinite(input) && input !== 0, span, tracker);
3219
+ }
3220
+ },
2760
3221
  {
2761
3222
  name: "subnormal",
2762
3223
  arity: 0,
@@ -2799,7 +3260,7 @@ const mathBuiltins = [
2799
3260
  {
2800
3261
  name: "min_by",
2801
3262
  arity: 1,
2802
- apply: function* (input, args, env, tracker, evaluate$1, span) {
3263
+ apply: function* (input, args, env, tracker, evaluate, span) {
2803
3264
  if (!Array.isArray(input)) throw new RuntimeError("min_by expects an array", span);
2804
3265
  if (input.length === 0) {
2805
3266
  yield emit$1(null, span, tracker);
@@ -2807,12 +3268,12 @@ const mathBuiltins = [
2807
3268
  }
2808
3269
  let minItem = input[0];
2809
3270
  let minKey;
2810
- const keys0 = Array.from(evaluate$1(args[0], minItem, env, tracker));
3271
+ const keys0 = Array.from(evaluate(args[0], minItem, env, tracker));
2811
3272
  if (keys0.length !== 1) throw new RuntimeError("min_by key must return one value", span);
2812
3273
  minKey = keys0[0];
2813
3274
  for (let i = 1; i < input.length; i++) {
2814
3275
  const item = input[i];
2815
- const keys = Array.from(evaluate$1(args[0], item, env, tracker));
3276
+ const keys = Array.from(evaluate(args[0], item, env, tracker));
2816
3277
  if (keys.length !== 1) throw new RuntimeError("min_by key must return one value", span);
2817
3278
  const key = keys[0];
2818
3279
  if (compareValues(key, minKey) < 0) {
@@ -2826,7 +3287,7 @@ const mathBuiltins = [
2826
3287
  {
2827
3288
  name: "max_by",
2828
3289
  arity: 1,
2829
- apply: function* (input, args, env, tracker, evaluate$1, span) {
3290
+ apply: function* (input, args, env, tracker, evaluate, span) {
2830
3291
  if (!Array.isArray(input)) throw new RuntimeError("max_by expects an array", span);
2831
3292
  if (input.length === 0) {
2832
3293
  yield emit$1(null, span, tracker);
@@ -2834,12 +3295,12 @@ const mathBuiltins = [
2834
3295
  }
2835
3296
  let maxItem = input[0];
2836
3297
  let maxKey;
2837
- const keys0 = Array.from(evaluate$1(args[0], maxItem, env, tracker));
3298
+ const keys0 = Array.from(evaluate(args[0], maxItem, env, tracker));
2838
3299
  if (keys0.length !== 1) throw new RuntimeError("max_by key must return one value", span);
2839
3300
  maxKey = keys0[0];
2840
3301
  for (let i = 1; i < input.length; i++) {
2841
3302
  const item = input[i];
2842
- const keys = Array.from(evaluate$1(args[0], item, env, tracker));
3303
+ const keys = Array.from(evaluate(args[0], item, env, tracker));
2843
3304
  if (keys.length !== 1) throw new RuntimeError("max_by key must return one value", span);
2844
3305
  const key = keys[0];
2845
3306
  if (compareValues(key, maxKey) > 0) {
@@ -2866,9 +3327,25 @@ const mathBuiltins = [
2866
3327
  }
2867
3328
  yield emit$1(acc, span, tracker);
2868
3329
  }
3330
+ },
3331
+ {
3332
+ name: "add",
3333
+ arity: 1,
3334
+ apply: function* (input, args, env, tracker, evaluate, span) {
3335
+ const values = Array.from(evaluate(args[0], input, env, tracker));
3336
+ if (values.length === 0) {
3337
+ yield emit$1(null, span, tracker);
3338
+ return;
3339
+ }
3340
+ let acc = values[0];
3341
+ for (let i = 1; i < values.length; i++) {
3342
+ tracker.step(span);
3343
+ acc = add(acc, values[i], span);
3344
+ }
3345
+ yield emit$1(acc, span, tracker);
3346
+ }
2869
3347
  }
2870
3348
  ];
2871
-
2872
3349
  //#endregion
2873
3350
  //#region src/builtins/index.ts
2874
3351
  const registerAllBuiltins = () => {
@@ -2880,11 +3357,9 @@ const registerAllBuiltins = () => {
2880
3357
  registerBuiltins(iteratorBuiltins);
2881
3358
  registerBuiltins(mathBuiltins);
2882
3359
  };
2883
-
2884
3360
  //#endregion
2885
3361
  //#region src/builtins.ts
2886
3362
  registerAllBuiltins();
2887
-
2888
3363
  //#endregion
2889
3364
  //#region src/validate.ts
2890
3365
  /**
@@ -2895,57 +3370,57 @@ registerAllBuiltins();
2895
3370
  * @throws {ValidationError} If validation fails.
2896
3371
  */
2897
3372
  const validate = (node) => {
2898
- visit(node, []);
3373
+ visit$1(node, []);
2899
3374
  };
2900
- const visit = (node, scope) => {
3375
+ const visit$1 = (node, scope) => {
2901
3376
  switch (node.kind) {
2902
3377
  case "Identity":
2903
3378
  case "Literal":
2904
3379
  case "Var": return;
2905
3380
  case "FieldAccess":
2906
- visit(node.target, scope);
3381
+ visit$1(node.target, scope);
2907
3382
  return;
2908
3383
  case "IndexAccess":
2909
- visit(node.target, scope);
2910
- visit(node.index, scope);
3384
+ visit$1(node.target, scope);
3385
+ visit$1(node.index, scope);
2911
3386
  return;
2912
3387
  case "Array":
2913
- node.items.forEach((n) => visit(n, scope));
3388
+ node.items.forEach((n) => visit$1(n, scope));
2914
3389
  return;
2915
3390
  case "Object":
2916
3391
  node.entries.forEach((entry) => {
2917
- if (entry.key.kind === "KeyExpr") visit(entry.key.expr, scope);
2918
- visit(entry.value, scope);
3392
+ if (entry.key.kind === "KeyExpr") visit$1(entry.key.expr, scope);
3393
+ visit$1(entry.value, scope);
2919
3394
  });
2920
3395
  return;
2921
3396
  case "Pipe":
2922
3397
  case "Comma":
2923
3398
  case "Alt":
2924
- visit(node.left, scope);
2925
- visit(node.right, scope);
3399
+ visit$1(node.left, scope);
3400
+ visit$1(node.right, scope);
2926
3401
  return;
2927
3402
  case "Binary":
2928
3403
  case "Bool":
2929
- visit(node.left, scope);
2930
- visit(node.right, scope);
3404
+ visit$1(node.left, scope);
3405
+ visit$1(node.right, scope);
2931
3406
  return;
2932
3407
  case "Unary":
2933
- visit(node.expr, scope);
3408
+ visit$1(node.expr, scope);
2934
3409
  return;
2935
3410
  case "If":
2936
3411
  node.branches.forEach((branch) => {
2937
- visit(branch.cond, scope);
2938
- visit(branch.then, scope);
3412
+ visit$1(branch.cond, scope);
3413
+ visit$1(branch.then, scope);
2939
3414
  });
2940
- visit(node.else, scope);
3415
+ visit$1(node.else, scope);
2941
3416
  return;
2942
3417
  case "As":
2943
- visit(node.bind, scope);
2944
- visit(node.body, scope);
3418
+ visit$1(node.bind, scope);
3419
+ visit$1(node.body, scope);
2945
3420
  return;
2946
3421
  case "Call": {
2947
3422
  for (let i = scope.length - 1; i >= 0; i--) if (scope[i].has(node.name)) {
2948
- for (const arg of node.args) visit(arg, scope);
3423
+ for (const arg of node.args) visit$1(arg, scope);
2949
3424
  return;
2950
3425
  }
2951
3426
  const specs = builtins[node.name];
@@ -2954,51 +3429,50 @@ const visit = (node, scope) => {
2954
3429
  const arities = specs.map((s) => s.arity).join(" or ");
2955
3430
  throw new ValidationError(`Function ${node.name} expects ${arities} arguments, but got ${node.args.length}`, node.span);
2956
3431
  }
2957
- for (const arg of node.args) visit(arg, scope);
3432
+ for (const arg of node.args) visit$1(arg, scope);
2958
3433
  return;
2959
3434
  }
2960
3435
  case "Assignment":
2961
- visit(node.left, scope);
2962
- visit(node.right, scope);
3436
+ visit$1(node.left, scope);
3437
+ visit$1(node.right, scope);
2963
3438
  return;
2964
3439
  case "Def": {
2965
3440
  const bodyScope = new Set(node.args);
2966
3441
  bodyScope.add(node.name);
2967
- visit(node.body, [...scope, bodyScope]);
3442
+ visit$1(node.body, [...scope, bodyScope]);
2968
3443
  const nextScope = new Set([node.name]);
2969
- visit(node.next, [...scope, nextScope]);
3444
+ visit$1(node.next, [...scope, nextScope]);
2970
3445
  return;
2971
3446
  }
2972
3447
  case "Reduce":
2973
- visit(node.source, scope);
2974
- visit(node.init, scope);
2975
- visit(node.update, scope);
3448
+ visit$1(node.source, scope);
3449
+ visit$1(node.init, scope);
3450
+ visit$1(node.update, scope);
2976
3451
  return;
2977
3452
  case "Foreach":
2978
- visit(node.source, scope);
2979
- visit(node.init, scope);
2980
- visit(node.update, scope);
2981
- if (node.extract) visit(node.extract, scope);
3453
+ visit$1(node.source, scope);
3454
+ visit$1(node.init, scope);
3455
+ visit$1(node.update, scope);
3456
+ if (node.extract) visit$1(node.extract, scope);
2982
3457
  return;
2983
3458
  case "Try":
2984
- visit(node.body, scope);
2985
- if (node.handler) visit(node.handler, scope);
3459
+ visit$1(node.body, scope);
3460
+ if (node.handler) visit$1(node.handler, scope);
2986
3461
  return;
2987
3462
  case "Recurse":
2988
3463
  case "Iterate":
2989
3464
  case "Break": return;
2990
3465
  case "Label":
2991
- visit(node.body, scope);
3466
+ visit$1(node.body, scope);
2992
3467
  return;
2993
3468
  case "Slice":
2994
- visit(node.target, scope);
2995
- if (node.start) visit(node.start, scope);
2996
- if (node.end) visit(node.end, scope);
3469
+ visit$1(node.target, scope);
3470
+ if (node.start) visit$1(node.start, scope);
3471
+ if (node.end) visit$1(node.end, scope);
2997
3472
  return;
2998
3473
  default: return node;
2999
3474
  }
3000
3475
  };
3001
-
3002
3476
  //#endregion
3003
3477
  //#region src/eval/break.ts
3004
3478
  /**
@@ -3012,7 +3486,6 @@ var BreakSignal = class BreakSignal extends Error {
3012
3486
  Object.setPrototypeOf(this, BreakSignal.prototype);
3013
3487
  }
3014
3488
  };
3015
-
3016
3489
  //#endregion
3017
3490
  //#region src/limits.ts
3018
3491
  const DEFAULT_LIMITS = {
@@ -3073,7 +3546,6 @@ var LimitTracker = class {
3073
3546
  if (this.outputs > this.limits.maxOutputs) throw new RuntimeError("Output limit exceeded", span);
3074
3547
  }
3075
3548
  };
3076
-
3077
3549
  //#endregion
3078
3550
  //#region src/eval/env.ts
3079
3551
  /**
@@ -3083,7 +3555,26 @@ var LimitTracker = class {
3083
3555
  const getVar = (env, name) => {
3084
3556
  for (let i = env.length - 1; i >= 0; i--) if (env[i].vars.has(name)) return env[i].vars.get(name);
3085
3557
  };
3086
-
3558
+ /**
3559
+ * Binds jq `as` destructuring patterns into a variable map.
3560
+ */
3561
+ const bindPattern = (pattern, value, bindings) => {
3562
+ switch (pattern.kind) {
3563
+ case "VariablePattern":
3564
+ bindings.set(pattern.name, value);
3565
+ return;
3566
+ case "ArrayPattern":
3567
+ if (!Array.isArray(value)) throw new RuntimeError(`Cannot index ${describeType(value)} with number`, pattern.span);
3568
+ pattern.items.forEach((item, index) => {
3569
+ bindPattern(item, index < value.length ? value[index] : null, bindings);
3570
+ });
3571
+ return;
3572
+ case "ObjectPattern":
3573
+ if (!isPlainObject$1(value)) throw new RuntimeError(`Cannot index ${describeType(value)} with string`, pattern.span);
3574
+ for (const entry of pattern.entries) bindPattern(entry.pattern, Object.prototype.hasOwnProperty.call(value, entry.key) ? value[entry.key] : null, bindings);
3575
+ return;
3576
+ }
3577
+ };
3087
3578
  //#endregion
3088
3579
  //#region src/eval/common.ts
3089
3580
  /**
@@ -3099,17 +3590,22 @@ const emit = (value, span, tracker) => {
3099
3590
  return value;
3100
3591
  };
3101
3592
  /**
3102
- * Ensures a value is an integer. Throws a RuntimeError otherwise.
3593
+ * Converts a value to an array index.
3594
+ * Truncates floats to integers. Returns null if input is null.
3595
+ * Throws a RuntimeError for non-numeric types.
3103
3596
  *
3104
- * @param value - The value to check.
3597
+ * @param value - The value to convert.
3105
3598
  * @param span - To report error.
3106
- * @returns The integer value.
3599
+ * @returns The integer index or null.
3107
3600
  */
3108
- const ensureInteger = (value, span) => {
3109
- if (typeof value === "number" && Number.isInteger(value)) return value;
3110
- throw new RuntimeError("Expected integer", span);
3601
+ const toIndex = (value, span) => {
3602
+ if (value === null) return null;
3603
+ if (typeof value === "number") {
3604
+ if (!Number.isFinite(value)) return null;
3605
+ return Math.trunc(value);
3606
+ }
3607
+ throw new RuntimeError("Expected numeric index", span);
3111
3608
  };
3112
-
3113
3609
  //#endregion
3114
3610
  //#region src/eval/assignment.ts
3115
3611
  /**
@@ -3125,15 +3621,15 @@ const ensureInteger = (value, span) => {
3125
3621
  * @param tracker - Limits tracker.
3126
3622
  * @param evaluate - Recursive evaluator.
3127
3623
  */
3128
- const evalAssignment = function* (node, input, env, tracker, evaluate$1) {
3129
- const paths = Array.from(evaluatePath(node.left, input, env, tracker, evaluate$1));
3624
+ const evalAssignment = function* (node, input, env, tracker, evaluate) {
3625
+ const paths = Array.from(evaluatePath(node.left, input, env, tracker, evaluate));
3130
3626
  paths.sort((a, b) => compareValues(a, b) * -1);
3131
3627
  if (paths.length === 0) {
3132
3628
  yield emit(input, node.span, tracker);
3133
3629
  return;
3134
3630
  }
3135
3631
  if (node.op === "=") {
3136
- const rhsValues = Array.from(evaluate$1(node.right, input, env, tracker));
3632
+ const rhsValues = Array.from(evaluate(node.right, input, env, tracker));
3137
3633
  if (rhsValues.length === 0) return;
3138
3634
  for (const rhsVal of rhsValues) {
3139
3635
  let current = input;
@@ -3142,9 +3638,9 @@ const evalAssignment = function* (node, input, env, tracker, evaluate$1) {
3142
3638
  }
3143
3639
  return;
3144
3640
  }
3145
- yield* applyUpdates(input, paths, 0, node.op, node.right, input, env, tracker, evaluate$1);
3641
+ yield* applyUpdates(input, paths, 0, node.op, node.right, input, env, tracker, evaluate);
3146
3642
  };
3147
- function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tracker, evaluate$1) {
3643
+ function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tracker, evaluate) {
3148
3644
  if (index >= paths.length) {
3149
3645
  yield current;
3150
3646
  return;
@@ -3152,9 +3648,9 @@ function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tr
3152
3648
  const path = paths[index];
3153
3649
  const oldValue = getPath(current, path) ?? null;
3154
3650
  let newValues = [];
3155
- if (op === "|=") newValues = Array.from(evaluate$1(rhsNode, oldValue, env, tracker));
3651
+ if (op === "|=") newValues = Array.from(evaluate(rhsNode, oldValue, env, tracker));
3156
3652
  else {
3157
- const rhsResults = Array.from(evaluate$1(rhsNode, contextInput, env, tracker));
3653
+ const rhsResults = Array.from(evaluate(rhsNode, contextInput, env, tracker));
3158
3654
  for (const rhs of rhsResults) {
3159
3655
  let res;
3160
3656
  switch (op) {
@@ -3182,12 +3678,11 @@ function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tr
3182
3678
  }
3183
3679
  }
3184
3680
  if (newValues.length === 0) {
3185
- yield* applyUpdates(deletePaths(current, [path], rhsNode.span), paths, index + 1, op, rhsNode, contextInput, env, tracker, evaluate$1);
3681
+ yield* applyUpdates(deletePaths(current, [path], rhsNode.span), paths, index + 1, op, rhsNode, contextInput, env, tracker, evaluate);
3186
3682
  return;
3187
3683
  }
3188
- for (const val of newValues) yield* applyUpdates(updatePath(current, path, () => val, rhsNode.span) ?? current, paths, index + 1, op, rhsNode, contextInput, env, tracker, evaluate$1);
3684
+ for (const val of newValues) yield* applyUpdates(updatePath(current, path, () => val, rhsNode.span) ?? current, paths, index + 1, op, rhsNode, contextInput, env, tracker, evaluate);
3189
3685
  }
3190
-
3191
3686
  //#endregion
3192
3687
  //#region src/eval/iterators.ts
3193
3688
  /**
@@ -3199,14 +3694,14 @@ function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tr
3199
3694
  * @param tracker - Limits tracker.
3200
3695
  * @param evaluate - Recursive evaluator.
3201
3696
  */
3202
- const evalIterate = function* (node, input, env, tracker, evaluate$1) {
3203
- for (const container of evaluate$1(node.target, input, env, tracker)) {
3697
+ const evalIterate = function* (node, input, env, tracker, evaluate) {
3698
+ for (const container of evaluate(node.target, input, env, tracker)) {
3204
3699
  if (container === null) continue;
3205
3700
  if (isValueArray(container)) {
3206
3701
  for (const item of container) yield emit(item, node.span, tracker);
3207
3702
  continue;
3208
3703
  }
3209
- if (isPlainObject(container)) {
3704
+ if (isPlainObject$1(container)) {
3210
3705
  const keys = Object.keys(container).sort();
3211
3706
  for (const key of keys) yield emit(container[key], node.span, tracker);
3212
3707
  continue;
@@ -3225,18 +3720,20 @@ const evalIterate = function* (node, input, env, tracker, evaluate$1) {
3225
3720
  * @param tracker - Limits tracker.
3226
3721
  * @param evaluate - Recursive evaluator.
3227
3722
  */
3228
- const evalReduce = function* (node, input, env, tracker, evaluate$1) {
3229
- const initValues = Array.from(evaluate$1(node.init, input, env, tracker));
3723
+ const evalReduce = function* (node, input, env, tracker, evaluate) {
3724
+ const initValues = Array.from(evaluate(node.init, input, env, tracker));
3230
3725
  if (initValues.length !== 1) throw new RuntimeError("Reduce init must single value", node.init.span);
3231
3726
  let acc = initValues[0];
3232
- for (const item of evaluate$1(node.source, input, env, tracker)) {
3727
+ for (const item of evaluate(node.source, input, env, tracker)) {
3233
3728
  tracker.step(node.span);
3729
+ const vars = /* @__PURE__ */ new Map();
3730
+ bindPattern(node.pattern, item, vars);
3234
3731
  const newFrame = {
3235
- vars: new Map([[node.var, item]]),
3732
+ vars,
3236
3733
  funcs: /* @__PURE__ */ new Map()
3237
3734
  };
3238
3735
  const newEnv = [...env, newFrame];
3239
- const updates = Array.from(evaluate$1(node.update, acc, newEnv, tracker));
3736
+ const updates = Array.from(evaluate(node.update, acc, newEnv, tracker));
3240
3737
  if (updates.length !== 1) throw new RuntimeError("Reduce update must produce single value", node.update.span);
3241
3738
  acc = updates[0];
3242
3739
  }
@@ -3253,21 +3750,23 @@ const evalReduce = function* (node, input, env, tracker, evaluate$1) {
3253
3750
  * @param tracker - Limits tracker.
3254
3751
  * @param evaluate - Recursive evaluator.
3255
3752
  */
3256
- const evalForeach = function* (node, input, env, tracker, evaluate$1) {
3257
- const initValues = Array.from(evaluate$1(node.init, input, env, tracker));
3753
+ const evalForeach = function* (node, input, env, tracker, evaluate) {
3754
+ const initValues = Array.from(evaluate(node.init, input, env, tracker));
3258
3755
  if (initValues.length !== 1) throw new RuntimeError("Foreach init must single value", node.init.span);
3259
3756
  let acc = initValues[0];
3260
- for (const item of evaluate$1(node.source, input, env, tracker)) {
3757
+ for (const item of evaluate(node.source, input, env, tracker)) {
3261
3758
  tracker.step(node.span);
3759
+ const vars = /* @__PURE__ */ new Map();
3760
+ bindPattern(node.pattern, item, vars);
3262
3761
  const newFrame = {
3263
- vars: new Map([[node.var, item]]),
3762
+ vars,
3264
3763
  funcs: /* @__PURE__ */ new Map()
3265
3764
  };
3266
3765
  const newEnv = [...env, newFrame];
3267
- const updates = Array.from(evaluate$1(node.update, acc, newEnv, tracker));
3766
+ const updates = Array.from(evaluate(node.update, acc, newEnv, tracker));
3268
3767
  if (updates.length !== 1) throw new RuntimeError("Foreach update must produce single value", node.update.span);
3269
3768
  acc = updates[0];
3270
- if (node.extract) for (const extracted of evaluate$1(node.extract, acc, newEnv, tracker)) yield emit(extracted, node.span, tracker);
3769
+ if (node.extract) for (const extracted of evaluate(node.extract, acc, newEnv, tracker)) yield emit(extracted, node.span, tracker);
3271
3770
  else yield emit(acc, node.span, tracker);
3272
3771
  }
3273
3772
  };
@@ -3281,17 +3780,16 @@ const evalForeach = function* (node, input, env, tracker, evaluate$1) {
3281
3780
  * @param tracker - Limits tracker.
3282
3781
  * @param evaluate - Recursive evaluator.
3283
3782
  */
3284
- const evalRecurse = function* (node, input, env, tracker, evaluate$1) {
3783
+ const evalRecurse = function* (node, input, env, tracker, evaluate) {
3285
3784
  yield emit(input, node.span, tracker);
3286
3785
  const children = [];
3287
3786
  if (isValueArray(input)) children.push(...input);
3288
- else if (isPlainObject(input)) {
3787
+ else if (isPlainObject$1(input)) {
3289
3788
  const keys = Object.keys(input).sort();
3290
3789
  for (const key of keys) children.push(input[key]);
3291
3790
  }
3292
- for (const child of children) yield* evalRecurse(node, child, env, tracker, evaluate$1);
3791
+ for (const child of children) yield* evalRecurse(node, child, env, tracker, evaluate);
3293
3792
  };
3294
-
3295
3793
  //#endregion
3296
3794
  //#region src/eval/access.ts
3297
3795
  /**
@@ -3303,13 +3801,13 @@ const evalRecurse = function* (node, input, env, tracker, evaluate$1) {
3303
3801
  * @param tracker - Limits tracker.
3304
3802
  * @param evaluate - Recursive evaluator.
3305
3803
  */
3306
- const evalField = function* (node, input, env, tracker, evaluate$1) {
3307
- for (const container of evaluate$1(node.target, input, env, tracker)) {
3804
+ const evalField = function* (node, input, env, tracker, evaluate) {
3805
+ for (const container of evaluate(node.target, input, env, tracker)) {
3308
3806
  if (container === null) {
3309
3807
  yield emit(null, node.span, tracker);
3310
3808
  continue;
3311
3809
  }
3312
- if (isPlainObject(container)) {
3810
+ if (isPlainObject$1(container)) {
3313
3811
  yield emit(Object.prototype.hasOwnProperty.call(container, node.field) ? container[node.field] : null, node.span, tracker);
3314
3812
  continue;
3315
3813
  }
@@ -3326,23 +3824,27 @@ const evalField = function* (node, input, env, tracker, evaluate$1) {
3326
3824
  * @param tracker - Limits tracker.
3327
3825
  * @param evaluate - Recursive evaluator.
3328
3826
  */
3329
- const evalIndex = function* (node, input, env, tracker, evaluate$1) {
3330
- const indexValues = Array.from(evaluate$1(node.index, input, env, tracker));
3331
- for (const container of evaluate$1(node.target, input, env, tracker)) {
3827
+ const evalIndex = function* (node, input, env, tracker, evaluate) {
3828
+ const indexValues = Array.from(evaluate(node.index, input, env, tracker));
3829
+ for (const container of evaluate(node.target, input, env, tracker)) {
3332
3830
  if (container === null) {
3333
3831
  yield emit(null, node.span, tracker);
3334
3832
  continue;
3335
3833
  }
3336
3834
  if (isValueArray(container)) {
3337
3835
  for (const idxValue of indexValues) {
3338
- const index = ensureInteger(idxValue, node.span);
3836
+ const index = toIndex(idxValue, node.span);
3837
+ if (index === null) {
3838
+ yield emit(null, node.span, tracker);
3839
+ continue;
3840
+ }
3339
3841
  const resolved = index < 0 ? container.length + index : index;
3340
3842
  if (resolved < 0 || resolved >= container.length) yield emit(null, node.span, tracker);
3341
3843
  else yield emit(container[resolved], node.span, tracker);
3342
3844
  }
3343
3845
  continue;
3344
3846
  }
3345
- if (isPlainObject(container)) {
3847
+ if (isPlainObject$1(container)) {
3346
3848
  for (const keyValue of indexValues) {
3347
3849
  if (typeof keyValue !== "string") throw new RuntimeError(`Cannot index object with ${describeType(keyValue)}`, node.span);
3348
3850
  yield emit(Object.prototype.hasOwnProperty.call(container, keyValue) ? container[keyValue] : null, node.span, tracker);
@@ -3362,25 +3864,26 @@ const evalIndex = function* (node, input, env, tracker, evaluate$1) {
3362
3864
  * @param tracker - Limits tracker.
3363
3865
  * @param evaluate - Recursive evaluator.
3364
3866
  */
3365
- const evalSlice = function* (node, input, env, tracker, evaluate$1) {
3366
- for (const target of evaluate$1(node.target, input, env, tracker)) {
3867
+ const evalSlice = function* (node, input, env, tracker, evaluate) {
3868
+ for (const target of evaluate(node.target, input, env, tracker)) {
3367
3869
  if (typeof target !== "string" && !Array.isArray(target)) throw new RuntimeError("Slice expected string or array", node.span);
3368
3870
  const starts = [];
3369
- if (node.start) for (const s of evaluate$1(node.start, input, env, tracker)) {
3871
+ if (node.start) for (const s of evaluate(node.start, input, env, tracker)) {
3370
3872
  if (typeof s !== "number") throw new RuntimeError("Slice start must be number", node.span);
3371
3873
  starts.push(s);
3372
3874
  }
3373
3875
  else starts.push(0);
3374
3876
  const ends = [];
3375
- if (node.end) for (const e of evaluate$1(node.end, input, env, tracker)) {
3877
+ if (node.end) for (const e of evaluate(node.end, input, env, tracker)) {
3376
3878
  if (typeof e !== "number") throw new RuntimeError("Slice end must be number", node.span);
3377
3879
  ends.push(e);
3378
3880
  }
3379
3881
  else ends.push(target.length);
3380
- for (const s of starts) for (const e of ends) yield emit(target.slice(s, e), node.span, tracker);
3882
+ for (const s of starts) for (const e of ends) yield emit(target.slice(normalizeSliceStart(s), normalizeSliceEnd(e)), node.span, tracker);
3381
3883
  }
3382
3884
  };
3383
-
3885
+ const normalizeSliceStart = (value) => Math.floor(value);
3886
+ const normalizeSliceEnd = (value) => Math.ceil(value);
3384
3887
  //#endregion
3385
3888
  //#region src/eval/constructors.ts
3386
3889
  /**
@@ -3395,9 +3898,9 @@ const evalSlice = function* (node, input, env, tracker, evaluate$1) {
3395
3898
  * @param tracker - Limits tracker.
3396
3899
  * @param evaluate - Recursive evaluator.
3397
3900
  */
3398
- const buildArray = function* (node, input, env, tracker, evaluate$1) {
3901
+ const buildArray = function* (node, input, env, tracker, evaluate) {
3399
3902
  const result = [];
3400
- for (const itemNode of node.items) for (const itemVal of evaluate$1(itemNode, input, env, tracker)) result.push(itemVal);
3903
+ for (const itemNode of node.items) for (const itemVal of evaluate(itemNode, input, env, tracker)) result.push(itemVal);
3401
3904
  yield result;
3402
3905
  };
3403
3906
  /**
@@ -3412,10 +3915,10 @@ const buildArray = function* (node, input, env, tracker, evaluate$1) {
3412
3915
  * @param tracker - Limits tracker.
3413
3916
  * @param evaluate - Recursive evaluator.
3414
3917
  */
3415
- const buildObjects = function* (node, input, env, tracker, evaluate$1) {
3416
- yield* fillObject(node.entries, 0, {}, input, env, tracker, evaluate$1);
3918
+ const buildObjects = function* (node, input, env, tracker, evaluate) {
3919
+ yield* fillObject(node.entries, 0, {}, input, env, tracker, evaluate);
3417
3920
  };
3418
- function* fillObject(entries, index, current, input, env, tracker, evaluate$1) {
3921
+ function* fillObject(entries, index, current, input, env, tracker, evaluate) {
3419
3922
  if (index >= entries.length) {
3420
3923
  yield { ...current };
3421
3924
  return;
@@ -3424,17 +3927,16 @@ function* fillObject(entries, index, current, input, env, tracker, evaluate$1) {
3424
3927
  let keys = [];
3425
3928
  if (entry.key.kind === "KeyIdentifier") keys = [entry.key.name];
3426
3929
  else if (entry.key.kind === "KeyString") keys = [entry.key.value];
3427
- else for (const k of evaluate$1(entry.key.expr, input, env, tracker)) {
3930
+ else for (const k of evaluate(entry.key.expr, input, env, tracker)) {
3428
3931
  if (typeof k !== "string") throw new RuntimeError("Object key must be a string", entry.key.span);
3429
3932
  keys.push(k);
3430
3933
  }
3431
- for (const key of keys) for (const val of evaluate$1(entry.value, input, env, tracker)) {
3934
+ for (const key of keys) for (const val of evaluate(entry.value, input, env, tracker)) {
3432
3935
  current[key] = val;
3433
- yield* fillObject(entries, index + 1, current, input, env, tracker, evaluate$1);
3936
+ yield* fillObject(entries, index + 1, current, input, env, tracker, evaluate);
3434
3937
  delete current[key];
3435
3938
  }
3436
3939
  }
3437
-
3438
3940
  //#endregion
3439
3941
  //#region src/eval/functions.ts
3440
3942
  /**
@@ -3452,7 +3954,7 @@ function* fillObject(entries, index, current, input, env, tracker, evaluate$1) {
3452
3954
  * @param tracker - Limits tracker.
3453
3955
  * @param evaluate - Recursive evaluator.
3454
3956
  */
3455
- const evalCall = function* (node, input, env, tracker, evaluate$1) {
3957
+ const evalCall = function* (node, input, env, tracker, evaluate) {
3456
3958
  for (let i = env.length - 1; i >= 0; i--) {
3457
3959
  const funcs = env[i].funcs.get(node.name);
3458
3960
  if (funcs) {
@@ -3474,7 +3976,7 @@ const evalCall = function* (node, input, env, tracker, evaluate$1) {
3474
3976
  newFrame.funcs.set(argName, argDefs);
3475
3977
  }
3476
3978
  const newStack = [...def.closure, newFrame];
3477
- yield* evaluate$1(def.body, input, newStack, tracker);
3979
+ yield* evaluate(def.body, input, newStack, tracker);
3478
3980
  return;
3479
3981
  }
3480
3982
  }
@@ -3483,7 +3985,7 @@ const evalCall = function* (node, input, env, tracker, evaluate$1) {
3483
3985
  if (!specs) throw new RuntimeError(`Unknown function: ${node.name}`, node.span);
3484
3986
  const builtin = specs.find((s) => s.arity === node.args.length);
3485
3987
  if (!builtin) throw new RuntimeError(`Function ${node.name} does not accept ${node.args.length} arguments`, node.span);
3486
- yield* builtin.apply(input, node.args, env, tracker, evaluate$1, node.span);
3988
+ yield* builtin.apply(input, node.args, env, tracker, evaluate, node.span);
3487
3989
  };
3488
3990
  /**
3489
3991
  * Defines a new function in the environment.
@@ -3497,7 +3999,7 @@ const evalCall = function* (node, input, env, tracker, evaluate$1) {
3497
3999
  * @param tracker - Limits tracker.
3498
4000
  * @param evaluate - Recursive evaluator.
3499
4001
  */
3500
- const evalDef = function* (node, input, env, tracker, evaluate$1) {
4002
+ const evalDef = function* (node, input, env, tracker, evaluate) {
3501
4003
  const newFrame = {
3502
4004
  vars: /* @__PURE__ */ new Map(),
3503
4005
  funcs: /* @__PURE__ */ new Map()
@@ -3512,9 +4014,8 @@ const evalDef = function* (node, input, env, tracker, evaluate$1) {
3512
4014
  newFrame.funcs.set(node.name, currentDefs);
3513
4015
  const newStack = [...env, newFrame];
3514
4016
  funDef.closure = newStack;
3515
- yield* evaluate$1(node.next, input, newStack, tracker);
4017
+ yield* evaluate(node.next, input, newStack, tracker);
3516
4018
  };
3517
-
3518
4019
  //#endregion
3519
4020
  //#region src/eval/control_flow.ts
3520
4021
  /**
@@ -3526,17 +4027,17 @@ const evalDef = function* (node, input, env, tracker, evaluate$1) {
3526
4027
  * @param tracker - Limits tracker.
3527
4028
  * @param evaluate - Recursive evaluator.
3528
4029
  */
3529
- const evalIf = function* (node, input, env, tracker, evaluate$1) {
3530
- yield* evalIfBranch(node, 0, input, env, tracker, evaluate$1);
4030
+ const evalIf = function* (node, input, env, tracker, evaluate) {
4031
+ yield* evalIfBranch(node, 0, input, env, tracker, evaluate);
3531
4032
  };
3532
- function* evalIfBranch(node, branchIndex, input, env, tracker, evaluate$1) {
4033
+ function* evalIfBranch(node, branchIndex, input, env, tracker, evaluate) {
3533
4034
  if (branchIndex >= node.branches.length) {
3534
- yield* evaluate$1(node.else, input, env, tracker);
4035
+ yield* evaluate(node.else, input, env, tracker);
3535
4036
  return;
3536
4037
  }
3537
4038
  const branch = node.branches[branchIndex];
3538
- for (const cond of evaluate$1(branch.cond, input, env, tracker)) if (isTruthy(cond)) yield* evaluate$1(branch.then, input, env, tracker);
3539
- else yield* evalIfBranch(node, branchIndex + 1, input, env, tracker, evaluate$1);
4039
+ for (const cond of evaluate(branch.cond, input, env, tracker)) if (isTruthy(cond)) yield* evaluate(branch.then, input, env, tracker);
4040
+ else yield* evalIfBranch(node, branchIndex + 1, input, env, tracker, evaluate);
3540
4041
  }
3541
4042
  /**
3542
4043
  * Evaluates a `try-catch` expression.
@@ -3547,12 +4048,12 @@ function* evalIfBranch(node, branchIndex, input, env, tracker, evaluate$1) {
3547
4048
  * @param tracker - Limits tracker.
3548
4049
  * @param evaluate - Recursive evaluator.
3549
4050
  */
3550
- const evalTry = function* (node, input, env, tracker, evaluate$1) {
4051
+ const evalTry = function* (node, input, env, tracker, evaluate) {
3551
4052
  try {
3552
- yield* evaluate$1(node.body, input, env, tracker);
4053
+ yield* evaluate(node.body, input, env, tracker);
3553
4054
  } catch (err) {
3554
4055
  if (err instanceof RuntimeError) {
3555
- if (node.handler) yield* evaluate$1(node.handler, err.message, env, tracker);
4056
+ if (node.handler) yield* evaluate(node.handler, err.message, env, tracker);
3556
4057
  } else throw err;
3557
4058
  }
3558
4059
  };
@@ -3565,9 +4066,9 @@ const evalTry = function* (node, input, env, tracker, evaluate$1) {
3565
4066
  * @param tracker - Limits tracker.
3566
4067
  * @param evaluate - Recursive evaluator.
3567
4068
  */
3568
- const evalLabel = function* (node, input, env, tracker, evaluate$1) {
4069
+ const evalLabel = function* (node, input, env, tracker, evaluate) {
3569
4070
  try {
3570
- yield* evaluate$1(node.body, input, env, tracker);
4071
+ yield* evaluate(node.body, input, env, tracker);
3571
4072
  } catch (e) {
3572
4073
  if (e instanceof BreakSignal) {
3573
4074
  if (e.label === node.label) return;
@@ -3575,7 +4076,6 @@ const evalLabel = function* (node, input, env, tracker, evaluate$1) {
3575
4076
  throw e;
3576
4077
  }
3577
4078
  };
3578
-
3579
4079
  //#endregion
3580
4080
  //#region src/eval/dispatch.ts
3581
4081
  /**
@@ -3696,8 +4196,10 @@ function* evaluate(node, input, env, tracker) {
3696
4196
  case "As": {
3697
4197
  const values = Array.from(evaluate(node.bind, input, env, tracker));
3698
4198
  for (const val of values) {
4199
+ const vars = /* @__PURE__ */ new Map();
4200
+ bindPattern(node.pattern, val, vars);
3699
4201
  const newFrame = {
3700
- vars: new Map([[node.name, val]]),
4202
+ vars,
3701
4203
  funcs: /* @__PURE__ */ new Map()
3702
4204
  };
3703
4205
  const newEnv = [...env, newFrame];
@@ -3716,7 +4218,301 @@ function* evaluate(node, input, env, tracker) {
3716
4218
  tracker.exit();
3717
4219
  }
3718
4220
  }
3719
-
4221
+ //#endregion
4222
+ //#region src/compat.ts
4223
+ const semanticWarnings = {
4224
+ unique: "jq sorts unique results; jq-ts preserves first-seen order for determinism.",
4225
+ unique_by: "jq sorts unique_by results by key; jq-ts preserves first-seen order.",
4226
+ to_entries: "jq preserves object insertion order; jq-ts sorts object keys deterministically.",
4227
+ with_entries: "jq preserves object insertion order; jq-ts processes object keys in sorted order.",
4228
+ tostring: "jq stringifies objects in input key order; jq-ts uses stable sorted-key stringification.",
4229
+ tojson: "jq tojson preserves input object order; jq-ts uses stable sorted-key stringification.",
4230
+ infinite: "jq serializes infinite as a finite JSON number; jq-ts returns JavaScript Infinity internally.",
4231
+ normal: "jq documents isnormal; jq-ts exposes normal with approximate JavaScript number semantics.",
4232
+ subnormal: "jq documents subnormal classification; jq-ts currently approximates this as false."
4233
+ };
4234
+ const specialVariableWarnings = {
4235
+ ENV: "jq $ENV is an environment snapshot; jq-ts does not populate it unless the caller injects an ENV variable.",
4236
+ __loc__: "jq $__loc__ reports source location metadata; jq-ts does not populate it unless the caller injects a __loc__ variable.",
4237
+ JQ_BUILD_CONFIGURATION: "jq $JQ_BUILD_CONFIGURATION reports jq build metadata; jq-ts does not populate it unless the caller injects a JQ_BUILD_CONFIGURATION variable.",
4238
+ ARGS: "jq $ARGS is populated from CLI arguments; jq-ts does not populate it unless the caller injects an ARGS variable."
4239
+ };
4240
+ const syntaxWarningsByKind = { Slice: "jq slice bounds have jq-specific numeric coercion; jq-ts uses JavaScript slice semantics." };
4241
+ /**
4242
+ * Checks whether a jq expression can be parsed and statically validated by jq-ts.
4243
+ *
4244
+ * This is a syntax/subset check only. It does not prove that runtime behavior
4245
+ * matches the jq binary for every possible input.
4246
+ */
4247
+ const checkCompatibility = (source) => {
4248
+ try {
4249
+ validate(parse(source));
4250
+ return {
4251
+ compatible: true,
4252
+ findings: []
4253
+ };
4254
+ } catch (err) {
4255
+ const finding = toFinding(err);
4256
+ if (finding) return {
4257
+ compatible: false,
4258
+ findings: [finding]
4259
+ };
4260
+ throw err;
4261
+ }
4262
+ };
4263
+ /**
4264
+ * Checks jq-ts compatibility and reports known semantic differences from jq.
4265
+ */
4266
+ const analyzeCompatibility = (source) => {
4267
+ const check = checkCompatibility(source);
4268
+ if (!check.compatible) return {
4269
+ ...check,
4270
+ warnings: []
4271
+ };
4272
+ const warnings = collectWarnings(parse(source));
4273
+ return {
4274
+ compatible: true,
4275
+ findings: warnings,
4276
+ warnings
4277
+ };
4278
+ };
4279
+ /**
4280
+ * Compares jq-ts execution against a caller-provided jq runner or jq result.
4281
+ *
4282
+ * The function is safe to export from the isolate-safe library because it does
4283
+ * not spawn the jq binary itself. Tests and development tools can pass a runner
4284
+ * that shells out to jq.
4285
+ */
4286
+ const compareWithJq = (source, input, jq, options = {}) => {
4287
+ const analysis = analyzeCompatibility(source);
4288
+ const jqTs = runJqTs(source, input, options);
4289
+ const jqResult = typeof jq === "function" ? runExternalJq(jq, source, input) : jq;
4290
+ const findings = [...analysis.findings];
4291
+ if (!jqTs.ok) findings.push({
4292
+ severity: "error",
4293
+ stage: jqTs.stage ?? "runtime",
4294
+ category: "runtime-error",
4295
+ message: jqTs.error
4296
+ });
4297
+ if (!jqResult.ok) findings.push({
4298
+ severity: "error",
4299
+ stage: "compare",
4300
+ category: "jq-error",
4301
+ message: jqResult.error
4302
+ });
4303
+ const equivalent = jqTs.ok && jqResult.ok ? outputStreamsEqual(jqTs.outputs, jqResult.outputs) : null;
4304
+ if (equivalent === false) findings.push({
4305
+ severity: "error",
4306
+ stage: "compare",
4307
+ category: "output-mismatch",
4308
+ message: "jq-ts output stream does not match jq output stream."
4309
+ });
4310
+ return {
4311
+ compatible: analysis.compatible && jqTs.ok,
4312
+ equivalent,
4313
+ analysis,
4314
+ jqTs,
4315
+ jq: jqResult,
4316
+ findings
4317
+ };
4318
+ };
4319
+ const runJqTs = (source, input, options) => {
4320
+ try {
4321
+ const ast = parse(source);
4322
+ validate(ast);
4323
+ return {
4324
+ ok: true,
4325
+ outputs: runAst(ast, input, options)
4326
+ };
4327
+ } catch (err) {
4328
+ const jqTsError = asJqTsError(err);
4329
+ return {
4330
+ ok: false,
4331
+ error: err instanceof Error ? err.message : String(err),
4332
+ stage: jqTsError?.kind
4333
+ };
4334
+ }
4335
+ };
4336
+ const runExternalJq = (runner, source, input) => {
4337
+ try {
4338
+ const result = runner(source, input);
4339
+ if (Array.isArray(result)) return {
4340
+ ok: true,
4341
+ outputs: result
4342
+ };
4343
+ return result;
4344
+ } catch (err) {
4345
+ return {
4346
+ ok: false,
4347
+ error: err instanceof Error ? err.message : String(err),
4348
+ stage: "compare"
4349
+ };
4350
+ }
4351
+ };
4352
+ const outputStreamsEqual = (left, right) => left.length === right.length && left.every((value, index) => valueEquals(value, right[index]));
4353
+ const toFinding = (err) => {
4354
+ const jqTsError = asJqTsError(err);
4355
+ if (!jqTsError) return null;
4356
+ return {
4357
+ severity: "error",
4358
+ stage: jqTsError.kind,
4359
+ category: classifyError(jqTsError),
4360
+ message: jqTsError.message,
4361
+ span: jqTsError.span
4362
+ };
4363
+ };
4364
+ const asJqTsError = (err) => {
4365
+ if (err instanceof LexError || err instanceof ParseError || err instanceof ValidationError || err instanceof RuntimeError) return err;
4366
+ return null;
4367
+ };
4368
+ const classifyError = (err) => {
4369
+ if (err.kind === "parse" || err.kind === "lex") return "unsupported-syntax";
4370
+ if (err.kind === "runtime") return "runtime-error";
4371
+ if (err.message.startsWith("Unknown function:")) return isIntentionalExclusion(err.message) ? "intentional-exclusion" : "unsupported-builtin";
4372
+ if (err.message.includes("expects") && err.message.includes("arguments")) return "arity-mismatch";
4373
+ return "unsupported-syntax";
4374
+ };
4375
+ const isIntentionalExclusion = (message) => [
4376
+ "now",
4377
+ "input",
4378
+ "inputs",
4379
+ "env"
4380
+ ].some((name) => message === `Unknown function: ${name}`);
4381
+ const collectWarnings = (node) => {
4382
+ const warnings = [];
4383
+ visit(node, (current) => {
4384
+ const syntaxWarning = syntaxWarningsByKind[current.kind];
4385
+ if (syntaxWarning) warnings.push({
4386
+ severity: "warning",
4387
+ stage: "validate",
4388
+ category: "input-dependent",
4389
+ message: syntaxWarning,
4390
+ span: current.span
4391
+ });
4392
+ if (current.kind === "Call") {
4393
+ const warning = semanticWarnings[current.name];
4394
+ if (warning) warnings.push({
4395
+ severity: "warning",
4396
+ stage: "validate",
4397
+ category: "semantic-deviation",
4398
+ message: warning,
4399
+ span: current.span
4400
+ });
4401
+ }
4402
+ if (current.kind === "Var") {
4403
+ const warning = specialVariableWarnings[current.name];
4404
+ if (warning) warnings.push({
4405
+ severity: "warning",
4406
+ stage: "validate",
4407
+ category: current.name === "ENV" ? "intentional-exclusion" : "semantic-deviation",
4408
+ message: warning,
4409
+ span: current.span
4410
+ });
4411
+ }
4412
+ });
4413
+ return dedupeFindings(warnings);
4414
+ };
4415
+ const dedupeFindings = (findings) => {
4416
+ const seen = /* @__PURE__ */ new Set();
4417
+ const result = [];
4418
+ for (const finding of findings) {
4419
+ const key = `${finding.category}:${finding.message}:${finding.span?.start ?? ""}:${finding.span?.end ?? ""}`;
4420
+ if (seen.has(key)) continue;
4421
+ seen.add(key);
4422
+ result.push(finding);
4423
+ }
4424
+ return result;
4425
+ };
4426
+ const visit = (node, callback) => {
4427
+ callback(node);
4428
+ switch (node.kind) {
4429
+ case "Identity":
4430
+ case "Literal":
4431
+ case "Var":
4432
+ case "Recurse":
4433
+ case "Break": return;
4434
+ case "FieldAccess":
4435
+ visit(node.target, callback);
4436
+ return;
4437
+ case "IndexAccess":
4438
+ visit(node.target, callback);
4439
+ visit(node.index, callback);
4440
+ return;
4441
+ case "Iterate":
4442
+ visit(node.target, callback);
4443
+ return;
4444
+ case "Slice":
4445
+ visit(node.target, callback);
4446
+ if (node.start) visit(node.start, callback);
4447
+ if (node.end) visit(node.end, callback);
4448
+ return;
4449
+ case "Array":
4450
+ node.items.forEach((item) => visit(item, callback));
4451
+ return;
4452
+ case "Object":
4453
+ node.entries.forEach((entry) => visitObjectEntry(entry, callback));
4454
+ return;
4455
+ case "Pipe":
4456
+ case "Comma":
4457
+ case "Alt":
4458
+ case "Binary":
4459
+ case "Bool":
4460
+ visit(node.left, callback);
4461
+ visit(node.right, callback);
4462
+ return;
4463
+ case "Unary":
4464
+ visit(node.expr, callback);
4465
+ return;
4466
+ case "If":
4467
+ node.branches.forEach((branch) => {
4468
+ visit(branch.cond, callback);
4469
+ visit(branch.then, callback);
4470
+ });
4471
+ visit(node.else, callback);
4472
+ return;
4473
+ case "As":
4474
+ visit(node.bind, callback);
4475
+ visit(node.body, callback);
4476
+ return;
4477
+ case "Call":
4478
+ node.args.forEach((arg) => visit(arg, callback));
4479
+ return;
4480
+ case "Reduce":
4481
+ visit(node.source, callback);
4482
+ visit(node.init, callback);
4483
+ visit(node.update, callback);
4484
+ return;
4485
+ case "Foreach":
4486
+ visit(node.source, callback);
4487
+ visit(node.init, callback);
4488
+ visit(node.update, callback);
4489
+ if (node.extract) visit(node.extract, callback);
4490
+ return;
4491
+ case "Try":
4492
+ visit(node.body, callback);
4493
+ if (node.handler) visit(node.handler, callback);
4494
+ return;
4495
+ case "Assignment":
4496
+ visit(node.left, callback);
4497
+ visit(node.right, callback);
4498
+ return;
4499
+ case "Def":
4500
+ visit(node.body, callback);
4501
+ visit(node.next, callback);
4502
+ return;
4503
+ case "Label":
4504
+ visit(node.body, callback);
4505
+ return;
4506
+ default: return node;
4507
+ }
4508
+ };
4509
+ const visitObjectEntry = (entry, callback) => {
4510
+ visitObjectKey(entry.key, callback);
4511
+ visit(entry.value, callback);
4512
+ };
4513
+ const visitObjectKey = (key, callback) => {
4514
+ if (key.kind === "KeyExpr") visit(key.expr, callback);
4515
+ };
3720
4516
  //#endregion
3721
4517
  //#region src/index.ts
3722
4518
  /**
@@ -3736,15 +4532,17 @@ const run = (source, input, options = {}) => {
3736
4532
  validate(ast);
3737
4533
  return runAst(ast, input, options);
3738
4534
  };
3739
-
3740
4535
  //#endregion
3741
4536
  exports.LexError = LexError;
3742
4537
  exports.LimitTracker = LimitTracker;
3743
4538
  exports.ParseError = ParseError;
3744
4539
  exports.RuntimeError = RuntimeError;
3745
4540
  exports.ValidationError = ValidationError;
4541
+ exports.analyzeCompatibility = analyzeCompatibility;
4542
+ exports.checkCompatibility = checkCompatibility;
4543
+ exports.compareWithJq = compareWithJq;
3746
4544
  exports.parse = parse;
3747
4545
  exports.resolveLimits = resolveLimits;
3748
4546
  exports.run = run;
3749
4547
  exports.runAst = runAst;
3750
- exports.validate = validate;
4548
+ exports.validate = validate;