squint-cljs 0.14.200 → 0.14.201

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.
@@ -65,6 +65,16 @@ function dequal(foo, bar) {
65
65
  return true;
66
66
  }
67
67
 
68
+ // A plain object and a js/Map are both map reps; compare by entries.
69
+ // Same-type pairs skip this and keep their fast paths below.
70
+ if (isMapLike(foo) && isMapLike(bar) && foo.constructor !== bar.constructor) {
71
+ if (mapCount(foo) !== mapCount(bar)) return false;
72
+ for (const k of foo instanceof Map ? foo.keys() : Object.keys(foo)) {
73
+ if (!mapHas(bar, k) || !dequal(mapGet(foo, k), mapGet(bar, k))) return false;
74
+ }
75
+ return true;
76
+ }
77
+
68
78
  // Sets (hash or sorted) compare by elements, across concrete types.
69
79
  if (isSetLike(foo) || isSetLike(bar)) {
70
80
  if (!isSetLike(foo) || !isSetLike(bar) || foo.size !== bar.size) return false;
@@ -80,6 +90,8 @@ function dequal(foo, bar) {
80
90
 
81
91
  if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
82
92
  if (ctor === Date) return foo.getTime() === bar.getTime();
93
+ // regexes only compare by identity, like CLJS
94
+ if (ctor === RegExp) return false;
83
95
 
84
96
  if (ctor === Array) {
85
97
  if ((len = foo.length) === bar.length) {
@@ -272,9 +284,24 @@ function copy(o) {
272
284
  }
273
285
 
274
286
  export function assoc(o, k, v, ...kvs) {
275
- if (!o) {
287
+ // only nil puns to an empty map; assoc on false throws, like CLJS
288
+ if (o == null) {
276
289
  o = {};
277
290
  }
291
+ if (isVectorArray(o)) {
292
+ // like CLJS: a vector key is an index in [0, count], count appends
293
+ let len = o.length;
294
+ for (let i = 0; i < kvs.length + 2; i += 2) {
295
+ const key = i === 0 ? k : kvs[i - 2];
296
+ if (!Number.isInteger(key)) {
297
+ throw new Error("Vector's key for assoc must be a number.");
298
+ }
299
+ if (key < 0 || key > len) {
300
+ throw new Error(`Index ${key} out of bounds [0,${len}]`);
301
+ }
302
+ if (key === len) len++;
303
+ }
304
+ }
278
305
  const ret = copy(o);
279
306
  assoc_BANG_(ret, k, v, ...kvs);
280
307
  return ret;
@@ -283,6 +310,9 @@ export function assoc(o, k, v, ...kvs) {
283
310
  // squint has no distinct hash-map or array-map type; both build a plain object.
284
311
  export function hash_map(...kvs) {
285
312
  if (kvs.length === 0) return {};
313
+ if (kvs.length % 2 !== 0) {
314
+ throw new Error('No value supplied for key: ' + kvs[kvs.length - 1]);
315
+ }
286
316
  return assoc({}, ...kvs);
287
317
  }
288
318
 
@@ -444,6 +474,10 @@ export function conj_BANG_(...xs) {
444
474
  if (n === 0) {
445
475
  return vector();
446
476
  }
477
+ // single arg: return the coll unchanged, including nil, like CLJS
478
+ if (n === 1) {
479
+ return xs[0];
480
+ }
447
481
 
448
482
  let o = xs[0];
449
483
  if (o === null || o === undefined) {
@@ -477,17 +511,14 @@ export function conj_BANG_(...xs) {
477
511
  break;
478
512
  case MAP_TYPE:
479
513
  for (const x of rest) {
480
- if (!Array.isArray(x))
481
- iterable(x).forEach((kv) => {
482
- o.set(kv[0], kv[1]);
483
- });
484
- else o.set(x[0], x[1]);
514
+ if (isVectorArray(x)) { asMapEntry(x); o.set(x[0], x[1]); }
515
+ else for (const kv of mapEntriesOf(x)) o.set(kv[0], kv[1]);
485
516
  }
486
517
  break;
487
518
  case OBJECT_TYPE:
488
519
  for (const x of rest) {
489
- if (!Array.isArray(x)) Object.assign(o, x);
490
- else o[x[0]] = x[1];
520
+ if (isVectorArray(x)) { asMapEntry(x); o[x[0]] = x[1]; }
521
+ else for (const kv of mapEntriesOf(x)) o[kv[0]] = kv[1];
491
522
  }
492
523
  break;
493
524
  default:
@@ -499,6 +530,28 @@ export function conj_BANG_(...xs) {
499
530
  return o;
500
531
  }
501
532
 
533
+ // entries carried by a non-entry conj arg onto a map: a map merges, a
534
+ // seqable must contain entry vectors, like CLJS
535
+ function* mapEntriesOf(x) {
536
+ if (isMapLike(x)) {
537
+ yield* iterable(x);
538
+ return;
539
+ }
540
+ for (const kv of iterable(x)) {
541
+ if (!isVectorArray(kv)) {
542
+ throw new Error('conj on a map takes map entries or seqables of map entries');
543
+ }
544
+ yield kv;
545
+ }
546
+ }
547
+
548
+ function asMapEntry(x) {
549
+ if (x.length < 2) {
550
+ throw new Error('Vector arg to map conj must be a pair');
551
+ }
552
+ return x;
553
+ }
554
+
502
555
  export function conj(...xs) {
503
556
  if (xs.length === 0) {
504
557
  return vector();
@@ -530,11 +583,8 @@ export function conj(...xs) {
530
583
  case MAP_TYPE:
531
584
  m = new Map(o);
532
585
  for (const x of rest) {
533
- if (!Array.isArray(x))
534
- iterable(x).forEach((kv) => {
535
- m.set(kv[0], kv[1]);
536
- });
537
- else m.set(x[0], x[1]);
586
+ if (isVectorArray(x)) { asMapEntry(x); m.set(x[0], x[1]); }
587
+ else for (const kv of mapEntriesOf(x)) m.set(kv[0], kv[1]);
538
588
  }
539
589
 
540
590
  return copyMeta(o, m);
@@ -547,8 +597,8 @@ export function conj(...xs) {
547
597
  o2 = { ...o };
548
598
 
549
599
  for (const x of rest) {
550
- if (!Array.isArray(x)) Object.assign(o2, x);
551
- else o2[x[0]] = x[1];
600
+ if (isVectorArray(x)) { asMapEntry(x); o2[x[0]] = x[1]; }
601
+ else for (const kv of mapEntriesOf(x)) o2[kv[0]] = kv[1];
552
602
  }
553
603
 
554
604
  return copyMeta(o, o2);
@@ -570,7 +620,7 @@ export function disj(s, ...xs) {
570
620
  if (s == null) return s;
571
621
  // pass s itself (not a spread) so a SortedSet keeps its comparator
572
622
  const s1 = new s.constructor(s);
573
- return disj_BANG_(s1, ...xs);
623
+ return copyMeta(s, disj_BANG_(s1, ...xs));
574
624
  }
575
625
 
576
626
  export function contains_QMARK_(coll, v) {
@@ -599,7 +649,11 @@ export function dissoc_BANG_(m, ...ks) {
599
649
  export function dissoc(m, ...ks) {
600
650
  if (!m) return;
601
651
  if (ks.length === 0) return m;
602
- if (typeConst(m) === MAP_TYPE) {
652
+ const tc = typeConst(m);
653
+ if (tc !== MAP_TYPE && tc !== OBJECT_TYPE) {
654
+ throw new Error('dissoc expects a map, got: ' + typeof m);
655
+ }
656
+ if (tc === MAP_TYPE) {
603
657
  let present = false;
604
658
  for (const k of ks) if (m.has(k)) { present = true; break; }
605
659
  if (!present) return m;
@@ -641,6 +695,9 @@ export function pr(...xs) {
641
695
  }
642
696
 
643
697
  export function nth(coll, idx, orElse) {
698
+ if (typeof idx !== 'number') {
699
+ throw new Error('Index argument to nth must be a number');
700
+ }
644
701
  const hasDefault = arguments.length > 2;
645
702
  // nil coll puns to nil, like Clojure
646
703
  if (coll == null) return hasDefault ? orElse : null;
@@ -727,7 +784,8 @@ export function seqable_QMARK_(x) {
727
784
  object_QMARK_(x) ||
728
785
  // we used to check instanceof Object but this returns false for TC39 Records
729
786
  // also we used to write `Symbol.iterator in` but this does not work for strings and some other types
730
- !!x[Symbol.iterator]
787
+ !!x[Symbol.iterator] ||
788
+ !!x[ISEQABLE_SYM]
731
789
  );
732
790
  }
733
791
 
@@ -757,6 +815,8 @@ export function iterable(x) {
757
815
  if (x[Symbol.iterator]) {
758
816
  return x;
759
817
  }
818
+ // a type extended to ISeqable seqs through its -seq method
819
+ if (x[ISeqable__seq] !== undefined) return iterable(x[ISeqable__seq](x));
760
820
  if (x instanceof Object) return Object.entries(x).map(tagMapEntry);
761
821
  throw new TypeError(`${x} is not iterable`);
762
822
  }
@@ -773,6 +833,7 @@ export const es6_iterator = _iterator;
773
833
 
774
834
  export function seq(x) {
775
835
  if (x == null) return x;
836
+ if (!seqable_QMARK_(x)) throw new TypeError(x + ' is not ISeqable');
776
837
  // a string seqs into its characters, like CLJS.
777
838
  if (typeof x === 'string') return x.length ? [...x] : null;
778
839
  const iter = iterable(x);
@@ -833,13 +894,13 @@ export function rest(coll) {
833
894
  return cell._rest; // first chunk had one element; the next cell is the rest
834
895
  }
835
896
 
897
+ const REDUCED_DEREF = (self) => self.value;
898
+
836
899
  class Reduced {
837
900
  value;
838
901
  constructor(x) {
839
902
  this.value = x;
840
- }
841
- _deref() {
842
- return this.value;
903
+ this[IDeref__deref] = REDUCED_DEREF;
843
904
  }
844
905
  }
845
906
 
@@ -1128,6 +1189,8 @@ class Cons {
1128
1189
  );
1129
1190
 
1130
1191
  export function cons(x, coll) {
1192
+ // like CLJS cons, which seqs a non-ISeq tail
1193
+ if (!seqable_QMARK_(coll)) throw new TypeError(coll + ' is not ISeqable');
1131
1194
  return new Cons(x, coll);
1132
1195
  }
1133
1196
 
@@ -1291,48 +1354,167 @@ export function nil_QMARK_(v) {
1291
1354
 
1292
1355
  export const PROTOCOL_SENTINEL = {};
1293
1356
 
1357
+ // marker protocols so (satisfies? IAtom x) works, like CLJS. Marked in the
1358
+ // constructor, not on the prototype, so no top-level mutation pins Atom
1359
+ // into bundles that do not use it.
1360
+ const IATOM_SYM = Symbol('squint.core.IAtom');
1361
+ const IDEREF_SYM = Symbol('squint.core.IDeref');
1362
+ const ISEQABLE_SYM = Symbol('squint.core.ISeqable');
1363
+ export const IAtom = { __sym: IATOM_SYM };
1364
+ export const IDeref = { __sym: IDEREF_SYM };
1365
+ // method slot for (-deref x), named like the defprotocol emission so
1366
+ // (extend-type T IDeref (-deref [x] ...)) fills it
1367
+ export const IDeref__deref = Symbol('IDeref_-deref');
1368
+ export function _deref(o) {
1369
+ if (o != null && o[IDeref__deref] !== undefined) return o[IDeref__deref](o);
1370
+ return nilImpl(_deref, 'IDeref.-deref', o)(o);
1371
+ }
1372
+ export const ISeqable = { __sym: ISEQABLE_SYM };
1373
+ export const ISeqable__seq = Symbol('ISeqable_-seq');
1374
+ export function _seq(o) {
1375
+ if (o != null && o[ISeqable__seq] !== undefined) return o[ISeqable__seq](o);
1376
+ return nilImpl(_seq, 'ISeqable.-seq', o)(o);
1377
+ }
1378
+
1379
+ // an extend-type on nil stores the impl on the dispatch fn under null,
1380
+ // the same convention the generated protocol dispatch fns use
1381
+ function nilImpl(dispatchFn, protoMethod, o) {
1382
+ const f = dispatchFn[null];
1383
+ if (f === undefined) throw missing_protocol(protoMethod, o);
1384
+ return f;
1385
+ }
1386
+ export const IReset = { __sym: Symbol('squint.core.IReset') };
1387
+ export const IReset__reset_BANG_ = Symbol('IReset_-reset!');
1388
+ export function _reset_BANG_(o, v) {
1389
+ if (o != null && o[IReset__reset_BANG_] !== undefined) return o[IReset__reset_BANG_](o, v);
1390
+ return nilImpl(_reset_BANG_, 'IReset.-reset!', o)(o, v);
1391
+ }
1392
+ export const ISwap = { __sym: Symbol('squint.core.ISwap') };
1393
+ export const ISwap__swap_BANG_ = Symbol('ISwap_-swap!');
1394
+ export function _swap_BANG_(o, f, ...args) {
1395
+ if (o != null && o[ISwap__swap_BANG_] !== undefined) return o[ISwap__swap_BANG_](o, f, ...args);
1396
+ return nilImpl(_swap_BANG_, 'ISwap.-swap!', o)(o, f, ...args);
1397
+ }
1398
+ export const IWatchable = { __sym: Symbol('squint.core.IWatchable') };
1399
+ export const IWatchable__add_watch = Symbol('IWatchable_-add-watch');
1400
+ export const IWatchable__remove_watch = Symbol('IWatchable_-remove-watch');
1401
+ export const IWatchable__notify_watches = Symbol('IWatchable_-notify-watches');
1402
+ export function _add_watch(o, k, f) {
1403
+ if (o != null && o[IWatchable__add_watch] !== undefined) return o[IWatchable__add_watch](o, k, f);
1404
+ return nilImpl(_add_watch, 'IWatchable.-add-watch', o)(o, k, f);
1405
+ }
1406
+ export function _remove_watch(o, k) {
1407
+ if (o != null && o[IWatchable__remove_watch] !== undefined) return o[IWatchable__remove_watch](o, k);
1408
+ return nilImpl(_remove_watch, 'IWatchable.-remove-watch', o)(o, k);
1409
+ }
1410
+ export function _notify_watches(o, oldv, newv) {
1411
+ if (o != null && o[IWatchable__notify_watches] !== undefined) return o[IWatchable__notify_watches](o, oldv, newv);
1412
+ return nilImpl(_notify_watches, 'IWatchable.-notify-watches', o)(o, oldv, newv);
1413
+ }
1414
+
1415
+ // shared protocol impls: one fn per operation, a pointer per instance
1416
+ const ATOM_DEREF = (self) => self.val;
1417
+ const ATOM_RESET = (self, x) => {
1418
+ if (self._validator && !truth_(self._validator(x))) {
1419
+ throw new Error('Validator rejected reference state');
1420
+ }
1421
+ const old_val = self.val;
1422
+ self.val = x;
1423
+ if (self._hasWatches) {
1424
+ for (const [k, f] of Object.entries(self._watches)) f(k, self, old_val, x);
1425
+ }
1426
+ return x;
1427
+ };
1428
+ const ATOM_SWAP = function (self, f, a, b, xs) {
1429
+ switch (arguments.length) {
1430
+ case 2:
1431
+ return ATOM_RESET(self, f(self.val));
1432
+ case 3:
1433
+ return ATOM_RESET(self, f(self.val, a));
1434
+ case 4:
1435
+ return ATOM_RESET(self, f(self.val, a, b));
1436
+ default:
1437
+ return ATOM_RESET(self, f(self.val, a, b, ...xs));
1438
+ }
1439
+ };
1440
+ const ATOM_ADD_WATCH = (self, k, f) => {
1441
+ self._watches[k] = f;
1442
+ self._hasWatches = true;
1443
+ };
1444
+ const ATOM_REMOVE_WATCH = (self, k) => {
1445
+ delete self._watches[k];
1446
+ };
1447
+ const ATOM_NOTIFY = (self, oldv, newv) => {
1448
+ for (const [k, f] of Object.entries(self._watches)) f(k, self, oldv, newv);
1449
+ };
1450
+
1294
1451
  export class Atom {
1295
1452
  constructor(init) {
1296
1453
  this.val = init;
1297
1454
  this._watches = {};
1298
- this._deref = () => this.val;
1299
1455
  this._hasWatches = false;
1300
- this._reset_BANG_ = (x) => {
1301
- const old_val = this.val;
1302
- this.val = x;
1303
- if (this._hasWatches) {
1304
- for (const entry of Object.entries(this._watches)) {
1305
- const k = entry[0];
1306
- const f = entry[1];
1307
- f(k, this, old_val, x);
1308
- }
1309
- }
1310
- return x;
1311
- };
1312
- this._add_watch = (k, fn) => {
1313
- this._watches[k] = fn;
1314
- this._hasWatches = true;
1315
- };
1316
- this._remove_watch = (k) => {
1317
- delete this._watches[k];
1318
- };
1319
- }
1320
- }
1321
-
1322
- export function atom(init) {
1323
- return new Atom(init);
1456
+ this[IATOM_SYM] = true;
1457
+ this[IDEREF_SYM] = true;
1458
+ this[IDeref__deref] = ATOM_DEREF;
1459
+ this[IReset.__sym] = true;
1460
+ this[IReset__reset_BANG_] = ATOM_RESET;
1461
+ this[ISwap.__sym] = true;
1462
+ this[ISwap__swap_BANG_] = ATOM_SWAP;
1463
+ this[IWatchable.__sym] = true;
1464
+ this[IWatchable__add_watch] = ATOM_ADD_WATCH;
1465
+ this[IWatchable__remove_watch] = ATOM_REMOVE_WATCH;
1466
+ this[IWatchable__notify_watches] = ATOM_NOTIFY;
1467
+ }
1468
+ }
1469
+
1470
+ export function atom(init, ...opts) {
1471
+ const a = new Atom(init);
1472
+ for (let i = 0; i < opts.length; i += 2) {
1473
+ if (opts[i] === 'meta') a[_metaSym] = opts[i + 1];
1474
+ else if (opts[i] === 'validator') a._validator = opts[i + 1];
1475
+ }
1476
+ return a;
1477
+ }
1478
+
1479
+ // the CLJS missing-protocol error, used by every protocol dispatch miss
1480
+ export function missing_protocol(proto, obj) {
1481
+ let ty;
1482
+ if (obj === null) ty = 'null';
1483
+ else if (obj === undefined) ty = 'undefined';
1484
+ else if (Array.isArray(obj)) ty = 'array';
1485
+ else if (typeof obj === 'object' && obj.constructor && obj.constructor !== Object) {
1486
+ ty = obj.constructor.name;
1487
+ } else ty = typeof obj;
1488
+ return new Error(
1489
+ `No protocol method ${proto} defined for type ${ty}: ${obj ?? ''}`
1490
+ );
1324
1491
  }
1325
1492
 
1326
1493
  export function deref(ref) {
1327
- return ref._deref();
1494
+ if (ref?.[IDeref__deref] !== undefined) return ref[IDeref__deref](ref);
1495
+ return nilImpl(_deref, 'IDeref.-deref', ref)(ref);
1328
1496
  }
1329
1497
 
1330
1498
  export function reset_BANG_(atm, v) {
1331
- atm._reset_BANG_(v);
1499
+ if (atm?.[IReset__reset_BANG_] !== undefined) return atm[IReset__reset_BANG_](atm, v);
1500
+ return nilImpl(_reset_BANG_, 'IReset.-reset!', atm)(atm, v);
1332
1501
  }
1333
1502
 
1334
1503
  export function swap_BANG_(atm, f, ...args) {
1335
1504
  f = __toFn(f);
1505
+ if (atm?.[ISwap__swap_BANG_] !== undefined) {
1506
+ // the CLJS -swap! contract: up to two positional args, the rest packed
1507
+ switch (args.length) {
1508
+ case 0:
1509
+ return atm[ISwap__swap_BANG_](atm, f);
1510
+ case 1:
1511
+ return atm[ISwap__swap_BANG_](atm, f, args[0]);
1512
+ case 2:
1513
+ return atm[ISwap__swap_BANG_](atm, f, args[0], args[1]);
1514
+ default:
1515
+ return atm[ISwap__swap_BANG_](atm, f, args[0], args[1], args.slice(2));
1516
+ }
1517
+ }
1336
1518
  const v = f(deref(atm), ...args);
1337
1519
  reset_BANG_(atm, v);
1338
1520
  return v;
@@ -1342,19 +1524,19 @@ export function swap_vals_BANG_(atm, f, ...args) {
1342
1524
  const oldv = deref(atm);
1343
1525
  f = __toFn(f);
1344
1526
  const newv = f(oldv, ...args);
1345
- atm._reset_BANG_(newv);
1527
+ reset_BANG_(atm, newv);
1346
1528
  return [oldv, newv];
1347
1529
  }
1348
1530
 
1349
1531
  export function reset_vals_BANG_(atm, newv) {
1350
1532
  const oldv = deref(atm);
1351
- atm._reset_BANG_(newv);
1533
+ reset_BANG_(atm, newv);
1352
1534
  return [oldv, newv];
1353
1535
  }
1354
1536
 
1355
1537
  export function compare_and_set_BANG_(atm, oldv, newv) {
1356
1538
  if (deref(atm) === oldv) {
1357
- atm._reset_BANG_(newv);
1539
+ reset_BANG_(atm, newv);
1358
1540
  return true;
1359
1541
  } else {
1360
1542
  return false;
@@ -1519,6 +1701,18 @@ export function set_QMARK_(x) {
1519
1701
  return typeConst(x) === SET_TYPE;
1520
1702
  }
1521
1703
 
1704
+ export function hash_set(...xs) {
1705
+ return new Set(xs);
1706
+ }
1707
+
1708
+ export function sorted_QMARK_(x) {
1709
+ return x != null && x[SORTED_TAG] === true;
1710
+ }
1711
+
1712
+ export function char_QMARK_(x) {
1713
+ return typeof x === 'string' && x.length === 1;
1714
+ }
1715
+
1522
1716
  export function apply(f, ...args) {
1523
1717
  f = __toFn(f);
1524
1718
  const xs = args.slice(0, args.length - 1);
@@ -1697,9 +1891,10 @@ export function interpose(sep, coll) {
1697
1891
 
1698
1892
  export function select_keys(o, ks) {
1699
1893
  const type = typeConst(o);
1700
- // ret could be object or array, but in the future, maybe we'll have an IEmpty protocol
1701
- const ret = emptyOfType(type) || {};
1702
- for (const k of ks) {
1894
+ // always a map, like CLJS; a js/Map source keeps its rep
1895
+ const ret = type === MAP_TYPE ? new Map() : {};
1896
+ // iterable puns nil to no keys and a map to its entries, like CLJS seq
1897
+ for (const k of iterable(ks)) {
1703
1898
  const v = get(o, k);
1704
1899
  if (v !== undefined) {
1705
1900
  assoc_BANG_(ret, k, v);
@@ -1906,6 +2101,9 @@ export function merge(...args) {
1906
2101
  let obj;
1907
2102
  if (firstArg === null || firstArg === undefined) {
1908
2103
  obj = {};
2104
+ } else if (typeConst(firstArg) === undefined) {
2105
+ // a non-collection passes through; conj! throws when maps follow, like CLJS
2106
+ obj = firstArg;
1909
2107
  } else {
1910
2108
  obj = into(empty(firstArg), firstArg);
1911
2109
  }
@@ -2023,7 +2221,15 @@ function take1(n) {
2023
2221
  });
2024
2222
  }
2025
2223
 
2224
+ function assertNumber(n) {
2225
+ if (typeof n !== 'number') {
2226
+ throw new Error('Assert failed: (number? n)');
2227
+ }
2228
+ return n;
2229
+ }
2230
+
2026
2231
  export function take(n, coll) {
2232
+ assertNumber(n);
2027
2233
  if (arguments.length === 1) {
2028
2234
  return take1(n);
2029
2235
  }
@@ -2041,6 +2247,7 @@ export function take(n, coll) {
2041
2247
  }
2042
2248
 
2043
2249
  export function take_last(n, coll) {
2250
+ assertNumber(n);
2044
2251
  if (n <= 0) {
2045
2252
  return null;
2046
2253
  }
@@ -2113,8 +2320,18 @@ export function partial(f, ...xs) {
2113
2320
  }
2114
2321
 
2115
2322
  export function cycle(coll) {
2323
+ // seq the coll eagerly: nil or empty cycles to an empty seq and a
2324
+ // non-iterable throws, like the seq call in CLJS cycle. The first lap
2325
+ // is cached and replayed, like the retained seq in CLJS Cycle, so a
2326
+ // one-shot iterator source cycles instead of ending after one lap.
2327
+ const it = iterable(coll);
2116
2328
  return lazy(function* () {
2117
- while (true) yield* coll;
2329
+ const cache = [];
2330
+ for (const x of it) {
2331
+ cache.push(x);
2332
+ yield x;
2333
+ }
2334
+ while (cache.length) yield* cache;
2118
2335
  });
2119
2336
  }
2120
2337
 
@@ -2126,6 +2343,7 @@ function drop1(n) {
2126
2343
  }
2127
2344
 
2128
2345
  export function drop(n, xs) {
2346
+ assertNumber(n);
2129
2347
  if (arguments.length === 1) return drop1(n);
2130
2348
  return lazyIter(xs, function* (iter) {
2131
2349
  for (let x = 0; x < n; x++) {
@@ -2220,7 +2438,8 @@ export function update(coll, k, f, ...args) {
2220
2438
 
2221
2439
  export function get_in(coll, path, orElse) {
2222
2440
  let entry = coll;
2223
- for (const item of path) {
2441
+ // iterable puns a nil path to an empty path, like CLJS
2442
+ for (const item of iterable(path)) {
2224
2443
  entry = get(entry, item);
2225
2444
  }
2226
2445
  if (entry === undefined) return orElse;
@@ -2285,6 +2504,18 @@ export function reverse(coll) {
2285
2504
  return toArray(coll).reverse();
2286
2505
  }
2287
2506
 
2507
+ export function rseq(x) {
2508
+ // vectors and sorted maps/sets are reversible, like CLJS
2509
+ if (isVectorArray(x)) {
2510
+ return x.length === 0 ? null : [...x].reverse();
2511
+ }
2512
+ if (x != null && x[SORTED_TAG] === true) {
2513
+ const xs = [...x].reverse();
2514
+ return xs.length === 0 ? null : xs;
2515
+ }
2516
+ throw new Error('rseq not supported on: ' + typeof x);
2517
+ }
2518
+
2288
2519
  export function sort(f, coll) {
2289
2520
  if (arguments.length === 1) {
2290
2521
  coll = f;
@@ -2571,8 +2802,10 @@ export function dorun(x) {
2571
2802
  }
2572
2803
 
2573
2804
  export function doall(x) {
2574
- // realize as concrete array
2575
- return vec(x);
2805
+ // realize a lazy seq and return it, like CLJS; anything else is
2806
+ // already concrete
2807
+ if (x != null && x[TYPE_TAG] === LAZY_ITERABLE_TYPE) for (const _ of x);
2808
+ return x;
2576
2809
  }
2577
2810
 
2578
2811
  export function aclone(arr) {
@@ -2580,13 +2813,53 @@ export function aclone(arr) {
2580
2813
  return cloned;
2581
2814
  }
2582
2815
 
2816
+ function typed_array(sizeOrSeq, initValOrSeq) {
2817
+ if (initValOrSeq !== undefined) {
2818
+ const a = new Array(sizeOrSeq);
2819
+ if (typeof initValOrSeq === 'number') return a.fill(initValOrSeq);
2820
+ let i = 0;
2821
+ for (const x of iterable(initValOrSeq)) {
2822
+ if (i >= sizeOrSeq) break;
2823
+ a[i++] = x;
2824
+ }
2825
+ return a;
2826
+ }
2827
+ if (typeof sizeOrSeq === 'number') return new Array(sizeOrSeq).fill(null);
2828
+ return [...iterable(sizeOrSeq)];
2829
+ }
2830
+
2831
+ // like CLJS: provided for compatibility, all make a plain array
2832
+ export function int_array(sizeOrSeq, initValOrSeq) {
2833
+ return typed_array(sizeOrSeq, initValOrSeq);
2834
+ }
2835
+ export function long_array(sizeOrSeq, initValOrSeq) {
2836
+ return typed_array(sizeOrSeq, initValOrSeq);
2837
+ }
2838
+ export function float_array(sizeOrSeq, initValOrSeq) {
2839
+ return typed_array(sizeOrSeq, initValOrSeq);
2840
+ }
2841
+ export function double_array(sizeOrSeq, initValOrSeq) {
2842
+ return typed_array(sizeOrSeq, initValOrSeq);
2843
+ }
2844
+ export function object_array(sizeOrSeq, initValOrSeq) {
2845
+ return typed_array(sizeOrSeq, initValOrSeq);
2846
+ }
2847
+
2583
2848
  export function add_watch(ref, key, fn) {
2584
- ref._add_watch(key, fn);
2849
+ if (ref?.[IWatchable__add_watch] !== undefined) {
2850
+ ref[IWatchable__add_watch](ref, key, fn);
2851
+ return ref;
2852
+ }
2853
+ nilImpl(_add_watch, 'IWatchable.-add-watch', ref)(ref, key, fn);
2585
2854
  return ref;
2586
2855
  }
2587
2856
 
2588
2857
  export function remove_watch(ref, key) {
2589
- ref._remove_watch(key);
2858
+ if (ref?.[IWatchable__remove_watch] !== undefined) {
2859
+ ref[IWatchable__remove_watch](ref, key);
2860
+ return ref;
2861
+ }
2862
+ nilImpl(_remove_watch, 'IWatchable.-remove-watch', ref)(ref, key);
2590
2863
  return ref;
2591
2864
  }
2592
2865
 
@@ -2639,15 +2912,15 @@ export function every_pred(...preds) {
2639
2912
 
2640
2913
  export function some_fn(...fns) {
2641
2914
  return (...args) => {
2915
+ let res;
2642
2916
  for (const f of fns) {
2643
2917
  for (const a of args) {
2644
- const res = f(a);
2645
- if (res) {
2646
- return res;
2647
- }
2918
+ res = f(a);
2919
+ // truth_, not JS truthiness: 0 and "" are truthy in CLJS
2920
+ if (truth_(res)) return res;
2648
2921
  }
2649
2922
  }
2650
- return undefined;
2923
+ return res;
2651
2924
  };
2652
2925
  }
2653
2926
 
@@ -2791,7 +3064,8 @@ export function re_seq(re, s) {
2791
3064
  }
2792
3065
 
2793
3066
  export function NaN_QMARK_(x) {
2794
- return Number.isNaN(x);
3067
+ // coercing, like CLJS js/isNaN: (NaN? "foo") is true
3068
+ return isNaN(x);
2795
3069
  }
2796
3070
 
2797
3071
  export function number_QMARK_(x) {
@@ -2799,7 +3073,7 @@ export function number_QMARK_(x) {
2799
3073
  }
2800
3074
 
2801
3075
  export function keys(obj) {
2802
- if (obj == null) return;
3076
+ if (obj == null) return null;
2803
3077
  const t = typeConst(obj);
2804
3078
  switch (t) {
2805
3079
  case OBJECT_TYPE: {
@@ -2811,6 +3085,11 @@ export function keys(obj) {
2811
3085
  if (obj.size) return Array.from(obj.keys());
2812
3086
  return;
2813
3087
  }
3088
+ // not a map: nil when empty, like seq in CLJS, else throw
3089
+ for (const _ of iterable(obj)) {
3090
+ throw new TypeError(obj + ' is not a map');
3091
+ }
3092
+ return null;
2814
3093
  }
2815
3094
 
2816
3095
  export function js_keys(obj) {
@@ -2818,7 +3097,7 @@ export function js_keys(obj) {
2818
3097
  }
2819
3098
 
2820
3099
  export function vals(obj) {
2821
- if (obj == null) return;
3100
+ if (obj == null) return null;
2822
3101
  const t = typeConst(obj);
2823
3102
  switch (t) {
2824
3103
  case OBJECT_TYPE: {
@@ -2830,6 +3109,11 @@ export function vals(obj) {
2830
3109
  if (obj.size) return Array.from(obj.values());
2831
3110
  return;
2832
3111
  }
3112
+ // not a map: nil when empty, like seq in CLJS, else throw
3113
+ for (const _ of iterable(obj)) {
3114
+ throw new TypeError(obj + ' is not a map');
3115
+ }
3116
+ return null;
2833
3117
  }
2834
3118
 
2835
3119
  export function string_QMARK_(s) {
@@ -3024,34 +3308,22 @@ export function mod(x, y) {
3024
3308
  }
3025
3309
 
3026
3310
  export function min_key(k, x, ...more) {
3027
- if (more.length == 0) {
3028
- return x;
3311
+ k = __toFn(k);
3312
+ // pairwise (if (< (k x) (k y)) x y), like CLJS, so NaN propagates right
3313
+ let min = x;
3314
+ for (const y of more) {
3315
+ if (!(k(min) < k(y))) min = y;
3029
3316
  }
3030
- var kx = k(x);
3031
- var min = x;
3032
- more.forEach((y) => {
3033
- var ky = k(y);
3034
- if (ky <= kx) {
3035
- kx = ky;
3036
- min = y;
3037
- }
3038
- });
3039
3317
  return min;
3040
3318
  }
3041
3319
 
3042
3320
  export function max_key(k, x, ...more) {
3043
- if (more.length == 0) {
3044
- return x;
3321
+ k = __toFn(k);
3322
+ // pairwise (if (> (k x) (k y)) x y), like CLJS, so NaN propagates right
3323
+ let max = x;
3324
+ for (const y of more) {
3325
+ if (!(k(max) > k(y))) max = y;
3045
3326
  }
3046
- var kx = k(x);
3047
- var max = x;
3048
- more.forEach((y) => {
3049
- var ky = k(y);
3050
- if (ky >= kx) {
3051
- kx = ky;
3052
- max = y;
3053
- }
3054
- });
3055
3327
  return max;
3056
3328
  }
3057
3329
 
@@ -3465,6 +3737,7 @@ export function memoize(f) {
3465
3737
  }
3466
3738
 
3467
3739
  export function peek(vec) {
3740
+ if (vec == null) return null;
3468
3741
  // A list peeks at its front; squint lists are array-backed, so check list
3469
3742
  // before array to avoid returning the last element.
3470
3743
  if (list_QMARK_(vec)) {
@@ -3472,7 +3745,7 @@ export function peek(vec) {
3472
3745
  } else if (array_QMARK_(vec)) {
3473
3746
  return vec[vec.length - 1];
3474
3747
  } else {
3475
- return first(vec);
3748
+ throw missing_protocol('IStack.-peek', vec);
3476
3749
  }
3477
3750
  }
3478
3751
 
@@ -3487,7 +3760,7 @@ export function pop(vec) {
3487
3760
  ret.pop();
3488
3761
  return ret;
3489
3762
  } else {
3490
- return rest(vec);
3763
+ throw missing_protocol('IStack.-pop', vec);
3491
3764
  }
3492
3765
  }
3493
3766
 
@@ -3518,7 +3791,7 @@ export function update_vals(m, f) {
3518
3791
  }
3519
3792
 
3520
3793
  export function random_uuid() {
3521
- return crypto.randomUUID();
3794
+ return new UUID(crypto.randomUUID());
3522
3795
  }
3523
3796
 
3524
3797
  export class UUID {
@@ -3531,20 +3804,34 @@ export class UUID {
3531
3804
  }
3532
3805
 
3533
3806
  export function uuid(s) {
3534
- return new UUID(s);
3807
+ // lowercased, like CLJS
3808
+ return new UUID(s.toLowerCase());
3535
3809
  }
3536
3810
 
3537
3811
  export function uuid_QMARK_(x) {
3538
3812
  return x instanceof UUID;
3539
3813
  }
3540
3814
 
3815
+ const UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
3816
+
3817
+ export function parse_uuid(s) {
3818
+ if (typeof s !== 'string') {
3819
+ throw new Error('Expected string, got: ' + (s === null ? 'nil' : typeof s));
3820
+ }
3821
+ return UUID_REGEX.test(s) ? uuid(s) : null;
3822
+ }
3823
+
3541
3824
  export function inst_QMARK_(x) {
3542
3825
  return x instanceof Date;
3543
3826
  }
3544
3827
 
3828
+ const DELAY_DEREF = (self) => self._deref();
3829
+
3545
3830
  export class Delay {
3546
3831
  constructor(f) {
3547
3832
  this.f = f;
3833
+ this[IDEREF_SYM] = true;
3834
+ this[IDeref__deref] = DELAY_DEREF;
3548
3835
  }
3549
3836
  _deref() {
3550
3837
  if (this.realized) {
@@ -3564,6 +3851,10 @@ export function realized_QMARK_(x) {
3564
3851
  throw new Error('realized? not supported on: ' + str(x));
3565
3852
  }
3566
3853
 
3854
+ export function force(x) {
3855
+ return x instanceof Delay ? x._deref() : x;
3856
+ }
3857
+
3567
3858
  function clj__GT_js_(x, seen) {
3568
3859
  // we need to protect against circular objects
3569
3860
  if (seen.has(x)) return x;
@@ -3591,12 +3882,12 @@ export function not_EQ_(...more) {
3591
3882
  return not(_EQ_(...more));
3592
3883
  }
3593
3884
 
3885
+ const VOLATILE_DEREF = (self) => self.v;
3886
+
3594
3887
  class Volatile {
3595
3888
  constructor(v) {
3596
3889
  this.v = v;
3597
- }
3598
- _deref() {
3599
- return this.v;
3890
+ this[IDeref__deref] = VOLATILE_DEREF;
3600
3891
  }
3601
3892
  }
3602
3893