@gabrielbryk/jq-ts 1.3.6 → 1.5.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/README.md +1 -0
- package/dist/index.cjs +2375 -1024
- package/dist/index.d.cts +118 -6
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +118 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2220 -871
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
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
|
/**
|
|
@@ -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
|
|
451
|
-
this.consume("Pipe", "Expected \"|\" after
|
|
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
|
-
|
|
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")) {
|
|
@@ -693,10 +764,7 @@ var Parser = class {
|
|
|
693
764
|
expr = {
|
|
694
765
|
kind: "Try",
|
|
695
766
|
body: expr,
|
|
696
|
-
handler:
|
|
697
|
-
kind: "Identity",
|
|
698
|
-
span: op.span
|
|
699
|
-
},
|
|
767
|
+
handler: void 0,
|
|
700
768
|
span: spanBetween(expr.span, op.span)
|
|
701
769
|
};
|
|
702
770
|
continue;
|
|
@@ -754,8 +822,8 @@ var Parser = class {
|
|
|
754
822
|
parseReduce(start) {
|
|
755
823
|
const source = this.parsePipe();
|
|
756
824
|
this.consume("As", "Expected \"as\" after reduce source");
|
|
757
|
-
const
|
|
758
|
-
this.consume("LParen", "Expected \"(\" after
|
|
825
|
+
const pattern = this.parseBindingPattern();
|
|
826
|
+
this.consume("LParen", "Expected \"(\" after binding pattern");
|
|
759
827
|
const init = this.parseComma();
|
|
760
828
|
this.consume("Semicolon", "Expected \";\" after init");
|
|
761
829
|
const update = this.parseComma();
|
|
@@ -763,7 +831,7 @@ var Parser = class {
|
|
|
763
831
|
return {
|
|
764
832
|
kind: "Reduce",
|
|
765
833
|
source,
|
|
766
|
-
|
|
834
|
+
pattern,
|
|
767
835
|
init,
|
|
768
836
|
update,
|
|
769
837
|
span: spanBetween(start.span, end.span)
|
|
@@ -772,8 +840,8 @@ var Parser = class {
|
|
|
772
840
|
parseForeach(start) {
|
|
773
841
|
const source = this.parsePipe();
|
|
774
842
|
this.consume("As", "Expected \"as\" after foreach source");
|
|
775
|
-
const
|
|
776
|
-
this.consume("LParen", "Expected \"(\" after
|
|
843
|
+
const pattern = this.parseBindingPattern();
|
|
844
|
+
this.consume("LParen", "Expected \"(\" after binding pattern");
|
|
777
845
|
const init = this.parseComma();
|
|
778
846
|
this.consume("Semicolon", "Expected \";\" after init");
|
|
779
847
|
const update = this.parseComma();
|
|
@@ -783,7 +851,7 @@ var Parser = class {
|
|
|
783
851
|
return {
|
|
784
852
|
kind: "Foreach",
|
|
785
853
|
source,
|
|
786
|
-
|
|
854
|
+
pattern,
|
|
787
855
|
init,
|
|
788
856
|
update,
|
|
789
857
|
extract,
|
|
@@ -1005,10 +1073,7 @@ var Parser = class {
|
|
|
1005
1073
|
expr = {
|
|
1006
1074
|
kind: "Try",
|
|
1007
1075
|
body: expr,
|
|
1008
|
-
handler:
|
|
1009
|
-
kind: "Identity",
|
|
1010
|
-
span: op.span
|
|
1011
|
-
},
|
|
1076
|
+
handler: void 0,
|
|
1012
1077
|
span: spanBetween(expr.span, op.span)
|
|
1013
1078
|
};
|
|
1014
1079
|
continue;
|
|
@@ -1154,7 +1219,6 @@ const spanBetween = (a, b) => ({
|
|
|
1154
1219
|
start: Math.min(a.start, b.start),
|
|
1155
1220
|
end: Math.max(a.end, b.end)
|
|
1156
1221
|
});
|
|
1157
|
-
|
|
1158
1222
|
//#endregion
|
|
1159
1223
|
//#region src/builtins/registry.ts
|
|
1160
1224
|
const builtins = {};
|
|
@@ -1165,7 +1229,6 @@ const registerBuiltin = (spec) => {
|
|
|
1165
1229
|
const registerBuiltins = (specs) => {
|
|
1166
1230
|
for (const spec of specs) registerBuiltin(spec);
|
|
1167
1231
|
};
|
|
1168
|
-
|
|
1169
1232
|
//#endregion
|
|
1170
1233
|
//#region src/value.ts
|
|
1171
1234
|
/**
|
|
@@ -1192,7 +1255,7 @@ const valueEquals = (a, b) => {
|
|
|
1192
1255
|
for (let i = 0; i < a.length; i += 1) if (!valueEquals(a[i], b[i])) return false;
|
|
1193
1256
|
return true;
|
|
1194
1257
|
}
|
|
1195
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
1258
|
+
if (isPlainObject$1(a) && isPlainObject$1(b)) {
|
|
1196
1259
|
const aKeys = Object.keys(a).sort();
|
|
1197
1260
|
const bKeys = Object.keys(b).sort();
|
|
1198
1261
|
if (aKeys.length !== bKeys.length) return false;
|
|
@@ -1229,7 +1292,7 @@ const compareValues = (a, b) => {
|
|
|
1229
1292
|
}
|
|
1230
1293
|
return a.length < b.length ? -1 : 1;
|
|
1231
1294
|
}
|
|
1232
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
1295
|
+
if (isPlainObject$1(a) && isPlainObject$1(b)) {
|
|
1233
1296
|
const aKeys = Object.keys(a).sort();
|
|
1234
1297
|
const bKeys = Object.keys(b).sort();
|
|
1235
1298
|
const len = Math.min(aKeys.length, bKeys.length);
|
|
@@ -1263,7 +1326,7 @@ const typeRank = (value) => {
|
|
|
1263
1326
|
* @param value - The value to check.
|
|
1264
1327
|
* @returns `true` if `value` is a non-null object (and not an array).
|
|
1265
1328
|
*/
|
|
1266
|
-
const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1329
|
+
const isPlainObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1267
1330
|
/**
|
|
1268
1331
|
* Checks if a value is a JSON array.
|
|
1269
1332
|
*
|
|
@@ -1286,7 +1349,6 @@ const describeType = (value) => {
|
|
|
1286
1349
|
if (Array.isArray(value)) return "array";
|
|
1287
1350
|
return "object";
|
|
1288
1351
|
};
|
|
1289
|
-
|
|
1290
1352
|
//#endregion
|
|
1291
1353
|
//#region src/builtins/utils.ts
|
|
1292
1354
|
const emit$1 = (value, span, tracker) => {
|
|
@@ -1308,7 +1370,6 @@ const stableStringify = (value) => {
|
|
|
1308
1370
|
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
1309
1371
|
return `{${Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(",")}}`;
|
|
1310
1372
|
};
|
|
1311
|
-
|
|
1312
1373
|
//#endregion
|
|
1313
1374
|
//#region src/builtins/std.ts
|
|
1314
1375
|
const toJqString = (value) => {
|
|
@@ -1354,9 +1415,87 @@ const stdBuiltins = [
|
|
|
1354
1415
|
if (typeof input === "string") yield emit$1(Array.from(input).length, span, tracker);
|
|
1355
1416
|
else if (Array.isArray(input)) yield emit$1(input.length, span, tracker);
|
|
1356
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);
|
|
1357
1419
|
else throw new RuntimeError(`Cannot take length of ${describeType(input)}`, span);
|
|
1358
1420
|
}
|
|
1359
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
|
+
},
|
|
1360
1499
|
{
|
|
1361
1500
|
name: "empty",
|
|
1362
1501
|
arity: 0,
|
|
@@ -1379,7 +1518,7 @@ const stdBuiltins = [
|
|
|
1379
1518
|
{
|
|
1380
1519
|
name: "walk",
|
|
1381
1520
|
arity: 1,
|
|
1382
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1521
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
1383
1522
|
const f = args[0];
|
|
1384
1523
|
const walkRec = function* (curr) {
|
|
1385
1524
|
tracker.step(span);
|
|
@@ -1388,7 +1527,7 @@ const stdBuiltins = [
|
|
|
1388
1527
|
const newArr = [];
|
|
1389
1528
|
for (const item of curr) for (const walkedItem of walkRec(item)) newArr.push(walkedItem);
|
|
1390
1529
|
newStruct = newArr;
|
|
1391
|
-
} else if (isPlainObject(curr)) {
|
|
1530
|
+
} else if (isPlainObject$1(curr)) {
|
|
1392
1531
|
const newObj = {};
|
|
1393
1532
|
const keys = Object.keys(curr).sort();
|
|
1394
1533
|
let objValid = true;
|
|
@@ -1409,23 +1548,27 @@ const stdBuiltins = [
|
|
|
1409
1548
|
if (!objValid) return;
|
|
1410
1549
|
newStruct = newObj;
|
|
1411
1550
|
}
|
|
1412
|
-
yield* evaluate
|
|
1551
|
+
yield* evaluate(f, newStruct, env, tracker);
|
|
1413
1552
|
};
|
|
1414
1553
|
yield* walkRec(input);
|
|
1415
1554
|
}
|
|
1416
1555
|
}
|
|
1417
1556
|
];
|
|
1418
|
-
|
|
1419
1557
|
//#endregion
|
|
1420
1558
|
//#region src/builtins/errors.ts
|
|
1421
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
|
+
}, {
|
|
1422
1566
|
name: "error",
|
|
1423
1567
|
arity: 1,
|
|
1424
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1425
|
-
for (const msg of evaluate
|
|
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);
|
|
1426
1570
|
}
|
|
1427
1571
|
}];
|
|
1428
|
-
|
|
1429
1572
|
//#endregion
|
|
1430
1573
|
//#region src/builtins/strings.ts
|
|
1431
1574
|
const checkContains = (a, b) => {
|
|
@@ -1433,7 +1576,7 @@ const checkContains = (a, b) => {
|
|
|
1433
1576
|
if (typeof a !== typeof b) return false;
|
|
1434
1577
|
if (typeof a === "string" && typeof b === "string") return a.includes(b);
|
|
1435
1578
|
if (Array.isArray(a) && Array.isArray(b)) return b.every((bItem) => a.some((aItem) => checkContains(aItem, bItem)));
|
|
1436
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
1579
|
+
if (isPlainObject$1(a) && isPlainObject$1(b)) {
|
|
1437
1580
|
const keys = Object.keys(b);
|
|
1438
1581
|
for (const key of keys) {
|
|
1439
1582
|
if (!Object.prototype.hasOwnProperty.call(a, key)) return false;
|
|
@@ -1449,9 +1592,9 @@ const stringBuiltins = [
|
|
|
1449
1592
|
{
|
|
1450
1593
|
name: "split",
|
|
1451
1594
|
arity: 1,
|
|
1452
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1595
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
1453
1596
|
if (typeof input !== "string") throw new RuntimeError("split input must be a string", span);
|
|
1454
|
-
const sepGen = evaluate
|
|
1597
|
+
const sepGen = evaluate(args[0], input, env, tracker);
|
|
1455
1598
|
for (const sep of sepGen) {
|
|
1456
1599
|
if (typeof sep !== "string") throw new RuntimeError("split separator must be a string", span);
|
|
1457
1600
|
yield emit$1(input.split(sep), span, tracker);
|
|
@@ -1461,16 +1604,15 @@ const stringBuiltins = [
|
|
|
1461
1604
|
{
|
|
1462
1605
|
name: "join",
|
|
1463
1606
|
arity: 1,
|
|
1464
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1607
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
1465
1608
|
if (!Array.isArray(input)) throw new RuntimeError("join input must be an array", span);
|
|
1466
|
-
const sepGen = evaluate
|
|
1609
|
+
const sepGen = evaluate(args[0], input, env, tracker);
|
|
1467
1610
|
for (const sep of sepGen) {
|
|
1468
1611
|
if (typeof sep !== "string") throw new RuntimeError("join separator must be a string", span);
|
|
1469
1612
|
const parts = [];
|
|
1470
|
-
for (const item of input)
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
}
|
|
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);
|
|
1474
1616
|
yield emit$1(parts.join(sep), span, tracker);
|
|
1475
1617
|
}
|
|
1476
1618
|
}
|
|
@@ -1478,9 +1620,9 @@ const stringBuiltins = [
|
|
|
1478
1620
|
{
|
|
1479
1621
|
name: "startswith",
|
|
1480
1622
|
arity: 1,
|
|
1481
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1623
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
1482
1624
|
if (typeof input !== "string") throw new RuntimeError("startswith input must be a string", span);
|
|
1483
|
-
const prefixGen = evaluate
|
|
1625
|
+
const prefixGen = evaluate(args[0], input, env, tracker);
|
|
1484
1626
|
for (const prefix of prefixGen) {
|
|
1485
1627
|
if (typeof prefix !== "string") throw new RuntimeError("startswith prefix must be a string", span);
|
|
1486
1628
|
yield emit$1(input.startsWith(prefix), span, tracker);
|
|
@@ -1490,9 +1632,9 @@ const stringBuiltins = [
|
|
|
1490
1632
|
{
|
|
1491
1633
|
name: "endswith",
|
|
1492
1634
|
arity: 1,
|
|
1493
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1635
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
1494
1636
|
if (typeof input !== "string") throw new RuntimeError("endswith input must be a string", span);
|
|
1495
|
-
const suffixGen = evaluate
|
|
1637
|
+
const suffixGen = evaluate(args[0], input, env, tracker);
|
|
1496
1638
|
for (const suffix of suffixGen) {
|
|
1497
1639
|
if (typeof suffix !== "string") throw new RuntimeError("endswith suffix must be a string", span);
|
|
1498
1640
|
yield emit$1(input.endsWith(suffix), span, tracker);
|
|
@@ -1502,16 +1644,16 @@ const stringBuiltins = [
|
|
|
1502
1644
|
{
|
|
1503
1645
|
name: "contains",
|
|
1504
1646
|
arity: 1,
|
|
1505
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1506
|
-
const bGen = evaluate
|
|
1647
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
1648
|
+
const bGen = evaluate(args[0], input, env, tracker);
|
|
1507
1649
|
for (const b of bGen) yield emit$1(checkContains(input, b), span, tracker);
|
|
1508
1650
|
}
|
|
1509
1651
|
},
|
|
1510
1652
|
{
|
|
1511
1653
|
name: "index",
|
|
1512
1654
|
arity: 1,
|
|
1513
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1514
|
-
const searchGen = evaluate
|
|
1655
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
1656
|
+
const searchGen = evaluate(args[0], input, env, tracker);
|
|
1515
1657
|
for (const search of searchGen) if (Array.isArray(input)) {
|
|
1516
1658
|
let foundIndex = null;
|
|
1517
1659
|
for (let i = 0; i < input.length; i++) {
|
|
@@ -1533,8 +1675,8 @@ const stringBuiltins = [
|
|
|
1533
1675
|
{
|
|
1534
1676
|
name: "rindex",
|
|
1535
1677
|
arity: 1,
|
|
1536
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1537
|
-
const searchGen = evaluate
|
|
1678
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
1679
|
+
const searchGen = evaluate(args[0], input, env, tracker);
|
|
1538
1680
|
for (const search of searchGen) if (Array.isArray(input)) {
|
|
1539
1681
|
let foundIndex = null;
|
|
1540
1682
|
for (let i = input.length - 1; i >= 0; i--) {
|
|
@@ -1556,8 +1698,8 @@ const stringBuiltins = [
|
|
|
1556
1698
|
{
|
|
1557
1699
|
name: "indices",
|
|
1558
1700
|
arity: 1,
|
|
1559
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1560
|
-
const searchGen = evaluate
|
|
1701
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
1702
|
+
const searchGen = evaluate(args[0], input, env, tracker);
|
|
1561
1703
|
for (const search of searchGen) {
|
|
1562
1704
|
const indices = [];
|
|
1563
1705
|
if (Array.isArray(input)) for (let i = 0; i < input.length; i++) {
|
|
@@ -1595,6 +1737,14 @@ const stringBuiltins = [
|
|
|
1595
1737
|
yield emit$1(Array.from(input).map((c) => c.codePointAt(0)), span, tracker);
|
|
1596
1738
|
}
|
|
1597
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
|
+
},
|
|
1598
1748
|
{
|
|
1599
1749
|
name: "implode",
|
|
1600
1750
|
arity: 0,
|
|
@@ -1611,9 +1761,9 @@ const stringBuiltins = [
|
|
|
1611
1761
|
{
|
|
1612
1762
|
name: "ltrimstr",
|
|
1613
1763
|
arity: 1,
|
|
1614
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1764
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
1615
1765
|
if (typeof input !== "string") throw new RuntimeError("ltrimstr expects string", span);
|
|
1616
|
-
const prefixGen = evaluate
|
|
1766
|
+
const prefixGen = evaluate(args[0], input, env, tracker);
|
|
1617
1767
|
for (const prefix of prefixGen) {
|
|
1618
1768
|
if (typeof prefix !== "string") throw new RuntimeError("ltrimstr prefix must be a string", span);
|
|
1619
1769
|
if (input.startsWith(prefix)) yield emit$1(input.slice(prefix.length), span, tracker);
|
|
@@ -1622,435 +1772,103 @@ const stringBuiltins = [
|
|
|
1622
1772
|
}
|
|
1623
1773
|
},
|
|
1624
1774
|
{
|
|
1625
|
-
name: "
|
|
1775
|
+
name: "trimstr",
|
|
1626
1776
|
arity: 1,
|
|
1627
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1628
|
-
if (typeof input !== "string") throw new RuntimeError("
|
|
1629
|
-
const
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
if (
|
|
1633
|
-
|
|
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);
|
|
1634
1785
|
}
|
|
1635
1786
|
}
|
|
1636
1787
|
},
|
|
1637
1788
|
{
|
|
1638
|
-
name: "
|
|
1789
|
+
name: "trim",
|
|
1639
1790
|
arity: 0,
|
|
1640
1791
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1641
|
-
if (typeof input !== "string") throw new RuntimeError("
|
|
1642
|
-
yield emit$1(input.
|
|
1792
|
+
if (typeof input !== "string") throw new RuntimeError("trim expects string", span);
|
|
1793
|
+
yield emit$1(input.trim(), span, tracker);
|
|
1643
1794
|
}
|
|
1644
1795
|
},
|
|
1645
1796
|
{
|
|
1646
|
-
name: "
|
|
1797
|
+
name: "ltrim",
|
|
1647
1798
|
arity: 0,
|
|
1648
1799
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1649
|
-
if (typeof input !== "string") throw new RuntimeError("
|
|
1650
|
-
yield emit$1(input.
|
|
1800
|
+
if (typeof input !== "string") throw new RuntimeError("ltrim expects string", span);
|
|
1801
|
+
yield emit$1(input.trimStart(), span, tracker);
|
|
1651
1802
|
}
|
|
1652
|
-
}
|
|
1653
|
-
];
|
|
1654
|
-
|
|
1655
|
-
//#endregion
|
|
1656
|
-
//#region src/builtins/collections.ts
|
|
1657
|
-
function sortStable(arr, compare$1) {
|
|
1658
|
-
return arr.map((item, index) => ({
|
|
1659
|
-
item,
|
|
1660
|
-
index
|
|
1661
|
-
})).sort((a, b) => {
|
|
1662
|
-
const cmp = compare$1(a.item, b.item);
|
|
1663
|
-
return cmp !== 0 ? cmp : a.index - b.index;
|
|
1664
|
-
}).map((p) => p.item);
|
|
1665
|
-
}
|
|
1666
|
-
const collectionBuiltins = [
|
|
1803
|
+
},
|
|
1667
1804
|
{
|
|
1668
|
-
name: "
|
|
1805
|
+
name: "rtrim",
|
|
1669
1806
|
arity: 0,
|
|
1670
1807
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1671
|
-
if (
|
|
1672
|
-
|
|
1673
|
-
else throw new RuntimeError(`keys expects an array or object`, span);
|
|
1674
|
-
}
|
|
1675
|
-
},
|
|
1676
|
-
{
|
|
1677
|
-
name: "has",
|
|
1678
|
-
arity: 1,
|
|
1679
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1680
|
-
const keyFilter = args[0];
|
|
1681
|
-
for (const key of evaluate$1(keyFilter, input, env, tracker)) if (Array.isArray(input)) {
|
|
1682
|
-
const idx = ensureIndex(key);
|
|
1683
|
-
yield emit$1(idx !== void 0 && idx >= 0 && idx < input.length, span, tracker);
|
|
1684
|
-
} else if (input !== null && typeof input === "object") {
|
|
1685
|
-
let keyStr;
|
|
1686
|
-
if (typeof key === "string") keyStr = key;
|
|
1687
|
-
else if (typeof key === "number") keyStr = key.toString();
|
|
1688
|
-
else throw new RuntimeError(`has() key must be string or number for object input`, span);
|
|
1689
|
-
yield emit$1(Object.prototype.hasOwnProperty.call(input, keyStr), span, tracker);
|
|
1690
|
-
} else throw new RuntimeError(`has() expects an array or object input`, span);
|
|
1691
|
-
}
|
|
1692
|
-
},
|
|
1693
|
-
{
|
|
1694
|
-
name: "map",
|
|
1695
|
-
arity: 1,
|
|
1696
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1697
|
-
if (!Array.isArray(input)) throw new RuntimeError("map expects an array", span);
|
|
1698
|
-
const result = [];
|
|
1699
|
-
const filter = args[0];
|
|
1700
|
-
for (const item of input) {
|
|
1701
|
-
tracker.step(span);
|
|
1702
|
-
for (const output of evaluate$1(filter, item, env, tracker)) result.push(output);
|
|
1703
|
-
}
|
|
1704
|
-
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);
|
|
1705
1810
|
}
|
|
1706
1811
|
},
|
|
1707
1812
|
{
|
|
1708
|
-
name: "
|
|
1813
|
+
name: "rtrimstr",
|
|
1709
1814
|
arity: 1,
|
|
1710
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
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);
|
|
1715
1822
|
}
|
|
1716
1823
|
}
|
|
1717
1824
|
},
|
|
1718
1825
|
{
|
|
1719
|
-
name: "
|
|
1826
|
+
name: "ascii_downcase",
|
|
1720
1827
|
arity: 0,
|
|
1721
1828
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1722
|
-
if (
|
|
1723
|
-
|
|
1724
|
-
tracker.step(span);
|
|
1725
|
-
yield emit$1(sorted, span, tracker);
|
|
1726
|
-
}
|
|
1727
|
-
},
|
|
1728
|
-
{
|
|
1729
|
-
name: "sort_by",
|
|
1730
|
-
arity: 1,
|
|
1731
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1732
|
-
if (!Array.isArray(input)) throw new RuntimeError("sort_by expects an array", span);
|
|
1733
|
-
const filter = args[0];
|
|
1734
|
-
const pairs = [];
|
|
1735
|
-
for (const item of input) {
|
|
1736
|
-
tracker.step(span);
|
|
1737
|
-
const keys = Array.from(evaluate$1(filter, item, env, tracker));
|
|
1738
|
-
if (keys.length !== 1) throw new RuntimeError("sort_by key expression must return exactly one value", span);
|
|
1739
|
-
pairs.push({
|
|
1740
|
-
val: item,
|
|
1741
|
-
key: keys[0]
|
|
1742
|
-
});
|
|
1743
|
-
}
|
|
1744
|
-
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);
|
|
1745
1831
|
}
|
|
1746
1832
|
},
|
|
1747
1833
|
{
|
|
1748
|
-
name: "
|
|
1834
|
+
name: "ascii_upcase",
|
|
1749
1835
|
arity: 0,
|
|
1750
1836
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1751
|
-
if (
|
|
1752
|
-
|
|
1753
|
-
const result = [];
|
|
1754
|
-
for (const item of input) {
|
|
1755
|
-
tracker.step(span);
|
|
1756
|
-
if (!seen.some((s) => valueEquals(s, item))) {
|
|
1757
|
-
seen.push(item);
|
|
1758
|
-
result.push(item);
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
yield emit$1(result, span, tracker);
|
|
1762
|
-
}
|
|
1763
|
-
},
|
|
1764
|
-
{
|
|
1765
|
-
name: "unique_by",
|
|
1766
|
-
arity: 1,
|
|
1767
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1768
|
-
if (!Array.isArray(input)) throw new RuntimeError("unique_by expects an array", span);
|
|
1769
|
-
const filter = args[0];
|
|
1770
|
-
const seenKeys = [];
|
|
1771
|
-
const result = [];
|
|
1772
|
-
for (const item of input) {
|
|
1773
|
-
tracker.step(span);
|
|
1774
|
-
const keys = Array.from(evaluate$1(filter, item, env, tracker));
|
|
1775
|
-
if (keys.length !== 1) throw new RuntimeError("unique_by key expression must return exactly one value", span);
|
|
1776
|
-
const key = keys[0];
|
|
1777
|
-
if (!seenKeys.some((s) => valueEquals(s, key))) {
|
|
1778
|
-
seenKeys.push(key);
|
|
1779
|
-
result.push(item);
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
|
-
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);
|
|
1783
1839
|
}
|
|
1784
1840
|
},
|
|
1785
1841
|
{
|
|
1786
|
-
name: "
|
|
1842
|
+
name: "tojson",
|
|
1787
1843
|
arity: 0,
|
|
1788
1844
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1789
|
-
|
|
1790
|
-
key: i,
|
|
1791
|
-
value: v
|
|
1792
|
-
})), span, tracker);
|
|
1793
|
-
else if (input !== null && typeof input === "object") yield emit$1(Object.keys(input).sort().map((k) => ({
|
|
1794
|
-
key: k,
|
|
1795
|
-
value: input[k]
|
|
1796
|
-
})), span, tracker);
|
|
1797
|
-
else throw new RuntimeError("to_entries expects array or object", span);
|
|
1845
|
+
yield emit$1(stableStringify(input), span, tracker);
|
|
1798
1846
|
}
|
|
1799
1847
|
},
|
|
1800
1848
|
{
|
|
1801
|
-
name: "
|
|
1849
|
+
name: "fromjson",
|
|
1802
1850
|
arity: 0,
|
|
1803
1851
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1804
|
-
if (
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
const obj = item;
|
|
1810
|
-
if (!("key" in obj) || !("value" in obj)) throw new RuntimeError("from_entries items must have \"key\" and \"value\"", span);
|
|
1811
|
-
const key = obj["key"];
|
|
1812
|
-
if (typeof key !== "string") throw new RuntimeError("from_entries object keys must be strings", span);
|
|
1813
|
-
result[key] = obj["value"];
|
|
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);
|
|
1814
1857
|
}
|
|
1815
|
-
yield emit$1(result, span, tracker);
|
|
1816
|
-
}
|
|
1817
|
-
},
|
|
1818
|
-
{
|
|
1819
|
-
name: "with_entries",
|
|
1820
|
-
arity: 1,
|
|
1821
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1822
|
-
let entries;
|
|
1823
|
-
if (Array.isArray(input)) entries = input.map((v, i) => ({
|
|
1824
|
-
key: i,
|
|
1825
|
-
value: v
|
|
1826
|
-
}));
|
|
1827
|
-
else if (input !== null && typeof input === "object") entries = Object.keys(input).sort().map((k) => ({
|
|
1828
|
-
key: k,
|
|
1829
|
-
value: input[k]
|
|
1830
|
-
}));
|
|
1831
|
-
else throw new RuntimeError("with_entries expects array or object", span);
|
|
1832
|
-
const transformed = [];
|
|
1833
|
-
const filter = args[0];
|
|
1834
|
-
for (const entry of entries) {
|
|
1835
|
-
tracker.step(span);
|
|
1836
|
-
for (const outVar of evaluate$1(filter, entry, env, tracker)) transformed.push(outVar);
|
|
1837
|
-
}
|
|
1838
|
-
const result = {};
|
|
1839
|
-
for (const item of transformed) {
|
|
1840
|
-
if (item === null || typeof item !== "object" || Array.isArray(item)) throw new RuntimeError("with_entries filter must produce objects", span);
|
|
1841
|
-
const obj = item;
|
|
1842
|
-
if (!("key" in obj) || !("value" in obj)) throw new RuntimeError("with_entries items must have \"key\" and \"value\"", span);
|
|
1843
|
-
const key = obj["key"];
|
|
1844
|
-
if (typeof key !== "string") throw new RuntimeError("with_entries keys must be strings", span);
|
|
1845
|
-
result[key] = obj["value"];
|
|
1846
|
-
}
|
|
1847
|
-
yield emit$1(result, span, tracker);
|
|
1848
|
-
}
|
|
1849
|
-
},
|
|
1850
|
-
{
|
|
1851
|
-
name: "group_by",
|
|
1852
|
-
arity: 1,
|
|
1853
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1854
|
-
if (!Array.isArray(input)) throw new RuntimeError("group_by expects an array", span);
|
|
1855
|
-
const pairs = [];
|
|
1856
|
-
const filter = args[0];
|
|
1857
|
-
for (const item of input) {
|
|
1858
|
-
tracker.step(span);
|
|
1859
|
-
const keys = Array.from(evaluate$1(filter, item, env, tracker));
|
|
1860
|
-
if (keys.length !== 1) throw new RuntimeError("group_by key expression must return exactly one value", span);
|
|
1861
|
-
pairs.push({
|
|
1862
|
-
val: item,
|
|
1863
|
-
key: keys[0]
|
|
1864
|
-
});
|
|
1865
|
-
}
|
|
1866
|
-
const sorted = sortStable(pairs, (a, b) => compareValues(a.key, b.key));
|
|
1867
|
-
const groups = [];
|
|
1868
|
-
if (sorted.length > 0) {
|
|
1869
|
-
let currentGroup = [sorted[0].val];
|
|
1870
|
-
let currentKey = sorted[0].key;
|
|
1871
|
-
for (let i = 1; i < sorted.length; i++) {
|
|
1872
|
-
const pair = sorted[i];
|
|
1873
|
-
if (compareValues(pair.key, currentKey) === 0) currentGroup.push(pair.val);
|
|
1874
|
-
else {
|
|
1875
|
-
groups.push(currentGroup);
|
|
1876
|
-
currentGroup = [pair.val];
|
|
1877
|
-
currentKey = pair.key;
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
groups.push(currentGroup);
|
|
1881
|
-
}
|
|
1882
|
-
yield emit$1(groups, span, tracker);
|
|
1883
|
-
}
|
|
1884
|
-
},
|
|
1885
|
-
{
|
|
1886
|
-
name: "reverse",
|
|
1887
|
-
arity: 0,
|
|
1888
|
-
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1889
|
-
if (!Array.isArray(input)) throw new RuntimeError("reverse expects an array", span);
|
|
1890
|
-
yield emit$1([...input].reverse(), span, tracker);
|
|
1891
|
-
}
|
|
1892
|
-
},
|
|
1893
|
-
{
|
|
1894
|
-
name: "flatten",
|
|
1895
|
-
arity: 0,
|
|
1896
|
-
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1897
|
-
if (!Array.isArray(input)) throw new RuntimeError("flatten expects an array", span);
|
|
1898
|
-
const flattenRec = (arr) => {
|
|
1899
|
-
let res = [];
|
|
1900
|
-
for (const item of arr) if (Array.isArray(item)) res = res.concat(flattenRec(item));
|
|
1901
|
-
else res.push(item);
|
|
1902
|
-
return res;
|
|
1903
|
-
};
|
|
1904
|
-
yield emit$1(flattenRec(input), span, tracker);
|
|
1905
|
-
}
|
|
1906
|
-
},
|
|
1907
|
-
{
|
|
1908
|
-
name: "flatten",
|
|
1909
|
-
arity: 1,
|
|
1910
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1911
|
-
if (!Array.isArray(input)) throw new RuntimeError("flatten expects an array", span);
|
|
1912
|
-
const depths = evaluate$1(args[0], input, env, tracker);
|
|
1913
|
-
for (const depthVal of depths) {
|
|
1914
|
-
if (typeof depthVal !== "number") throw new RuntimeError("flatten depth must be a number", span);
|
|
1915
|
-
const flattenDepth = (arr, d) => {
|
|
1916
|
-
if (d <= 0) return arr;
|
|
1917
|
-
let res = [];
|
|
1918
|
-
for (const item of arr) if (Array.isArray(item)) res = res.concat(flattenDepth(item, d - 1));
|
|
1919
|
-
else res.push(item);
|
|
1920
|
-
return res;
|
|
1921
|
-
};
|
|
1922
|
-
yield emit$1(flattenDepth(input, depthVal), span, tracker);
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
},
|
|
1926
|
-
{
|
|
1927
|
-
name: "keys_unsorted",
|
|
1928
|
-
arity: 0,
|
|
1929
|
-
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1930
|
-
if (Array.isArray(input)) yield emit$1(Array.from({ length: input.length }, (_, i) => i), span, tracker);
|
|
1931
|
-
else if (input !== null && typeof input === "object") yield emit$1(Object.keys(input), span, tracker);
|
|
1932
|
-
else throw new RuntimeError(`keys_unsorted expects an array or object`, span);
|
|
1933
|
-
}
|
|
1934
|
-
},
|
|
1935
|
-
{
|
|
1936
|
-
name: "transpose",
|
|
1937
|
-
arity: 0,
|
|
1938
|
-
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1939
|
-
if (!Array.isArray(input)) throw new RuntimeError("transpose expects an array", span);
|
|
1940
|
-
const arr = input;
|
|
1941
|
-
if (arr.length === 0) {
|
|
1942
|
-
yield emit$1([], span, tracker);
|
|
1943
|
-
return;
|
|
1944
|
-
}
|
|
1945
|
-
let maxLen = 0;
|
|
1946
|
-
for (const row of arr) {
|
|
1947
|
-
if (!Array.isArray(row)) throw new RuntimeError("transpose input must be array of arrays", span);
|
|
1948
|
-
if (row.length > maxLen) maxLen = row.length;
|
|
1949
|
-
}
|
|
1950
|
-
const result = [];
|
|
1951
|
-
for (let j = 0; j < maxLen; j++) {
|
|
1952
|
-
const newRow = [];
|
|
1953
|
-
for (let i = 0; i < arr.length; i++) {
|
|
1954
|
-
const row = arr[i];
|
|
1955
|
-
const val = j < row.length ? row[j] : null;
|
|
1956
|
-
newRow.push(val);
|
|
1957
|
-
}
|
|
1958
|
-
result.push(newRow);
|
|
1959
|
-
}
|
|
1960
|
-
yield emit$1(result, span, tracker);
|
|
1961
|
-
}
|
|
1962
|
-
},
|
|
1963
|
-
{
|
|
1964
|
-
name: "bsearch",
|
|
1965
|
-
arity: 1,
|
|
1966
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1967
|
-
if (!Array.isArray(input)) throw new RuntimeError("bsearch expects an array", span);
|
|
1968
|
-
const targetGen = evaluate$1(args[0], input, env, tracker);
|
|
1969
|
-
for (const target of targetGen) {
|
|
1970
|
-
let low = 0;
|
|
1971
|
-
let high = input.length - 1;
|
|
1972
|
-
let idx = -1;
|
|
1973
|
-
while (low <= high) {
|
|
1974
|
-
const mid = Math.floor((low + high) / 2);
|
|
1975
|
-
const cmp = compareValues(input[mid], target);
|
|
1976
|
-
if (cmp === 0) {
|
|
1977
|
-
idx = mid;
|
|
1978
|
-
break;
|
|
1979
|
-
} else if (cmp < 0) low = mid + 1;
|
|
1980
|
-
else high = mid - 1;
|
|
1981
|
-
}
|
|
1982
|
-
if (idx !== -1) yield emit$1(idx, span, tracker);
|
|
1983
|
-
else yield emit$1(-low - 1, span, tracker);
|
|
1984
|
-
}
|
|
1985
|
-
}
|
|
1986
|
-
},
|
|
1987
|
-
{
|
|
1988
|
-
name: "combinations",
|
|
1989
|
-
arity: 0,
|
|
1990
|
-
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1991
|
-
if (!Array.isArray(input)) throw new RuntimeError("combinations expects an array", span);
|
|
1992
|
-
if (input.some((x) => !Array.isArray(x))) throw new RuntimeError("combinations input must be array of arrays", span);
|
|
1993
|
-
const arrays = input;
|
|
1994
|
-
if (arrays.length === 0) {
|
|
1995
|
-
yield emit$1([], span, tracker);
|
|
1996
|
-
return;
|
|
1997
|
-
}
|
|
1998
|
-
const helper = function* (idx, current) {
|
|
1999
|
-
if (idx === arrays.length) {
|
|
2000
|
-
yield [...current];
|
|
2001
|
-
return;
|
|
2002
|
-
}
|
|
2003
|
-
const arr = arrays[idx];
|
|
2004
|
-
if (arr.length === 0) return;
|
|
2005
|
-
for (const item of arr) {
|
|
2006
|
-
current.push(item);
|
|
2007
|
-
yield* helper(idx + 1, current);
|
|
2008
|
-
current.pop();
|
|
2009
|
-
}
|
|
2010
|
-
};
|
|
2011
|
-
for (const combo of helper(0, [])) yield emit$1(combo, span, tracker);
|
|
2012
|
-
}
|
|
2013
|
-
},
|
|
2014
|
-
{
|
|
2015
|
-
name: "combinations",
|
|
2016
|
-
arity: 1,
|
|
2017
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
2018
|
-
if (!Array.isArray(input)) throw new RuntimeError("combinations expects an array", span);
|
|
2019
|
-
const nGen = evaluate$1(args[0], input, env, tracker);
|
|
2020
|
-
for (const nVal of nGen) {
|
|
2021
|
-
if (typeof nVal !== "number") throw new RuntimeError("combinations(n) expects n to be number", span);
|
|
2022
|
-
if (nVal === 0) {
|
|
2023
|
-
yield emit$1([], span, tracker);
|
|
2024
|
-
continue;
|
|
2025
|
-
}
|
|
2026
|
-
const arrays = [];
|
|
2027
|
-
for (let i = 0; i < nVal; i++) arrays.push(input);
|
|
2028
|
-
const helper = function* (idx, current) {
|
|
2029
|
-
if (idx === arrays.length) {
|
|
2030
|
-
yield [...current];
|
|
2031
|
-
return;
|
|
2032
|
-
}
|
|
2033
|
-
const arr = arrays[idx];
|
|
2034
|
-
for (const item of arr) {
|
|
2035
|
-
current.push(item);
|
|
2036
|
-
yield* helper(idx + 1, current);
|
|
2037
|
-
current.pop();
|
|
2038
|
-
}
|
|
2039
|
-
};
|
|
2040
|
-
if (input.length === 0 && nVal > 0) {} else for (const combo of helper(0, [])) yield emit$1(combo, span, tracker);
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
|
-
},
|
|
2044
|
-
{
|
|
2045
|
-
name: "inside",
|
|
2046
|
-
arity: 1,
|
|
2047
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
2048
|
-
const bGen = evaluate$1(args[0], input, env, tracker);
|
|
2049
|
-
for (const b of bGen) yield emit$1(checkContains(b, input), span, tracker);
|
|
2050
1858
|
}
|
|
2051
1859
|
}
|
|
2052
1860
|
];
|
|
2053
|
-
|
|
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
|
+
};
|
|
2054
1872
|
//#endregion
|
|
2055
1873
|
//#region src/eval/path_eval.ts
|
|
2056
1874
|
/**
|
|
@@ -2063,17 +1881,17 @@ const collectionBuiltins = [
|
|
|
2063
1881
|
* @param tracker - Limits tracker.
|
|
2064
1882
|
* @param evaluate - Recursive evaluator.
|
|
2065
1883
|
*/
|
|
2066
|
-
const evaluatePath = function* (node, input, env, tracker, evaluate
|
|
1884
|
+
const evaluatePath = function* (node, input, env, tracker, evaluate) {
|
|
2067
1885
|
switch (node.kind) {
|
|
2068
1886
|
case "Identity":
|
|
2069
1887
|
yield [];
|
|
2070
1888
|
return;
|
|
2071
1889
|
case "FieldAccess":
|
|
2072
|
-
for (const parent of evaluatePath(node.target, input, env, tracker, evaluate
|
|
1890
|
+
for (const parent of evaluatePath(node.target, input, env, tracker, evaluate)) yield [...parent, node.field];
|
|
2073
1891
|
return;
|
|
2074
1892
|
case "IndexAccess": {
|
|
2075
|
-
const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate
|
|
2076
|
-
const output = evaluate
|
|
1893
|
+
const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate));
|
|
1894
|
+
const output = evaluate(node.index, input, env, tracker);
|
|
2077
1895
|
for (const keyVal of output) {
|
|
2078
1896
|
let key;
|
|
2079
1897
|
if (typeof keyVal === "string") key = keyVal;
|
|
@@ -2084,19 +1902,19 @@ const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
|
|
|
2084
1902
|
return;
|
|
2085
1903
|
}
|
|
2086
1904
|
case "Pipe": {
|
|
2087
|
-
const leftPaths = Array.from(evaluatePath(node.left, input, env, tracker, evaluate
|
|
1905
|
+
const leftPaths = Array.from(evaluatePath(node.left, input, env, tracker, evaluate));
|
|
2088
1906
|
for (const p of leftPaths) {
|
|
2089
1907
|
const val = getPath(input, p) ?? null;
|
|
2090
|
-
for (const q of evaluatePath(node.right, val, env, tracker, evaluate
|
|
1908
|
+
for (const q of evaluatePath(node.right, val, env, tracker, evaluate)) yield [...p, ...q];
|
|
2091
1909
|
}
|
|
2092
1910
|
return;
|
|
2093
1911
|
}
|
|
2094
1912
|
case "Comma":
|
|
2095
|
-
yield* evaluatePath(node.left, input, env, tracker, evaluate
|
|
2096
|
-
yield* evaluatePath(node.right, input, env, tracker, evaluate
|
|
1913
|
+
yield* evaluatePath(node.left, input, env, tracker, evaluate);
|
|
1914
|
+
yield* evaluatePath(node.right, input, env, tracker, evaluate);
|
|
2097
1915
|
return;
|
|
2098
1916
|
case "Iterate": {
|
|
2099
|
-
const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate
|
|
1917
|
+
const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate));
|
|
2100
1918
|
for (const p of parentPaths) {
|
|
2101
1919
|
const val = getPath(input, p);
|
|
2102
1920
|
if (Array.isArray(val)) for (let i = 0; i < val.length; i++) yield [...p, i];
|
|
@@ -2110,7 +1928,7 @@ const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
|
|
|
2110
1928
|
}
|
|
2111
1929
|
case "Call":
|
|
2112
1930
|
if (node.name === "select") {
|
|
2113
|
-
const conds = evaluate
|
|
1931
|
+
const conds = evaluate(node.args[0], input, env, tracker);
|
|
2114
1932
|
let matched = false;
|
|
2115
1933
|
for (const c of conds) if (c !== null && c !== false) matched = true;
|
|
2116
1934
|
if (matched) yield [];
|
|
@@ -2118,9 +1936,9 @@ const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
|
|
|
2118
1936
|
}
|
|
2119
1937
|
throw new RuntimeError(`Function ${node.name} not supported in path expression`, node.span);
|
|
2120
1938
|
case "Slice": {
|
|
2121
|
-
const parentPaths = Array.from(evaluatePath(node.target, input, env, tracker, evaluate
|
|
2122
|
-
const startRes = node.start ? Array.from(evaluate
|
|
2123
|
-
const endRes = node.end ? Array.from(evaluate
|
|
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];
|
|
2124
1942
|
for (const startVal of startRes) for (const endVal of endRes) {
|
|
2125
1943
|
const sliceSpec = {
|
|
2126
1944
|
start: typeof startVal === "number" ? startVal : null,
|
|
@@ -2132,7 +1950,7 @@ const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
|
|
|
2132
1950
|
}
|
|
2133
1951
|
case "Try":
|
|
2134
1952
|
try {
|
|
2135
|
-
yield* evaluatePath(node.body, input, env, tracker, evaluate
|
|
1953
|
+
yield* evaluatePath(node.body, input, env, tracker, evaluate);
|
|
2136
1954
|
} catch (e) {
|
|
2137
1955
|
if (!(e instanceof RuntimeError)) throw e;
|
|
2138
1956
|
}
|
|
@@ -2143,24 +1961,27 @@ const evaluatePath = function* (node, input, env, tracker, evaluate$1) {
|
|
|
2143
1961
|
default: throw new RuntimeError("Invalid path expression", node.span);
|
|
2144
1962
|
}
|
|
2145
1963
|
};
|
|
2146
|
-
|
|
2147
1964
|
//#endregion
|
|
2148
1965
|
//#region src/builtins/paths.ts
|
|
2149
1966
|
function* traversePaths(root, currentPath, span, tracker) {
|
|
2150
1967
|
tracker.step(span);
|
|
2151
|
-
if (
|
|
2152
|
-
|
|
2153
|
-
|
|
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);
|
|
2154
1972
|
}
|
|
2155
|
-
if (
|
|
2156
|
-
else if (isPlainObject(root)) {
|
|
1973
|
+
else if (isPlainObject$1(root)) {
|
|
2157
1974
|
const keys = Object.keys(root).sort();
|
|
2158
|
-
for (const key of keys)
|
|
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
|
+
}
|
|
2159
1980
|
}
|
|
2160
1981
|
}
|
|
2161
1982
|
const isPath = (val) => {
|
|
2162
1983
|
if (!Array.isArray(val)) return false;
|
|
2163
|
-
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));
|
|
2164
1985
|
};
|
|
2165
1986
|
const ensurePath = (val, span) => {
|
|
2166
1987
|
if (isPath(val)) return val;
|
|
@@ -2170,7 +1991,7 @@ const getPath = (root, path) => {
|
|
|
2170
1991
|
let curr = root;
|
|
2171
1992
|
for (const part of path) {
|
|
2172
1993
|
if (curr === null) return void 0;
|
|
2173
|
-
if (typeof part === "string" && isPlainObject(curr)) {
|
|
1994
|
+
if (typeof part === "string" && isPlainObject$1(curr)) {
|
|
2174
1995
|
if (!Object.prototype.hasOwnProperty.call(curr, part)) return void 0;
|
|
2175
1996
|
curr = curr[part];
|
|
2176
1997
|
} else if (typeof part === "number" && Array.isArray(curr)) {
|
|
@@ -2185,7 +2006,7 @@ const updatePath = (root, path, updateFn, span, depth = 0) => {
|
|
|
2185
2006
|
const [head, ...tail] = path;
|
|
2186
2007
|
if (typeof head === "string") {
|
|
2187
2008
|
let obj = {};
|
|
2188
|
-
if (isPlainObject(root)) obj = { ...root };
|
|
2009
|
+
if (isPlainObject$1(root)) obj = { ...root };
|
|
2189
2010
|
else if (root === null) obj = {};
|
|
2190
2011
|
else throw new RuntimeError(`Cannot index ${describeType(root)} with string "${head}"`, span);
|
|
2191
2012
|
const newVal = updatePath((Object.prototype.hasOwnProperty.call(obj, head) ? obj[head] : void 0) ?? null, tail, updateFn, span, depth + 1);
|
|
@@ -2225,7 +2046,7 @@ const updatePath = (root, path, updateFn, span, depth = 0) => {
|
|
|
2225
2046
|
};
|
|
2226
2047
|
const deletePaths = (root, paths, span) => {
|
|
2227
2048
|
if (paths.some((p) => p.length === 0)) return null;
|
|
2228
|
-
if (isPlainObject(root)) {
|
|
2049
|
+
if (isPlainObject$1(root)) {
|
|
2229
2050
|
const result = { ...root };
|
|
2230
2051
|
const relevantPaths = paths.filter((p) => p.length > 0 && typeof p[0] === "string");
|
|
2231
2052
|
const byKey = {};
|
|
@@ -2270,19 +2091,35 @@ const pathBuiltins = [
|
|
|
2270
2091
|
yield* traversePaths(input, [], span, tracker);
|
|
2271
2092
|
}
|
|
2272
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
|
+
},
|
|
2273
2110
|
{
|
|
2274
2111
|
name: "getpath",
|
|
2275
2112
|
arity: 1,
|
|
2276
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2277
|
-
for (const pathVal of evaluate
|
|
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);
|
|
2278
2115
|
}
|
|
2279
2116
|
},
|
|
2280
2117
|
{
|
|
2281
2118
|
name: "setpath",
|
|
2282
2119
|
arity: 2,
|
|
2283
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2284
|
-
const paths = Array.from(evaluate
|
|
2285
|
-
const values = Array.from(evaluate
|
|
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));
|
|
2286
2123
|
for (const pathVal of paths) {
|
|
2287
2124
|
const path = ensurePath(pathVal, span);
|
|
2288
2125
|
for (const val of values) yield emit$1(updatePath(input, path, () => val, span) ?? null, span, tracker);
|
|
@@ -2292,8 +2129,8 @@ const pathBuiltins = [
|
|
|
2292
2129
|
{
|
|
2293
2130
|
name: "delpaths",
|
|
2294
2131
|
arity: 1,
|
|
2295
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2296
|
-
for (const pathsVal of evaluate
|
|
2132
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2133
|
+
for (const pathsVal of evaluate(args[0], input, env, tracker)) {
|
|
2297
2134
|
if (!Array.isArray(pathsVal)) throw new RuntimeError("delpaths expects an array of paths", span);
|
|
2298
2135
|
yield emit$1(deletePaths(input, pathsVal.map((p) => ensurePath(p, span)), span), span, tracker);
|
|
2299
2136
|
}
|
|
@@ -2302,570 +2139,1747 @@ const pathBuiltins = [
|
|
|
2302
2139
|
{
|
|
2303
2140
|
name: "path",
|
|
2304
2141
|
arity: 1,
|
|
2305
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2306
|
-
for (const p of evaluatePath(args[0], input, env, tracker, evaluate
|
|
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);
|
|
2307
2144
|
}
|
|
2308
2145
|
}
|
|
2309
2146
|
];
|
|
2310
|
-
|
|
2311
2147
|
//#endregion
|
|
2312
|
-
//#region src/builtins/
|
|
2313
|
-
|
|
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 = [
|
|
2314
2159
|
{
|
|
2315
|
-
name: "
|
|
2316
|
-
arity:
|
|
2317
|
-
apply: function* (input,
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
for (let i = 0; i < end; i++) yield emit$1(i, span, tracker);
|
|
2322
|
-
}
|
|
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);
|
|
2323
2166
|
}
|
|
2324
2167
|
},
|
|
2325
2168
|
{
|
|
2326
|
-
name: "
|
|
2327
|
-
arity:
|
|
2328
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2329
|
-
const
|
|
2330
|
-
const
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
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);
|
|
2335
2183
|
}
|
|
2336
2184
|
},
|
|
2337
2185
|
{
|
|
2338
|
-
name: "
|
|
2339
|
-
arity:
|
|
2340
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2341
|
-
|
|
2342
|
-
const
|
|
2343
|
-
const
|
|
2344
|
-
for (const
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
if (step > 0) for (let i = start; i < end; i += step) yield emit$1(i, span, tracker);
|
|
2348
|
-
else for (let i = start; i > end; i += step) yield emit$1(i, span, tracker);
|
|
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);
|
|
2349
2195
|
}
|
|
2196
|
+
yield emit$1(result, span, tracker);
|
|
2350
2197
|
}
|
|
2351
2198
|
},
|
|
2352
2199
|
{
|
|
2353
|
-
name: "
|
|
2354
|
-
arity:
|
|
2355
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2356
|
-
const
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
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;
|
|
2364
2224
|
}
|
|
2225
|
+
yield emit$1(result, span, tracker);
|
|
2226
|
+
return;
|
|
2365
2227
|
}
|
|
2228
|
+
throw new RuntimeError("map_values expects an array or object", span);
|
|
2366
2229
|
}
|
|
2367
2230
|
},
|
|
2368
2231
|
{
|
|
2369
|
-
name: "
|
|
2232
|
+
name: "select",
|
|
2370
2233
|
arity: 1,
|
|
2371
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
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;
|
|
2375
2239
|
}
|
|
2376
2240
|
}
|
|
2377
2241
|
},
|
|
2378
2242
|
{
|
|
2379
|
-
name: "
|
|
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",
|
|
2380
2254
|
arity: 1,
|
|
2381
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
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
|
+
});
|
|
2387
2267
|
}
|
|
2388
|
-
|
|
2268
|
+
yield emit$1(sortStable(pairs, (a, b) => compareValues(a.key, b.key)).map((p) => p.val), span, tracker);
|
|
2389
2269
|
}
|
|
2390
2270
|
},
|
|
2391
2271
|
{
|
|
2392
|
-
name: "
|
|
2393
|
-
arity:
|
|
2394
|
-
apply: function* (input,
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
}
|
|
2404
|
-
count++;
|
|
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);
|
|
2405
2283
|
}
|
|
2406
2284
|
}
|
|
2285
|
+
yield emit$1(result, span, tracker);
|
|
2407
2286
|
}
|
|
2408
2287
|
},
|
|
2409
2288
|
{
|
|
2410
|
-
name: "
|
|
2289
|
+
name: "unique_by",
|
|
2411
2290
|
arity: 1,
|
|
2412
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
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
|
+
}
|
|
2417
2305
|
}
|
|
2418
|
-
yield emit$1(
|
|
2306
|
+
yield emit$1(result, span, tracker);
|
|
2419
2307
|
}
|
|
2420
2308
|
},
|
|
2421
2309
|
{
|
|
2422
|
-
name: "
|
|
2423
|
-
arity:
|
|
2424
|
-
apply: function* (input,
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
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;
|
|
2429
2344
|
}
|
|
2430
2345
|
yield emit$1(result, span, tracker);
|
|
2431
2346
|
}
|
|
2432
2347
|
},
|
|
2433
2348
|
{
|
|
2434
|
-
name: "
|
|
2349
|
+
name: "with_entries",
|
|
2435
2350
|
arity: 1,
|
|
2436
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2437
|
-
let
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
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"];
|
|
2441
2376
|
}
|
|
2442
2377
|
yield emit$1(result, span, tracker);
|
|
2443
2378
|
}
|
|
2444
2379
|
},
|
|
2445
2380
|
{
|
|
2446
|
-
name: "
|
|
2381
|
+
name: "group_by",
|
|
2447
2382
|
arity: 1,
|
|
2448
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
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);
|
|
2455
2413
|
}
|
|
2456
2414
|
},
|
|
2457
2415
|
{
|
|
2458
|
-
name: "
|
|
2459
|
-
arity:
|
|
2460
|
-
apply: function* (input,
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
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;
|
|
2469
2433
|
}
|
|
2470
|
-
if (
|
|
2471
|
-
|
|
2472
|
-
|
|
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;
|
|
2473
2438
|
}
|
|
2474
|
-
|
|
2475
|
-
|
|
2439
|
+
throw new RuntimeError("in expects an array or object argument", span);
|
|
2440
|
+
}
|
|
2476
2441
|
}
|
|
2477
2442
|
},
|
|
2478
2443
|
{
|
|
2479
|
-
name: "
|
|
2480
|
-
arity:
|
|
2481
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2482
|
-
|
|
2483
|
-
const updateExpr = args[1];
|
|
2484
|
-
const rec = function* (curr) {
|
|
2485
|
-
tracker.step(span);
|
|
2486
|
-
let condMatches = false;
|
|
2487
|
-
for (const c of evaluate$1(condExpr, curr, env, tracker)) if (isTruthy(c)) {
|
|
2488
|
-
condMatches = true;
|
|
2489
|
-
break;
|
|
2490
|
-
}
|
|
2491
|
-
if (condMatches) yield emit$1(curr, span, tracker);
|
|
2492
|
-
else for (const next of evaluate$1(updateExpr, curr, env, tracker)) yield* rec(next);
|
|
2493
|
-
};
|
|
2494
|
-
yield* rec(input);
|
|
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);
|
|
2495
2448
|
}
|
|
2496
2449
|
},
|
|
2497
2450
|
{
|
|
2498
|
-
name: "
|
|
2451
|
+
name: "pick",
|
|
2499
2452
|
arity: 1,
|
|
2500
|
-
apply: function* (input, args, env, tracker, evaluate
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
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;
|
|
2504
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",
|
|
2616
|
+
arity: 1,
|
|
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);
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
];
|
|
2623
|
+
const getEntryField = (obj, names) => {
|
|
2624
|
+
for (const name of names) if (Object.prototype.hasOwnProperty.call(obj, name)) return obj[name];
|
|
2625
|
+
};
|
|
2626
|
+
//#endregion
|
|
2627
|
+
//#region src/builtins/iterators.ts
|
|
2628
|
+
const iteratorBuiltins = [
|
|
2629
|
+
{
|
|
2630
|
+
name: "range",
|
|
2631
|
+
arity: 1,
|
|
2632
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2633
|
+
const ends = evaluate(args[0], input, env, tracker);
|
|
2634
|
+
for (const end of ends) {
|
|
2635
|
+
if (typeof end !== "number") throw new RuntimeError("range expects numbers", span);
|
|
2636
|
+
for (let i = 0; i < end; i++) yield emit$1(i, span, tracker);
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
},
|
|
2640
|
+
{
|
|
2641
|
+
name: "range",
|
|
2642
|
+
arity: 2,
|
|
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));
|
|
2646
|
+
for (const start of starts) for (const end of ends) {
|
|
2647
|
+
if (typeof start !== "number" || typeof end !== "number") throw new RuntimeError("range expects numbers", span);
|
|
2648
|
+
if (start < end) for (let i = start; i < end; i++) yield emit$1(i, span, tracker);
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
},
|
|
2652
|
+
{
|
|
2653
|
+
name: "range",
|
|
2654
|
+
arity: 3,
|
|
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));
|
|
2659
|
+
for (const start of starts) for (const end of ends) for (const step of steps) {
|
|
2660
|
+
if (typeof start !== "number" || typeof end !== "number" || typeof step !== "number") throw new RuntimeError("range expects numbers", span);
|
|
2661
|
+
if (step === 0) throw new RuntimeError("range step cannot be zero", span);
|
|
2662
|
+
if (step > 0) for (let i = start; i < end; i += step) yield emit$1(i, span, tracker);
|
|
2663
|
+
else for (let i = start; i > end; i += step) yield emit$1(i, span, tracker);
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
},
|
|
2667
|
+
{
|
|
2668
|
+
name: "limit",
|
|
2669
|
+
arity: 2,
|
|
2670
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2671
|
+
const limits = evaluate(args[0], input, env, tracker);
|
|
2672
|
+
for (const n of limits) {
|
|
2673
|
+
if (typeof n !== "number") throw new RuntimeError("limit expects number", span);
|
|
2674
|
+
let count = 0;
|
|
2675
|
+
if (n > 0) for (const val of evaluate(args[1], input, env, tracker)) {
|
|
2676
|
+
yield val;
|
|
2677
|
+
count++;
|
|
2678
|
+
if (count >= n) break;
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
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
|
+
},
|
|
2704
|
+
{
|
|
2705
|
+
name: "first",
|
|
2706
|
+
arity: 1,
|
|
2707
|
+
apply: function* (input, args, env, tracker, evaluate) {
|
|
2708
|
+
for (const val of evaluate(args[0], input, env, tracker)) {
|
|
2709
|
+
yield val;
|
|
2710
|
+
break;
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
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
|
+
},
|
|
2721
|
+
{
|
|
2722
|
+
name: "last",
|
|
2723
|
+
arity: 1,
|
|
2724
|
+
apply: function* (input, args, env, tracker, evaluate) {
|
|
2725
|
+
let lastVal;
|
|
2726
|
+
let found = false;
|
|
2727
|
+
for (const val of evaluate(args[0], input, env, tracker)) {
|
|
2728
|
+
lastVal = val;
|
|
2729
|
+
found = true;
|
|
2730
|
+
}
|
|
2731
|
+
if (found) yield lastVal;
|
|
2732
|
+
}
|
|
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
|
+
},
|
|
2746
|
+
{
|
|
2747
|
+
name: "nth",
|
|
2748
|
+
arity: 2,
|
|
2749
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2750
|
+
const indices = evaluate(args[0], input, env, tracker);
|
|
2751
|
+
for (const n of indices) {
|
|
2752
|
+
if (typeof n !== "number") throw new RuntimeError("nth expects number", span);
|
|
2753
|
+
let count = 0;
|
|
2754
|
+
for (const val of evaluate(args[1], input, env, tracker)) {
|
|
2755
|
+
if (count === n) {
|
|
2756
|
+
yield val;
|
|
2757
|
+
break;
|
|
2758
|
+
}
|
|
2759
|
+
count++;
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
},
|
|
2764
|
+
{
|
|
2765
|
+
name: "isempty",
|
|
2766
|
+
arity: 1,
|
|
2767
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2768
|
+
let empty = true;
|
|
2769
|
+
for (const _ of evaluate(args[0], input, env, tracker)) {
|
|
2770
|
+
empty = false;
|
|
2771
|
+
break;
|
|
2772
|
+
}
|
|
2773
|
+
yield emit$1(empty, span, tracker);
|
|
2774
|
+
}
|
|
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
|
+
},
|
|
2784
|
+
{
|
|
2785
|
+
name: "all",
|
|
2786
|
+
arity: 1,
|
|
2787
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2788
|
+
if (!Array.isArray(input)) throw new RuntimeError("all expects an array", span);
|
|
2789
|
+
let result = true;
|
|
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
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
yield emit$1(result, span, tracker);
|
|
2821
|
+
}
|
|
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
|
+
},
|
|
2831
|
+
{
|
|
2832
|
+
name: "any",
|
|
2833
|
+
arity: 1,
|
|
2834
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2835
|
+
if (!Array.isArray(input)) throw new RuntimeError("any expects an array", span);
|
|
2836
|
+
let result = false;
|
|
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;
|
|
2858
|
+
}
|
|
2859
|
+
yield emit$1(result, span, tracker);
|
|
2860
|
+
}
|
|
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
|
+
},
|
|
2877
|
+
{
|
|
2878
|
+
name: "recurse",
|
|
2879
|
+
arity: 1,
|
|
2880
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2881
|
+
const rec = function* (curr) {
|
|
2882
|
+
yield emit$1(curr, span, tracker);
|
|
2883
|
+
const nexts = evaluate(args[0], curr, env, tracker);
|
|
2884
|
+
for (const next of nexts) yield* rec(next);
|
|
2885
|
+
};
|
|
2886
|
+
yield* rec(input);
|
|
2887
|
+
}
|
|
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
|
+
},
|
|
2906
|
+
{
|
|
2907
|
+
name: "while",
|
|
2908
|
+
arity: 2,
|
|
2909
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2910
|
+
const condExpr = args[0];
|
|
2911
|
+
const updateExpr = args[1];
|
|
2912
|
+
const rec = function* (curr) {
|
|
2913
|
+
tracker.step(span);
|
|
2914
|
+
let condMatches = false;
|
|
2915
|
+
for (const c of evaluate(condExpr, curr, env, tracker)) if (isTruthy(c)) {
|
|
2916
|
+
condMatches = true;
|
|
2917
|
+
break;
|
|
2918
|
+
}
|
|
2919
|
+
if (condMatches) {
|
|
2920
|
+
yield emit$1(curr, span, tracker);
|
|
2921
|
+
for (const next of evaluate(updateExpr, curr, env, tracker)) yield* rec(next);
|
|
2922
|
+
}
|
|
2923
|
+
};
|
|
2924
|
+
yield* rec(input);
|
|
2925
|
+
}
|
|
2926
|
+
},
|
|
2927
|
+
{
|
|
2928
|
+
name: "until",
|
|
2929
|
+
arity: 2,
|
|
2930
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2931
|
+
const condExpr = args[0];
|
|
2932
|
+
const updateExpr = args[1];
|
|
2933
|
+
const rec = function* (curr) {
|
|
2934
|
+
tracker.step(span);
|
|
2935
|
+
let condMatches = false;
|
|
2936
|
+
for (const c of evaluate(condExpr, curr, env, tracker)) if (isTruthy(c)) {
|
|
2937
|
+
condMatches = true;
|
|
2938
|
+
break;
|
|
2939
|
+
}
|
|
2940
|
+
if (condMatches) yield emit$1(curr, span, tracker);
|
|
2941
|
+
else for (const next of evaluate(updateExpr, curr, env, tracker)) yield* rec(next);
|
|
2942
|
+
};
|
|
2943
|
+
yield* rec(input);
|
|
2944
|
+
}
|
|
2945
|
+
},
|
|
2946
|
+
{
|
|
2947
|
+
name: "repeat",
|
|
2948
|
+
arity: 1,
|
|
2949
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
2950
|
+
while (true) {
|
|
2951
|
+
tracker.step(span);
|
|
2952
|
+
yield* evaluate(args[0], input, env, tracker);
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
];
|
|
2957
|
+
//#endregion
|
|
2958
|
+
//#region src/eval/ops.ts
|
|
2959
|
+
/**
|
|
2960
|
+
* Applies a unary negation (`-`).
|
|
2961
|
+
*
|
|
2962
|
+
* @param value - The value to negate.
|
|
2963
|
+
* @param span - Source span for errors.
|
|
2964
|
+
* @returns The negated value.
|
|
2965
|
+
*/
|
|
2966
|
+
const applyUnaryNeg = (value, span) => {
|
|
2967
|
+
if (typeof value === "number") return -value;
|
|
2968
|
+
throw new RuntimeError(`Invalid operand for unary -: ${describeType(value)}`, span);
|
|
2969
|
+
};
|
|
2970
|
+
/**
|
|
2971
|
+
* Applies a binary operator.
|
|
2972
|
+
*
|
|
2973
|
+
* Supports arithmetic (`+`, `-`, `*`, `/`, `%`) and comparators.
|
|
2974
|
+
*
|
|
2975
|
+
* @param op - The operator string.
|
|
2976
|
+
* @param left - The left operand.
|
|
2977
|
+
* @param right - The right operand.
|
|
2978
|
+
* @param span - Source span for errors.
|
|
2979
|
+
* @returns The result of the operation.
|
|
2980
|
+
*/
|
|
2981
|
+
const applyBinaryOp = (op, left, right, span) => {
|
|
2982
|
+
switch (op) {
|
|
2983
|
+
case "+": return add(left, right, span);
|
|
2984
|
+
case "-": return sub(left, right, span);
|
|
2985
|
+
case "*": return mul(left, right, span);
|
|
2986
|
+
case "/": return div(left, right, span);
|
|
2987
|
+
case "%": return mod(left, right, span);
|
|
2988
|
+
case "Eq": return isEqual(left, right);
|
|
2989
|
+
case "Neq": return !isEqual(left, right);
|
|
2990
|
+
case "Lt": return compare(left, right) < 0;
|
|
2991
|
+
case "Lte": return compare(left, right) <= 0;
|
|
2992
|
+
case "Gt": return compare(left, right) > 0;
|
|
2993
|
+
case "Gte": return compare(left, right) >= 0;
|
|
2994
|
+
default: throw new RuntimeError(`Unknown binary operator: ${op}`, span);
|
|
2995
|
+
}
|
|
2996
|
+
};
|
|
2997
|
+
function isEqual(a, b) {
|
|
2998
|
+
if (a === b) return true;
|
|
2999
|
+
if (a === null || b === null) return false;
|
|
3000
|
+
if (typeof a !== typeof b) return false;
|
|
3001
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
3002
|
+
if (a.length !== b.length) return false;
|
|
3003
|
+
return a.every((v, i) => isEqual(v, b[i]));
|
|
3004
|
+
}
|
|
3005
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
3006
|
+
const ka = Object.keys(a).sort();
|
|
3007
|
+
const kb = Object.keys(b).sort();
|
|
3008
|
+
if (ka.length !== kb.length) return false;
|
|
3009
|
+
if (!ka.every((k, i) => k === kb[i])) return false;
|
|
3010
|
+
return ka.every((k) => isEqual(a[k], b[k]));
|
|
3011
|
+
}
|
|
3012
|
+
return false;
|
|
3013
|
+
}
|
|
3014
|
+
function compare(a, b) {
|
|
3015
|
+
if (a === b) return 0;
|
|
3016
|
+
const typeOrder = (v) => {
|
|
3017
|
+
if (v === null) return 0;
|
|
3018
|
+
if (typeof v === "boolean") return 1;
|
|
3019
|
+
if (typeof v === "number") return 2;
|
|
3020
|
+
if (typeof v === "string") return 3;
|
|
3021
|
+
if (Array.isArray(v)) return 4;
|
|
3022
|
+
if (isPlainObject(v)) return 5;
|
|
3023
|
+
return 6;
|
|
3024
|
+
};
|
|
3025
|
+
const ta = typeOrder(a);
|
|
3026
|
+
const tb = typeOrder(b);
|
|
3027
|
+
if (ta !== tb) return ta - tb;
|
|
3028
|
+
if (typeof a === "boolean" && typeof b === "boolean") return (a ? 1 : 0) - (b ? 1 : 0);
|
|
3029
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
3030
|
+
if (typeof a === "string" && typeof b === "string") return a < b ? -1 : 1;
|
|
3031
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
3032
|
+
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
3033
|
+
const c = compare(a[i], b[i]);
|
|
3034
|
+
if (c !== 0) return c;
|
|
3035
|
+
}
|
|
3036
|
+
return a.length - b.length;
|
|
3037
|
+
}
|
|
3038
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
3039
|
+
const keysA = Object.keys(a).sort();
|
|
3040
|
+
const keysB = Object.keys(b).sort();
|
|
3041
|
+
for (let i = 0; i < Math.min(keysA.length, keysB.length); i++) {
|
|
3042
|
+
const kA = keysA[i];
|
|
3043
|
+
const kB = keysB[i];
|
|
3044
|
+
if (kA !== kB) return kA < kB ? -1 : 1;
|
|
3045
|
+
const c = compare(a[kA], b[kB]);
|
|
3046
|
+
if (c !== 0) return c;
|
|
3047
|
+
}
|
|
3048
|
+
return keysA.length - keysB.length;
|
|
3049
|
+
}
|
|
3050
|
+
return 0;
|
|
3051
|
+
}
|
|
3052
|
+
function add(left, right, span) {
|
|
3053
|
+
if (left === null) return right;
|
|
3054
|
+
if (right === null) return left;
|
|
3055
|
+
if (typeof left === "number" && typeof right === "number") return left + right;
|
|
3056
|
+
if (typeof left === "string" && typeof right === "string") return left + right;
|
|
3057
|
+
if (Array.isArray(left) && Array.isArray(right)) return [...left, ...right];
|
|
3058
|
+
if (isPlainObject(left) && isPlainObject(right)) return {
|
|
3059
|
+
...left,
|
|
3060
|
+
...right
|
|
3061
|
+
};
|
|
3062
|
+
throw new RuntimeError(`Cannot add ${describeType(left)} and ${describeType(right)}`, span);
|
|
3063
|
+
}
|
|
3064
|
+
function sub(left, right, span) {
|
|
3065
|
+
if (typeof left === "number" && typeof right === "number") return left - right;
|
|
3066
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
3067
|
+
const toRemove = new Set(right.map(stableStringify));
|
|
3068
|
+
return left.filter((x) => !toRemove.has(stableStringify(x)));
|
|
3069
|
+
}
|
|
3070
|
+
throw new RuntimeError(`Cannot subtract ${describeType(right)} from ${describeType(left)}`, span);
|
|
3071
|
+
}
|
|
3072
|
+
function mul(left, right, span) {
|
|
3073
|
+
if (typeof left === "number" && typeof right === "number") return left * right;
|
|
3074
|
+
if (typeof left === "string" && typeof right === "number") return repeatString(left, right);
|
|
3075
|
+
if (typeof left === "number" && typeof right === "string") return repeatString(right, left);
|
|
3076
|
+
if (isPlainObject(left) && isPlainObject(right)) return mergeDeep(left, right);
|
|
3077
|
+
throw new RuntimeError(`Cannot multiply ${describeType(left)} by ${describeType(right)}`, span);
|
|
3078
|
+
}
|
|
3079
|
+
function div(left, right, span) {
|
|
3080
|
+
if (typeof left === "number" && typeof right === "number") {
|
|
3081
|
+
if (right === 0) throw new RuntimeError("Division by zero", span);
|
|
3082
|
+
return left / right;
|
|
3083
|
+
}
|
|
3084
|
+
if (typeof left === "string" && typeof right === "string") return left.split(right);
|
|
3085
|
+
throw new RuntimeError(`Cannot divide ${describeType(left)} by ${describeType(right)}`, span);
|
|
3086
|
+
}
|
|
3087
|
+
function mod(left, right, span) {
|
|
3088
|
+
if (typeof left === "number" && typeof right === "number") {
|
|
3089
|
+
if (right === 0) throw new RuntimeError("Modulo by zero", span);
|
|
3090
|
+
return left % right;
|
|
3091
|
+
}
|
|
3092
|
+
throw new RuntimeError(`Cannot modulo ${describeType(left)} by ${describeType(right)}`, span);
|
|
3093
|
+
}
|
|
3094
|
+
function repeatString(str, count) {
|
|
3095
|
+
if (count <= 0) return null;
|
|
3096
|
+
const n = Math.floor(count);
|
|
3097
|
+
if (n <= 0) return null;
|
|
3098
|
+
return str.repeat(n);
|
|
3099
|
+
}
|
|
3100
|
+
function mergeDeep(target, source) {
|
|
3101
|
+
const result = { ...target };
|
|
3102
|
+
for (const key of Object.keys(source)) {
|
|
3103
|
+
const sVal = source[key];
|
|
3104
|
+
const tVal = result[key];
|
|
3105
|
+
if (isPlainObject(sVal) && tVal !== void 0 && isPlainObject(tVal)) result[key] = mergeDeep(tVal, sVal);
|
|
3106
|
+
else result[key] = sVal;
|
|
3107
|
+
}
|
|
3108
|
+
return result;
|
|
3109
|
+
}
|
|
3110
|
+
function isPlainObject(v) {
|
|
3111
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3112
|
+
}
|
|
3113
|
+
//#endregion
|
|
3114
|
+
//#region src/builtins/math.ts
|
|
3115
|
+
const mathBuiltins = [
|
|
3116
|
+
{
|
|
3117
|
+
name: "floor",
|
|
3118
|
+
arity: 0,
|
|
3119
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3120
|
+
if (typeof input !== "number") throw new RuntimeError("floor expects number", span);
|
|
3121
|
+
yield emit$1(Math.floor(input), span, tracker);
|
|
3122
|
+
}
|
|
3123
|
+
},
|
|
3124
|
+
{
|
|
3125
|
+
name: "ceil",
|
|
3126
|
+
arity: 0,
|
|
3127
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3128
|
+
if (typeof input !== "number") throw new RuntimeError("ceil expects number", span);
|
|
3129
|
+
yield emit$1(Math.ceil(input), span, tracker);
|
|
3130
|
+
}
|
|
3131
|
+
},
|
|
3132
|
+
{
|
|
3133
|
+
name: "round",
|
|
3134
|
+
arity: 0,
|
|
3135
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3136
|
+
if (typeof input !== "number") throw new RuntimeError("round expects number", span);
|
|
3137
|
+
yield emit$1(Math.round(input), span, tracker);
|
|
3138
|
+
}
|
|
3139
|
+
},
|
|
3140
|
+
{
|
|
3141
|
+
name: "abs",
|
|
3142
|
+
arity: 0,
|
|
3143
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3144
|
+
if (typeof input !== "number") throw new RuntimeError("abs expects number", span);
|
|
3145
|
+
yield emit$1(Math.abs(input), span, tracker);
|
|
3146
|
+
}
|
|
3147
|
+
},
|
|
3148
|
+
{
|
|
3149
|
+
name: "sqrt",
|
|
3150
|
+
arity: 0,
|
|
3151
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3152
|
+
if (typeof input !== "number") throw new RuntimeError("sqrt expects number", span);
|
|
3153
|
+
yield emit$1(Math.sqrt(input), span, tracker);
|
|
3154
|
+
}
|
|
3155
|
+
},
|
|
3156
|
+
{
|
|
3157
|
+
name: "isnan",
|
|
3158
|
+
arity: 0,
|
|
3159
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3160
|
+
if (typeof input !== "number") {
|
|
3161
|
+
yield emit$1(false, span, tracker);
|
|
3162
|
+
return;
|
|
3163
|
+
}
|
|
3164
|
+
yield emit$1(Number.isNaN(input), span, tracker);
|
|
3165
|
+
}
|
|
3166
|
+
},
|
|
3167
|
+
{
|
|
3168
|
+
name: "infinite",
|
|
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,
|
|
3184
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3185
|
+
yield emit$1(typeof input === "number" && !Number.isFinite(input) && !Number.isNaN(input), span, tracker);
|
|
3186
|
+
}
|
|
3187
|
+
},
|
|
3188
|
+
{
|
|
3189
|
+
name: "isfinite",
|
|
3190
|
+
arity: 0,
|
|
3191
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3192
|
+
if (typeof input !== "number") {
|
|
3193
|
+
yield emit$1(true, span, tracker);
|
|
3194
|
+
return;
|
|
3195
|
+
}
|
|
3196
|
+
yield emit$1(Number.isFinite(input), span, tracker);
|
|
3197
|
+
}
|
|
3198
|
+
},
|
|
3199
|
+
{
|
|
3200
|
+
name: "normal",
|
|
3201
|
+
arity: 0,
|
|
3202
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3203
|
+
if (typeof input !== "number") {
|
|
3204
|
+
yield emit$1(false, span, tracker);
|
|
3205
|
+
return;
|
|
3206
|
+
}
|
|
3207
|
+
if (!Number.isFinite(input) || Number.isNaN(input) || input === 0) {
|
|
3208
|
+
yield emit$1(false, span, tracker);
|
|
3209
|
+
return;
|
|
3210
|
+
}
|
|
3211
|
+
yield emit$1(true, span, tracker);
|
|
3212
|
+
}
|
|
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
|
+
},
|
|
3221
|
+
{
|
|
3222
|
+
name: "subnormal",
|
|
3223
|
+
arity: 0,
|
|
3224
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3225
|
+
if (typeof input !== "number") {
|
|
3226
|
+
yield emit$1(false, span, tracker);
|
|
3227
|
+
return;
|
|
3228
|
+
}
|
|
3229
|
+
yield emit$1(false, span, tracker);
|
|
3230
|
+
}
|
|
3231
|
+
},
|
|
3232
|
+
{
|
|
3233
|
+
name: "min",
|
|
3234
|
+
arity: 0,
|
|
3235
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3236
|
+
if (!Array.isArray(input)) throw new RuntimeError("min expects an array", span);
|
|
3237
|
+
if (input.length === 0) {
|
|
3238
|
+
yield emit$1(null, span, tracker);
|
|
3239
|
+
return;
|
|
3240
|
+
}
|
|
3241
|
+
let minVal = input[0];
|
|
3242
|
+
for (let i = 1; i < input.length; i++) if (compareValues(input[i], minVal) < 0) minVal = input[i];
|
|
3243
|
+
yield emit$1(minVal, span, tracker);
|
|
3244
|
+
}
|
|
3245
|
+
},
|
|
3246
|
+
{
|
|
3247
|
+
name: "max",
|
|
3248
|
+
arity: 0,
|
|
3249
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3250
|
+
if (!Array.isArray(input)) throw new RuntimeError("max expects an array", span);
|
|
3251
|
+
if (input.length === 0) {
|
|
3252
|
+
yield emit$1(null, span, tracker);
|
|
3253
|
+
return;
|
|
3254
|
+
}
|
|
3255
|
+
let maxVal = input[0];
|
|
3256
|
+
for (let i = 1; i < input.length; i++) if (compareValues(input[i], maxVal) > 0) maxVal = input[i];
|
|
3257
|
+
yield emit$1(maxVal, span, tracker);
|
|
3258
|
+
}
|
|
3259
|
+
},
|
|
3260
|
+
{
|
|
3261
|
+
name: "min_by",
|
|
3262
|
+
arity: 1,
|
|
3263
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
3264
|
+
if (!Array.isArray(input)) throw new RuntimeError("min_by expects an array", span);
|
|
3265
|
+
if (input.length === 0) {
|
|
3266
|
+
yield emit$1(null, span, tracker);
|
|
3267
|
+
return;
|
|
3268
|
+
}
|
|
3269
|
+
let minItem = input[0];
|
|
3270
|
+
let minKey;
|
|
3271
|
+
const keys0 = Array.from(evaluate(args[0], minItem, env, tracker));
|
|
3272
|
+
if (keys0.length !== 1) throw new RuntimeError("min_by key must return one value", span);
|
|
3273
|
+
minKey = keys0[0];
|
|
3274
|
+
for (let i = 1; i < input.length; i++) {
|
|
3275
|
+
const item = input[i];
|
|
3276
|
+
const keys = Array.from(evaluate(args[0], item, env, tracker));
|
|
3277
|
+
if (keys.length !== 1) throw new RuntimeError("min_by key must return one value", span);
|
|
3278
|
+
const key = keys[0];
|
|
3279
|
+
if (compareValues(key, minKey) < 0) {
|
|
3280
|
+
minKey = key;
|
|
3281
|
+
minItem = item;
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
yield emit$1(minItem, span, tracker);
|
|
3285
|
+
}
|
|
3286
|
+
},
|
|
3287
|
+
{
|
|
3288
|
+
name: "max_by",
|
|
3289
|
+
arity: 1,
|
|
3290
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
3291
|
+
if (!Array.isArray(input)) throw new RuntimeError("max_by expects an array", span);
|
|
3292
|
+
if (input.length === 0) {
|
|
3293
|
+
yield emit$1(null, span, tracker);
|
|
3294
|
+
return;
|
|
3295
|
+
}
|
|
3296
|
+
let maxItem = input[0];
|
|
3297
|
+
let maxKey;
|
|
3298
|
+
const keys0 = Array.from(evaluate(args[0], maxItem, env, tracker));
|
|
3299
|
+
if (keys0.length !== 1) throw new RuntimeError("max_by key must return one value", span);
|
|
3300
|
+
maxKey = keys0[0];
|
|
3301
|
+
for (let i = 1; i < input.length; i++) {
|
|
3302
|
+
const item = input[i];
|
|
3303
|
+
const keys = Array.from(evaluate(args[0], item, env, tracker));
|
|
3304
|
+
if (keys.length !== 1) throw new RuntimeError("max_by key must return one value", span);
|
|
3305
|
+
const key = keys[0];
|
|
3306
|
+
if (compareValues(key, maxKey) > 0) {
|
|
3307
|
+
maxKey = key;
|
|
3308
|
+
maxItem = item;
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
yield emit$1(maxItem, span, tracker);
|
|
3312
|
+
}
|
|
3313
|
+
},
|
|
3314
|
+
{
|
|
3315
|
+
name: "add",
|
|
3316
|
+
arity: 0,
|
|
3317
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
3318
|
+
if (!Array.isArray(input)) throw new RuntimeError("add expects an array", span);
|
|
3319
|
+
if (input.length === 0) {
|
|
3320
|
+
yield emit$1(null, span, tracker);
|
|
3321
|
+
return;
|
|
3322
|
+
}
|
|
3323
|
+
let acc = input[0];
|
|
3324
|
+
for (let i = 1; i < input.length; i++) {
|
|
3325
|
+
tracker.step(span);
|
|
3326
|
+
acc = add(acc, input[i], span);
|
|
3327
|
+
}
|
|
3328
|
+
yield emit$1(acc, span, tracker);
|
|
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);
|
|
2505
3346
|
}
|
|
2506
3347
|
}
|
|
2507
3348
|
];
|
|
2508
|
-
|
|
2509
3349
|
//#endregion
|
|
2510
|
-
//#region src/
|
|
3350
|
+
//#region src/builtins/dates.ts
|
|
2511
3351
|
/**
|
|
2512
|
-
*
|
|
3352
|
+
* Date/time builtins matching the jq binary (jq 1.7+/1.8).
|
|
2513
3353
|
*
|
|
2514
|
-
*
|
|
2515
|
-
*
|
|
2516
|
-
*
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
/**
|
|
2523
|
-
* Applies a binary operator.
|
|
3354
|
+
* jq represents time in two forms:
|
|
3355
|
+
* - a number of seconds since the Unix epoch (possibly fractional), and
|
|
3356
|
+
* - a "broken down time": an 8-element array
|
|
3357
|
+
* [ year, month(0-11), mday, hour, minute, second,
|
|
3358
|
+
* weekday(0-6, Sun=0), yearday(0-365) ].
|
|
3359
|
+
* The second slot carries the fractional part of the input, and `year` is
|
|
3360
|
+
* the full year (NOT year-1900). This mirrors `1425599507 | gmtime ==
|
|
3361
|
+
* [2015,2,5,23,51,47,4,63]`.
|
|
2524
3362
|
*
|
|
2525
|
-
*
|
|
3363
|
+
* `now` is the only clock-dependent builtin; it reads the instant injected via
|
|
3364
|
+
* `options.now` and throws when none was supplied (jq-ts never reads the host
|
|
3365
|
+
* clock on its own). Every other builtin here is a pure function of its input.
|
|
2526
3366
|
*
|
|
2527
|
-
*
|
|
2528
|
-
*
|
|
2529
|
-
*
|
|
2530
|
-
* @param span - Source span for errors.
|
|
2531
|
-
* @returns The result of the operation.
|
|
3367
|
+
* Known deviation: `strftime`'s `%s` specifier is computed as the UTC epoch of
|
|
3368
|
+
* the broken-down time, whereas glibc's `%s` uses the host timezone. jq-ts
|
|
3369
|
+
* favors determinism/portability here; every other specifier matches jq.
|
|
2532
3370
|
*/
|
|
2533
|
-
const
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
3371
|
+
const WEEKDAY_ABBR = [
|
|
3372
|
+
"Sun",
|
|
3373
|
+
"Mon",
|
|
3374
|
+
"Tue",
|
|
3375
|
+
"Wed",
|
|
3376
|
+
"Thu",
|
|
3377
|
+
"Fri",
|
|
3378
|
+
"Sat"
|
|
3379
|
+
];
|
|
3380
|
+
const WEEKDAY_FULL = [
|
|
3381
|
+
"Sunday",
|
|
3382
|
+
"Monday",
|
|
3383
|
+
"Tuesday",
|
|
3384
|
+
"Wednesday",
|
|
3385
|
+
"Thursday",
|
|
3386
|
+
"Friday",
|
|
3387
|
+
"Saturday"
|
|
3388
|
+
];
|
|
3389
|
+
const MONTH_ABBR = [
|
|
3390
|
+
"Jan",
|
|
3391
|
+
"Feb",
|
|
3392
|
+
"Mar",
|
|
3393
|
+
"Apr",
|
|
3394
|
+
"May",
|
|
3395
|
+
"Jun",
|
|
3396
|
+
"Jul",
|
|
3397
|
+
"Aug",
|
|
3398
|
+
"Sep",
|
|
3399
|
+
"Oct",
|
|
3400
|
+
"Nov",
|
|
3401
|
+
"Dec"
|
|
3402
|
+
];
|
|
3403
|
+
const MONTH_FULL = [
|
|
3404
|
+
"January",
|
|
3405
|
+
"February",
|
|
3406
|
+
"March",
|
|
3407
|
+
"April",
|
|
3408
|
+
"May",
|
|
3409
|
+
"June",
|
|
3410
|
+
"July",
|
|
3411
|
+
"August",
|
|
3412
|
+
"September",
|
|
3413
|
+
"October",
|
|
3414
|
+
"November",
|
|
3415
|
+
"December"
|
|
3416
|
+
];
|
|
3417
|
+
const MS_PER_DAY = 864e5;
|
|
3418
|
+
/**
|
|
3419
|
+
* `Date.UTC` / `new Date(y, …)` map years 0–99 to 1900–1999 (a legacy JS
|
|
3420
|
+
* quirk). jq uses the literal year, so these helpers correct it via
|
|
3421
|
+
* `setUTCFullYear` / `setFullYear`, which accept the true year.
|
|
3422
|
+
*/
|
|
3423
|
+
const utcMillis = (year, mon, mday, hour = 0, min = 0, sec = 0) => {
|
|
3424
|
+
const ms = Date.UTC(year, mon, mday, hour, min, sec);
|
|
3425
|
+
if (year >= 0 && year <= 99) {
|
|
3426
|
+
const d = new Date(ms);
|
|
3427
|
+
d.setUTCFullYear(year);
|
|
3428
|
+
return d.getTime();
|
|
2547
3429
|
}
|
|
3430
|
+
return ms;
|
|
2548
3431
|
};
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
if (
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
}
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
const
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
3432
|
+
const localMillis = (year, mon, mday, hour = 0, min = 0, sec = 0) => {
|
|
3433
|
+
const d = new Date(year, mon, mday, hour, min, sec);
|
|
3434
|
+
if (year >= 0 && year <= 99) d.setFullYear(year);
|
|
3435
|
+
return d.getTime();
|
|
3436
|
+
};
|
|
3437
|
+
const pad = (value, width, fill = "0") => String(Math.trunc(value)).padStart(width, fill);
|
|
3438
|
+
const requireNumber = (input, fn, span) => {
|
|
3439
|
+
if (typeof input !== "number") throw new RuntimeError(`${fn}() requires numeric inputs`, span);
|
|
3440
|
+
return input;
|
|
3441
|
+
};
|
|
3442
|
+
const requireString = (input, fn, span) => {
|
|
3443
|
+
if (typeof input !== "string") throw new RuntimeError(`${fn} requires a string, got ${describeType(input)}`, span);
|
|
3444
|
+
return input;
|
|
3445
|
+
};
|
|
3446
|
+
/** Day-of-year (0-based), computed with date-only UTC math so DST can't skew it. */
|
|
3447
|
+
const yearDay = (year, mon, mday) => Math.round((utcMillis(year, mon, mday) - utcMillis(year, 0, 1)) / MS_PER_DAY);
|
|
3448
|
+
/** Converts epoch seconds into broken-down time fields (UTC or local). */
|
|
3449
|
+
const fieldsFromEpoch = (epochSeconds, utc) => {
|
|
3450
|
+
const whole = Math.floor(epochSeconds);
|
|
3451
|
+
const frac = epochSeconds - whole;
|
|
3452
|
+
const d = /* @__PURE__ */ new Date(whole * 1e3);
|
|
3453
|
+
const year = utc ? d.getUTCFullYear() : d.getFullYear();
|
|
3454
|
+
const mon = utc ? d.getUTCMonth() : d.getMonth();
|
|
3455
|
+
const mday = utc ? d.getUTCDate() : d.getDate();
|
|
3456
|
+
const hour = utc ? d.getUTCHours() : d.getHours();
|
|
3457
|
+
const min = utc ? d.getUTCMinutes() : d.getMinutes();
|
|
3458
|
+
const sec = utc ? d.getUTCSeconds() : d.getSeconds();
|
|
3459
|
+
const wday = utc ? d.getUTCDay() : d.getDay();
|
|
3460
|
+
return {
|
|
3461
|
+
year,
|
|
3462
|
+
mon,
|
|
3463
|
+
mday,
|
|
3464
|
+
hour,
|
|
3465
|
+
min,
|
|
3466
|
+
sec: sec + frac,
|
|
3467
|
+
wday,
|
|
3468
|
+
yday: yearDay(year, mon, mday)
|
|
2576
3469
|
};
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
3470
|
+
};
|
|
3471
|
+
const fieldsToArray = (f) => [
|
|
3472
|
+
f.year,
|
|
3473
|
+
f.mon,
|
|
3474
|
+
f.mday,
|
|
3475
|
+
f.hour,
|
|
3476
|
+
f.min,
|
|
3477
|
+
f.sec,
|
|
3478
|
+
f.wday,
|
|
3479
|
+
f.yday
|
|
3480
|
+
];
|
|
3481
|
+
/**
|
|
3482
|
+
* Parses a jq broken-down time array into fields. Missing trailing slots
|
|
3483
|
+
* default to 0 (jq is lenient: `[1,2,3] | mktime` works); present-but-non-number
|
|
3484
|
+
* slots are an error. wday/yday are derived from the calendar date when absent.
|
|
3485
|
+
*/
|
|
3486
|
+
const fieldsFromArray = (input, fn, span) => {
|
|
3487
|
+
if (!Array.isArray(input)) throw new RuntimeError(`${fn} requires array inputs`, span);
|
|
3488
|
+
const at = (index) => {
|
|
3489
|
+
if (index >= input.length) return 0;
|
|
3490
|
+
const raw = input[index];
|
|
3491
|
+
if (typeof raw !== "number") throw new RuntimeError(`${fn} requires an array of numbers`, span);
|
|
3492
|
+
return raw;
|
|
3493
|
+
};
|
|
3494
|
+
const year = at(0);
|
|
3495
|
+
const mon = at(1);
|
|
3496
|
+
const mday = at(2);
|
|
3497
|
+
return {
|
|
3498
|
+
year,
|
|
3499
|
+
mon,
|
|
3500
|
+
mday,
|
|
3501
|
+
hour: at(3),
|
|
3502
|
+
min: at(4),
|
|
3503
|
+
sec: at(5),
|
|
3504
|
+
wday: input.length > 6 && typeof input[6] === "number" ? input[6] : new Date(utcMillis(year, mon, mday)).getUTCDay(),
|
|
3505
|
+
yday: input.length > 7 && typeof input[7] === "number" ? input[7] : yearDay(year, mon, mday)
|
|
3506
|
+
};
|
|
3507
|
+
};
|
|
3508
|
+
/** Converts broken-down time fields back into epoch seconds (mktime). */
|
|
3509
|
+
const epochFromFields = (f, utc) => {
|
|
3510
|
+
const wholeSec = Math.floor(f.sec);
|
|
3511
|
+
const frac = f.sec - wholeSec;
|
|
3512
|
+
return (utc ? utcMillis(f.year, f.mon, f.mday, f.hour, f.min, wholeSec) : localMillis(f.year, f.mon, f.mday, f.hour, f.min, wholeSec)) / 1e3 + frac;
|
|
3513
|
+
};
|
|
3514
|
+
/** ISO-8601 week-numbering year and week (for %G / %V). */
|
|
3515
|
+
const isoWeek = (year, mon, mday) => {
|
|
3516
|
+
const date = new Date(utcMillis(year, mon, mday));
|
|
3517
|
+
const dayNum = (date.getUTCDay() + 6) % 7;
|
|
3518
|
+
date.setUTCDate(date.getUTCDate() - dayNum + 3);
|
|
3519
|
+
const isoYear = date.getUTCFullYear();
|
|
3520
|
+
const firstThursday = new Date(utcMillis(isoYear, 0, 4));
|
|
3521
|
+
const firstDayNum = (firstThursday.getUTCDay() + 6) % 7;
|
|
3522
|
+
firstThursday.setUTCDate(firstThursday.getUTCDate() - firstDayNum + 3);
|
|
3523
|
+
return {
|
|
3524
|
+
year: isoYear,
|
|
3525
|
+
week: 1 + Math.round((date.getTime() - firstThursday.getTime()) / (7 * MS_PER_DAY))
|
|
3526
|
+
};
|
|
3527
|
+
};
|
|
3528
|
+
const localOffsetString = (f) => {
|
|
3529
|
+
const offsetMin = -new Date(localMillis(f.year, f.mon, f.mday, f.hour, f.min, Math.floor(f.sec))).getTimezoneOffset();
|
|
3530
|
+
const sign = offsetMin >= 0 ? "+" : "-";
|
|
3531
|
+
const abs = Math.abs(offsetMin);
|
|
3532
|
+
return `${sign}${pad(Math.floor(abs / 60), 2)}${pad(abs % 60, 2)}`;
|
|
3533
|
+
};
|
|
3534
|
+
/** Best-effort local timezone abbreviation via Intl, falling back to the offset. */
|
|
3535
|
+
const localTzAbbr = (f) => {
|
|
3536
|
+
try {
|
|
3537
|
+
const tz = new Intl.DateTimeFormat("en-US", { timeZoneName: "short" }).formatToParts(new Date(localMillis(f.year, f.mon, f.mday, f.hour, f.min, Math.floor(f.sec)))).find((p) => p.type === "timeZoneName")?.value;
|
|
3538
|
+
if (tz) return tz;
|
|
3539
|
+
} catch {}
|
|
3540
|
+
return localOffsetString(f);
|
|
3541
|
+
};
|
|
3542
|
+
/** Formats broken-down time with a C `strftime`-style format. */
|
|
3543
|
+
const formatStrftime = (f, fmt, utc) => {
|
|
3544
|
+
const hour12 = f.hour % 12 === 0 ? 12 : f.hour % 12;
|
|
3545
|
+
let out = "";
|
|
3546
|
+
for (let i = 0; i < fmt.length; i++) {
|
|
3547
|
+
if (fmt[i] !== "%") {
|
|
3548
|
+
out += fmt[i];
|
|
3549
|
+
continue;
|
|
2587
3550
|
}
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
3551
|
+
i++;
|
|
3552
|
+
const spec = fmt[i];
|
|
3553
|
+
switch (spec) {
|
|
3554
|
+
case "Y":
|
|
3555
|
+
out += String(f.year);
|
|
3556
|
+
break;
|
|
3557
|
+
case "C":
|
|
3558
|
+
out += pad(Math.floor(f.year / 100), 2);
|
|
3559
|
+
break;
|
|
3560
|
+
case "y":
|
|
3561
|
+
out += pad((f.year % 100 + 100) % 100, 2);
|
|
3562
|
+
break;
|
|
3563
|
+
case "m":
|
|
3564
|
+
out += pad(f.mon + 1, 2);
|
|
3565
|
+
break;
|
|
3566
|
+
case "d":
|
|
3567
|
+
out += pad(f.mday, 2);
|
|
3568
|
+
break;
|
|
3569
|
+
case "e":
|
|
3570
|
+
out += pad(f.mday, 2, " ");
|
|
3571
|
+
break;
|
|
3572
|
+
case "H":
|
|
3573
|
+
out += pad(f.hour, 2);
|
|
3574
|
+
break;
|
|
3575
|
+
case "k":
|
|
3576
|
+
out += pad(f.hour, 2, " ");
|
|
3577
|
+
break;
|
|
3578
|
+
case "I":
|
|
3579
|
+
out += pad(hour12, 2);
|
|
3580
|
+
break;
|
|
3581
|
+
case "l":
|
|
3582
|
+
out += pad(hour12, 2, " ");
|
|
3583
|
+
break;
|
|
3584
|
+
case "M":
|
|
3585
|
+
out += pad(f.min, 2);
|
|
3586
|
+
break;
|
|
3587
|
+
case "S":
|
|
3588
|
+
out += pad(Math.floor(f.sec), 2);
|
|
3589
|
+
break;
|
|
3590
|
+
case "p":
|
|
3591
|
+
out += f.hour < 12 ? "AM" : "PM";
|
|
3592
|
+
break;
|
|
3593
|
+
case "P":
|
|
3594
|
+
out += f.hour < 12 ? "am" : "pm";
|
|
3595
|
+
break;
|
|
3596
|
+
case "j":
|
|
3597
|
+
out += pad(f.yday + 1, 3);
|
|
3598
|
+
break;
|
|
3599
|
+
case "a":
|
|
3600
|
+
out += WEEKDAY_ABBR[(f.wday % 7 + 7) % 7];
|
|
3601
|
+
break;
|
|
3602
|
+
case "A":
|
|
3603
|
+
out += WEEKDAY_FULL[(f.wday % 7 + 7) % 7];
|
|
3604
|
+
break;
|
|
3605
|
+
case "b":
|
|
3606
|
+
case "h":
|
|
3607
|
+
out += MONTH_ABBR[(f.mon % 12 + 12) % 12];
|
|
3608
|
+
break;
|
|
3609
|
+
case "B":
|
|
3610
|
+
out += MONTH_FULL[(f.mon % 12 + 12) % 12];
|
|
3611
|
+
break;
|
|
3612
|
+
case "u":
|
|
3613
|
+
out += String(f.wday === 0 ? 7 : f.wday);
|
|
3614
|
+
break;
|
|
3615
|
+
case "w":
|
|
3616
|
+
out += String(f.wday);
|
|
3617
|
+
break;
|
|
3618
|
+
case "V":
|
|
3619
|
+
out += pad(isoWeek(f.year, f.mon, f.mday).week, 2);
|
|
3620
|
+
break;
|
|
3621
|
+
case "G":
|
|
3622
|
+
out += String(isoWeek(f.year, f.mon, f.mday).year);
|
|
3623
|
+
break;
|
|
3624
|
+
case "Z":
|
|
3625
|
+
out += utc ? "GMT" : localTzAbbr(f);
|
|
3626
|
+
break;
|
|
3627
|
+
case "z":
|
|
3628
|
+
out += utc ? "+0000" : localOffsetString(f);
|
|
3629
|
+
break;
|
|
3630
|
+
case "s":
|
|
3631
|
+
out += String(Math.floor(epochFromFields(f, true)));
|
|
3632
|
+
break;
|
|
3633
|
+
case "T":
|
|
3634
|
+
out += `${pad(f.hour, 2)}:${pad(f.min, 2)}:${pad(Math.floor(f.sec), 2)}`;
|
|
3635
|
+
break;
|
|
3636
|
+
case "R":
|
|
3637
|
+
out += `${pad(f.hour, 2)}:${pad(f.min, 2)}`;
|
|
3638
|
+
break;
|
|
3639
|
+
case "F":
|
|
3640
|
+
out += `${String(f.year)}-${pad(f.mon + 1, 2)}-${pad(f.mday, 2)}`;
|
|
3641
|
+
break;
|
|
3642
|
+
case "D":
|
|
3643
|
+
out += `${pad(f.mon + 1, 2)}/${pad(f.mday, 2)}/${pad((f.year % 100 + 100) % 100, 2)}`;
|
|
3644
|
+
break;
|
|
3645
|
+
case "n":
|
|
3646
|
+
out += "\n";
|
|
3647
|
+
break;
|
|
3648
|
+
case "t":
|
|
3649
|
+
out += " ";
|
|
3650
|
+
break;
|
|
3651
|
+
case "%":
|
|
3652
|
+
out += "%";
|
|
3653
|
+
break;
|
|
3654
|
+
case void 0:
|
|
3655
|
+
out += "%";
|
|
3656
|
+
break;
|
|
3657
|
+
default:
|
|
3658
|
+
out += `%${spec}`;
|
|
3659
|
+
break;
|
|
2599
3660
|
}
|
|
2600
|
-
return keysA.length - keysB.length;
|
|
2601
3661
|
}
|
|
2602
|
-
return
|
|
2603
|
-
}
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
3662
|
+
return out;
|
|
3663
|
+
};
|
|
3664
|
+
/** Parses a string into broken-down time fields using a C `strptime`-style format. */
|
|
3665
|
+
const parseStrptime = (input, fmt, span) => {
|
|
3666
|
+
let s = 0;
|
|
3667
|
+
let year = 1900;
|
|
3668
|
+
let mon = 0;
|
|
3669
|
+
let mday = 1;
|
|
3670
|
+
let hour = 0;
|
|
3671
|
+
let min = 0;
|
|
3672
|
+
let sec = 0;
|
|
3673
|
+
const fail = () => {
|
|
3674
|
+
throw new RuntimeError(`date "${input}" does not match format "${fmt}"`, span);
|
|
2613
3675
|
};
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
if (
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
const n = Math.floor(count);
|
|
2649
|
-
if (n <= 0) return null;
|
|
2650
|
-
return str.repeat(n);
|
|
2651
|
-
}
|
|
2652
|
-
function mergeDeep(target, source) {
|
|
2653
|
-
const result = { ...target };
|
|
2654
|
-
for (const key of Object.keys(source)) {
|
|
2655
|
-
const sVal = source[key];
|
|
2656
|
-
const tVal = result[key];
|
|
2657
|
-
if (isPlainObject$1(sVal) && tVal !== void 0 && isPlainObject$1(tVal)) result[key] = mergeDeep(tVal, sVal);
|
|
2658
|
-
else result[key] = sVal;
|
|
2659
|
-
}
|
|
2660
|
-
return result;
|
|
2661
|
-
}
|
|
2662
|
-
function isPlainObject$1(v) {
|
|
2663
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2664
|
-
}
|
|
2665
|
-
|
|
2666
|
-
//#endregion
|
|
2667
|
-
//#region src/builtins/math.ts
|
|
2668
|
-
const mathBuiltins = [
|
|
2669
|
-
{
|
|
2670
|
-
name: "floor",
|
|
2671
|
-
arity: 0,
|
|
2672
|
-
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
2673
|
-
if (typeof input !== "number") throw new RuntimeError("floor expects number", span);
|
|
2674
|
-
yield emit$1(Math.floor(input), span, tracker);
|
|
3676
|
+
const readInt = (maxLen) => {
|
|
3677
|
+
const start = s;
|
|
3678
|
+
if (input[s] === "+" || input[s] === "-") s++;
|
|
3679
|
+
let digits = 0;
|
|
3680
|
+
while (s < input.length && digits < maxLen && /[0-9]/.test(input[s])) {
|
|
3681
|
+
s++;
|
|
3682
|
+
digits++;
|
|
3683
|
+
}
|
|
3684
|
+
if (digits === 0) fail();
|
|
3685
|
+
return parseInt(input.slice(start, s), 10);
|
|
3686
|
+
};
|
|
3687
|
+
const matchName = (names) => {
|
|
3688
|
+
const lower = input.slice(s).toLowerCase();
|
|
3689
|
+
let best = -1;
|
|
3690
|
+
let bestLen = 0;
|
|
3691
|
+
names.forEach((name, index) => {
|
|
3692
|
+
const n = name.toLowerCase();
|
|
3693
|
+
if (lower.startsWith(n) && n.length > bestLen) {
|
|
3694
|
+
best = index;
|
|
3695
|
+
bestLen = n.length;
|
|
3696
|
+
}
|
|
3697
|
+
});
|
|
3698
|
+
if (best < 0) fail();
|
|
3699
|
+
s += bestLen;
|
|
3700
|
+
return best;
|
|
3701
|
+
};
|
|
3702
|
+
for (let i = 0; i < fmt.length; i++) {
|
|
3703
|
+
if (fmt[i] !== "%") {
|
|
3704
|
+
if (/\s/.test(fmt[i])) while (s < input.length && /\s/.test(input[s])) s++;
|
|
3705
|
+
else {
|
|
3706
|
+
if (input[s] !== fmt[i]) fail();
|
|
3707
|
+
s++;
|
|
3708
|
+
}
|
|
3709
|
+
continue;
|
|
2675
3710
|
}
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
3711
|
+
i++;
|
|
3712
|
+
switch (fmt[i]) {
|
|
3713
|
+
case "Y":
|
|
3714
|
+
year = readInt(4);
|
|
3715
|
+
break;
|
|
3716
|
+
case "y": {
|
|
3717
|
+
const yy = readInt(2);
|
|
3718
|
+
year = yy < 69 ? 2e3 + yy : 1900 + yy;
|
|
3719
|
+
break;
|
|
3720
|
+
}
|
|
3721
|
+
case "C":
|
|
3722
|
+
year = readInt(2) * 100;
|
|
3723
|
+
break;
|
|
3724
|
+
case "m":
|
|
3725
|
+
mon = readInt(2) - 1;
|
|
3726
|
+
break;
|
|
3727
|
+
case "d":
|
|
3728
|
+
case "e":
|
|
3729
|
+
while (s < input.length && input[s] === " ") s++;
|
|
3730
|
+
mday = readInt(2);
|
|
3731
|
+
break;
|
|
3732
|
+
case "H":
|
|
3733
|
+
case "k":
|
|
3734
|
+
case "I":
|
|
3735
|
+
case "l":
|
|
3736
|
+
while (s < input.length && input[s] === " ") s++;
|
|
3737
|
+
hour = readInt(2);
|
|
3738
|
+
break;
|
|
3739
|
+
case "M":
|
|
3740
|
+
min = readInt(2);
|
|
3741
|
+
break;
|
|
3742
|
+
case "S":
|
|
3743
|
+
sec = readInt(2);
|
|
3744
|
+
break;
|
|
3745
|
+
case "j":
|
|
3746
|
+
readInt(3);
|
|
3747
|
+
break;
|
|
3748
|
+
case "b":
|
|
3749
|
+
case "B":
|
|
3750
|
+
case "h":
|
|
3751
|
+
mon = matchName([...MONTH_ABBR, ...MONTH_FULL]) % 12;
|
|
3752
|
+
break;
|
|
3753
|
+
case "a":
|
|
3754
|
+
case "A":
|
|
3755
|
+
matchName([...WEEKDAY_ABBR, ...WEEKDAY_FULL]);
|
|
3756
|
+
break;
|
|
3757
|
+
case "p":
|
|
3758
|
+
case "P": {
|
|
3759
|
+
const ampm = input.slice(s, s + 2).toUpperCase();
|
|
3760
|
+
if (ampm === "AM") {
|
|
3761
|
+
if (hour === 12) hour = 0;
|
|
3762
|
+
s += 2;
|
|
3763
|
+
} else if (ampm === "PM") {
|
|
3764
|
+
if (hour < 12) hour += 12;
|
|
3765
|
+
s += 2;
|
|
3766
|
+
} else fail();
|
|
3767
|
+
break;
|
|
3768
|
+
}
|
|
3769
|
+
case "z":
|
|
3770
|
+
if (input[s] === "Z") s++;
|
|
3771
|
+
else {
|
|
3772
|
+
if (input[s] === "+" || input[s] === "-") s++;
|
|
3773
|
+
s += 2;
|
|
3774
|
+
if (input[s] === ":") s++;
|
|
3775
|
+
s += 2;
|
|
3776
|
+
}
|
|
3777
|
+
break;
|
|
3778
|
+
case "Z":
|
|
3779
|
+
while (s < input.length && /[A-Za-z]/.test(input[s])) s++;
|
|
3780
|
+
break;
|
|
3781
|
+
case "n":
|
|
3782
|
+
case "t":
|
|
3783
|
+
while (s < input.length && /\s/.test(input[s])) s++;
|
|
3784
|
+
break;
|
|
3785
|
+
case "%":
|
|
3786
|
+
if (input[s] !== "%") fail();
|
|
3787
|
+
s++;
|
|
3788
|
+
break;
|
|
3789
|
+
default: fail();
|
|
2683
3790
|
}
|
|
2684
|
-
}
|
|
3791
|
+
}
|
|
3792
|
+
return fieldsFromEpoch(utcMillis(year, mon, mday, hour, min, sec) / 1e3, true);
|
|
3793
|
+
};
|
|
3794
|
+
/** Resolves strftime input that may be either an epoch number or a broken-down array. */
|
|
3795
|
+
const fieldsForFormat = (input, fn, span, utc) => typeof input === "number" ? fieldsFromEpoch(input, utc) : fieldsFromArray(input, fn, span);
|
|
3796
|
+
const readFormat = (value, fn, span) => {
|
|
3797
|
+
if (typeof value !== "string") throw new RuntimeError(`${fn}/1 requires a string format`, span);
|
|
3798
|
+
return value;
|
|
3799
|
+
};
|
|
3800
|
+
const ISO8601 = "%Y-%m-%dT%H:%M:%SZ";
|
|
3801
|
+
const dateBuiltins = [
|
|
2685
3802
|
{
|
|
2686
|
-
name: "
|
|
3803
|
+
name: "now",
|
|
2687
3804
|
arity: 0,
|
|
2688
|
-
apply: function* (
|
|
2689
|
-
|
|
2690
|
-
yield emit$1(Math.round(input), span, tracker);
|
|
3805
|
+
apply: function* (_input, _args, _env, tracker, _eval, span) {
|
|
3806
|
+
yield emit$1(tracker.now(span), span, tracker);
|
|
2691
3807
|
}
|
|
2692
3808
|
},
|
|
2693
3809
|
{
|
|
2694
|
-
name: "
|
|
3810
|
+
name: "gmtime",
|
|
2695
3811
|
arity: 0,
|
|
2696
3812
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
2697
|
-
|
|
2698
|
-
yield emit$1(Math.abs(input), span, tracker);
|
|
3813
|
+
yield emit$1(fieldsToArray(fieldsFromEpoch(requireNumber(input, "gmtime", span), true)), span, tracker);
|
|
2699
3814
|
}
|
|
2700
3815
|
},
|
|
2701
3816
|
{
|
|
2702
|
-
name: "
|
|
3817
|
+
name: "localtime",
|
|
2703
3818
|
arity: 0,
|
|
2704
3819
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
2705
|
-
|
|
2706
|
-
yield emit$1(Math.sqrt(input), span, tracker);
|
|
3820
|
+
yield emit$1(fieldsToArray(fieldsFromEpoch(requireNumber(input, "localtime", span), false)), span, tracker);
|
|
2707
3821
|
}
|
|
2708
3822
|
},
|
|
2709
3823
|
{
|
|
2710
|
-
name: "
|
|
3824
|
+
name: "mktime",
|
|
2711
3825
|
arity: 0,
|
|
2712
3826
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
2713
|
-
|
|
2714
|
-
yield emit$1(false, span, tracker);
|
|
2715
|
-
return;
|
|
2716
|
-
}
|
|
2717
|
-
yield emit$1(Number.isNaN(input), span, tracker);
|
|
3827
|
+
yield emit$1(epochFromFields(fieldsFromArray(input, "mktime", span), true), span, tracker);
|
|
2718
3828
|
}
|
|
2719
3829
|
},
|
|
2720
3830
|
{
|
|
2721
|
-
name: "
|
|
2722
|
-
arity:
|
|
2723
|
-
apply: function* (input,
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
return;
|
|
2727
|
-
}
|
|
2728
|
-
yield emit$1(!Number.isFinite(input) && !Number.isNaN(input), span, tracker);
|
|
3831
|
+
name: "strftime",
|
|
3832
|
+
arity: 1,
|
|
3833
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
3834
|
+
const fields = fieldsForFormat(input, "strftime", span, true);
|
|
3835
|
+
for (const fmt of evaluate(args[0], input, env, tracker)) yield emit$1(formatStrftime(fields, readFormat(fmt, "strftime", span), true), span, tracker);
|
|
2729
3836
|
}
|
|
2730
3837
|
},
|
|
2731
3838
|
{
|
|
2732
|
-
name: "
|
|
2733
|
-
arity:
|
|
2734
|
-
apply: function* (input,
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
return;
|
|
2738
|
-
}
|
|
2739
|
-
yield emit$1(Number.isFinite(input), span, tracker);
|
|
3839
|
+
name: "strflocaltime",
|
|
3840
|
+
arity: 1,
|
|
3841
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
3842
|
+
const fields = fieldsForFormat(input, "strflocaltime", span, false);
|
|
3843
|
+
for (const fmt of evaluate(args[0], input, env, tracker)) yield emit$1(formatStrftime(fields, readFormat(fmt, "strflocaltime", span), false), span, tracker);
|
|
2740
3844
|
}
|
|
2741
3845
|
},
|
|
2742
3846
|
{
|
|
2743
|
-
name: "
|
|
2744
|
-
arity:
|
|
2745
|
-
apply: function* (input,
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
return;
|
|
2749
|
-
}
|
|
2750
|
-
if (!Number.isFinite(input) || Number.isNaN(input) || input === 0) {
|
|
2751
|
-
yield emit$1(false, span, tracker);
|
|
2752
|
-
return;
|
|
2753
|
-
}
|
|
2754
|
-
yield emit$1(true, span, tracker);
|
|
3847
|
+
name: "strptime",
|
|
3848
|
+
arity: 1,
|
|
3849
|
+
apply: function* (input, args, env, tracker, evaluate, span) {
|
|
3850
|
+
const str = requireString(input, "strptime", span);
|
|
3851
|
+
for (const fmt of evaluate(args[0], input, env, tracker)) yield emit$1(fieldsToArray(parseStrptime(str, readFormat(fmt, "strptime", span), span)), span, tracker);
|
|
2755
3852
|
}
|
|
2756
3853
|
},
|
|
2757
3854
|
{
|
|
2758
|
-
name: "
|
|
3855
|
+
name: "todate",
|
|
2759
3856
|
arity: 0,
|
|
2760
3857
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
2761
|
-
|
|
2762
|
-
yield emit$1(false, span, tracker);
|
|
2763
|
-
return;
|
|
2764
|
-
}
|
|
2765
|
-
yield emit$1(false, span, tracker);
|
|
3858
|
+
yield emit$1(formatStrftime(fieldsFromEpoch(requireNumber(input, "todate", span), true), ISO8601, true), span, tracker);
|
|
2766
3859
|
}
|
|
2767
3860
|
},
|
|
2768
3861
|
{
|
|
2769
|
-
name: "
|
|
3862
|
+
name: "todateiso8601",
|
|
2770
3863
|
arity: 0,
|
|
2771
3864
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
2772
|
-
|
|
2773
|
-
if (input.length === 0) {
|
|
2774
|
-
yield emit$1(null, span, tracker);
|
|
2775
|
-
return;
|
|
2776
|
-
}
|
|
2777
|
-
let minVal = input[0];
|
|
2778
|
-
for (let i = 1; i < input.length; i++) if (compareValues(input[i], minVal) < 0) minVal = input[i];
|
|
2779
|
-
yield emit$1(minVal, span, tracker);
|
|
3865
|
+
yield emit$1(formatStrftime(fieldsFromEpoch(requireNumber(input, "todateiso8601", span), true), ISO8601, true), span, tracker);
|
|
2780
3866
|
}
|
|
2781
3867
|
},
|
|
2782
3868
|
{
|
|
2783
|
-
name: "
|
|
3869
|
+
name: "fromdate",
|
|
2784
3870
|
arity: 0,
|
|
2785
3871
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
2786
|
-
|
|
2787
|
-
if (input.length === 0) {
|
|
2788
|
-
yield emit$1(null, span, tracker);
|
|
2789
|
-
return;
|
|
2790
|
-
}
|
|
2791
|
-
let maxVal = input[0];
|
|
2792
|
-
for (let i = 1; i < input.length; i++) if (compareValues(input[i], maxVal) > 0) maxVal = input[i];
|
|
2793
|
-
yield emit$1(maxVal, span, tracker);
|
|
2794
|
-
}
|
|
2795
|
-
},
|
|
2796
|
-
{
|
|
2797
|
-
name: "min_by",
|
|
2798
|
-
arity: 1,
|
|
2799
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
2800
|
-
if (!Array.isArray(input)) throw new RuntimeError("min_by expects an array", span);
|
|
2801
|
-
if (input.length === 0) {
|
|
2802
|
-
yield emit$1(null, span, tracker);
|
|
2803
|
-
return;
|
|
2804
|
-
}
|
|
2805
|
-
let minItem = input[0];
|
|
2806
|
-
let minKey;
|
|
2807
|
-
const keys0 = Array.from(evaluate$1(args[0], minItem, env, tracker));
|
|
2808
|
-
if (keys0.length !== 1) throw new RuntimeError("min_by key must return one value", span);
|
|
2809
|
-
minKey = keys0[0];
|
|
2810
|
-
for (let i = 1; i < input.length; i++) {
|
|
2811
|
-
const item = input[i];
|
|
2812
|
-
const keys = Array.from(evaluate$1(args[0], item, env, tracker));
|
|
2813
|
-
if (keys.length !== 1) throw new RuntimeError("min_by key must return one value", span);
|
|
2814
|
-
const key = keys[0];
|
|
2815
|
-
if (compareValues(key, minKey) < 0) {
|
|
2816
|
-
minKey = key;
|
|
2817
|
-
minItem = item;
|
|
2818
|
-
}
|
|
2819
|
-
}
|
|
2820
|
-
yield emit$1(minItem, span, tracker);
|
|
3872
|
+
yield emit$1(epochFromFields(parseStrptime(requireString(input, "fromdate", span), ISO8601, span), true), span, tracker);
|
|
2821
3873
|
}
|
|
2822
3874
|
},
|
|
2823
3875
|
{
|
|
2824
|
-
name: "
|
|
2825
|
-
arity: 1,
|
|
2826
|
-
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
2827
|
-
if (!Array.isArray(input)) throw new RuntimeError("max_by expects an array", span);
|
|
2828
|
-
if (input.length === 0) {
|
|
2829
|
-
yield emit$1(null, span, tracker);
|
|
2830
|
-
return;
|
|
2831
|
-
}
|
|
2832
|
-
let maxItem = input[0];
|
|
2833
|
-
let maxKey;
|
|
2834
|
-
const keys0 = Array.from(evaluate$1(args[0], maxItem, env, tracker));
|
|
2835
|
-
if (keys0.length !== 1) throw new RuntimeError("max_by key must return one value", span);
|
|
2836
|
-
maxKey = keys0[0];
|
|
2837
|
-
for (let i = 1; i < input.length; i++) {
|
|
2838
|
-
const item = input[i];
|
|
2839
|
-
const keys = Array.from(evaluate$1(args[0], item, env, tracker));
|
|
2840
|
-
if (keys.length !== 1) throw new RuntimeError("max_by key must return one value", span);
|
|
2841
|
-
const key = keys[0];
|
|
2842
|
-
if (compareValues(key, maxKey) > 0) {
|
|
2843
|
-
maxKey = key;
|
|
2844
|
-
maxItem = item;
|
|
2845
|
-
}
|
|
2846
|
-
}
|
|
2847
|
-
yield emit$1(maxItem, span, tracker);
|
|
2848
|
-
}
|
|
2849
|
-
},
|
|
2850
|
-
{
|
|
2851
|
-
name: "add",
|
|
3876
|
+
name: "fromdateiso8601",
|
|
2852
3877
|
arity: 0,
|
|
2853
3878
|
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
2854
|
-
|
|
2855
|
-
if (input.length === 0) {
|
|
2856
|
-
yield emit$1(null, span, tracker);
|
|
2857
|
-
return;
|
|
2858
|
-
}
|
|
2859
|
-
let acc = input[0];
|
|
2860
|
-
for (let i = 1; i < input.length; i++) {
|
|
2861
|
-
tracker.step(span);
|
|
2862
|
-
acc = add(acc, input[i], span);
|
|
2863
|
-
}
|
|
2864
|
-
yield emit$1(acc, span, tracker);
|
|
3879
|
+
yield emit$1(epochFromFields(parseStrptime(requireString(input, "fromdateiso8601", span), ISO8601, span), true), span, tracker);
|
|
2865
3880
|
}
|
|
2866
3881
|
}
|
|
2867
3882
|
];
|
|
2868
|
-
|
|
2869
3883
|
//#endregion
|
|
2870
3884
|
//#region src/builtins/index.ts
|
|
2871
3885
|
const registerAllBuiltins = () => {
|
|
@@ -2876,12 +3890,11 @@ const registerAllBuiltins = () => {
|
|
|
2876
3890
|
registerBuiltins(pathBuiltins);
|
|
2877
3891
|
registerBuiltins(iteratorBuiltins);
|
|
2878
3892
|
registerBuiltins(mathBuiltins);
|
|
3893
|
+
registerBuiltins(dateBuiltins);
|
|
2879
3894
|
};
|
|
2880
|
-
|
|
2881
3895
|
//#endregion
|
|
2882
3896
|
//#region src/builtins.ts
|
|
2883
3897
|
registerAllBuiltins();
|
|
2884
|
-
|
|
2885
3898
|
//#endregion
|
|
2886
3899
|
//#region src/validate.ts
|
|
2887
3900
|
/**
|
|
@@ -2892,57 +3905,57 @@ registerAllBuiltins();
|
|
|
2892
3905
|
* @throws {ValidationError} If validation fails.
|
|
2893
3906
|
*/
|
|
2894
3907
|
const validate = (node) => {
|
|
2895
|
-
visit(node, []);
|
|
3908
|
+
visit$1(node, []);
|
|
2896
3909
|
};
|
|
2897
|
-
const visit = (node, scope) => {
|
|
3910
|
+
const visit$1 = (node, scope) => {
|
|
2898
3911
|
switch (node.kind) {
|
|
2899
3912
|
case "Identity":
|
|
2900
3913
|
case "Literal":
|
|
2901
3914
|
case "Var": return;
|
|
2902
3915
|
case "FieldAccess":
|
|
2903
|
-
visit(node.target, scope);
|
|
3916
|
+
visit$1(node.target, scope);
|
|
2904
3917
|
return;
|
|
2905
3918
|
case "IndexAccess":
|
|
2906
|
-
visit(node.target, scope);
|
|
2907
|
-
visit(node.index, scope);
|
|
3919
|
+
visit$1(node.target, scope);
|
|
3920
|
+
visit$1(node.index, scope);
|
|
2908
3921
|
return;
|
|
2909
3922
|
case "Array":
|
|
2910
|
-
node.items.forEach((n) => visit(n, scope));
|
|
3923
|
+
node.items.forEach((n) => visit$1(n, scope));
|
|
2911
3924
|
return;
|
|
2912
3925
|
case "Object":
|
|
2913
3926
|
node.entries.forEach((entry) => {
|
|
2914
|
-
if (entry.key.kind === "KeyExpr") visit(entry.key.expr, scope);
|
|
2915
|
-
visit(entry.value, scope);
|
|
3927
|
+
if (entry.key.kind === "KeyExpr") visit$1(entry.key.expr, scope);
|
|
3928
|
+
visit$1(entry.value, scope);
|
|
2916
3929
|
});
|
|
2917
3930
|
return;
|
|
2918
3931
|
case "Pipe":
|
|
2919
3932
|
case "Comma":
|
|
2920
3933
|
case "Alt":
|
|
2921
|
-
visit(node.left, scope);
|
|
2922
|
-
visit(node.right, scope);
|
|
3934
|
+
visit$1(node.left, scope);
|
|
3935
|
+
visit$1(node.right, scope);
|
|
2923
3936
|
return;
|
|
2924
3937
|
case "Binary":
|
|
2925
3938
|
case "Bool":
|
|
2926
|
-
visit(node.left, scope);
|
|
2927
|
-
visit(node.right, scope);
|
|
3939
|
+
visit$1(node.left, scope);
|
|
3940
|
+
visit$1(node.right, scope);
|
|
2928
3941
|
return;
|
|
2929
3942
|
case "Unary":
|
|
2930
|
-
visit(node.expr, scope);
|
|
3943
|
+
visit$1(node.expr, scope);
|
|
2931
3944
|
return;
|
|
2932
3945
|
case "If":
|
|
2933
3946
|
node.branches.forEach((branch) => {
|
|
2934
|
-
visit(branch.cond, scope);
|
|
2935
|
-
visit(branch.then, scope);
|
|
3947
|
+
visit$1(branch.cond, scope);
|
|
3948
|
+
visit$1(branch.then, scope);
|
|
2936
3949
|
});
|
|
2937
|
-
visit(node.else, scope);
|
|
3950
|
+
visit$1(node.else, scope);
|
|
2938
3951
|
return;
|
|
2939
3952
|
case "As":
|
|
2940
|
-
visit(node.bind, scope);
|
|
2941
|
-
visit(node.body, scope);
|
|
3953
|
+
visit$1(node.bind, scope);
|
|
3954
|
+
visit$1(node.body, scope);
|
|
2942
3955
|
return;
|
|
2943
3956
|
case "Call": {
|
|
2944
3957
|
for (let i = scope.length - 1; i >= 0; i--) if (scope[i].has(node.name)) {
|
|
2945
|
-
for (const arg of node.args) visit(arg, scope);
|
|
3958
|
+
for (const arg of node.args) visit$1(arg, scope);
|
|
2946
3959
|
return;
|
|
2947
3960
|
}
|
|
2948
3961
|
const specs = builtins[node.name];
|
|
@@ -2951,51 +3964,50 @@ const visit = (node, scope) => {
|
|
|
2951
3964
|
const arities = specs.map((s) => s.arity).join(" or ");
|
|
2952
3965
|
throw new ValidationError(`Function ${node.name} expects ${arities} arguments, but got ${node.args.length}`, node.span);
|
|
2953
3966
|
}
|
|
2954
|
-
for (const arg of node.args) visit(arg, scope);
|
|
3967
|
+
for (const arg of node.args) visit$1(arg, scope);
|
|
2955
3968
|
return;
|
|
2956
3969
|
}
|
|
2957
3970
|
case "Assignment":
|
|
2958
|
-
visit(node.left, scope);
|
|
2959
|
-
visit(node.right, scope);
|
|
3971
|
+
visit$1(node.left, scope);
|
|
3972
|
+
visit$1(node.right, scope);
|
|
2960
3973
|
return;
|
|
2961
3974
|
case "Def": {
|
|
2962
3975
|
const bodyScope = new Set(node.args);
|
|
2963
3976
|
bodyScope.add(node.name);
|
|
2964
|
-
visit(node.body, [...scope, bodyScope]);
|
|
3977
|
+
visit$1(node.body, [...scope, bodyScope]);
|
|
2965
3978
|
const nextScope = new Set([node.name]);
|
|
2966
|
-
visit(node.next, [...scope, nextScope]);
|
|
3979
|
+
visit$1(node.next, [...scope, nextScope]);
|
|
2967
3980
|
return;
|
|
2968
3981
|
}
|
|
2969
3982
|
case "Reduce":
|
|
2970
|
-
visit(node.source, scope);
|
|
2971
|
-
visit(node.init, scope);
|
|
2972
|
-
visit(node.update, scope);
|
|
3983
|
+
visit$1(node.source, scope);
|
|
3984
|
+
visit$1(node.init, scope);
|
|
3985
|
+
visit$1(node.update, scope);
|
|
2973
3986
|
return;
|
|
2974
3987
|
case "Foreach":
|
|
2975
|
-
visit(node.source, scope);
|
|
2976
|
-
visit(node.init, scope);
|
|
2977
|
-
visit(node.update, scope);
|
|
2978
|
-
if (node.extract) visit(node.extract, scope);
|
|
3988
|
+
visit$1(node.source, scope);
|
|
3989
|
+
visit$1(node.init, scope);
|
|
3990
|
+
visit$1(node.update, scope);
|
|
3991
|
+
if (node.extract) visit$1(node.extract, scope);
|
|
2979
3992
|
return;
|
|
2980
3993
|
case "Try":
|
|
2981
|
-
visit(node.body, scope);
|
|
2982
|
-
if (node.handler) visit(node.handler, scope);
|
|
3994
|
+
visit$1(node.body, scope);
|
|
3995
|
+
if (node.handler) visit$1(node.handler, scope);
|
|
2983
3996
|
return;
|
|
2984
3997
|
case "Recurse":
|
|
2985
3998
|
case "Iterate":
|
|
2986
3999
|
case "Break": return;
|
|
2987
4000
|
case "Label":
|
|
2988
|
-
visit(node.body, scope);
|
|
4001
|
+
visit$1(node.body, scope);
|
|
2989
4002
|
return;
|
|
2990
4003
|
case "Slice":
|
|
2991
|
-
visit(node.target, scope);
|
|
2992
|
-
if (node.start) visit(node.start, scope);
|
|
2993
|
-
if (node.end) visit(node.end, scope);
|
|
4004
|
+
visit$1(node.target, scope);
|
|
4005
|
+
if (node.start) visit$1(node.start, scope);
|
|
4006
|
+
if (node.end) visit$1(node.end, scope);
|
|
2994
4007
|
return;
|
|
2995
4008
|
default: return node;
|
|
2996
4009
|
}
|
|
2997
4010
|
};
|
|
2998
|
-
|
|
2999
4011
|
//#endregion
|
|
3000
4012
|
//#region src/eval/break.ts
|
|
3001
4013
|
/**
|
|
@@ -3009,7 +4021,6 @@ var BreakSignal = class BreakSignal extends Error {
|
|
|
3009
4021
|
Object.setPrototypeOf(this, BreakSignal.prototype);
|
|
3010
4022
|
}
|
|
3011
4023
|
};
|
|
3012
|
-
|
|
3013
4024
|
//#endregion
|
|
3014
4025
|
//#region src/limits.ts
|
|
3015
4026
|
const DEFAULT_LIMITS = {
|
|
@@ -3036,8 +4047,27 @@ var LimitTracker = class {
|
|
|
3036
4047
|
steps = 0;
|
|
3037
4048
|
depth = 0;
|
|
3038
4049
|
outputs = 0;
|
|
3039
|
-
|
|
4050
|
+
/**
|
|
4051
|
+
* @param limits - Resolved execution limits.
|
|
4052
|
+
* @param nowSeconds - The wall-clock instant exposed to the `now` builtin, as
|
|
4053
|
+
* seconds since the Unix epoch (may be fractional). When `undefined`, the
|
|
4054
|
+
* `now` builtin throws rather than reading the host clock — jq-ts never
|
|
4055
|
+
* reads the real clock on its own, so date programs stay deterministic
|
|
4056
|
+
* unless the caller injects a clock via `options.now`.
|
|
4057
|
+
*/
|
|
4058
|
+
constructor(limits, nowSeconds) {
|
|
3040
4059
|
this.limits = limits;
|
|
4060
|
+
this.nowSeconds = nowSeconds;
|
|
4061
|
+
}
|
|
4062
|
+
/**
|
|
4063
|
+
* Returns the injected wall-clock instant (seconds since the Unix epoch) for
|
|
4064
|
+
* the `now` builtin.
|
|
4065
|
+
* @param span - The source span for error reporting.
|
|
4066
|
+
* @throws {RuntimeError} If no clock was injected (`options.now` was unset).
|
|
4067
|
+
*/
|
|
4068
|
+
now(span) {
|
|
4069
|
+
if (this.nowSeconds === void 0) throw new RuntimeError("now/0 requires an injected clock; pass options.now (a Date or epoch seconds)", span);
|
|
4070
|
+
return this.nowSeconds;
|
|
3041
4071
|
}
|
|
3042
4072
|
/**
|
|
3043
4073
|
* Records a single execution step (AST node visit).
|
|
@@ -3070,7 +4100,6 @@ var LimitTracker = class {
|
|
|
3070
4100
|
if (this.outputs > this.limits.maxOutputs) throw new RuntimeError("Output limit exceeded", span);
|
|
3071
4101
|
}
|
|
3072
4102
|
};
|
|
3073
|
-
|
|
3074
4103
|
//#endregion
|
|
3075
4104
|
//#region src/eval/env.ts
|
|
3076
4105
|
/**
|
|
@@ -3080,7 +4109,26 @@ var LimitTracker = class {
|
|
|
3080
4109
|
const getVar = (env, name) => {
|
|
3081
4110
|
for (let i = env.length - 1; i >= 0; i--) if (env[i].vars.has(name)) return env[i].vars.get(name);
|
|
3082
4111
|
};
|
|
3083
|
-
|
|
4112
|
+
/**
|
|
4113
|
+
* Binds jq `as` destructuring patterns into a variable map.
|
|
4114
|
+
*/
|
|
4115
|
+
const bindPattern = (pattern, value, bindings) => {
|
|
4116
|
+
switch (pattern.kind) {
|
|
4117
|
+
case "VariablePattern":
|
|
4118
|
+
bindings.set(pattern.name, value);
|
|
4119
|
+
return;
|
|
4120
|
+
case "ArrayPattern":
|
|
4121
|
+
if (!Array.isArray(value)) throw new RuntimeError(`Cannot index ${describeType(value)} with number`, pattern.span);
|
|
4122
|
+
pattern.items.forEach((item, index) => {
|
|
4123
|
+
bindPattern(item, index < value.length ? value[index] : null, bindings);
|
|
4124
|
+
});
|
|
4125
|
+
return;
|
|
4126
|
+
case "ObjectPattern":
|
|
4127
|
+
if (!isPlainObject$1(value)) throw new RuntimeError(`Cannot index ${describeType(value)} with string`, pattern.span);
|
|
4128
|
+
for (const entry of pattern.entries) bindPattern(entry.pattern, Object.prototype.hasOwnProperty.call(value, entry.key) ? value[entry.key] : null, bindings);
|
|
4129
|
+
return;
|
|
4130
|
+
}
|
|
4131
|
+
};
|
|
3084
4132
|
//#endregion
|
|
3085
4133
|
//#region src/eval/common.ts
|
|
3086
4134
|
/**
|
|
@@ -3112,7 +4160,6 @@ const toIndex = (value, span) => {
|
|
|
3112
4160
|
}
|
|
3113
4161
|
throw new RuntimeError("Expected numeric index", span);
|
|
3114
4162
|
};
|
|
3115
|
-
|
|
3116
4163
|
//#endregion
|
|
3117
4164
|
//#region src/eval/assignment.ts
|
|
3118
4165
|
/**
|
|
@@ -3128,15 +4175,15 @@ const toIndex = (value, span) => {
|
|
|
3128
4175
|
* @param tracker - Limits tracker.
|
|
3129
4176
|
* @param evaluate - Recursive evaluator.
|
|
3130
4177
|
*/
|
|
3131
|
-
const evalAssignment = function* (node, input, env, tracker, evaluate
|
|
3132
|
-
const paths = Array.from(evaluatePath(node.left, input, env, tracker, evaluate
|
|
4178
|
+
const evalAssignment = function* (node, input, env, tracker, evaluate) {
|
|
4179
|
+
const paths = Array.from(evaluatePath(node.left, input, env, tracker, evaluate));
|
|
3133
4180
|
paths.sort((a, b) => compareValues(a, b) * -1);
|
|
3134
4181
|
if (paths.length === 0) {
|
|
3135
4182
|
yield emit(input, node.span, tracker);
|
|
3136
4183
|
return;
|
|
3137
4184
|
}
|
|
3138
4185
|
if (node.op === "=") {
|
|
3139
|
-
const rhsValues = Array.from(evaluate
|
|
4186
|
+
const rhsValues = Array.from(evaluate(node.right, input, env, tracker));
|
|
3140
4187
|
if (rhsValues.length === 0) return;
|
|
3141
4188
|
for (const rhsVal of rhsValues) {
|
|
3142
4189
|
let current = input;
|
|
@@ -3145,9 +4192,9 @@ const evalAssignment = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3145
4192
|
}
|
|
3146
4193
|
return;
|
|
3147
4194
|
}
|
|
3148
|
-
yield* applyUpdates(input, paths, 0, node.op, node.right, input, env, tracker, evaluate
|
|
4195
|
+
yield* applyUpdates(input, paths, 0, node.op, node.right, input, env, tracker, evaluate);
|
|
3149
4196
|
};
|
|
3150
|
-
function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tracker, evaluate
|
|
4197
|
+
function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tracker, evaluate) {
|
|
3151
4198
|
if (index >= paths.length) {
|
|
3152
4199
|
yield current;
|
|
3153
4200
|
return;
|
|
@@ -3155,9 +4202,9 @@ function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tr
|
|
|
3155
4202
|
const path = paths[index];
|
|
3156
4203
|
const oldValue = getPath(current, path) ?? null;
|
|
3157
4204
|
let newValues = [];
|
|
3158
|
-
if (op === "|=") newValues = Array.from(evaluate
|
|
4205
|
+
if (op === "|=") newValues = Array.from(evaluate(rhsNode, oldValue, env, tracker));
|
|
3159
4206
|
else {
|
|
3160
|
-
const rhsResults = Array.from(evaluate
|
|
4207
|
+
const rhsResults = Array.from(evaluate(rhsNode, contextInput, env, tracker));
|
|
3161
4208
|
for (const rhs of rhsResults) {
|
|
3162
4209
|
let res;
|
|
3163
4210
|
switch (op) {
|
|
@@ -3185,12 +4232,11 @@ function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tr
|
|
|
3185
4232
|
}
|
|
3186
4233
|
}
|
|
3187
4234
|
if (newValues.length === 0) {
|
|
3188
|
-
yield* applyUpdates(deletePaths(current, [path], rhsNode.span), paths, index + 1, op, rhsNode, contextInput, env, tracker, evaluate
|
|
4235
|
+
yield* applyUpdates(deletePaths(current, [path], rhsNode.span), paths, index + 1, op, rhsNode, contextInput, env, tracker, evaluate);
|
|
3189
4236
|
return;
|
|
3190
4237
|
}
|
|
3191
|
-
for (const val of newValues) yield* applyUpdates(updatePath(current, path, () => val, rhsNode.span) ?? current, paths, index + 1, op, rhsNode, contextInput, env, tracker, evaluate
|
|
4238
|
+
for (const val of newValues) yield* applyUpdates(updatePath(current, path, () => val, rhsNode.span) ?? current, paths, index + 1, op, rhsNode, contextInput, env, tracker, evaluate);
|
|
3192
4239
|
}
|
|
3193
|
-
|
|
3194
4240
|
//#endregion
|
|
3195
4241
|
//#region src/eval/iterators.ts
|
|
3196
4242
|
/**
|
|
@@ -3202,14 +4248,14 @@ function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tr
|
|
|
3202
4248
|
* @param tracker - Limits tracker.
|
|
3203
4249
|
* @param evaluate - Recursive evaluator.
|
|
3204
4250
|
*/
|
|
3205
|
-
const evalIterate = function* (node, input, env, tracker, evaluate
|
|
3206
|
-
for (const container of evaluate
|
|
4251
|
+
const evalIterate = function* (node, input, env, tracker, evaluate) {
|
|
4252
|
+
for (const container of evaluate(node.target, input, env, tracker)) {
|
|
3207
4253
|
if (container === null) continue;
|
|
3208
4254
|
if (isValueArray(container)) {
|
|
3209
4255
|
for (const item of container) yield emit(item, node.span, tracker);
|
|
3210
4256
|
continue;
|
|
3211
4257
|
}
|
|
3212
|
-
if (isPlainObject(container)) {
|
|
4258
|
+
if (isPlainObject$1(container)) {
|
|
3213
4259
|
const keys = Object.keys(container).sort();
|
|
3214
4260
|
for (const key of keys) yield emit(container[key], node.span, tracker);
|
|
3215
4261
|
continue;
|
|
@@ -3228,18 +4274,20 @@ const evalIterate = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3228
4274
|
* @param tracker - Limits tracker.
|
|
3229
4275
|
* @param evaluate - Recursive evaluator.
|
|
3230
4276
|
*/
|
|
3231
|
-
const evalReduce = function* (node, input, env, tracker, evaluate
|
|
3232
|
-
const initValues = Array.from(evaluate
|
|
4277
|
+
const evalReduce = function* (node, input, env, tracker, evaluate) {
|
|
4278
|
+
const initValues = Array.from(evaluate(node.init, input, env, tracker));
|
|
3233
4279
|
if (initValues.length !== 1) throw new RuntimeError("Reduce init must single value", node.init.span);
|
|
3234
4280
|
let acc = initValues[0];
|
|
3235
|
-
for (const item of evaluate
|
|
4281
|
+
for (const item of evaluate(node.source, input, env, tracker)) {
|
|
3236
4282
|
tracker.step(node.span);
|
|
4283
|
+
const vars = /* @__PURE__ */ new Map();
|
|
4284
|
+
bindPattern(node.pattern, item, vars);
|
|
3237
4285
|
const newFrame = {
|
|
3238
|
-
vars
|
|
4286
|
+
vars,
|
|
3239
4287
|
funcs: /* @__PURE__ */ new Map()
|
|
3240
4288
|
};
|
|
3241
4289
|
const newEnv = [...env, newFrame];
|
|
3242
|
-
const updates = Array.from(evaluate
|
|
4290
|
+
const updates = Array.from(evaluate(node.update, acc, newEnv, tracker));
|
|
3243
4291
|
if (updates.length !== 1) throw new RuntimeError("Reduce update must produce single value", node.update.span);
|
|
3244
4292
|
acc = updates[0];
|
|
3245
4293
|
}
|
|
@@ -3256,21 +4304,23 @@ const evalReduce = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3256
4304
|
* @param tracker - Limits tracker.
|
|
3257
4305
|
* @param evaluate - Recursive evaluator.
|
|
3258
4306
|
*/
|
|
3259
|
-
const evalForeach = function* (node, input, env, tracker, evaluate
|
|
3260
|
-
const initValues = Array.from(evaluate
|
|
4307
|
+
const evalForeach = function* (node, input, env, tracker, evaluate) {
|
|
4308
|
+
const initValues = Array.from(evaluate(node.init, input, env, tracker));
|
|
3261
4309
|
if (initValues.length !== 1) throw new RuntimeError("Foreach init must single value", node.init.span);
|
|
3262
4310
|
let acc = initValues[0];
|
|
3263
|
-
for (const item of evaluate
|
|
4311
|
+
for (const item of evaluate(node.source, input, env, tracker)) {
|
|
3264
4312
|
tracker.step(node.span);
|
|
4313
|
+
const vars = /* @__PURE__ */ new Map();
|
|
4314
|
+
bindPattern(node.pattern, item, vars);
|
|
3265
4315
|
const newFrame = {
|
|
3266
|
-
vars
|
|
4316
|
+
vars,
|
|
3267
4317
|
funcs: /* @__PURE__ */ new Map()
|
|
3268
4318
|
};
|
|
3269
4319
|
const newEnv = [...env, newFrame];
|
|
3270
|
-
const updates = Array.from(evaluate
|
|
4320
|
+
const updates = Array.from(evaluate(node.update, acc, newEnv, tracker));
|
|
3271
4321
|
if (updates.length !== 1) throw new RuntimeError("Foreach update must produce single value", node.update.span);
|
|
3272
4322
|
acc = updates[0];
|
|
3273
|
-
if (node.extract) for (const extracted of evaluate
|
|
4323
|
+
if (node.extract) for (const extracted of evaluate(node.extract, acc, newEnv, tracker)) yield emit(extracted, node.span, tracker);
|
|
3274
4324
|
else yield emit(acc, node.span, tracker);
|
|
3275
4325
|
}
|
|
3276
4326
|
};
|
|
@@ -3284,17 +4334,16 @@ const evalForeach = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3284
4334
|
* @param tracker - Limits tracker.
|
|
3285
4335
|
* @param evaluate - Recursive evaluator.
|
|
3286
4336
|
*/
|
|
3287
|
-
const evalRecurse = function* (node, input, env, tracker, evaluate
|
|
4337
|
+
const evalRecurse = function* (node, input, env, tracker, evaluate) {
|
|
3288
4338
|
yield emit(input, node.span, tracker);
|
|
3289
4339
|
const children = [];
|
|
3290
4340
|
if (isValueArray(input)) children.push(...input);
|
|
3291
|
-
else if (isPlainObject(input)) {
|
|
4341
|
+
else if (isPlainObject$1(input)) {
|
|
3292
4342
|
const keys = Object.keys(input).sort();
|
|
3293
4343
|
for (const key of keys) children.push(input[key]);
|
|
3294
4344
|
}
|
|
3295
|
-
for (const child of children) yield* evalRecurse(node, child, env, tracker, evaluate
|
|
4345
|
+
for (const child of children) yield* evalRecurse(node, child, env, tracker, evaluate);
|
|
3296
4346
|
};
|
|
3297
|
-
|
|
3298
4347
|
//#endregion
|
|
3299
4348
|
//#region src/eval/access.ts
|
|
3300
4349
|
/**
|
|
@@ -3306,13 +4355,13 @@ const evalRecurse = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3306
4355
|
* @param tracker - Limits tracker.
|
|
3307
4356
|
* @param evaluate - Recursive evaluator.
|
|
3308
4357
|
*/
|
|
3309
|
-
const evalField = function* (node, input, env, tracker, evaluate
|
|
3310
|
-
for (const container of evaluate
|
|
4358
|
+
const evalField = function* (node, input, env, tracker, evaluate) {
|
|
4359
|
+
for (const container of evaluate(node.target, input, env, tracker)) {
|
|
3311
4360
|
if (container === null) {
|
|
3312
4361
|
yield emit(null, node.span, tracker);
|
|
3313
4362
|
continue;
|
|
3314
4363
|
}
|
|
3315
|
-
if (isPlainObject(container)) {
|
|
4364
|
+
if (isPlainObject$1(container)) {
|
|
3316
4365
|
yield emit(Object.prototype.hasOwnProperty.call(container, node.field) ? container[node.field] : null, node.span, tracker);
|
|
3317
4366
|
continue;
|
|
3318
4367
|
}
|
|
@@ -3329,9 +4378,9 @@ const evalField = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3329
4378
|
* @param tracker - Limits tracker.
|
|
3330
4379
|
* @param evaluate - Recursive evaluator.
|
|
3331
4380
|
*/
|
|
3332
|
-
const evalIndex = function* (node, input, env, tracker, evaluate
|
|
3333
|
-
const indexValues = Array.from(evaluate
|
|
3334
|
-
for (const container of evaluate
|
|
4381
|
+
const evalIndex = function* (node, input, env, tracker, evaluate) {
|
|
4382
|
+
const indexValues = Array.from(evaluate(node.index, input, env, tracker));
|
|
4383
|
+
for (const container of evaluate(node.target, input, env, tracker)) {
|
|
3335
4384
|
if (container === null) {
|
|
3336
4385
|
yield emit(null, node.span, tracker);
|
|
3337
4386
|
continue;
|
|
@@ -3349,7 +4398,7 @@ const evalIndex = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3349
4398
|
}
|
|
3350
4399
|
continue;
|
|
3351
4400
|
}
|
|
3352
|
-
if (isPlainObject(container)) {
|
|
4401
|
+
if (isPlainObject$1(container)) {
|
|
3353
4402
|
for (const keyValue of indexValues) {
|
|
3354
4403
|
if (typeof keyValue !== "string") throw new RuntimeError(`Cannot index object with ${describeType(keyValue)}`, node.span);
|
|
3355
4404
|
yield emit(Object.prototype.hasOwnProperty.call(container, keyValue) ? container[keyValue] : null, node.span, tracker);
|
|
@@ -3369,25 +4418,26 @@ const evalIndex = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3369
4418
|
* @param tracker - Limits tracker.
|
|
3370
4419
|
* @param evaluate - Recursive evaluator.
|
|
3371
4420
|
*/
|
|
3372
|
-
const evalSlice = function* (node, input, env, tracker, evaluate
|
|
3373
|
-
for (const target of evaluate
|
|
4421
|
+
const evalSlice = function* (node, input, env, tracker, evaluate) {
|
|
4422
|
+
for (const target of evaluate(node.target, input, env, tracker)) {
|
|
3374
4423
|
if (typeof target !== "string" && !Array.isArray(target)) throw new RuntimeError("Slice expected string or array", node.span);
|
|
3375
4424
|
const starts = [];
|
|
3376
|
-
if (node.start) for (const s of evaluate
|
|
4425
|
+
if (node.start) for (const s of evaluate(node.start, input, env, tracker)) {
|
|
3377
4426
|
if (typeof s !== "number") throw new RuntimeError("Slice start must be number", node.span);
|
|
3378
4427
|
starts.push(s);
|
|
3379
4428
|
}
|
|
3380
4429
|
else starts.push(0);
|
|
3381
4430
|
const ends = [];
|
|
3382
|
-
if (node.end) for (const e of evaluate
|
|
4431
|
+
if (node.end) for (const e of evaluate(node.end, input, env, tracker)) {
|
|
3383
4432
|
if (typeof e !== "number") throw new RuntimeError("Slice end must be number", node.span);
|
|
3384
4433
|
ends.push(e);
|
|
3385
4434
|
}
|
|
3386
4435
|
else ends.push(target.length);
|
|
3387
|
-
for (const s of starts) for (const e of ends) yield emit(target.slice(s, e), node.span, tracker);
|
|
4436
|
+
for (const s of starts) for (const e of ends) yield emit(target.slice(normalizeSliceStart(s), normalizeSliceEnd(e)), node.span, tracker);
|
|
3388
4437
|
}
|
|
3389
4438
|
};
|
|
3390
|
-
|
|
4439
|
+
const normalizeSliceStart = (value) => Math.floor(value);
|
|
4440
|
+
const normalizeSliceEnd = (value) => Math.ceil(value);
|
|
3391
4441
|
//#endregion
|
|
3392
4442
|
//#region src/eval/constructors.ts
|
|
3393
4443
|
/**
|
|
@@ -3402,9 +4452,9 @@ const evalSlice = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3402
4452
|
* @param tracker - Limits tracker.
|
|
3403
4453
|
* @param evaluate - Recursive evaluator.
|
|
3404
4454
|
*/
|
|
3405
|
-
const buildArray = function* (node, input, env, tracker, evaluate
|
|
4455
|
+
const buildArray = function* (node, input, env, tracker, evaluate) {
|
|
3406
4456
|
const result = [];
|
|
3407
|
-
for (const itemNode of node.items) for (const itemVal of evaluate
|
|
4457
|
+
for (const itemNode of node.items) for (const itemVal of evaluate(itemNode, input, env, tracker)) result.push(itemVal);
|
|
3408
4458
|
yield result;
|
|
3409
4459
|
};
|
|
3410
4460
|
/**
|
|
@@ -3419,10 +4469,10 @@ const buildArray = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3419
4469
|
* @param tracker - Limits tracker.
|
|
3420
4470
|
* @param evaluate - Recursive evaluator.
|
|
3421
4471
|
*/
|
|
3422
|
-
const buildObjects = function* (node, input, env, tracker, evaluate
|
|
3423
|
-
yield* fillObject(node.entries, 0, {}, input, env, tracker, evaluate
|
|
4472
|
+
const buildObjects = function* (node, input, env, tracker, evaluate) {
|
|
4473
|
+
yield* fillObject(node.entries, 0, {}, input, env, tracker, evaluate);
|
|
3424
4474
|
};
|
|
3425
|
-
function* fillObject(entries, index, current, input, env, tracker, evaluate
|
|
4475
|
+
function* fillObject(entries, index, current, input, env, tracker, evaluate) {
|
|
3426
4476
|
if (index >= entries.length) {
|
|
3427
4477
|
yield { ...current };
|
|
3428
4478
|
return;
|
|
@@ -3431,17 +4481,16 @@ function* fillObject(entries, index, current, input, env, tracker, evaluate$1) {
|
|
|
3431
4481
|
let keys = [];
|
|
3432
4482
|
if (entry.key.kind === "KeyIdentifier") keys = [entry.key.name];
|
|
3433
4483
|
else if (entry.key.kind === "KeyString") keys = [entry.key.value];
|
|
3434
|
-
else for (const k of evaluate
|
|
4484
|
+
else for (const k of evaluate(entry.key.expr, input, env, tracker)) {
|
|
3435
4485
|
if (typeof k !== "string") throw new RuntimeError("Object key must be a string", entry.key.span);
|
|
3436
4486
|
keys.push(k);
|
|
3437
4487
|
}
|
|
3438
|
-
for (const key of keys) for (const val of evaluate
|
|
4488
|
+
for (const key of keys) for (const val of evaluate(entry.value, input, env, tracker)) {
|
|
3439
4489
|
current[key] = val;
|
|
3440
|
-
yield* fillObject(entries, index + 1, current, input, env, tracker, evaluate
|
|
4490
|
+
yield* fillObject(entries, index + 1, current, input, env, tracker, evaluate);
|
|
3441
4491
|
delete current[key];
|
|
3442
4492
|
}
|
|
3443
4493
|
}
|
|
3444
|
-
|
|
3445
4494
|
//#endregion
|
|
3446
4495
|
//#region src/eval/functions.ts
|
|
3447
4496
|
/**
|
|
@@ -3459,7 +4508,7 @@ function* fillObject(entries, index, current, input, env, tracker, evaluate$1) {
|
|
|
3459
4508
|
* @param tracker - Limits tracker.
|
|
3460
4509
|
* @param evaluate - Recursive evaluator.
|
|
3461
4510
|
*/
|
|
3462
|
-
const evalCall = function* (node, input, env, tracker, evaluate
|
|
4511
|
+
const evalCall = function* (node, input, env, tracker, evaluate) {
|
|
3463
4512
|
for (let i = env.length - 1; i >= 0; i--) {
|
|
3464
4513
|
const funcs = env[i].funcs.get(node.name);
|
|
3465
4514
|
if (funcs) {
|
|
@@ -3481,7 +4530,7 @@ const evalCall = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3481
4530
|
newFrame.funcs.set(argName, argDefs);
|
|
3482
4531
|
}
|
|
3483
4532
|
const newStack = [...def.closure, newFrame];
|
|
3484
|
-
yield* evaluate
|
|
4533
|
+
yield* evaluate(def.body, input, newStack, tracker);
|
|
3485
4534
|
return;
|
|
3486
4535
|
}
|
|
3487
4536
|
}
|
|
@@ -3490,7 +4539,7 @@ const evalCall = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3490
4539
|
if (!specs) throw new RuntimeError(`Unknown function: ${node.name}`, node.span);
|
|
3491
4540
|
const builtin = specs.find((s) => s.arity === node.args.length);
|
|
3492
4541
|
if (!builtin) throw new RuntimeError(`Function ${node.name} does not accept ${node.args.length} arguments`, node.span);
|
|
3493
|
-
yield* builtin.apply(input, node.args, env, tracker, evaluate
|
|
4542
|
+
yield* builtin.apply(input, node.args, env, tracker, evaluate, node.span);
|
|
3494
4543
|
};
|
|
3495
4544
|
/**
|
|
3496
4545
|
* Defines a new function in the environment.
|
|
@@ -3504,7 +4553,7 @@ const evalCall = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3504
4553
|
* @param tracker - Limits tracker.
|
|
3505
4554
|
* @param evaluate - Recursive evaluator.
|
|
3506
4555
|
*/
|
|
3507
|
-
const evalDef = function* (node, input, env, tracker, evaluate
|
|
4556
|
+
const evalDef = function* (node, input, env, tracker, evaluate) {
|
|
3508
4557
|
const newFrame = {
|
|
3509
4558
|
vars: /* @__PURE__ */ new Map(),
|
|
3510
4559
|
funcs: /* @__PURE__ */ new Map()
|
|
@@ -3519,9 +4568,8 @@ const evalDef = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3519
4568
|
newFrame.funcs.set(node.name, currentDefs);
|
|
3520
4569
|
const newStack = [...env, newFrame];
|
|
3521
4570
|
funDef.closure = newStack;
|
|
3522
|
-
yield* evaluate
|
|
4571
|
+
yield* evaluate(node.next, input, newStack, tracker);
|
|
3523
4572
|
};
|
|
3524
|
-
|
|
3525
4573
|
//#endregion
|
|
3526
4574
|
//#region src/eval/control_flow.ts
|
|
3527
4575
|
/**
|
|
@@ -3533,17 +4581,17 @@ const evalDef = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3533
4581
|
* @param tracker - Limits tracker.
|
|
3534
4582
|
* @param evaluate - Recursive evaluator.
|
|
3535
4583
|
*/
|
|
3536
|
-
const evalIf = function* (node, input, env, tracker, evaluate
|
|
3537
|
-
yield* evalIfBranch(node, 0, input, env, tracker, evaluate
|
|
4584
|
+
const evalIf = function* (node, input, env, tracker, evaluate) {
|
|
4585
|
+
yield* evalIfBranch(node, 0, input, env, tracker, evaluate);
|
|
3538
4586
|
};
|
|
3539
|
-
function* evalIfBranch(node, branchIndex, input, env, tracker, evaluate
|
|
4587
|
+
function* evalIfBranch(node, branchIndex, input, env, tracker, evaluate) {
|
|
3540
4588
|
if (branchIndex >= node.branches.length) {
|
|
3541
|
-
yield* evaluate
|
|
4589
|
+
yield* evaluate(node.else, input, env, tracker);
|
|
3542
4590
|
return;
|
|
3543
4591
|
}
|
|
3544
4592
|
const branch = node.branches[branchIndex];
|
|
3545
|
-
for (const cond of evaluate
|
|
3546
|
-
else yield* evalIfBranch(node, branchIndex + 1, input, env, tracker, evaluate
|
|
4593
|
+
for (const cond of evaluate(branch.cond, input, env, tracker)) if (isTruthy(cond)) yield* evaluate(branch.then, input, env, tracker);
|
|
4594
|
+
else yield* evalIfBranch(node, branchIndex + 1, input, env, tracker, evaluate);
|
|
3547
4595
|
}
|
|
3548
4596
|
/**
|
|
3549
4597
|
* Evaluates a `try-catch` expression.
|
|
@@ -3554,12 +4602,12 @@ function* evalIfBranch(node, branchIndex, input, env, tracker, evaluate$1) {
|
|
|
3554
4602
|
* @param tracker - Limits tracker.
|
|
3555
4603
|
* @param evaluate - Recursive evaluator.
|
|
3556
4604
|
*/
|
|
3557
|
-
const evalTry = function* (node, input, env, tracker, evaluate
|
|
4605
|
+
const evalTry = function* (node, input, env, tracker, evaluate) {
|
|
3558
4606
|
try {
|
|
3559
|
-
yield* evaluate
|
|
4607
|
+
yield* evaluate(node.body, input, env, tracker);
|
|
3560
4608
|
} catch (err) {
|
|
3561
4609
|
if (err instanceof RuntimeError) {
|
|
3562
|
-
if (node.handler) yield* evaluate
|
|
4610
|
+
if (node.handler) yield* evaluate(node.handler, err.message, env, tracker);
|
|
3563
4611
|
} else throw err;
|
|
3564
4612
|
}
|
|
3565
4613
|
};
|
|
@@ -3572,9 +4620,9 @@ const evalTry = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3572
4620
|
* @param tracker - Limits tracker.
|
|
3573
4621
|
* @param evaluate - Recursive evaluator.
|
|
3574
4622
|
*/
|
|
3575
|
-
const evalLabel = function* (node, input, env, tracker, evaluate
|
|
4623
|
+
const evalLabel = function* (node, input, env, tracker, evaluate) {
|
|
3576
4624
|
try {
|
|
3577
|
-
yield* evaluate
|
|
4625
|
+
yield* evaluate(node.body, input, env, tracker);
|
|
3578
4626
|
} catch (e) {
|
|
3579
4627
|
if (e instanceof BreakSignal) {
|
|
3580
4628
|
if (e.label === node.label) return;
|
|
@@ -3582,10 +4630,16 @@ const evalLabel = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3582
4630
|
throw e;
|
|
3583
4631
|
}
|
|
3584
4632
|
};
|
|
3585
|
-
|
|
3586
4633
|
//#endregion
|
|
3587
4634
|
//#region src/eval/dispatch.ts
|
|
3588
4635
|
/**
|
|
4636
|
+
* Normalizes the `now` option to seconds since the Unix epoch.
|
|
4637
|
+
*/
|
|
4638
|
+
const resolveNowSeconds = (now) => {
|
|
4639
|
+
if (now === void 0) return void 0;
|
|
4640
|
+
return now instanceof Date ? now.getTime() / 1e3 : now;
|
|
4641
|
+
};
|
|
4642
|
+
/**
|
|
3589
4643
|
* Runs a jq AST against an input value.
|
|
3590
4644
|
*
|
|
3591
4645
|
* @param ast - The parsed AST.
|
|
@@ -3594,7 +4648,7 @@ const evalLabel = function* (node, input, env, tracker, evaluate$1) {
|
|
|
3594
4648
|
* @returns An array of all values yielded by the filter.
|
|
3595
4649
|
*/
|
|
3596
4650
|
const runAst = (ast, input, options = {}) => {
|
|
3597
|
-
const tracker = new LimitTracker(resolveLimits(options.limits));
|
|
4651
|
+
const tracker = new LimitTracker(resolveLimits(options.limits), resolveNowSeconds(options.now));
|
|
3598
4652
|
const env = [{
|
|
3599
4653
|
vars: new Map(Object.entries(options.vars ?? {})),
|
|
3600
4654
|
funcs: /* @__PURE__ */ new Map()
|
|
@@ -3703,8 +4757,10 @@ function* evaluate(node, input, env, tracker) {
|
|
|
3703
4757
|
case "As": {
|
|
3704
4758
|
const values = Array.from(evaluate(node.bind, input, env, tracker));
|
|
3705
4759
|
for (const val of values) {
|
|
4760
|
+
const vars = /* @__PURE__ */ new Map();
|
|
4761
|
+
bindPattern(node.pattern, val, vars);
|
|
3706
4762
|
const newFrame = {
|
|
3707
|
-
vars
|
|
4763
|
+
vars,
|
|
3708
4764
|
funcs: /* @__PURE__ */ new Map()
|
|
3709
4765
|
};
|
|
3710
4766
|
const newEnv = [...env, newFrame];
|
|
@@ -3723,7 +4779,300 @@ function* evaluate(node, input, env, tracker) {
|
|
|
3723
4779
|
tracker.exit();
|
|
3724
4780
|
}
|
|
3725
4781
|
}
|
|
3726
|
-
|
|
4782
|
+
//#endregion
|
|
4783
|
+
//#region src/compat.ts
|
|
4784
|
+
const semanticWarnings = {
|
|
4785
|
+
unique: "jq sorts unique results; jq-ts preserves first-seen order for determinism.",
|
|
4786
|
+
unique_by: "jq sorts unique_by results by key; jq-ts preserves first-seen order.",
|
|
4787
|
+
to_entries: "jq preserves object insertion order; jq-ts sorts object keys deterministically.",
|
|
4788
|
+
with_entries: "jq preserves object insertion order; jq-ts processes object keys in sorted order.",
|
|
4789
|
+
tostring: "jq stringifies objects in input key order; jq-ts uses stable sorted-key stringification.",
|
|
4790
|
+
tojson: "jq tojson preserves input object order; jq-ts uses stable sorted-key stringification.",
|
|
4791
|
+
infinite: "jq serializes infinite as a finite JSON number; jq-ts returns JavaScript Infinity internally.",
|
|
4792
|
+
normal: "jq documents isnormal; jq-ts exposes normal with approximate JavaScript number semantics.",
|
|
4793
|
+
subnormal: "jq documents subnormal classification; jq-ts currently approximates this as false."
|
|
4794
|
+
};
|
|
4795
|
+
const specialVariableWarnings = {
|
|
4796
|
+
ENV: "jq $ENV is an environment snapshot; jq-ts does not populate it unless the caller injects an ENV variable.",
|
|
4797
|
+
__loc__: "jq $__loc__ reports source location metadata; jq-ts does not populate it unless the caller injects a __loc__ variable.",
|
|
4798
|
+
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.",
|
|
4799
|
+
ARGS: "jq $ARGS is populated from CLI arguments; jq-ts does not populate it unless the caller injects an ARGS variable."
|
|
4800
|
+
};
|
|
4801
|
+
const syntaxWarningsByKind = { Slice: "jq slice bounds have jq-specific numeric coercion; jq-ts uses JavaScript slice semantics." };
|
|
4802
|
+
/**
|
|
4803
|
+
* Checks whether a jq expression can be parsed and statically validated by jq-ts.
|
|
4804
|
+
*
|
|
4805
|
+
* This is a syntax/subset check only. It does not prove that runtime behavior
|
|
4806
|
+
* matches the jq binary for every possible input.
|
|
4807
|
+
*/
|
|
4808
|
+
const checkCompatibility = (source) => {
|
|
4809
|
+
try {
|
|
4810
|
+
validate(parse(source));
|
|
4811
|
+
return {
|
|
4812
|
+
compatible: true,
|
|
4813
|
+
findings: []
|
|
4814
|
+
};
|
|
4815
|
+
} catch (err) {
|
|
4816
|
+
const finding = toFinding(err);
|
|
4817
|
+
if (finding) return {
|
|
4818
|
+
compatible: false,
|
|
4819
|
+
findings: [finding]
|
|
4820
|
+
};
|
|
4821
|
+
throw err;
|
|
4822
|
+
}
|
|
4823
|
+
};
|
|
4824
|
+
/**
|
|
4825
|
+
* Checks jq-ts compatibility and reports known semantic differences from jq.
|
|
4826
|
+
*/
|
|
4827
|
+
const analyzeCompatibility = (source) => {
|
|
4828
|
+
const check = checkCompatibility(source);
|
|
4829
|
+
if (!check.compatible) return {
|
|
4830
|
+
...check,
|
|
4831
|
+
warnings: []
|
|
4832
|
+
};
|
|
4833
|
+
const warnings = collectWarnings(parse(source));
|
|
4834
|
+
return {
|
|
4835
|
+
compatible: true,
|
|
4836
|
+
findings: warnings,
|
|
4837
|
+
warnings
|
|
4838
|
+
};
|
|
4839
|
+
};
|
|
4840
|
+
/**
|
|
4841
|
+
* Compares jq-ts execution against a caller-provided jq runner or jq result.
|
|
4842
|
+
*
|
|
4843
|
+
* The function is safe to export from the isolate-safe library because it does
|
|
4844
|
+
* not spawn the jq binary itself. Tests and development tools can pass a runner
|
|
4845
|
+
* that shells out to jq.
|
|
4846
|
+
*/
|
|
4847
|
+
const compareWithJq = (source, input, jq, options = {}) => {
|
|
4848
|
+
const analysis = analyzeCompatibility(source);
|
|
4849
|
+
const jqTs = runJqTs(source, input, options);
|
|
4850
|
+
const jqResult = typeof jq === "function" ? runExternalJq(jq, source, input) : jq;
|
|
4851
|
+
const findings = [...analysis.findings];
|
|
4852
|
+
if (!jqTs.ok) findings.push({
|
|
4853
|
+
severity: "error",
|
|
4854
|
+
stage: jqTs.stage ?? "runtime",
|
|
4855
|
+
category: "runtime-error",
|
|
4856
|
+
message: jqTs.error
|
|
4857
|
+
});
|
|
4858
|
+
if (!jqResult.ok) findings.push({
|
|
4859
|
+
severity: "error",
|
|
4860
|
+
stage: "compare",
|
|
4861
|
+
category: "jq-error",
|
|
4862
|
+
message: jqResult.error
|
|
4863
|
+
});
|
|
4864
|
+
const equivalent = jqTs.ok && jqResult.ok ? outputStreamsEqual(jqTs.outputs, jqResult.outputs) : null;
|
|
4865
|
+
if (equivalent === false) findings.push({
|
|
4866
|
+
severity: "error",
|
|
4867
|
+
stage: "compare",
|
|
4868
|
+
category: "output-mismatch",
|
|
4869
|
+
message: "jq-ts output stream does not match jq output stream."
|
|
4870
|
+
});
|
|
4871
|
+
return {
|
|
4872
|
+
compatible: analysis.compatible && jqTs.ok,
|
|
4873
|
+
equivalent,
|
|
4874
|
+
analysis,
|
|
4875
|
+
jqTs,
|
|
4876
|
+
jq: jqResult,
|
|
4877
|
+
findings
|
|
4878
|
+
};
|
|
4879
|
+
};
|
|
4880
|
+
const runJqTs = (source, input, options) => {
|
|
4881
|
+
try {
|
|
4882
|
+
const ast = parse(source);
|
|
4883
|
+
validate(ast);
|
|
4884
|
+
return {
|
|
4885
|
+
ok: true,
|
|
4886
|
+
outputs: runAst(ast, input, options)
|
|
4887
|
+
};
|
|
4888
|
+
} catch (err) {
|
|
4889
|
+
const jqTsError = asJqTsError(err);
|
|
4890
|
+
return {
|
|
4891
|
+
ok: false,
|
|
4892
|
+
error: err instanceof Error ? err.message : String(err),
|
|
4893
|
+
stage: jqTsError?.kind
|
|
4894
|
+
};
|
|
4895
|
+
}
|
|
4896
|
+
};
|
|
4897
|
+
const runExternalJq = (runner, source, input) => {
|
|
4898
|
+
try {
|
|
4899
|
+
const result = runner(source, input);
|
|
4900
|
+
if (Array.isArray(result)) return {
|
|
4901
|
+
ok: true,
|
|
4902
|
+
outputs: result
|
|
4903
|
+
};
|
|
4904
|
+
return result;
|
|
4905
|
+
} catch (err) {
|
|
4906
|
+
return {
|
|
4907
|
+
ok: false,
|
|
4908
|
+
error: err instanceof Error ? err.message : String(err),
|
|
4909
|
+
stage: "compare"
|
|
4910
|
+
};
|
|
4911
|
+
}
|
|
4912
|
+
};
|
|
4913
|
+
const outputStreamsEqual = (left, right) => left.length === right.length && left.every((value, index) => valueEquals(value, right[index]));
|
|
4914
|
+
const toFinding = (err) => {
|
|
4915
|
+
const jqTsError = asJqTsError(err);
|
|
4916
|
+
if (!jqTsError) return null;
|
|
4917
|
+
return {
|
|
4918
|
+
severity: "error",
|
|
4919
|
+
stage: jqTsError.kind,
|
|
4920
|
+
category: classifyError(jqTsError),
|
|
4921
|
+
message: jqTsError.message,
|
|
4922
|
+
span: jqTsError.span
|
|
4923
|
+
};
|
|
4924
|
+
};
|
|
4925
|
+
const asJqTsError = (err) => {
|
|
4926
|
+
if (err instanceof LexError || err instanceof ParseError || err instanceof ValidationError || err instanceof RuntimeError) return err;
|
|
4927
|
+
return null;
|
|
4928
|
+
};
|
|
4929
|
+
const classifyError = (err) => {
|
|
4930
|
+
if (err.kind === "parse" || err.kind === "lex") return "unsupported-syntax";
|
|
4931
|
+
if (err.kind === "runtime") return "runtime-error";
|
|
4932
|
+
if (err.message.startsWith("Unknown function:")) return isIntentionalExclusion(err.message) ? "intentional-exclusion" : "unsupported-builtin";
|
|
4933
|
+
if (err.message.includes("expects") && err.message.includes("arguments")) return "arity-mismatch";
|
|
4934
|
+
return "unsupported-syntax";
|
|
4935
|
+
};
|
|
4936
|
+
const isIntentionalExclusion = (message) => [
|
|
4937
|
+
"input",
|
|
4938
|
+
"inputs",
|
|
4939
|
+
"env"
|
|
4940
|
+
].some((name) => message === `Unknown function: ${name}`);
|
|
4941
|
+
const collectWarnings = (node) => {
|
|
4942
|
+
const warnings = [];
|
|
4943
|
+
visit(node, (current) => {
|
|
4944
|
+
const syntaxWarning = syntaxWarningsByKind[current.kind];
|
|
4945
|
+
if (syntaxWarning) warnings.push({
|
|
4946
|
+
severity: "warning",
|
|
4947
|
+
stage: "validate",
|
|
4948
|
+
category: "input-dependent",
|
|
4949
|
+
message: syntaxWarning,
|
|
4950
|
+
span: current.span
|
|
4951
|
+
});
|
|
4952
|
+
if (current.kind === "Call") {
|
|
4953
|
+
const warning = semanticWarnings[current.name];
|
|
4954
|
+
if (warning) warnings.push({
|
|
4955
|
+
severity: "warning",
|
|
4956
|
+
stage: "validate",
|
|
4957
|
+
category: "semantic-deviation",
|
|
4958
|
+
message: warning,
|
|
4959
|
+
span: current.span
|
|
4960
|
+
});
|
|
4961
|
+
}
|
|
4962
|
+
if (current.kind === "Var") {
|
|
4963
|
+
const warning = specialVariableWarnings[current.name];
|
|
4964
|
+
if (warning) warnings.push({
|
|
4965
|
+
severity: "warning",
|
|
4966
|
+
stage: "validate",
|
|
4967
|
+
category: current.name === "ENV" ? "intentional-exclusion" : "semantic-deviation",
|
|
4968
|
+
message: warning,
|
|
4969
|
+
span: current.span
|
|
4970
|
+
});
|
|
4971
|
+
}
|
|
4972
|
+
});
|
|
4973
|
+
return dedupeFindings(warnings);
|
|
4974
|
+
};
|
|
4975
|
+
const dedupeFindings = (findings) => {
|
|
4976
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4977
|
+
const result = [];
|
|
4978
|
+
for (const finding of findings) {
|
|
4979
|
+
const key = `${finding.category}:${finding.message}:${finding.span?.start ?? ""}:${finding.span?.end ?? ""}`;
|
|
4980
|
+
if (seen.has(key)) continue;
|
|
4981
|
+
seen.add(key);
|
|
4982
|
+
result.push(finding);
|
|
4983
|
+
}
|
|
4984
|
+
return result;
|
|
4985
|
+
};
|
|
4986
|
+
const visit = (node, callback) => {
|
|
4987
|
+
callback(node);
|
|
4988
|
+
switch (node.kind) {
|
|
4989
|
+
case "Identity":
|
|
4990
|
+
case "Literal":
|
|
4991
|
+
case "Var":
|
|
4992
|
+
case "Recurse":
|
|
4993
|
+
case "Break": return;
|
|
4994
|
+
case "FieldAccess":
|
|
4995
|
+
visit(node.target, callback);
|
|
4996
|
+
return;
|
|
4997
|
+
case "IndexAccess":
|
|
4998
|
+
visit(node.target, callback);
|
|
4999
|
+
visit(node.index, callback);
|
|
5000
|
+
return;
|
|
5001
|
+
case "Iterate":
|
|
5002
|
+
visit(node.target, callback);
|
|
5003
|
+
return;
|
|
5004
|
+
case "Slice":
|
|
5005
|
+
visit(node.target, callback);
|
|
5006
|
+
if (node.start) visit(node.start, callback);
|
|
5007
|
+
if (node.end) visit(node.end, callback);
|
|
5008
|
+
return;
|
|
5009
|
+
case "Array":
|
|
5010
|
+
node.items.forEach((item) => visit(item, callback));
|
|
5011
|
+
return;
|
|
5012
|
+
case "Object":
|
|
5013
|
+
node.entries.forEach((entry) => visitObjectEntry(entry, callback));
|
|
5014
|
+
return;
|
|
5015
|
+
case "Pipe":
|
|
5016
|
+
case "Comma":
|
|
5017
|
+
case "Alt":
|
|
5018
|
+
case "Binary":
|
|
5019
|
+
case "Bool":
|
|
5020
|
+
visit(node.left, callback);
|
|
5021
|
+
visit(node.right, callback);
|
|
5022
|
+
return;
|
|
5023
|
+
case "Unary":
|
|
5024
|
+
visit(node.expr, callback);
|
|
5025
|
+
return;
|
|
5026
|
+
case "If":
|
|
5027
|
+
node.branches.forEach((branch) => {
|
|
5028
|
+
visit(branch.cond, callback);
|
|
5029
|
+
visit(branch.then, callback);
|
|
5030
|
+
});
|
|
5031
|
+
visit(node.else, callback);
|
|
5032
|
+
return;
|
|
5033
|
+
case "As":
|
|
5034
|
+
visit(node.bind, callback);
|
|
5035
|
+
visit(node.body, callback);
|
|
5036
|
+
return;
|
|
5037
|
+
case "Call":
|
|
5038
|
+
node.args.forEach((arg) => visit(arg, callback));
|
|
5039
|
+
return;
|
|
5040
|
+
case "Reduce":
|
|
5041
|
+
visit(node.source, callback);
|
|
5042
|
+
visit(node.init, callback);
|
|
5043
|
+
visit(node.update, callback);
|
|
5044
|
+
return;
|
|
5045
|
+
case "Foreach":
|
|
5046
|
+
visit(node.source, callback);
|
|
5047
|
+
visit(node.init, callback);
|
|
5048
|
+
visit(node.update, callback);
|
|
5049
|
+
if (node.extract) visit(node.extract, callback);
|
|
5050
|
+
return;
|
|
5051
|
+
case "Try":
|
|
5052
|
+
visit(node.body, callback);
|
|
5053
|
+
if (node.handler) visit(node.handler, callback);
|
|
5054
|
+
return;
|
|
5055
|
+
case "Assignment":
|
|
5056
|
+
visit(node.left, callback);
|
|
5057
|
+
visit(node.right, callback);
|
|
5058
|
+
return;
|
|
5059
|
+
case "Def":
|
|
5060
|
+
visit(node.body, callback);
|
|
5061
|
+
visit(node.next, callback);
|
|
5062
|
+
return;
|
|
5063
|
+
case "Label":
|
|
5064
|
+
visit(node.body, callback);
|
|
5065
|
+
return;
|
|
5066
|
+
default: return node;
|
|
5067
|
+
}
|
|
5068
|
+
};
|
|
5069
|
+
const visitObjectEntry = (entry, callback) => {
|
|
5070
|
+
visitObjectKey(entry.key, callback);
|
|
5071
|
+
visit(entry.value, callback);
|
|
5072
|
+
};
|
|
5073
|
+
const visitObjectKey = (key, callback) => {
|
|
5074
|
+
if (key.kind === "KeyExpr") visit(key.expr, callback);
|
|
5075
|
+
};
|
|
3727
5076
|
//#endregion
|
|
3728
5077
|
//#region src/index.ts
|
|
3729
5078
|
/**
|
|
@@ -3743,15 +5092,17 @@ const run = (source, input, options = {}) => {
|
|
|
3743
5092
|
validate(ast);
|
|
3744
5093
|
return runAst(ast, input, options);
|
|
3745
5094
|
};
|
|
3746
|
-
|
|
3747
5095
|
//#endregion
|
|
3748
5096
|
exports.LexError = LexError;
|
|
3749
5097
|
exports.LimitTracker = LimitTracker;
|
|
3750
5098
|
exports.ParseError = ParseError;
|
|
3751
5099
|
exports.RuntimeError = RuntimeError;
|
|
3752
5100
|
exports.ValidationError = ValidationError;
|
|
5101
|
+
exports.analyzeCompatibility = analyzeCompatibility;
|
|
5102
|
+
exports.checkCompatibility = checkCompatibility;
|
|
5103
|
+
exports.compareWithJq = compareWithJq;
|
|
3753
5104
|
exports.parse = parse;
|
|
3754
5105
|
exports.resolveLimits = resolveLimits;
|
|
3755
5106
|
exports.run = run;
|
|
3756
5107
|
exports.runAst = runAst;
|
|
3757
|
-
exports.validate = validate;
|
|
5108
|
+
exports.validate = validate;
|