@bcts/envelope-pattern 1.0.0-alpha.22 → 1.0.0-beta.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.
Files changed (60) hide show
  1. package/dist/index.cjs +1291 -826
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +101 -59
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.mts +102 -60
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.iife.js +1643 -1179
  8. package/dist/index.iife.js.map +1 -1
  9. package/dist/index.mjs +1315 -853
  10. package/dist/index.mjs.map +1 -1
  11. package/package.json +13 -11
  12. package/src/error.ts +1 -1
  13. package/src/format.ts +19 -31
  14. package/src/parse/index.ts +17 -1010
  15. package/src/parse/leaf/array-parser.ts +36 -0
  16. package/src/parse/leaf/cbor-parser.ts +43 -0
  17. package/src/parse/leaf/date-parser.ts +81 -0
  18. package/src/parse/leaf/known-value-parser.ts +73 -0
  19. package/src/parse/leaf/null-parser.ts +16 -0
  20. package/src/parse/leaf/number-parser.ts +90 -0
  21. package/src/parse/leaf/tag-parser.ts +160 -0
  22. package/src/parse/meta/and-parser.ts +40 -0
  23. package/src/parse/meta/capture-parser.ts +50 -0
  24. package/src/parse/meta/group-parser.ts +77 -0
  25. package/src/parse/meta/not-parser.ts +30 -0
  26. package/src/parse/meta/or-parser.ts +36 -0
  27. package/src/parse/meta/primary-parser.ts +234 -0
  28. package/src/parse/meta/search-parser.ts +41 -0
  29. package/src/parse/meta/traverse-parser.ts +42 -0
  30. package/src/parse/structure/assertion-obj-parser.ts +44 -0
  31. package/src/parse/structure/assertion-parser.ts +22 -0
  32. package/src/parse/structure/assertion-pred-parser.ts +45 -0
  33. package/src/parse/structure/compressed-parser.ts +17 -0
  34. package/src/parse/structure/digest-parser.ts +132 -0
  35. package/src/parse/structure/elided-parser.ts +17 -0
  36. package/src/parse/structure/encrypted-parser.ts +17 -0
  37. package/src/parse/structure/node-parser.ts +54 -0
  38. package/src/parse/structure/object-parser.ts +32 -0
  39. package/src/parse/structure/obscured-parser.ts +17 -0
  40. package/src/parse/structure/predicate-parser.ts +32 -0
  41. package/src/parse/structure/subject-parser.ts +32 -0
  42. package/src/parse/structure/wrapped-parser.ts +36 -0
  43. package/src/pattern/dcbor-integration.ts +40 -8
  44. package/src/pattern/index.ts +29 -0
  45. package/src/pattern/leaf/array-pattern.ts +67 -169
  46. package/src/pattern/leaf/cbor-pattern.ts +37 -23
  47. package/src/pattern/leaf/index.ts +1 -1
  48. package/src/pattern/leaf/map-pattern.ts +21 -2
  49. package/src/pattern/leaf/tagged-pattern.ts +6 -1
  50. package/src/pattern/meta/search-pattern.ts +13 -38
  51. package/src/pattern/meta/traverse-pattern.ts +2 -2
  52. package/src/pattern/structure/assertions-pattern.ts +19 -53
  53. package/src/pattern/structure/digest-pattern.ts +18 -22
  54. package/src/pattern/structure/index.ts +3 -0
  55. package/src/pattern/structure/node-pattern.ts +10 -29
  56. package/src/pattern/structure/object-pattern.ts +2 -2
  57. package/src/pattern/structure/predicate-pattern.ts +2 -2
  58. package/src/pattern/structure/subject-pattern.ts +31 -4
  59. package/src/pattern/structure/wrapped-pattern.ts +28 -9
  60. package/src/pattern/vm.ts +4 -4
package/dist/index.cjs CHANGED
@@ -1,10 +1,9 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _bcts_dcbor_pattern = require("@bcts/dcbor-pattern");
3
3
  let _bcts_known_values = require("@bcts/known-values");
4
- let _bcts_envelope = require("@bcts/envelope");
5
4
  let _bcts_dcbor = require("@bcts/dcbor");
5
+ let _bcts_envelope = require("@bcts/envelope");
6
6
  let _bcts_dcbor_parse = require("@bcts/dcbor-parse");
7
-
8
7
  //#region src/error.ts
9
8
  /**
10
9
  * Creates a successful result.
@@ -219,7 +218,6 @@ function dcborPatternError(error) {
219
218
  error
220
219
  };
221
220
  }
222
-
223
221
  //#endregion
224
222
  //#region src/format.ts
225
223
  /**
@@ -308,6 +306,14 @@ function formatPathsOpts() {
308
306
  /**
309
307
  * Gets a summary of an envelope for display.
310
308
  *
309
+ * Mirrors Rust `envelope_summary` in `format.rs`: defers to
310
+ * `Envelope::format_flat()` for nodes / wrapped / assertions and to
311
+ * `cbor.envelope_summary(usize::MAX, ...)` for raw CBOR leaves. The
312
+ * obscured cases (`elided` / `encrypted` / `compressed`) emit just the
313
+ * keyword. KnownValue envelopes look up the canonical name via
314
+ * `KnownValue.name()`, matching the Rust call to
315
+ * `KnownValuesStore::known_value_for_raw_value(value, …)`.
316
+ *
311
317
  * @param env - The envelope to summarize
312
318
  * @returns A string summary of the envelope
313
319
  */
@@ -316,25 +322,17 @@ function envelopeSummary(env) {
316
322
  const c = env.case();
317
323
  let summary;
318
324
  switch (c.type) {
319
- case "node": {
320
- const subjectSummary = env.subject().summary(Number.MAX_SAFE_INTEGER);
321
- const assertions = env.assertions();
322
- if (assertions.length > 0) summary = `NODE ${subjectSummary} [ ${assertions.map((a) => {
323
- const ac = a.case();
324
- if (ac.type === "assertion") return `${ac.assertion.predicate().summary(Number.MAX_SAFE_INTEGER)}: ${ac.assertion.object().summary(Number.MAX_SAFE_INTEGER)}`;
325
- return a.summary(Number.MAX_SAFE_INTEGER);
326
- }).join(", ")} ]`;
327
- else summary = `NODE ${subjectSummary}`;
325
+ case "node":
326
+ summary = `NODE ${env.formatFlat()}`;
328
327
  break;
329
- }
330
328
  case "leaf":
331
329
  summary = `LEAF ${env.summary(Number.MAX_SAFE_INTEGER)}`;
332
330
  break;
333
331
  case "wrapped":
334
- summary = `WRAPPED ${env.summary(Number.MAX_SAFE_INTEGER)}`;
332
+ summary = `WRAPPED ${env.formatFlat()}`;
335
333
  break;
336
334
  case "assertion":
337
- summary = `ASSERTION ${c.assertion.predicate().summary(Number.MAX_SAFE_INTEGER)}: ${c.assertion.object().summary(Number.MAX_SAFE_INTEGER)}`;
335
+ summary = `ASSERTION ${env.formatFlat()}`;
338
336
  break;
339
337
  case "elided":
340
338
  summary = "ELIDED";
@@ -380,8 +378,8 @@ function formatPathOpt(path, opts = defaultFormatPathsOpts()) {
380
378
  if (element === void 0) return "";
381
379
  switch (opts.elementFormat.type) {
382
380
  case "Summary": return truncateWithEllipsis(envelopeSummary(element), opts.elementFormat.maxLength);
383
- case "EnvelopeUR": return element.digest().toString();
384
- case "DigestUR": return element.digest().toString();
381
+ case "EnvelopeUR": return element.urString();
382
+ case "DigestUR": return element.digest().urString();
385
383
  }
386
384
  }
387
385
  switch (opts.elementFormat.type) {
@@ -396,8 +394,8 @@ function formatPathOpt(path, opts = defaultFormatPathsOpts()) {
396
394
  }
397
395
  return lines.join("\n");
398
396
  }
399
- case "EnvelopeUR": return path.map((element) => element.digest().toString()).join(" ");
400
- case "DigestUR": return path.map((element) => element.digest().toString()).join(" ");
397
+ case "EnvelopeUR": return path.map((element) => element.urString()).join(" ");
398
+ case "DigestUR": return path.map((element) => element.digest().urString()).join(" ");
401
399
  }
402
400
  }
403
401
  /**
@@ -478,19 +476,27 @@ function formatPathsOpt(paths, opts = defaultFormatPathsOpts()) {
478
476
  function formatPaths(paths) {
479
477
  return formatPathsOpt(paths, defaultFormatPathsOpts());
480
478
  }
481
-
482
479
  //#endregion
483
480
  //#region src/pattern/matcher.ts
484
481
  /**
485
482
  * Default implementations for Matcher methods.
486
483
  */
487
484
  const MatcherDefaults = {
485
+ /**
486
+ * Default implementation of paths() - calls pathsWithCaptures and discards captures.
487
+ */
488
488
  paths(matcher, haystack) {
489
489
  return matcher.pathsWithCaptures(haystack)[0];
490
490
  },
491
+ /**
492
+ * Default implementation of matches() - checks if paths() returns any results.
493
+ */
491
494
  matches(matcher, haystack) {
492
495
  return matcher.paths(haystack).length > 0;
493
496
  },
497
+ /**
498
+ * Default implementation of isComplex() - returns false.
499
+ */
494
500
  isComplex() {
495
501
  return false;
496
502
  }
@@ -578,7 +584,6 @@ function dispatchPatternToString(pattern) {
578
584
  if (patternToStringFn === void 0) throw new Error("Pattern dispatch functions not registered");
579
585
  return patternToStringFn(pattern);
580
586
  }
581
-
582
587
  //#endregion
583
588
  //#region src/pattern/leaf/bool-pattern.ts
584
589
  let createLeafBoolPattern;
@@ -662,7 +667,6 @@ var BoolPattern = class BoolPattern {
662
667
  return hash;
663
668
  }
664
669
  };
665
-
666
670
  //#endregion
667
671
  //#region src/pattern/leaf/null-pattern.ts
668
672
  let createLeafNullPattern;
@@ -731,7 +735,6 @@ var NullPattern = class NullPattern {
731
735
  return 0;
732
736
  }
733
737
  };
734
-
735
738
  //#endregion
736
739
  //#region src/pattern/leaf/number-pattern.ts
737
740
  let createLeafNumberPattern;
@@ -904,7 +907,6 @@ var NumberPattern = class NumberPattern {
904
907
  return hash;
905
908
  }
906
909
  };
907
-
908
910
  //#endregion
909
911
  //#region src/pattern/leaf/text-pattern.ts
910
912
  let createLeafTextPattern;
@@ -1009,7 +1011,6 @@ var TextPattern = class TextPattern {
1009
1011
  return hash;
1010
1012
  }
1011
1013
  };
1012
-
1013
1014
  //#endregion
1014
1015
  //#region src/pattern/leaf/byte-string-pattern.ts
1015
1016
  let createLeafByteStringPattern;
@@ -1120,7 +1121,6 @@ var ByteStringPattern = class ByteStringPattern {
1120
1121
  return hash;
1121
1122
  }
1122
1123
  };
1123
-
1124
1124
  //#endregion
1125
1125
  //#region src/pattern/leaf/date-pattern.ts
1126
1126
  let createLeafDatePattern;
@@ -1235,28 +1235,18 @@ var DatePattern = class DatePattern {
1235
1235
  return hash;
1236
1236
  }
1237
1237
  };
1238
-
1239
1238
  //#endregion
1240
1239
  //#region src/pattern/leaf/array-pattern.ts
1241
- /**
1242
- * Copyright © 2023-2026 Blockchain Commons, LLC
1243
- * Copyright © 2025-2026 Parity Technologies
1244
- *
1245
- *
1246
- * @bcts/envelope-pattern - Array pattern matching
1247
- *
1248
- * This is a 1:1 TypeScript port of bc-envelope-pattern-rust array_pattern.rs
1249
- *
1250
- * @module envelope-pattern/pattern/leaf/array-pattern
1251
- */
1252
1240
  let createLeafArrayPattern;
1253
1241
  function registerArrayPatternFactory(factory) {
1254
1242
  createLeafArrayPattern = factory;
1255
1243
  }
1256
1244
  /**
1257
- * Pattern for matching array values in envelope leaf nodes.
1245
+ * Pattern for matching arrays.
1258
1246
  *
1259
- * Corresponds to the Rust `ArrayPattern` struct in array_pattern.rs
1247
+ * Mirrors Rust `ArrayPattern(dcbor_pattern::ArrayPattern)` from
1248
+ * `bc-envelope-pattern-rust/src/pattern/leaf/array_pattern.rs`. All
1249
+ * matching, display, and equality is delegated to dcbor-pattern.
1260
1250
  */
1261
1251
  var ArrayPattern = class ArrayPattern {
1262
1252
  _pattern;
@@ -1267,93 +1257,54 @@ var ArrayPattern = class ArrayPattern {
1267
1257
  * Creates a new ArrayPattern that matches any array.
1268
1258
  */
1269
1259
  static any() {
1270
- return new ArrayPattern({ type: "Any" });
1260
+ return new ArrayPattern((0, _bcts_dcbor_pattern.arrayPatternAny)());
1271
1261
  }
1272
1262
  /**
1273
1263
  * Creates a new ArrayPattern that matches arrays with a specific length.
1274
1264
  */
1275
1265
  static count(count) {
1276
- return new ArrayPattern({
1277
- type: "Interval",
1278
- interval: _bcts_dcbor_pattern.Interval.exactly(count)
1279
- });
1266
+ return new ArrayPattern((0, _bcts_dcbor_pattern.arrayPatternWithLength)(count));
1280
1267
  }
1281
1268
  /**
1282
1269
  * Creates a new ArrayPattern that matches arrays within a length range.
1283
1270
  */
1284
1271
  static interval(min, max) {
1285
- return new ArrayPattern({
1286
- type: "Interval",
1287
- interval: max !== void 0 ? _bcts_dcbor_pattern.Interval.from(min, max) : _bcts_dcbor_pattern.Interval.atLeast(min)
1288
- });
1272
+ return new ArrayPattern((0, _bcts_dcbor_pattern.arrayPatternWithLengthRange)(min, max));
1289
1273
  }
1290
1274
  /**
1291
- * Creates a new ArrayPattern from a dcbor-pattern.
1275
+ * Creates a new ArrayPattern from a length Interval.
1292
1276
  */
1293
- static fromDcborPattern(dcborPattern) {
1294
- return new ArrayPattern({
1295
- type: "DCBORPattern",
1296
- pattern: dcborPattern
1297
- });
1277
+ static fromInterval(interval) {
1278
+ return new ArrayPattern((0, _bcts_dcbor_pattern.arrayPatternWithLengthInterval)(interval));
1298
1279
  }
1299
1280
  /**
1300
- * Creates a new ArrayPattern with envelope patterns for element matching.
1281
+ * Creates a new ArrayPattern from a top-level dcbor-pattern.
1282
+ *
1283
+ * Mirrors Rust `ArrayPattern::from_dcbor_pattern`, which constructs an
1284
+ * `ArrayPattern::Elements`-style dcbor array pattern.
1301
1285
  */
1302
- static withPatterns(patterns) {
1303
- return new ArrayPattern({
1304
- type: "WithPatterns",
1305
- patterns
1306
- });
1286
+ static fromDcborPattern(pattern) {
1287
+ return new ArrayPattern((0, _bcts_dcbor_pattern.arrayPatternWithElements)(pattern));
1307
1288
  }
1308
1289
  /**
1309
- * Gets the pattern type.
1290
+ * Creates a new ArrayPattern from an existing dcbor-pattern ArrayPattern.
1291
+ *
1292
+ * Mirrors Rust `ArrayPattern::from_dcbor_array_pattern`.
1310
1293
  */
1311
- get pattern() {
1294
+ static fromDcborArrayPattern(arrayPattern) {
1295
+ return new ArrayPattern(arrayPattern);
1296
+ }
1297
+ /**
1298
+ * Returns the underlying dcbor-pattern ArrayPattern.
1299
+ */
1300
+ inner() {
1312
1301
  return this._pattern;
1313
1302
  }
1314
1303
  pathsWithCaptures(haystack) {
1315
1304
  const cbor = haystack.subject().asLeaf();
1316
1305
  if (cbor === void 0) return [[], /* @__PURE__ */ new Map()];
1317
- const array = (0, _bcts_dcbor.asCborArray)(cbor);
1318
- if (array === void 0) return [[], /* @__PURE__ */ new Map()];
1319
- switch (this._pattern.type) {
1320
- case "Any": return [[[haystack]], /* @__PURE__ */ new Map()];
1321
- case "Interval": {
1322
- const length = array.length;
1323
- if (this._pattern.interval.contains(length)) return [[[haystack]], /* @__PURE__ */ new Map()];
1324
- return [[], /* @__PURE__ */ new Map()];
1325
- }
1326
- case "DCBORPattern": {
1327
- const { paths: dcborPaths, captures: dcborCaptures } = (0, _bcts_dcbor_pattern.patternPathsWithCaptures)(this._pattern.pattern, cbor);
1328
- if (dcborPaths.length > 0) {
1329
- const envelopePaths = dcborPaths.map((dcborPath) => {
1330
- const envPath = [haystack];
1331
- for (let i = 1; i < dcborPath.length; i++) {
1332
- const elem = dcborPath[i];
1333
- if (elem !== void 0) envPath.push(_bcts_envelope.Envelope.newLeaf(elem));
1334
- }
1335
- return envPath;
1336
- });
1337
- const envelopeCaptures = /* @__PURE__ */ new Map();
1338
- for (const [name, capturePaths] of dcborCaptures) {
1339
- const envCapturePaths = capturePaths.map((dcborPath) => {
1340
- const envPath = [haystack];
1341
- for (let i = 1; i < dcborPath.length; i++) {
1342
- const elem = dcborPath[i];
1343
- if (elem !== void 0) envPath.push(_bcts_envelope.Envelope.newLeaf(elem));
1344
- }
1345
- return envPath;
1346
- });
1347
- envelopeCaptures.set(name, envCapturePaths);
1348
- }
1349
- return [envelopePaths, envelopeCaptures];
1350
- }
1351
- return [[], /* @__PURE__ */ new Map()];
1352
- }
1353
- case "WithPatterns":
1354
- if (array.length === this._pattern.patterns.length) return [[[haystack]], /* @__PURE__ */ new Map()];
1355
- return [[], /* @__PURE__ */ new Map()];
1356
- }
1306
+ if ((0, _bcts_dcbor_pattern.arrayPatternMatches)(this._pattern, cbor)) return [[[haystack]], /* @__PURE__ */ new Map()];
1307
+ return [[], /* @__PURE__ */ new Map()];
1357
1308
  }
1358
1309
  paths(haystack) {
1359
1310
  return this.pathsWithCaptures(haystack)[0];
@@ -1369,55 +1320,31 @@ var ArrayPattern = class ArrayPattern {
1369
1320
  return false;
1370
1321
  }
1371
1322
  toString() {
1372
- switch (this._pattern.type) {
1373
- case "Any": return "[*]";
1374
- case "Interval": return `[{${this._pattern.interval.toString()}}]`;
1375
- case "DCBORPattern": return (0, _bcts_dcbor_pattern.patternDisplay)(this._pattern.pattern);
1376
- case "WithPatterns": return `[${this._pattern.patterns.map(String).join(", ")}]`;
1377
- }
1323
+ return (0, _bcts_dcbor_pattern.arrayPatternDisplay)(this._pattern, _bcts_dcbor_pattern.patternDisplay);
1378
1324
  }
1379
1325
  /**
1380
- * Equality comparison.
1326
+ * Equality comparison. Delegates to dcbor-pattern's structural equality
1327
+ * with a display-string fallback for pattern-equality (mirrors Rust's
1328
+ * `Hash` impl that hashes the display, since dcbor `ArrayPattern`
1329
+ * itself does not derive `Hash`).
1381
1330
  */
1382
1331
  equals(other) {
1383
- if (this._pattern.type !== other._pattern.type) return false;
1384
- switch (this._pattern.type) {
1385
- case "Any": return true;
1386
- case "Interval": return this._pattern.interval.equals(other._pattern.interval);
1387
- case "DCBORPattern": return (0, _bcts_dcbor_pattern.patternDisplay)(this._pattern.pattern) === (0, _bcts_dcbor_pattern.patternDisplay)(other._pattern.pattern);
1388
- case "WithPatterns": {
1389
- const otherPatterns = other._pattern.patterns;
1390
- if (this._pattern.patterns.length !== otherPatterns.length) return false;
1391
- for (let i = 0; i < this._pattern.patterns.length; i++) if (this._pattern.patterns[i] !== otherPatterns[i]) return false;
1392
- return true;
1393
- }
1394
- }
1332
+ return (0, _bcts_dcbor_pattern.arrayPatternEquals)(this._pattern, other._pattern, (a, b) => (0, _bcts_dcbor_pattern.patternDisplay)(a) === (0, _bcts_dcbor_pattern.patternDisplay)(b));
1395
1333
  }
1396
1334
  /**
1397
- * Hash code for use in Maps/Sets.
1335
+ * Hash code for use in Maps/Sets. Mirrors Rust's
1336
+ * "hash the string representation" approach.
1398
1337
  */
1399
1338
  hashCode() {
1400
- switch (this._pattern.type) {
1401
- case "Any": return 0;
1402
- case "Interval": return this._pattern.interval.min() * 31 + (this._pattern.interval.max() ?? 0);
1403
- case "DCBORPattern": return simpleStringHash$3((0, _bcts_dcbor_pattern.patternDisplay)(this._pattern.pattern));
1404
- case "WithPatterns": return this._pattern.patterns.length;
1339
+ let hash = 0;
1340
+ const str = this.toString();
1341
+ for (let i = 0; i < str.length; i++) {
1342
+ hash = (hash << 5) - hash + str.charCodeAt(i);
1343
+ hash = hash & hash;
1405
1344
  }
1345
+ return hash;
1406
1346
  }
1407
1347
  };
1408
- /**
1409
- * Simple string hash function for hashCode implementations.
1410
- */
1411
- function simpleStringHash$3(str) {
1412
- let hash = 0;
1413
- for (let i = 0; i < str.length; i++) {
1414
- const char = str.charCodeAt(i);
1415
- hash = (hash << 5) - hash + char;
1416
- hash = hash & hash;
1417
- }
1418
- return hash;
1419
- }
1420
-
1421
1348
  //#endregion
1422
1349
  //#region src/pattern/leaf/map-pattern.ts
1423
1350
  let createLeafMapPattern;
@@ -1450,6 +1377,19 @@ var MapPattern = class MapPattern {
1450
1377
  });
1451
1378
  }
1452
1379
  /**
1380
+ * Creates a new MapPattern from a length Interval.
1381
+ *
1382
+ * Mirrors Rust `MapPattern::from_interval`. Used by the
1383
+ * dcbor-pattern → envelope-pattern bridge to preserve `{{n,m}}`
1384
+ * length info.
1385
+ */
1386
+ static fromInterval(interval) {
1387
+ return new MapPattern({
1388
+ type: "Interval",
1389
+ interval
1390
+ });
1391
+ }
1392
+ /**
1453
1393
  * Gets the pattern type.
1454
1394
  */
1455
1395
  get pattern() {
@@ -1484,8 +1424,8 @@ var MapPattern = class MapPattern {
1484
1424
  }
1485
1425
  toString() {
1486
1426
  switch (this._pattern.type) {
1487
- case "Any": return "{*}";
1488
- case "Interval": return `{{${this._pattern.interval.toString()}}}`;
1427
+ case "Any": return "map";
1428
+ case "Interval": return `{${this._pattern.interval.toString()}}`;
1489
1429
  }
1490
1430
  }
1491
1431
  /**
@@ -1508,7 +1448,6 @@ var MapPattern = class MapPattern {
1508
1448
  }
1509
1449
  }
1510
1450
  };
1511
-
1512
1451
  //#endregion
1513
1452
  //#region src/pattern/leaf/known-value-pattern.ts
1514
1453
  let createLeafKnownValuePattern;
@@ -1629,7 +1568,6 @@ function simpleStringHash$2(str) {
1629
1568
  }
1630
1569
  return hash;
1631
1570
  }
1632
-
1633
1571
  //#endregion
1634
1572
  //#region src/pattern/leaf/tagged-pattern.ts
1635
1573
  /**
@@ -1740,7 +1678,7 @@ var TaggedPattern = class TaggedPattern {
1740
1678
  return false;
1741
1679
  }
1742
1680
  toString() {
1743
- return (0, _bcts_dcbor_pattern.taggedPatternDisplay)(this._inner, _bcts_dcbor_pattern.patternDisplay);
1681
+ return (0, _bcts_dcbor_pattern.taggedPatternDisplay)(this._inner, _bcts_dcbor_pattern.patternDisplay).replace(", ", ", ");
1744
1682
  }
1745
1683
  /**
1746
1684
  * Equality comparison.
@@ -1787,7 +1725,6 @@ function simpleStringHash$1(str) {
1787
1725
  }
1788
1726
  return hash;
1789
1727
  }
1790
-
1791
1728
  //#endregion
1792
1729
  //#region src/pattern/leaf/cbor-pattern.ts
1793
1730
  /**
@@ -1867,10 +1804,18 @@ var CBORPattern = class CBORPattern {
1867
1804
  }
1868
1805
  /**
1869
1806
  * Convert a single dcbor path to an envelope path.
1807
+ *
1808
+ * Uses canonical CBOR-byte equality (`cborEquals`) for the "skip the
1809
+ * dcbor root if it duplicates our base envelope" check, mirroring
1810
+ * Rust's `dcbor_path.first().map(|first| first == &base_cbor)`. The
1811
+ * earlier port compared diagnostic strings, which collapses values
1812
+ * that share a textual representation but differ structurally
1813
+ * (e.g. NaN payloads).
1870
1814
  */
1871
1815
  _convertDcborPathToEnvelopePath(dcborPath, baseEnvelope, baseCbor) {
1872
1816
  const envelopePath = [baseEnvelope];
1873
- const elementsToAdd = dcborPath.length > 0 && dcborPath[0]?.toDiagnostic() === baseCbor.toDiagnostic() ? dcborPath.slice(1) : dcborPath;
1817
+ const first = dcborPath[0];
1818
+ const elementsToAdd = first !== void 0 && (0, _bcts_dcbor.cborEquals)(first, baseCbor) ? dcborPath.slice(1) : dcborPath;
1874
1819
  for (const cborElement of elementsToAdd) envelopePath.push(_bcts_envelope.Envelope.newLeaf(cborElement));
1875
1820
  return envelopePath;
1876
1821
  }
@@ -1897,7 +1842,7 @@ var CBORPattern = class CBORPattern {
1897
1842
  switch (this._pattern.type) {
1898
1843
  case "Any": return [[[haystack]], /* @__PURE__ */ new Map()];
1899
1844
  case "Value":
1900
- if (knownValueCbor.toDiagnostic() === this._pattern.cbor.toDiagnostic()) return [[[haystack]], /* @__PURE__ */ new Map()];
1845
+ if ((0, _bcts_dcbor.cborEquals)(knownValueCbor, this._pattern.cbor)) return [[[haystack]], /* @__PURE__ */ new Map()];
1901
1846
  return [[], /* @__PURE__ */ new Map()];
1902
1847
  case "Pattern": {
1903
1848
  const { paths: dcborPaths, captures: dcborCaptures } = (0, _bcts_dcbor_pattern.patternPathsWithCaptures)(this._pattern.pattern, knownValueCbor);
@@ -1921,7 +1866,7 @@ var CBORPattern = class CBORPattern {
1921
1866
  switch (this._pattern.type) {
1922
1867
  case "Any": return [[[haystack]], /* @__PURE__ */ new Map()];
1923
1868
  case "Value":
1924
- if (leafCbor.toDiagnostic() === this._pattern.cbor.toDiagnostic()) return [[[haystack]], /* @__PURE__ */ new Map()];
1869
+ if ((0, _bcts_dcbor.cborEquals)(leafCbor, this._pattern.cbor)) return [[[haystack]], /* @__PURE__ */ new Map()];
1925
1870
  return [[], /* @__PURE__ */ new Map()];
1926
1871
  case "Pattern": {
1927
1872
  const { paths: dcborPaths, captures: dcborCaptures } = (0, _bcts_dcbor_pattern.patternPathsWithCaptures)(this._pattern.pattern, leafCbor);
@@ -1929,7 +1874,8 @@ var CBORPattern = class CBORPattern {
1929
1874
  const basePath = [haystack];
1930
1875
  return [dcborPaths.map((dcborPath) => {
1931
1876
  const extendedPath = [...basePath];
1932
- const elementsToAdd = dcborPath.length > 0 && dcborPath[0]?.toDiagnostic() === leafCbor.toDiagnostic() ? dcborPath.slice(1) : dcborPath;
1877
+ const first = dcborPath[0];
1878
+ const elementsToAdd = first !== void 0 && (0, _bcts_dcbor.cborEquals)(first, leafCbor) ? dcborPath.slice(1) : dcborPath;
1933
1879
  for (const cborElement of elementsToAdd) extendedPath.push(_bcts_envelope.Envelope.newLeaf(cborElement));
1934
1880
  return extendedPath;
1935
1881
  }), this._convertDcborCapturesToEnvelopeCaptures(dcborCaptures, haystack, leafCbor)];
@@ -1964,13 +1910,16 @@ var CBORPattern = class CBORPattern {
1964
1910
  }
1965
1911
  }
1966
1912
  /**
1967
- * Equality comparison.
1913
+ * Equality comparison. `Value` variants compare by canonical CBOR
1914
+ * byte sequence (mirrors Rust `==` on `CBOR`); `Pattern` variants fall
1915
+ * back to display-string compare since `DCBORPattern` doesn't expose
1916
+ * structural equality outside the crate.
1968
1917
  */
1969
1918
  equals(other) {
1970
1919
  if (this._pattern.type !== other._pattern.type) return false;
1971
1920
  switch (this._pattern.type) {
1972
1921
  case "Any": return true;
1973
- case "Value": return this._pattern.cbor.toDiagnostic() === other._pattern.cbor.toDiagnostic();
1922
+ case "Value": return (0, _bcts_dcbor.cborEquals)(this._pattern.cbor, other._pattern.cbor);
1974
1923
  case "Pattern": return (0, _bcts_dcbor_pattern.patternDisplay)(this._pattern.pattern) === (0, _bcts_dcbor_pattern.patternDisplay)(other._pattern.pattern);
1975
1924
  }
1976
1925
  }
@@ -1980,7 +1929,12 @@ var CBORPattern = class CBORPattern {
1980
1929
  hashCode() {
1981
1930
  switch (this._pattern.type) {
1982
1931
  case "Any": return 0;
1983
- case "Value": return simpleStringHash(this._pattern.cbor.toDiagnostic());
1932
+ case "Value": {
1933
+ const bytes = (0, _bcts_dcbor.cborData)(this._pattern.cbor);
1934
+ let hash = 0;
1935
+ for (const byte of bytes) hash = hash * 31 + byte | 0;
1936
+ return hash;
1937
+ }
1984
1938
  case "Pattern": return simpleStringHash((0, _bcts_dcbor_pattern.patternDisplay)(this._pattern.pattern));
1985
1939
  }
1986
1940
  }
@@ -1996,7 +1950,6 @@ function simpleStringHash(str) {
1996
1950
  }
1997
1951
  return hash;
1998
1952
  }
1999
-
2000
1953
  //#endregion
2001
1954
  //#region src/pattern/leaf/index.ts
2002
1955
  /**
@@ -2198,7 +2151,6 @@ function leafPatternToString(pattern) {
2198
2151
  case "KnownValue": return pattern.pattern.toString();
2199
2152
  }
2200
2153
  }
2201
-
2202
2154
  //#endregion
2203
2155
  //#region src/pattern/structure/leaf-structure-pattern.ts
2204
2156
  let createStructureLeafPattern;
@@ -2251,12 +2203,12 @@ var LeafStructurePattern = class LeafStructurePattern {
2251
2203
  return 0;
2252
2204
  }
2253
2205
  };
2254
-
2255
- //#endregion
2256
- //#region src/pattern/structure/subject-pattern.ts
2257
- let createStructureSubjectPattern;
2258
- function registerSubjectPatternFactory(factory) {
2259
- createStructureSubjectPattern = factory;
2206
+ let dispatchPatternCompile$1;
2207
+ let dispatchPatternToString$3;
2208
+ function registerSubjectPatternFactory(factory) {}
2209
+ function registerSubjectPatternDispatch(dispatch) {
2210
+ dispatchPatternCompile$1 = dispatch.compile;
2211
+ dispatchPatternToString$3 = dispatch.toString;
2260
2212
  }
2261
2213
  /**
2262
2214
  * Pattern for matching subjects in envelopes.
@@ -2321,9 +2273,10 @@ var SubjectPattern = class SubjectPattern {
2321
2273
  code.push({ type: "NavigateSubject" });
2322
2274
  break;
2323
2275
  case "Pattern":
2276
+ if (dispatchPatternCompile$1 === void 0) throw new Error("SubjectPattern.compile requires the top-level Pattern compile dispatch; not registered");
2324
2277
  code.push({ type: "NavigateSubject" });
2325
2278
  code.push({ type: "ExtendTraversal" });
2326
- this._pattern.pattern.compile(code, literals, captures);
2279
+ dispatchPatternCompile$1(this._pattern.pattern, code, literals, captures);
2327
2280
  code.push({ type: "CombineTraversal" });
2328
2281
  break;
2329
2282
  }
@@ -2334,7 +2287,10 @@ var SubjectPattern = class SubjectPattern {
2334
2287
  toString() {
2335
2288
  switch (this._pattern.type) {
2336
2289
  case "Any": return "subj";
2337
- case "Pattern": return `subj(${this._pattern.pattern.toString()})`;
2290
+ case "Pattern": {
2291
+ const fmt = dispatchPatternToString$3;
2292
+ return `subj(${fmt !== void 0 ? fmt(this._pattern.pattern) : "?"})`;
2293
+ }
2338
2294
  }
2339
2295
  }
2340
2296
  /**
@@ -2352,7 +2308,6 @@ var SubjectPattern = class SubjectPattern {
2352
2308
  return this._pattern.type === "Any" ? 0 : 1;
2353
2309
  }
2354
2310
  };
2355
-
2356
2311
  //#endregion
2357
2312
  //#region src/pattern/structure/predicate-pattern.ts
2358
2313
  let createStructurePredicatePattern;
@@ -2432,7 +2387,7 @@ var PredicatePattern = class PredicatePattern {
2432
2387
  toString() {
2433
2388
  switch (this._pattern.type) {
2434
2389
  case "Any": return "pred";
2435
- case "Pattern": return `pred(${this._pattern.pattern.toString()})`;
2390
+ case "Pattern": return `pred(${dispatchPatternToString(this._pattern.pattern)})`;
2436
2391
  }
2437
2392
  }
2438
2393
  /**
@@ -2450,7 +2405,6 @@ var PredicatePattern = class PredicatePattern {
2450
2405
  return this._pattern.type === "Any" ? 0 : 1;
2451
2406
  }
2452
2407
  };
2453
-
2454
2408
  //#endregion
2455
2409
  //#region src/pattern/structure/object-pattern.ts
2456
2410
  let createStructureObjectPattern;
@@ -2530,7 +2484,7 @@ var ObjectPattern = class ObjectPattern {
2530
2484
  toString() {
2531
2485
  switch (this._pattern.type) {
2532
2486
  case "Any": return "obj";
2533
- case "Pattern": return `obj(${this._pattern.pattern.toString()})`;
2487
+ case "Pattern": return `obj(${dispatchPatternToString(this._pattern.pattern)})`;
2534
2488
  }
2535
2489
  }
2536
2490
  /**
@@ -2548,13 +2502,16 @@ var ObjectPattern = class ObjectPattern {
2548
2502
  return this._pattern.type === "Any" ? 0 : 1;
2549
2503
  }
2550
2504
  };
2551
-
2552
2505
  //#endregion
2553
2506
  //#region src/pattern/structure/assertions-pattern.ts
2554
2507
  let createStructureAssertionsPattern;
2508
+ let dispatchPatternToString$2;
2555
2509
  function registerAssertionsPatternFactory(factory) {
2556
2510
  createStructureAssertionsPattern = factory;
2557
2511
  }
2512
+ function registerAssertionsPatternToStringDispatch(fn) {
2513
+ dispatchPatternToString$2 = fn;
2514
+ }
2558
2515
  /**
2559
2516
  * Pattern for matching assertions in envelopes.
2560
2517
  *
@@ -2592,17 +2549,6 @@ var AssertionsPattern = class AssertionsPattern {
2592
2549
  });
2593
2550
  }
2594
2551
  /**
2595
- * Creates a new AssertionsPattern that matches assertions with both
2596
- * predicate and object patterns.
2597
- */
2598
- static withBoth(predicatePattern, objectPattern) {
2599
- return new AssertionsPattern({
2600
- type: "WithBoth",
2601
- predicatePattern,
2602
- objectPattern
2603
- });
2604
- }
2605
- /**
2606
2552
  * Gets the pattern type.
2607
2553
  */
2608
2554
  get patternType() {
@@ -2613,14 +2559,12 @@ var AssertionsPattern = class AssertionsPattern {
2613
2559
  */
2614
2560
  predicatePattern() {
2615
2561
  if (this._pattern.type === "WithPredicate") return this._pattern.pattern;
2616
- if (this._pattern.type === "WithBoth") return this._pattern.predicatePattern;
2617
2562
  }
2618
2563
  /**
2619
2564
  * Gets the object pattern if this has one, undefined otherwise.
2620
2565
  */
2621
2566
  objectPattern() {
2622
2567
  if (this._pattern.type === "WithObject") return this._pattern.pattern;
2623
- if (this._pattern.type === "WithBoth") return this._pattern.objectPattern;
2624
2568
  }
2625
2569
  pathsWithCaptures(haystack) {
2626
2570
  const paths = [];
@@ -2642,14 +2586,6 @@ var AssertionsPattern = class AssertionsPattern {
2642
2586
  }
2643
2587
  break;
2644
2588
  }
2645
- case "WithBoth": {
2646
- const predicate = assertion.asPredicate?.();
2647
- const object = assertion.asObject?.();
2648
- if (predicate !== void 0 && object !== void 0) {
2649
- if (matchPattern(this._pattern.predicatePattern, predicate) && matchPattern(this._pattern.objectPattern, object)) paths.push([assertion]);
2650
- }
2651
- break;
2652
- }
2653
2589
  }
2654
2590
  return [paths, /* @__PURE__ */ new Map()];
2655
2591
  }
@@ -2672,11 +2608,11 @@ var AssertionsPattern = class AssertionsPattern {
2672
2608
  return false;
2673
2609
  }
2674
2610
  toString() {
2611
+ const fmt = dispatchPatternToString$2;
2675
2612
  switch (this._pattern.type) {
2676
2613
  case "Any": return "assert";
2677
- case "WithPredicate": return `assertpred(${this._pattern.pattern.toString()})`;
2678
- case "WithObject": return `assertobj(${this._pattern.pattern.toString()})`;
2679
- case "WithBoth": return `assert(${this._pattern.predicatePattern.toString()}, ${this._pattern.objectPattern.toString()})`;
2614
+ case "WithPredicate": return `assertpred(${fmt !== void 0 ? fmt(this._pattern.pattern) : "?"})`;
2615
+ case "WithObject": return `assertobj(${fmt !== void 0 ? fmt(this._pattern.pattern) : "?"})`;
2680
2616
  }
2681
2617
  }
2682
2618
  /**
@@ -2688,10 +2624,6 @@ var AssertionsPattern = class AssertionsPattern {
2688
2624
  case "Any": return true;
2689
2625
  case "WithPredicate":
2690
2626
  case "WithObject": return this._pattern.pattern === other._pattern.pattern;
2691
- case "WithBoth": {
2692
- const otherBoth = other._pattern;
2693
- return this._pattern.predicatePattern === otherBoth.predicatePattern && this._pattern.objectPattern === otherBoth.objectPattern;
2694
- }
2695
2627
  }
2696
2628
  }
2697
2629
  /**
@@ -2702,11 +2634,9 @@ var AssertionsPattern = class AssertionsPattern {
2702
2634
  case "Any": return 0;
2703
2635
  case "WithPredicate": return 1;
2704
2636
  case "WithObject": return 2;
2705
- case "WithBoth": return 3;
2706
2637
  }
2707
2638
  }
2708
2639
  };
2709
-
2710
2640
  //#endregion
2711
2641
  //#region src/pattern/structure/digest-pattern.ts
2712
2642
  let createStructureDigestPattern;
@@ -2732,12 +2662,6 @@ var DigestPattern = class DigestPattern {
2732
2662
  this._pattern = pattern;
2733
2663
  }
2734
2664
  /**
2735
- * Creates a new DigestPattern that matches any digest.
2736
- */
2737
- static any() {
2738
- return new DigestPattern({ type: "Any" });
2739
- }
2740
- /**
2741
2665
  * Creates a new DigestPattern that matches the exact digest.
2742
2666
  */
2743
2667
  static digest(digest) {
@@ -2775,9 +2699,6 @@ var DigestPattern = class DigestPattern {
2775
2699
  const digestData = digest.data();
2776
2700
  let isHit = false;
2777
2701
  switch (this._pattern.type) {
2778
- case "Any":
2779
- isHit = true;
2780
- break;
2781
2702
  case "Digest":
2782
2703
  isHit = digest.equals(this._pattern.digest);
2783
2704
  break;
@@ -2815,7 +2736,6 @@ var DigestPattern = class DigestPattern {
2815
2736
  }
2816
2737
  toString() {
2817
2738
  switch (this._pattern.type) {
2818
- case "Any": return "digest";
2819
2739
  case "Digest": return `digest(${this._pattern.digest.hex()})`;
2820
2740
  case "Prefix": return `digest(${(0, _bcts_dcbor.bytesToHex)(this._pattern.prefix)})`;
2821
2741
  case "BinaryRegex": return `digest(/${this._pattern.regex.source}/)`;
@@ -2823,17 +2743,26 @@ var DigestPattern = class DigestPattern {
2823
2743
  }
2824
2744
  /**
2825
2745
  * Equality comparison.
2746
+ *
2747
+ * `Prefix` comparison is case-insensitive on the *hex representation* to
2748
+ * mirror Rust's `eq_ignore_ascii_case` (which compares the underlying
2749
+ * `Vec<u8>` of hex bytes byte-for-byte modulo ASCII case). For raw byte
2750
+ * prefixes that happen to be ASCII, this is an ordinary byte compare.
2826
2751
  */
2827
2752
  equals(other) {
2828
2753
  if (this._pattern.type !== other._pattern.type) return false;
2829
2754
  switch (this._pattern.type) {
2830
- case "Any": return true;
2831
2755
  case "Digest": return this._pattern.digest.equals(other._pattern.digest);
2832
2756
  case "Prefix": {
2833
2757
  const thisPrefix = this._pattern.prefix;
2834
2758
  const otherPrefix = other._pattern.prefix;
2835
2759
  if (thisPrefix.length !== otherPrefix.length) return false;
2836
- for (let i = 0; i < thisPrefix.length; i++) if (thisPrefix[i] !== otherPrefix[i]) return false;
2760
+ for (let i = 0; i < thisPrefix.length; i++) {
2761
+ const a = thisPrefix[i];
2762
+ const b = otherPrefix[i];
2763
+ if (a === b) continue;
2764
+ if ((a >= 65 && a <= 90 ? a + 32 : a) !== (b >= 65 && b <= 90 ? b + 32 : b)) return false;
2765
+ }
2837
2766
  return true;
2838
2767
  }
2839
2768
  case "BinaryRegex": return this._pattern.regex.source === other._pattern.regex.source;
@@ -2844,7 +2773,6 @@ var DigestPattern = class DigestPattern {
2844
2773
  */
2845
2774
  hashCode() {
2846
2775
  switch (this._pattern.type) {
2847
- case "Any": return 0;
2848
2776
  case "Digest": {
2849
2777
  const data = this._pattern.digest.data().slice(0, 8);
2850
2778
  let hash = 0;
@@ -2853,7 +2781,10 @@ var DigestPattern = class DigestPattern {
2853
2781
  }
2854
2782
  case "Prefix": {
2855
2783
  let hash = 0;
2856
- for (const byte of this._pattern.prefix) hash = hash * 31 + byte | 0;
2784
+ for (const byte of this._pattern.prefix) {
2785
+ const folded = byte >= 65 && byte <= 90 ? byte + 32 : byte;
2786
+ hash = hash * 31 + folded | 0;
2787
+ }
2857
2788
  return hash;
2858
2789
  }
2859
2790
  case "BinaryRegex": {
@@ -2864,7 +2795,6 @@ var DigestPattern = class DigestPattern {
2864
2795
  }
2865
2796
  }
2866
2797
  };
2867
-
2868
2798
  //#endregion
2869
2799
  //#region src/pattern/structure/node-pattern.ts
2870
2800
  let createStructureNodePattern;
@@ -2906,28 +2836,19 @@ var NodePattern = class NodePattern {
2906
2836
  });
2907
2837
  }
2908
2838
  /**
2909
- * Creates a new NodePattern with a subject pattern constraint.
2910
- */
2911
- static withSubject(subjectPattern) {
2912
- return new NodePattern({
2913
- type: "WithSubject",
2914
- subjectPattern
2915
- });
2916
- }
2917
- /**
2918
2839
  * Gets the pattern type.
2919
2840
  */
2920
2841
  get patternType() {
2921
2842
  return this._pattern;
2922
2843
  }
2923
2844
  /**
2924
- * Gets the subject pattern if this is a WithSubject type, undefined otherwise.
2845
+ * Returns the subject pattern, if any. Rust's `NodePattern` does not carry
2846
+ * subject patterns, so this always returns `undefined`.
2925
2847
  */
2926
- subjectPattern() {
2927
- return this._pattern.type === "WithSubject" ? this._pattern.subjectPattern : void 0;
2928
- }
2848
+ subjectPattern() {}
2929
2849
  /**
2930
- * Gets the assertion patterns (empty array if none).
2850
+ * Returns the assertion patterns. Rust's `NodePattern` does not carry
2851
+ * assertion sub-patterns, so this always returns an empty array.
2931
2852
  */
2932
2853
  assertionPatterns() {
2933
2854
  return [];
@@ -2942,9 +2863,6 @@ var NodePattern = class NodePattern {
2942
2863
  case "AssertionsInterval":
2943
2864
  isHit = this._pattern.interval.contains(haystack.assertions().length);
2944
2865
  break;
2945
- case "WithSubject":
2946
- isHit = true;
2947
- break;
2948
2866
  }
2949
2867
  return [isHit ? [[haystack]] : [], /* @__PURE__ */ new Map()];
2950
2868
  }
@@ -2965,7 +2883,6 @@ var NodePattern = class NodePattern {
2965
2883
  switch (this._pattern.type) {
2966
2884
  case "Any": return "node";
2967
2885
  case "AssertionsInterval": return `node(${this._pattern.interval.toString()})`;
2968
- case "WithSubject": return `node(${this._pattern.subjectPattern.toString()})`;
2969
2886
  }
2970
2887
  }
2971
2888
  /**
@@ -2976,7 +2893,6 @@ var NodePattern = class NodePattern {
2976
2893
  switch (this._pattern.type) {
2977
2894
  case "Any": return true;
2978
2895
  case "AssertionsInterval": return this._pattern.interval.equals(other._pattern.interval);
2979
- case "WithSubject": return this._pattern.subjectPattern === other._pattern.subjectPattern;
2980
2896
  }
2981
2897
  }
2982
2898
  /**
@@ -2986,11 +2902,9 @@ var NodePattern = class NodePattern {
2986
2902
  switch (this._pattern.type) {
2987
2903
  case "Any": return 0;
2988
2904
  case "AssertionsInterval": return this._pattern.interval.min() * 31 + (this._pattern.interval.max() ?? 0);
2989
- case "WithSubject": return 1;
2990
2905
  }
2991
2906
  }
2992
2907
  };
2993
-
2994
2908
  //#endregion
2995
2909
  //#region src/pattern/structure/obscured-pattern.ts
2996
2910
  let createStructureObscuredPattern;
@@ -3094,16 +3008,19 @@ var ObscuredPattern = class ObscuredPattern {
3094
3008
  }
3095
3009
  }
3096
3010
  };
3097
-
3098
3011
  //#endregion
3099
3012
  //#region src/pattern/structure/wrapped-pattern.ts
3100
3013
  let createStructureWrappedPattern;
3014
+ let createAnyPattern;
3101
3015
  let dispatchPatternPathsWithCaptures;
3102
3016
  let dispatchPatternCompile;
3103
3017
  let dispatchPatternToString$1;
3104
3018
  function registerWrappedPatternFactory(factory) {
3105
3019
  createStructureWrappedPattern = factory;
3106
3020
  }
3021
+ function registerWrappedPatternAny(factory) {
3022
+ createAnyPattern = factory;
3023
+ }
3107
3024
  function registerWrappedPatternDispatch(dispatch) {
3108
3025
  dispatchPatternPathsWithCaptures = dispatch.pathsWithCaptures;
3109
3026
  dispatchPatternCompile = dispatch.compile;
@@ -3137,10 +3054,15 @@ var WrappedPattern = class WrappedPattern {
3137
3054
  }
3138
3055
  /**
3139
3056
  * Creates a new WrappedPattern that matches any wrapped envelope and descends into it.
3140
- * Note: This requires Pattern.any() to be available, so it's set up during registration.
3057
+ *
3058
+ * Mirrors Rust `WrappedPattern::unwrap()` which delegates to
3059
+ * `Self::unwrap_matching(Pattern::any())`. The `any` factory is wired in
3060
+ * during module-load registration to break the circular import on the
3061
+ * top-level `Pattern` type.
3141
3062
  */
3142
3063
  static unwrap() {
3143
- return new WrappedPattern({ type: "Any" });
3064
+ if (createAnyPattern === void 0) throw new Error("WrappedPattern.unwrap() requires Pattern.any factory; not registered");
3065
+ return WrappedPattern.unwrapMatching(createAnyPattern());
3144
3066
  }
3145
3067
  /**
3146
3068
  * Gets the pattern type.
@@ -3216,9 +3138,9 @@ var WrappedPattern = class WrappedPattern {
3216
3138
  switch (this._pattern.type) {
3217
3139
  case "Any": return "wrapped";
3218
3140
  case "Unwrap": {
3219
- const patternStr = dispatchPatternToString$1 !== void 0 ? dispatchPatternToString$1(this._pattern.pattern) : "*";
3220
- if (patternStr === "*") return "unwrap";
3221
- return `unwrap(${patternStr})`;
3141
+ const inner = this._pattern.pattern;
3142
+ if (inner.type === "Meta" && inner.pattern.type === "Any") return "unwrap";
3143
+ return `unwrap(${dispatchPatternToString$1 !== void 0 ? dispatchPatternToString$1(inner) : "?"})`;
3222
3144
  }
3223
3145
  }
3224
3146
  }
@@ -3237,7 +3159,6 @@ var WrappedPattern = class WrappedPattern {
3237
3159
  return this._pattern.type === "Any" ? 0 : 1;
3238
3160
  }
3239
3161
  };
3240
-
3241
3162
  //#endregion
3242
3163
  //#region src/pattern/structure/index.ts
3243
3164
  /**
@@ -3409,7 +3330,6 @@ function structurePatternToString(pattern) {
3409
3330
  case "Wrapped": return pattern.pattern.toString();
3410
3331
  }
3411
3332
  }
3412
-
3413
3333
  //#endregion
3414
3334
  //#region src/pattern/vm.ts
3415
3335
  let _patternPathsWithCaptures$1;
@@ -3444,10 +3364,7 @@ function axisChildren(axis, env) {
3444
3364
  case "Wrapped":
3445
3365
  if (envCase.type === "node") {
3446
3366
  const subject = envCase.subject;
3447
- if (subject.isWrapped()) {
3448
- const unwrapped = subject.unwrap();
3449
- if (unwrapped !== void 0) return [[unwrapped, "Content"]];
3450
- }
3367
+ if (subject.isWrapped()) return [[subject.tryUnwrap(), "Content"]];
3451
3368
  } else if (envCase.type === "wrapped") return [[envCase.envelope, "Content"]];
3452
3369
  return [];
3453
3370
  }
@@ -4056,7 +3973,6 @@ function compileMetaPattern(pattern, code, literals, captureNames) {
4056
3973
  }
4057
3974
  }
4058
3975
  }
4059
-
4060
3976
  //#endregion
4061
3977
  //#region src/pattern/meta/any-pattern.ts
4062
3978
  let createMetaAnyPattern;
@@ -4108,13 +4024,7 @@ var AnyPattern = class AnyPattern {
4108
4024
  return 0;
4109
4025
  }
4110
4026
  };
4111
-
4112
- //#endregion
4113
- //#region src/pattern/meta/and-pattern.ts
4114
- let createMetaAndPattern;
4115
- function registerAndPatternFactory(factory) {
4116
- createMetaAndPattern = factory;
4117
- }
4027
+ function registerAndPatternFactory(factory) {}
4118
4028
  /**
4119
4029
  * A pattern that matches if all contained patterns match.
4120
4030
  *
@@ -4170,13 +4080,7 @@ var AndPattern = class AndPattern {
4170
4080
  return this._patterns.length;
4171
4081
  }
4172
4082
  };
4173
-
4174
- //#endregion
4175
- //#region src/pattern/meta/or-pattern.ts
4176
- let createMetaOrPattern;
4177
- function registerOrPatternFactory(factory) {
4178
- createMetaOrPattern = factory;
4179
- }
4083
+ function registerOrPatternFactory(factory) {}
4180
4084
  /**
4181
4085
  * A pattern that matches if any contained pattern matches.
4182
4086
  *
@@ -4270,13 +4174,7 @@ var OrPattern = class OrPattern {
4270
4174
  return this._patterns.length;
4271
4175
  }
4272
4176
  };
4273
-
4274
- //#endregion
4275
- //#region src/pattern/meta/not-pattern.ts
4276
- let createMetaNotPattern;
4277
- function registerNotPatternFactory(factory) {
4278
- createMetaNotPattern = factory;
4279
- }
4177
+ function registerNotPatternFactory(factory) {}
4280
4178
  /**
4281
4179
  * A pattern that negates another pattern; matches when the inner pattern does not match.
4282
4180
  *
@@ -4335,13 +4233,7 @@ var NotPattern = class NotPattern {
4335
4233
  return 1;
4336
4234
  }
4337
4235
  };
4338
-
4339
- //#endregion
4340
- //#region src/pattern/meta/capture-pattern.ts
4341
- let createMetaCapturePattern;
4342
- function registerCapturePatternFactory(factory) {
4343
- createMetaCapturePattern = factory;
4344
- }
4236
+ function registerCapturePatternFactory(factory) {}
4345
4237
  /**
4346
4238
  * A pattern that captures a match with a name.
4347
4239
  *
@@ -4420,13 +4312,7 @@ var CapturePattern = class CapturePattern {
4420
4312
  return hash;
4421
4313
  }
4422
4314
  };
4423
-
4424
- //#endregion
4425
- //#region src/pattern/meta/search-pattern.ts
4426
- let createMetaSearchPattern;
4427
- function registerSearchPatternFactory(factory) {
4428
- createMetaSearchPattern = factory;
4429
- }
4315
+ function registerSearchPatternFactory(factory) {}
4430
4316
  /**
4431
4317
  * A pattern that searches the entire envelope tree for matches.
4432
4318
  *
@@ -4476,30 +4362,20 @@ var SearchPattern = class SearchPattern {
4476
4362
  return [uniquePaths, /* @__PURE__ */ new Map()];
4477
4363
  }
4478
4364
  /**
4479
- * Walk the envelope tree recursively.
4365
+ * Walk the envelope tree using the canonical `Envelope.walk` traversal.
4366
+ *
4367
+ * Mirrors Rust `bc_envelope::Envelope::walk(false, vec![], visitor)`
4368
+ * which is what `SearchPattern::paths_with_captures` uses. The earlier
4369
+ * port hand-rolled a recursion that double-recursed assertions and
4370
+ * stepped through wrapped subjects manually, producing a different
4371
+ * path order (and extra duplicates that the digest-set deduplication
4372
+ * would partially mask).
4480
4373
  */
4481
4374
  _walkEnvelope(envelope, pathToCurrent, visitor) {
4482
- visitor(envelope, pathToCurrent);
4483
- const subject = envelope.subject();
4484
- const newPath = [...pathToCurrent, envelope];
4485
- if (!subject.digest().equals(envelope.digest())) this._walkEnvelope(subject, newPath, visitor);
4486
- for (const assertion of envelope.assertions()) {
4487
- this._walkEnvelope(assertion, newPath, visitor);
4488
- const predicate = assertion.asPredicate?.();
4489
- if (predicate !== void 0) {
4490
- const assertionPath = [...newPath, assertion];
4491
- this._walkEnvelope(predicate, assertionPath, visitor);
4492
- }
4493
- const object = assertion.asObject?.();
4494
- if (object !== void 0) {
4495
- const assertionPath = [...newPath, assertion];
4496
- this._walkEnvelope(object, assertionPath, visitor);
4497
- }
4498
- }
4499
- if (subject.isWrapped()) {
4500
- const unwrapped = subject.tryUnwrap?.();
4501
- if (unwrapped !== void 0) this._walkEnvelope(unwrapped, newPath, visitor);
4502
- }
4375
+ envelope.walk(false, pathToCurrent, (current, _level, _edge, state) => {
4376
+ visitor(current, state);
4377
+ return [[...state, current], false];
4378
+ });
4503
4379
  }
4504
4380
  paths(haystack) {
4505
4381
  return this.pathsWithCaptures(haystack)[0];
@@ -4553,13 +4429,7 @@ function collectCaptureNames(pattern, out) {
4553
4429
  const p = pattern;
4554
4430
  if (p.collectCaptureNames !== void 0) p.collectCaptureNames(out);
4555
4431
  }
4556
-
4557
- //#endregion
4558
- //#region src/pattern/meta/traverse-pattern.ts
4559
- let createMetaTraversePattern;
4560
- function registerTraversePatternFactory(factory) {
4561
- createMetaTraversePattern = factory;
4562
- }
4432
+ function registerTraversePatternFactory(factory) {}
4563
4433
  let _patternPathsWithCaptures;
4564
4434
  let _patternCompile;
4565
4435
  let _patternIsComplex;
@@ -4634,7 +4504,7 @@ var TraversePattern = class TraversePattern {
4634
4504
  return _patternIsComplex(this._first) || this._rest !== void 0;
4635
4505
  }
4636
4506
  toString() {
4637
- return this.patterns().map((p) => p.toString()).join(" -> ");
4507
+ return this.patterns().map((p) => dispatchPatternToString(p)).join(" -> ");
4638
4508
  }
4639
4509
  /**
4640
4510
  * Equality comparison.
@@ -4653,13 +4523,7 @@ var TraversePattern = class TraversePattern {
4653
4523
  return this.patterns().length;
4654
4524
  }
4655
4525
  };
4656
-
4657
- //#endregion
4658
- //#region src/pattern/meta/group-pattern.ts
4659
- let createMetaGroupPattern;
4660
- function registerGroupPatternFactory(factory) {
4661
- createMetaGroupPattern = factory;
4662
- }
4526
+ function registerGroupPatternFactory(factory) {}
4663
4527
  /**
4664
4528
  * A pattern that matches with repetition.
4665
4529
  *
@@ -4735,7 +4599,6 @@ var GroupPattern = class GroupPattern {
4735
4599
  return this._quantifier.min() * 31 + (this._quantifier.max() ?? 0);
4736
4600
  }
4737
4601
  };
4738
-
4739
4602
  //#endregion
4740
4603
  //#region src/pattern/meta/index.ts
4741
4604
  /**
@@ -4925,7 +4788,6 @@ function collectCaptureNamesFromPattern(pattern, out) {
4925
4788
  const p = pattern;
4926
4789
  if (p.collectCaptureNames !== void 0) p.collectCaptureNames(out);
4927
4790
  }
4928
-
4929
4791
  //#endregion
4930
4792
  //#region src/pattern/dcbor-integration.ts
4931
4793
  /**
@@ -4991,17 +4853,44 @@ function convertValuePatternToEnvelopePattern(valuePattern) {
4991
4853
  */
4992
4854
  function convertStructurePatternToEnvelopePattern(structurePattern) {
4993
4855
  switch (structurePattern.type) {
4994
- case "Array": return ok({
4995
- type: "Leaf",
4996
- pattern: leafArray(ArrayPattern.fromDcborPattern({
4997
- kind: "Structure",
4998
- pattern: structurePattern
4999
- }))
5000
- });
5001
- case "Map": return ok({
5002
- type: "Leaf",
5003
- pattern: leafMap(MapPattern.any())
5004
- });
4856
+ case "Array": {
4857
+ const inner = structurePattern.pattern;
4858
+ let arrayPattern;
4859
+ switch (inner.variant) {
4860
+ case "Any":
4861
+ arrayPattern = ArrayPattern.any();
4862
+ break;
4863
+ case "Length":
4864
+ arrayPattern = ArrayPattern.fromInterval(inner.length);
4865
+ break;
4866
+ case "Elements":
4867
+ arrayPattern = ArrayPattern.fromDcborArrayPattern(inner);
4868
+ break;
4869
+ }
4870
+ return ok({
4871
+ type: "Leaf",
4872
+ pattern: leafArray(arrayPattern)
4873
+ });
4874
+ }
4875
+ case "Map": {
4876
+ const inner = structurePattern.pattern;
4877
+ let mapPattern;
4878
+ switch (inner.variant) {
4879
+ case "Any":
4880
+ mapPattern = MapPattern.any();
4881
+ break;
4882
+ case "Length":
4883
+ mapPattern = MapPattern.fromInterval(inner.length);
4884
+ break;
4885
+ case "Constraints":
4886
+ mapPattern = MapPattern.any();
4887
+ break;
4888
+ }
4889
+ return ok({
4890
+ type: "Leaf",
4891
+ pattern: leafMap(mapPattern)
4892
+ });
4893
+ }
5005
4894
  case "Tagged": return ok({
5006
4895
  type: "Leaf",
5007
4896
  pattern: leafTag(TaggedPattern.fromDcborPattern(structurePattern.pattern))
@@ -5058,7 +4947,169 @@ function convertMetaPatternToEnvelopePattern(metaPattern, originalPattern) {
5058
4947
  });
5059
4948
  }
5060
4949
  }
5061
-
4950
+ //#endregion
4951
+ //#region src/parse/utils.ts
4952
+ let createCborPattern;
4953
+ let createCborPatternFromDcbor;
4954
+ let createAnyArray;
4955
+ let createArrayWithCount;
4956
+ let createArrayWithRange;
4957
+ let createArrayFromDcborPattern;
4958
+ /**
4959
+ * Register pattern factory functions.
4960
+ * This is called by the pattern module to avoid circular dependencies.
4961
+ */
4962
+ function registerPatternFactories(factories) {
4963
+ createCborPattern = factories.cborPattern;
4964
+ createCborPatternFromDcbor = factories.cborPatternFromDcbor;
4965
+ createAnyArray = factories.anyArray;
4966
+ createArrayWithCount = factories.arrayWithCount;
4967
+ createArrayWithRange = factories.arrayWithRange;
4968
+ createArrayFromDcborPattern = factories.arrayFromDcborPattern;
4969
+ }
4970
+ /**
4971
+ * Skips whitespace in the source string.
4972
+ *
4973
+ * @param src - The source string
4974
+ * @param pos - The current position (modified in place)
4975
+ */
4976
+ function skipWs$1(src, pos) {
4977
+ while (pos.value < src.length) {
4978
+ const ch = src[pos.value];
4979
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f") pos.value++;
4980
+ else break;
4981
+ }
4982
+ }
4983
+ /**
4984
+ * Parses a CBOR value or dcbor-pattern expression.
4985
+ *
4986
+ * @param src - The source string
4987
+ * @returns The parsed pattern and consumed character count, or an error
4988
+ */
4989
+ function parseCborInner(src) {
4990
+ if (createCborPattern === void 0 || createCborPatternFromDcbor === void 0) return err(unknown());
4991
+ const pos = { value: 0 };
4992
+ skipWs$1(src, pos);
4993
+ if (src[pos.value] === "/") {
4994
+ pos.value++;
4995
+ const start = pos.value;
4996
+ let escape = false;
4997
+ while (pos.value < src.length) {
4998
+ const b = src[pos.value];
4999
+ pos.value++;
5000
+ if (escape) {
5001
+ escape = false;
5002
+ continue;
5003
+ }
5004
+ if (b === "\\") {
5005
+ escape = true;
5006
+ continue;
5007
+ }
5008
+ if (b === "/") {
5009
+ const parseResult = (0, _bcts_dcbor_pattern.parse)(src.slice(start, pos.value - 1));
5010
+ if (!parseResult.ok) return err(invalidPattern({
5011
+ start,
5012
+ end: pos.value - 1
5013
+ }));
5014
+ skipWs$1(src, pos);
5015
+ return ok([createCborPatternFromDcbor(parseResult.value), pos.value]);
5016
+ }
5017
+ }
5018
+ return err(unterminatedRegex({
5019
+ start: start - 1,
5020
+ end: pos.value
5021
+ }));
5022
+ }
5023
+ if (src.slice(pos.value, pos.value + 3) === "ur:") {
5024
+ const parseResult = (0, _bcts_dcbor_parse.parseDcborItemPartial)(src.slice(pos.value));
5025
+ if (!parseResult.ok) return err(unknown());
5026
+ const [cborValue, consumed] = parseResult.value;
5027
+ return ok([createCborPattern(cborValue), pos.value + consumed]);
5028
+ }
5029
+ const parseResult = (0, _bcts_dcbor_parse.parseDcborItemPartial)(src.slice(pos.value));
5030
+ if (!parseResult.ok) return err(unknown());
5031
+ const [cborValue, consumed] = parseResult.value;
5032
+ return ok([createCborPattern(cborValue), pos.value + consumed]);
5033
+ }
5034
+ /**
5035
+ * Parses an array pattern inner content.
5036
+ *
5037
+ * @param src - The source string (content between [ and ])
5038
+ * @returns The parsed pattern and consumed character count, or an error
5039
+ */
5040
+ function parseArrayInner(src) {
5041
+ if (createAnyArray === void 0 || createArrayWithCount === void 0 || createArrayWithRange === void 0 || createArrayFromDcborPattern === void 0) return err(unknown());
5042
+ const pos = { value: 0 };
5043
+ skipWs$1(src, pos);
5044
+ if (src[pos.value] === "*") {
5045
+ pos.value++;
5046
+ skipWs$1(src, pos);
5047
+ return ok([createAnyArray(), pos.value]);
5048
+ }
5049
+ if (src[pos.value] === "{") {
5050
+ pos.value++;
5051
+ skipWs$1(src, pos);
5052
+ const startPos = pos.value;
5053
+ while (pos.value < src.length && src[pos.value] !== void 0 && /\d/.test(src[pos.value])) pos.value++;
5054
+ if (startPos === pos.value) return err(invalidRange({
5055
+ start: pos.value,
5056
+ end: pos.value
5057
+ }));
5058
+ const firstNum = parseInt(src.slice(startPos, pos.value), 10);
5059
+ if (Number.isNaN(firstNum)) return err(invalidNumberFormat({
5060
+ start: startPos,
5061
+ end: pos.value
5062
+ }));
5063
+ skipWs$1(src, pos);
5064
+ if (pos.value >= src.length) return err(unexpectedEndOfInput());
5065
+ const ch = src[pos.value];
5066
+ if (ch === "}") {
5067
+ pos.value++;
5068
+ skipWs$1(src, pos);
5069
+ return ok([createArrayWithCount(firstNum), pos.value]);
5070
+ }
5071
+ if (ch === ",") {
5072
+ pos.value++;
5073
+ skipWs$1(src, pos);
5074
+ if (pos.value >= src.length) return err(unexpectedEndOfInput());
5075
+ const nextCh = src[pos.value];
5076
+ if (nextCh === "}") {
5077
+ pos.value++;
5078
+ skipWs$1(src, pos);
5079
+ return ok([createArrayWithRange(firstNum, void 0), pos.value]);
5080
+ }
5081
+ if (nextCh !== void 0 && /\d/.test(nextCh)) {
5082
+ const secondStart = pos.value;
5083
+ while (pos.value < src.length && src[pos.value] !== void 0 && /\d/.test(src[pos.value])) pos.value++;
5084
+ const secondNum = parseInt(src.slice(secondStart, pos.value), 10);
5085
+ if (Number.isNaN(secondNum)) return err(invalidNumberFormat({
5086
+ start: secondStart,
5087
+ end: pos.value
5088
+ }));
5089
+ skipWs$1(src, pos);
5090
+ if (pos.value >= src.length || src[pos.value] !== "}") return err(unexpectedEndOfInput());
5091
+ pos.value++;
5092
+ skipWs$1(src, pos);
5093
+ return ok([createArrayWithRange(firstNum, secondNum), pos.value]);
5094
+ }
5095
+ return err(invalidRange({
5096
+ start: pos.value,
5097
+ end: pos.value
5098
+ }));
5099
+ }
5100
+ return err(invalidRange({
5101
+ start: pos.value,
5102
+ end: pos.value
5103
+ }));
5104
+ }
5105
+ const parseResult = (0, _bcts_dcbor_pattern.parse)(`[${src.slice(pos.value)}]`);
5106
+ if (!parseResult.ok) return err(invalidPattern({
5107
+ start: pos.value,
5108
+ end: src.length
5109
+ }));
5110
+ const consumed = src.length - pos.value;
5111
+ return ok([createArrayFromDcborPattern(parseResult.value), consumed]);
5112
+ }
5062
5113
  //#endregion
5063
5114
  //#region src/pattern/index.ts
5064
5115
  /**
@@ -5574,6 +5625,12 @@ function registerAllFactories() {
5574
5625
  compile: patternCompile,
5575
5626
  toString: patternToString
5576
5627
  });
5628
+ registerWrappedPatternAny(any);
5629
+ registerAssertionsPatternToStringDispatch(patternToString);
5630
+ registerSubjectPatternDispatch({
5631
+ compile: patternCompile,
5632
+ toString: patternToString
5633
+ });
5577
5634
  registerAnyPatternFactory((p) => patternMeta(metaAny(p)));
5578
5635
  registerAndPatternFactory((p) => patternMeta(metaAnd(p)));
5579
5636
  registerOrPatternFactory((p) => patternMeta(metaOr(p)));
@@ -5585,6 +5642,14 @@ function registerAllFactories() {
5585
5642
  }
5586
5643
  registerAllFactories();
5587
5644
  registerVMPatternFunctions(patternPathsWithCaptures, patternMatches, patternPaths);
5645
+ registerPatternFactories({
5646
+ cborPattern: (value) => cborValue(value),
5647
+ cborPatternFromDcbor: (pattern) => cborPattern(pattern),
5648
+ anyArray,
5649
+ arrayWithCount: (count) => patternLeaf(leafArray(ArrayPattern.count(count))),
5650
+ arrayWithRange: (min, max) => patternLeaf(leafArray(ArrayPattern.interval(min, max))),
5651
+ arrayFromDcborPattern: (pattern) => patternLeaf(leafArray(ArrayPattern.fromDcborPattern(pattern)))
5652
+ });
5588
5653
  registerPatternMatchFn(patternMatches);
5589
5654
  registerPatternDispatchFns({
5590
5655
  pathsWithCaptures: patternPathsWithCaptures,
@@ -5594,7 +5659,6 @@ registerPatternDispatchFns({
5594
5659
  toString: patternToString
5595
5660
  });
5596
5661
  registerTraverseDispatchFunctions(patternPathsWithCaptures, patternCompile, patternIsComplex);
5597
-
5598
5662
  //#endregion
5599
5663
  //#region src/parse/token.ts
5600
5664
  /**
@@ -6338,163 +6402,773 @@ var Lexer = class {
6338
6402
  }
6339
6403
  }
6340
6404
  };
6341
-
6342
6405
  //#endregion
6343
- //#region src/parse/index.ts
6406
+ //#region src/parse/leaf/array-parser.ts
6344
6407
  /**
6345
6408
  * Copyright © 2023-2026 Blockchain Commons, LLC
6346
6409
  * Copyright © 2025-2026 Parity Technologies
6347
6410
  *
6411
+ * Array parser — port of `bc-envelope-pattern-rust`
6412
+ * `parse/leaf/array_parser.rs`.
6348
6413
  *
6349
- * @bcts/envelope-pattern - Parser entry point
6350
- *
6351
- * This is a 1:1 TypeScript port of bc-envelope-pattern-rust parse/mod.rs
6352
- * Recursive descent parser for Gordian Envelope pattern syntax.
6414
+ * Mirrors Rust's flow exactly: after the `[` token has been consumed,
6415
+ * delegate to `utils::parseArrayInner` (which handles `*`, `{n}`, `{n,m}`,
6416
+ * `{n,}` directly and otherwise wraps the body in `[...]` and re-parses
6417
+ * via dcbor-pattern), then expect a closing `]`.
6353
6418
  *
6354
- * @module envelope-pattern/parse
6419
+ * @module envelope-pattern/parse/leaf/array-parser
6355
6420
  */
6421
+ function parseArray(lexer) {
6422
+ const inner = parseArrayInner(lexer.remainder());
6423
+ if (!inner.ok) return inner;
6424
+ const [pattern, consumed] = inner.value;
6425
+ lexer.bump(consumed);
6426
+ const close = lexer.next();
6427
+ if (close === void 0) return err(expectedCloseBracket(lexer.span()));
6428
+ if (close.token.type !== "BracketClose") return err(unexpectedToken(close.token, close.span));
6429
+ return ok(pattern);
6430
+ }
6431
+ //#endregion
6432
+ //#region src/parse/leaf/cbor-parser.ts
6356
6433
  /**
6357
- * Parse a pattern expression string into a Pattern.
6358
- */
6359
- function parse(input) {
6360
- const lexer = new Lexer(input);
6361
- const result = parseOr(lexer);
6362
- if (!result.ok) {
6363
- const dcborResult = (0, _bcts_dcbor_pattern.parse)(input);
6364
- if (dcborResult.ok) return convertDcborPatternToEnvelopePattern$1(dcborResult.value);
6365
- return result;
6366
- }
6367
- const next = lexer.next();
6368
- if (next !== void 0) return err(extraData(next.span));
6369
- return result;
6434
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6435
+ * Copyright © 2025-2026 Parity Technologies
6436
+ *
6437
+ * CBOR pattern parser — port of `bc-envelope-pattern-rust`
6438
+ * `parse/leaf/cbor_parser.rs`.
6439
+ *
6440
+ * Mirrors Rust's flow: lookahead for `(`. If absent, return `any_cbor()`.
6441
+ * Otherwise consume the `(`, delegate to `parseCborInner` (handles
6442
+ * `/regex/`, `ur:…`, and CBOR diagnostic notation), and expect a closing
6443
+ * `)`.
6444
+ *
6445
+ * @module envelope-pattern/parse/leaf/cbor-parser
6446
+ */
6447
+ function parseCbor(lexer) {
6448
+ if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyCbor());
6449
+ lexer.next();
6450
+ const innerResult = parseCborInner(lexer.remainder());
6451
+ if (!innerResult.ok) return innerResult;
6452
+ const [pattern, consumed] = innerResult.value;
6453
+ lexer.bump(consumed);
6454
+ const close = lexer.next();
6455
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
6456
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
6457
+ return ok(pattern);
6370
6458
  }
6459
+ //#endregion
6460
+ //#region src/parse/leaf/date-parser.ts
6371
6461
  /**
6372
- * Parse a pattern, allowing extra data after the pattern.
6462
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6463
+ * Copyright © 2025-2026 Parity Technologies
6464
+ *
6465
+ * Date content parser — port of `bc-envelope-pattern-rust`
6466
+ * `parse/leaf/date_parser.rs`.
6467
+ *
6468
+ * Mirrors Rust's `Date::from_string`, which accepts a strict ISO-8601
6469
+ * subset, by deferring to dcbor's `CborDate.fromString`. Falls back to JS
6470
+ * `Date.parse` only as a defensive shim — that branch is unreachable for
6471
+ * conformant inputs.
6472
+ *
6473
+ * @module envelope-pattern/parse/leaf/date-parser
6373
6474
  */
6374
- function parsePartial(input) {
6375
- const lexer = new Lexer(input);
6376
- const result = parseOr(lexer);
6377
- if (!result.ok) return result;
6378
- return ok([result.value, lexer.position]);
6475
+ /**
6476
+ * Parse a date pattern of one of the forms accepted by Rust:
6477
+ *
6478
+ * - `/regex/` (regex match against ISO-8601 string)
6479
+ * - `start...end` (inclusive range)
6480
+ * - `start...` (earliest)
6481
+ * - `...end` (latest)
6482
+ * - `iso-8601` (exact)
6483
+ *
6484
+ * Mirrors `parse_date_content` in Rust; uses `CborDate.fromString` so the
6485
+ * accepted formats match Rust's `bc_envelope::prelude::Date::from_string`
6486
+ * exactly rather than the looser JS `Date.parse`.
6487
+ */
6488
+ function parseDateContent(content, span) {
6489
+ if (content.startsWith("/") && content.endsWith("/") && content.length >= 2) {
6490
+ const regexStr = content.slice(1, -1);
6491
+ try {
6492
+ return ok(dateRegex(new RegExp(regexStr)));
6493
+ } catch {
6494
+ return err(invalidRegex(span));
6495
+ }
6496
+ }
6497
+ const ellipsisIdx = content.indexOf("...");
6498
+ if (ellipsisIdx !== -1) {
6499
+ const left = content.slice(0, ellipsisIdx);
6500
+ const right = content.slice(ellipsisIdx + 3);
6501
+ if (left.length === 0 && right.length > 0) {
6502
+ const parsed = parseIsoDateStrict(right);
6503
+ if (parsed === void 0) return err(invalidDateFormat(span));
6504
+ return ok(dateLatest(parsed));
6505
+ }
6506
+ if (left.length > 0 && right.length === 0) {
6507
+ const parsed = parseIsoDateStrict(left);
6508
+ if (parsed === void 0) return err(invalidDateFormat(span));
6509
+ return ok(dateEarliest(parsed));
6510
+ }
6511
+ if (left.length > 0 && right.length > 0) {
6512
+ const start = parseIsoDateStrict(left);
6513
+ const end = parseIsoDateStrict(right);
6514
+ if (start === void 0 || end === void 0) return err(invalidDateFormat(span));
6515
+ return ok(dateRange(start, end));
6516
+ }
6517
+ return err(invalidDateFormat(span));
6518
+ }
6519
+ const parsed = parseIsoDateStrict(content);
6520
+ if (parsed === void 0) return err(invalidDateFormat(span));
6521
+ return ok(date(parsed));
6379
6522
  }
6523
+ function parseIsoDateStrict(value) {
6524
+ try {
6525
+ return _bcts_dcbor.CborDate.fromString(value);
6526
+ } catch {
6527
+ return;
6528
+ }
6529
+ }
6530
+ //#endregion
6531
+ //#region src/parse/leaf/known-value-parser.ts
6380
6532
  /**
6381
- * Convert a dcbor-pattern Pattern to an envelope-pattern Pattern.
6533
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6534
+ * Copyright © 2025-2026 Parity Technologies
6535
+ *
6536
+ * Helpers for parsing the body of a `'…'` (single-quoted) known-value
6537
+ * literal. Mirrors the inline body of Rust's `Token::SingleQuotedPattern`
6538
+ * branch in `parse_primary`:
6539
+ *
6540
+ * - If the contents are a valid `u64`, build `Pattern::known_value(...)`.
6541
+ * - Otherwise, build `Pattern::known_value_named(...)`.
6542
+ *
6543
+ * The earlier port duck-typed a fake `KnownValue`; this version uses the
6544
+ * real `KnownValue` constructor so all subsequent KnownValue methods work
6545
+ * (e.g., `taggedCbor()`, `name()`, etc.).
6546
+ *
6547
+ * @module envelope-pattern/parse/leaf/known-value-parser
6382
6548
  */
6383
- function convertDcborPatternToEnvelopePattern$1(_dcborPattern) {
6384
- return ok(any());
6549
+ /**
6550
+ * Maximum value of a Rust `u64`. Used to reject literals that would
6551
+ * silently wrap or lose precision when constructing a `KnownValue`.
6552
+ */
6553
+ const U64_MAX = 18446744073709551615n;
6554
+ /**
6555
+ * Parse the inner contents of a `'…'` known-value pattern token.
6556
+ *
6557
+ * Mirrors the Rust dispatch
6558
+ * ```ignore
6559
+ * if let Ok(value) = content.parse::<u64>() {
6560
+ * Pattern::known_value(KnownValue::new(value))
6561
+ * } else {
6562
+ * Pattern::known_value_named(content)
6563
+ * }
6564
+ * ```
6565
+ * but uses BigInt parsing to preserve full `u64` range — the previous
6566
+ * `parseInt(...)` path silently truncated above `2^53-1`.
6567
+ */
6568
+ function parseKnownValueContent(content) {
6569
+ if (isU64Literal(content)) return ok(knownValue(new _bcts_known_values.KnownValue(BigInt(content))));
6570
+ return ok(patternLeaf(leafKnownValue(KnownValuePattern.named(content))));
6385
6571
  }
6572
+ function isU64Literal(content) {
6573
+ if (content.length === 0) return false;
6574
+ for (let i = 0; i < content.length; i++) {
6575
+ const c = content.charCodeAt(i);
6576
+ if (c < 48 || c > 57) return false;
6577
+ }
6578
+ try {
6579
+ const value = BigInt(content);
6580
+ return value >= 0n && value <= U64_MAX;
6581
+ } catch {
6582
+ return false;
6583
+ }
6584
+ }
6585
+ //#endregion
6586
+ //#region src/parse/leaf/number-parser.ts
6386
6587
  /**
6387
- * Parse an Or expression: expr (| expr)*
6588
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6589
+ * Copyright © 2025-2026 Parity Technologies
6590
+ *
6591
+ * Number parsers — port of `bc-envelope-pattern-rust` `parse/leaf/number_parser.rs`.
6592
+ *
6593
+ * @module envelope-pattern/parse/leaf/number-parser
6388
6594
  */
6389
- function parseOr(lexer) {
6390
- const patterns = [];
6391
- const first = parseTraverse(lexer);
6392
- if (!first.ok) return first;
6393
- patterns.push(first.value);
6394
- while (true) {
6395
- if (lexer.peekToken()?.token.type !== "Or") break;
6595
+ /**
6596
+ * Parses an optional `...end` suffix following an already-consumed number,
6597
+ * mirroring Rust `parse_number_range_or_comparison`.
6598
+ */
6599
+ function parseNumberRangeOrComparison(lexer, firstValue) {
6600
+ const next = lexer.peekToken();
6601
+ if (next === void 0) return ok(number(firstValue));
6602
+ if (next.token.type === "Ellipsis") {
6396
6603
  lexer.next();
6397
- const nextExpr = parseTraverse(lexer);
6398
- if (!nextExpr.ok) return nextExpr;
6399
- patterns.push(nextExpr.value);
6604
+ const endToken = lexer.next();
6605
+ if (endToken === void 0) return err(unexpectedEndOfInput());
6606
+ let endValue;
6607
+ if (endToken.token.type === "UnsignedInteger" || endToken.token.type === "Integer" || endToken.token.type === "Float") {
6608
+ if (!endToken.token.value.ok) return err(endToken.token.value.error);
6609
+ endValue = endToken.token.value.value;
6610
+ } else return err(unexpectedToken(endToken.token, endToken.span));
6611
+ return ok(numberRange(firstValue, endValue));
6400
6612
  }
6401
- if (patterns.length === 1) return ok(patterns[0]);
6402
- return ok(or(patterns));
6613
+ return ok(number(firstValue));
6403
6614
  }
6404
6615
  /**
6405
- * Parse a Traverse expression: expr (-> expr)*
6616
+ * Parses a number following a comparison operator, mirroring Rust
6617
+ * `parse_comparison_number`.
6406
6618
  */
6407
- function parseTraverse(lexer) {
6408
- const patterns = [];
6409
- const first = parseAnd(lexer);
6410
- if (!first.ok) return first;
6411
- patterns.push(first.value);
6412
- while (true) {
6413
- if (lexer.peekToken()?.token.type !== "Traverse") break;
6414
- lexer.next();
6415
- const nextExpr = parseAnd(lexer);
6416
- if (!nextExpr.ok) return nextExpr;
6417
- patterns.push(nextExpr.value);
6619
+ function parseComparisonNumber(lexer, op) {
6620
+ const numToken = lexer.next();
6621
+ if (numToken === void 0) return err(unexpectedEndOfInput());
6622
+ let value;
6623
+ if (numToken.token.type === "UnsignedInteger" || numToken.token.type === "Integer" || numToken.token.type === "Float") {
6624
+ if (!numToken.token.value.ok) return err(numToken.token.value.error);
6625
+ value = numToken.token.value.value;
6626
+ } else return err(unexpectedToken(numToken.token, numToken.span));
6627
+ switch (op) {
6628
+ case ">=": return ok(patternLeaf(leafNumber(NumberPattern.greaterThanOrEqual(value))));
6629
+ case "<=": return ok(patternLeaf(leafNumber(NumberPattern.lessThanOrEqual(value))));
6630
+ case ">": return ok(numberGreaterThan(value));
6631
+ case "<": return ok(numberLessThan(value));
6418
6632
  }
6419
- if (patterns.length === 1) return ok(patterns[0]);
6420
- return ok(traverse(patterns));
6421
6633
  }
6634
+ //#endregion
6635
+ //#region src/parse/leaf/tag-parser.ts
6422
6636
  /**
6423
- * Parse an And expression: expr (& expr)*
6637
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6638
+ * Copyright © 2025-2026 Parity Technologies
6639
+ *
6640
+ * Tag parser — port of `bc-envelope-pattern-rust`
6641
+ * `parse/leaf/tag_parser.rs`.
6642
+ *
6643
+ * Mirrors the Rust dispatch exactly: lookahead for `(`; if absent, return
6644
+ * the bare `any_tag()`. Otherwise build a synthetic dcbor-pattern
6645
+ * expression `tagged(<inner>)`, parse it via `@bcts/dcbor-pattern`, and
6646
+ * extract the resulting `TaggedPattern` to wrap as an envelope-pattern
6647
+ * leaf. This keeps the **full** tag selector (number, name, regex)
6648
+ * intact — the previous port discarded the tag value entirely.
6649
+ *
6650
+ * @module envelope-pattern/parse/leaf/tag-parser
6424
6651
  */
6425
- function parseAnd(lexer) {
6426
- const patterns = [];
6427
- const first = parseNot(lexer);
6428
- if (!first.ok) return first;
6429
- patterns.push(first.value);
6430
- while (true) {
6431
- if (lexer.peekToken()?.token.type !== "And") break;
6432
- lexer.next();
6433
- const nextExpr = parseNot(lexer);
6434
- if (!nextExpr.ok) return nextExpr;
6435
- patterns.push(nextExpr.value);
6652
+ /**
6653
+ * Parse `tagged` and `tagged(...)` patterns.
6654
+ */
6655
+ function parseTag(lexer) {
6656
+ if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyTag());
6657
+ lexer.next();
6658
+ const remainder = lexer.remainder();
6659
+ const closeIdx = findMatchingCloseParen(remainder);
6660
+ if (closeIdx === void 0) return err(expectedCloseParen(lexer.span()));
6661
+ const innerContent = remainder.slice(0, closeIdx);
6662
+ const dcborResult = (0, _bcts_dcbor_pattern.parse)(`tagged(${innerContent})`);
6663
+ if (dcborResult.ok) {
6664
+ const dcborPattern = dcborResult.value;
6665
+ if (dcborPattern.kind === "Structure" && dcborPattern.pattern.type === "Tagged") {
6666
+ lexer.bump(closeIdx);
6667
+ const close = lexer.next();
6668
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
6669
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
6670
+ return ok(patternLeaf(leafTag(TaggedPattern.fromDcborPattern(dcborPattern.pattern.pattern))));
6671
+ }
6672
+ }
6673
+ const fallback = parseTagInner(innerContent);
6674
+ if (!fallback.ok) return fallback;
6675
+ lexer.bump(closeIdx);
6676
+ const close = lexer.next();
6677
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
6678
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
6679
+ return ok(fallback.value);
6680
+ }
6681
+ /**
6682
+ * Locate the index of the closing `)` matching the `(` that has already
6683
+ * been consumed by `parseTag`. Mirrors Rust `find_matching_paren`.
6684
+ */
6685
+ function findMatchingCloseParen(src) {
6686
+ let depth = 0;
6687
+ for (let i = 0; i < src.length; i++) {
6688
+ const ch = src.charCodeAt(i);
6689
+ if (ch === 40) depth += 1;
6690
+ else if (ch === 41) {
6691
+ if (depth === 0) return i;
6692
+ depth -= 1;
6693
+ }
6436
6694
  }
6437
- if (patterns.length === 1) return ok(patterns[0]);
6438
- return ok(and(patterns));
6439
6695
  }
6440
6696
  /**
6441
- * Parse a Not expression: !? group
6697
+ * Fallback for `tagged(N)` and `tagged(name)` when the full delegation
6698
+ * to dcbor-pattern fails. Mirrors Rust `parse_tag_inner`.
6442
6699
  */
6443
- function parseNot(lexer) {
6444
- if (lexer.peekToken()?.token.type === "Not") {
6445
- lexer.next();
6446
- const inner = parseGroup(lexer);
6447
- if (!inner.ok) return inner;
6448
- return ok(notMatching(inner.value));
6700
+ function parseTagInner(src) {
6701
+ const trimmed = src.trim();
6702
+ if (trimmed.length === 0) return err(unexpectedEndOfInput());
6703
+ if (trimmed.startsWith("/")) return err(unexpectedEndOfInput());
6704
+ if (/^\d+$/.test(trimmed)) try {
6705
+ const dcborResult = (0, _bcts_dcbor_pattern.parse)(`tagged(${trimmed})`);
6706
+ if (dcborResult.ok && dcborResult.value.kind === "Structure" && dcborResult.value.pattern.type === "Tagged") return ok(patternLeaf(leafTag(TaggedPattern.fromDcborPattern(dcborResult.value.pattern.pattern))));
6707
+ } catch {}
6708
+ const dcborResult = (0, _bcts_dcbor_pattern.parse)(`tagged(${trimmed})`);
6709
+ if (dcborResult.ok && dcborResult.value.kind === "Structure" && dcborResult.value.pattern.type === "Tagged") return ok(patternLeaf(leafTag(TaggedPattern.fromDcborPattern(dcborResult.value.pattern.pattern))));
6710
+ return err(unexpectedEndOfInput());
6711
+ }
6712
+ //#endregion
6713
+ //#region src/parse/structure/assertion-parser.ts
6714
+ /**
6715
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6716
+ * Copyright © 2025-2026 Parity Technologies
6717
+ *
6718
+ * Assertion parser — port of `bc-envelope-pattern-rust`
6719
+ * `parse/structure/assertion_parser.rs`.
6720
+ *
6721
+ * Note: Rust's `parse_assertion` ignores its lexer entirely and always
6722
+ * returns `Pattern::any_assertion()`. There is intentionally **no**
6723
+ * `assert(pred, obj)` syntax — predicate/object filters are written via
6724
+ * the dedicated `assertpred(...)` / `assertobj(...)` keywords.
6725
+ *
6726
+ * @module envelope-pattern/parse/structure/assertion-parser
6727
+ */
6728
+ function parseAssertion(_lexer) {
6729
+ return ok(anyAssertion());
6730
+ }
6731
+ //#endregion
6732
+ //#region src/parse/structure/assertion-obj-parser.ts
6733
+ /**
6734
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6735
+ * Copyright © 2025-2026 Parity Technologies
6736
+ *
6737
+ * Assertion-object parser — port of
6738
+ * `bc-envelope-pattern-rust/src/parse/structure/assertion_obj_parser.rs`.
6739
+ *
6740
+ * Requires `assertobj(<pattern>)`. The bare `assertobj` keyword is a
6741
+ * syntax error in Rust; we now mirror that behaviour.
6742
+ *
6743
+ * @module envelope-pattern/parse/structure/assertion-obj-parser
6744
+ */
6745
+ function parseAssertionObj(lexer) {
6746
+ const open = lexer.next();
6747
+ if (open === void 0) return err(unexpectedEndOfInput());
6748
+ if (open.token.type !== "ParenOpen") return err(unexpectedToken(open.token, open.span));
6749
+ const inner = parseOr(lexer);
6750
+ if (!inner.ok) return inner;
6751
+ const close = lexer.next();
6752
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
6753
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
6754
+ return ok(assertionWithObject(inner.value));
6755
+ }
6756
+ //#endregion
6757
+ //#region src/parse/structure/assertion-pred-parser.ts
6758
+ /**
6759
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6760
+ * Copyright © 2025-2026 Parity Technologies
6761
+ *
6762
+ * Assertion-predicate parser — port of
6763
+ * `bc-envelope-pattern-rust/src/parse/structure/assertion_pred_parser.rs`.
6764
+ *
6765
+ * Requires `assertpred(<pattern>)`. The bare `assertpred` keyword is a
6766
+ * syntax error in Rust (it errors on `UnexpectedEndOfInput` /
6767
+ * `UnexpectedToken`); we now mirror that behaviour.
6768
+ *
6769
+ * @module envelope-pattern/parse/structure/assertion-pred-parser
6770
+ */
6771
+ function parseAssertionPred(lexer) {
6772
+ const open = lexer.next();
6773
+ if (open === void 0) return err(unexpectedEndOfInput());
6774
+ if (open.token.type !== "ParenOpen") return err(unexpectedToken(open.token, open.span));
6775
+ const inner = parseOr(lexer);
6776
+ if (!inner.ok) return inner;
6777
+ const close = lexer.next();
6778
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
6779
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
6780
+ return ok(assertionWithPredicate(inner.value));
6781
+ }
6782
+ //#endregion
6783
+ //#region src/parse/structure/compressed-parser.ts
6784
+ /**
6785
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6786
+ * Copyright © 2025-2026 Parity Technologies
6787
+ *
6788
+ * Compressed parser — port of `bc-envelope-pattern-rust`
6789
+ * `parse/structure/compressed_parser.rs`.
6790
+ *
6791
+ * @module envelope-pattern/parse/structure/compressed-parser
6792
+ */
6793
+ function parseCompressed(_lexer) {
6794
+ return ok(compressed());
6795
+ }
6796
+ //#endregion
6797
+ //#region src/parse/structure/digest-parser.ts
6798
+ /**
6799
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6800
+ * Copyright © 2025-2026 Parity Technologies
6801
+ *
6802
+ * Digest parser — port of `bc-envelope-pattern-rust`
6803
+ * `parse/structure/digest_parser.rs`.
6804
+ *
6805
+ * Mirrors Rust exactly:
6806
+ *
6807
+ * - Requires `digest(...)` — bare `digest` is an `UnexpectedEndOfInput`
6808
+ * error (the previous TS port silently returned `digest(any)`).
6809
+ * - Inside the parens, accepts either a UR string (`ur:digest/...`,
6810
+ * parsed via `Digest.fromURString`) or a hex byte prefix.
6811
+ * - Hex prefixes must have even length and not exceed `Digest.DIGEST_SIZE`
6812
+ * bytes; otherwise the parser surfaces `InvalidHexString`.
6813
+ *
6814
+ * @module envelope-pattern/parse/structure/digest-parser
6815
+ */
6816
+ const DIGEST_SIZE = _bcts_envelope.Digest.DIGEST_SIZE;
6817
+ function parseDigest(lexer) {
6818
+ const open = lexer.next();
6819
+ if (open === void 0) return err(unexpectedEndOfInput());
6820
+ if (open.token.type !== "ParenOpen") return err(unexpectedToken(open.token, open.span));
6821
+ const innerResult = parseDigestInner(lexer.remainder(), lexer.position);
6822
+ if (!innerResult.ok) return innerResult;
6823
+ const [pattern, consumed] = innerResult.value;
6824
+ lexer.bump(consumed);
6825
+ const close = lexer.next();
6826
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
6827
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
6828
+ return ok(pattern);
6829
+ }
6830
+ function parseDigestInner(src, basePos) {
6831
+ let pos = 0;
6832
+ pos = skipWs(src, pos);
6833
+ if (src.startsWith("ur:", pos)) {
6834
+ const start = pos;
6835
+ while (pos < src.length && src[pos] !== ")") pos += 1;
6836
+ const ur = src.slice(start, pos).trimEnd();
6837
+ let parsed;
6838
+ try {
6839
+ parsed = _bcts_envelope.Digest.fromURString(ur);
6840
+ } catch {
6841
+ return err(invalidUr(ur, {
6842
+ start: basePos + start,
6843
+ end: basePos + pos
6844
+ }));
6845
+ }
6846
+ pos = skipWs(src, pos);
6847
+ return ok([digest(parsed), pos]);
6848
+ }
6849
+ const start = pos;
6850
+ while (pos < src.length && isAsciiHexDigit(src.charCodeAt(pos))) pos += 1;
6851
+ if (pos === start) return err(invalidHexString({
6852
+ start: basePos + pos,
6853
+ end: basePos + pos
6854
+ }));
6855
+ const hexStr = src.slice(start, pos);
6856
+ if (hexStr.length % 2 !== 0) return err(invalidHexString({
6857
+ start: basePos + pos,
6858
+ end: basePos + pos
6859
+ }));
6860
+ const bytes = decodeHex(hexStr);
6861
+ if (bytes === void 0) return err(invalidHexString({
6862
+ start: basePos + pos,
6863
+ end: basePos + pos
6864
+ }));
6865
+ if (bytes.length > DIGEST_SIZE) return err(invalidHexString({
6866
+ start: basePos + pos,
6867
+ end: basePos + pos
6868
+ }));
6869
+ pos = skipWs(src, pos);
6870
+ return ok([digestPrefix(bytes), pos]);
6871
+ }
6872
+ function skipWs(src, pos) {
6873
+ while (pos < src.length) {
6874
+ const ch = src[pos];
6875
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f") pos += 1;
6876
+ else break;
6449
6877
  }
6450
- return parseGroup(lexer);
6878
+ return pos;
6879
+ }
6880
+ function isAsciiHexDigit(c) {
6881
+ return c >= 48 && c <= 57 || c >= 65 && c <= 70 || c >= 97 && c <= 102;
6882
+ }
6883
+ function decodeHex(hex) {
6884
+ if (hex.length % 2 !== 0) return void 0;
6885
+ const out = new Uint8Array(hex.length / 2);
6886
+ for (let i = 0; i < hex.length; i += 2) {
6887
+ const value = Number.parseInt(hex.slice(i, i + 2), 16);
6888
+ if (Number.isNaN(value)) return void 0;
6889
+ out[i / 2] = value;
6890
+ }
6891
+ return out;
6892
+ }
6893
+ //#endregion
6894
+ //#region src/parse/structure/elided-parser.ts
6895
+ /**
6896
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6897
+ * Copyright © 2025-2026 Parity Technologies
6898
+ *
6899
+ * Elided parser — port of `bc-envelope-pattern-rust`
6900
+ * `parse/structure/elided_parser.rs`.
6901
+ *
6902
+ * @module envelope-pattern/parse/structure/elided-parser
6903
+ */
6904
+ function parseElided(_lexer) {
6905
+ return ok(elided());
6906
+ }
6907
+ //#endregion
6908
+ //#region src/parse/structure/encrypted-parser.ts
6909
+ /**
6910
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6911
+ * Copyright © 2025-2026 Parity Technologies
6912
+ *
6913
+ * Encrypted parser — port of `bc-envelope-pattern-rust`
6914
+ * `parse/structure/encrypted_parser.rs`.
6915
+ *
6916
+ * @module envelope-pattern/parse/structure/encrypted-parser
6917
+ */
6918
+ function parseEncrypted(_lexer) {
6919
+ return ok(encrypted());
6920
+ }
6921
+ //#endregion
6922
+ //#region src/parse/structure/node-parser.ts
6923
+ /**
6924
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6925
+ * Copyright © 2025-2026 Parity Technologies
6926
+ *
6927
+ * Node parser — port of `bc-envelope-pattern-rust`
6928
+ * `parse/structure/node_parser.rs`.
6929
+ *
6930
+ * Mirrors Rust:
6931
+ * - Bare `node` → `any_node()`.
6932
+ * - `node({n})` / `node({n,m})` / `node({n,})` → `node_with_assertions_range`.
6933
+ * - Anything else inside the parens (e.g. `node(text)`) is a syntax error
6934
+ * in Rust; the previous TS port silently produced an always-matching
6935
+ * `WithSubject` node, which we have removed.
6936
+ *
6937
+ * @module envelope-pattern/parse/structure/node-parser
6938
+ */
6939
+ function parseNode(lexer) {
6940
+ if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyNode());
6941
+ lexer.next();
6942
+ const inner = lexer.next();
6943
+ if (inner === void 0) return err(unexpectedEndOfInput());
6944
+ if (inner.token.type !== "Range") return err(unexpectedToken(inner.token, inner.span));
6945
+ if (!inner.token.value.ok) return err(inner.token.value.error);
6946
+ const interval = inner.token.value.value.interval();
6947
+ const close = lexer.next();
6948
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
6949
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
6950
+ return ok(patternStructure(structureNode(NodePattern.fromInterval(interval))));
6951
+ }
6952
+ //#endregion
6953
+ //#region src/parse/structure/object-parser.ts
6954
+ /**
6955
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6956
+ * Copyright © 2025-2026 Parity Technologies
6957
+ *
6958
+ * Object parser — port of `bc-envelope-pattern-rust`
6959
+ * `parse/structure/object_parser.rs`.
6960
+ *
6961
+ * @module envelope-pattern/parse/structure/object-parser
6962
+ */
6963
+ function parseObject(lexer) {
6964
+ if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyObject());
6965
+ lexer.next();
6966
+ const inner = parseOr(lexer);
6967
+ if (!inner.ok) return inner;
6968
+ const close = lexer.next();
6969
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
6970
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
6971
+ return ok(object(inner.value));
6972
+ }
6973
+ //#endregion
6974
+ //#region src/parse/structure/obscured-parser.ts
6975
+ /**
6976
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6977
+ * Copyright © 2025-2026 Parity Technologies
6978
+ *
6979
+ * Obscured parser — port of `bc-envelope-pattern-rust`
6980
+ * `parse/structure/obscured_parser.rs`.
6981
+ *
6982
+ * @module envelope-pattern/parse/structure/obscured-parser
6983
+ */
6984
+ function parseObscured(_lexer) {
6985
+ return ok(obscured());
6986
+ }
6987
+ //#endregion
6988
+ //#region src/parse/structure/predicate-parser.ts
6989
+ /**
6990
+ * Copyright © 2023-2026 Blockchain Commons, LLC
6991
+ * Copyright © 2025-2026 Parity Technologies
6992
+ *
6993
+ * Predicate parser — port of `bc-envelope-pattern-rust`
6994
+ * `parse/structure/predicate_parser.rs`.
6995
+ *
6996
+ * @module envelope-pattern/parse/structure/predicate-parser
6997
+ */
6998
+ function parsePredicate(lexer) {
6999
+ if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyPredicate());
7000
+ lexer.next();
7001
+ const inner = parseOr(lexer);
7002
+ if (!inner.ok) return inner;
7003
+ const close = lexer.next();
7004
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
7005
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
7006
+ return ok(predicate(inner.value));
7007
+ }
7008
+ //#endregion
7009
+ //#region src/parse/structure/subject-parser.ts
7010
+ /**
7011
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7012
+ * Copyright © 2025-2026 Parity Technologies
7013
+ *
7014
+ * Subject parser — port of `bc-envelope-pattern-rust`
7015
+ * `parse/structure/subject_parser.rs`.
7016
+ *
7017
+ * @module envelope-pattern/parse/structure/subject-parser
7018
+ */
7019
+ function parseSubject(lexer) {
7020
+ if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anySubject());
7021
+ lexer.next();
7022
+ const inner = parseOr(lexer);
7023
+ if (!inner.ok) return inner;
7024
+ const close = lexer.next();
7025
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
7026
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
7027
+ return ok(subject(inner.value));
7028
+ }
7029
+ //#endregion
7030
+ //#region src/parse/structure/wrapped-parser.ts
7031
+ /**
7032
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7033
+ * Copyright © 2025-2026 Parity Technologies
7034
+ *
7035
+ * Wrapped/unwrap parser — port of `bc-envelope-pattern-rust`
7036
+ * `parse/structure/wrapped_parser.rs`.
7037
+ *
7038
+ * @module envelope-pattern/parse/structure/wrapped-parser
7039
+ */
7040
+ function parseWrapped(_lexer) {
7041
+ return ok(wrapped());
6451
7042
  }
7043
+ function parseUnwrap(lexer) {
7044
+ if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(unwrapEnvelope());
7045
+ lexer.next();
7046
+ const inner = parseOr(lexer);
7047
+ if (!inner.ok) return inner;
7048
+ const close = lexer.next();
7049
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
7050
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
7051
+ return ok(unwrapMatching(inner.value));
7052
+ }
7053
+ //#endregion
7054
+ //#region src/parse/meta/capture-parser.ts
6452
7055
  /**
6453
- * Parse a Group expression: primary quantifier?
7056
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7057
+ * Copyright © 2025-2026 Parity Technologies
7058
+ *
7059
+ * Capture parser — port of `bc-envelope-pattern-rust`
7060
+ * `parse/meta/capture_parser.rs`.
7061
+ *
7062
+ * The `@name(...)` form requires explicit parentheses. Mirrors Rust
7063
+ * exactly:
7064
+ * ```ignore
7065
+ * @name ( expr )
7066
+ * ```
7067
+ * The previous TS port called `parse_group` (primary + quantifier), which
7068
+ * wrapped the inner expression in a redundant `GroupPattern` and accepted
7069
+ * the bare `@name p` form that Rust rejects.
7070
+ *
7071
+ * @module envelope-pattern/parse/meta/capture-parser
7072
+ */
7073
+ function parseCapture(lexer, name) {
7074
+ const open = lexer.next();
7075
+ if (open === void 0) return err(unexpectedEndOfInput());
7076
+ if (open.token.type !== "ParenOpen") return err(unexpectedToken(open.token, open.span));
7077
+ const inner = parseOr(lexer);
7078
+ if (!inner.ok) return inner;
7079
+ const close = lexer.next();
7080
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
7081
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
7082
+ return ok(capture(name, inner.value));
7083
+ }
7084
+ //#endregion
7085
+ //#region src/parse/meta/group-parser.ts
7086
+ /**
7087
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7088
+ * Copyright © 2025-2026 Parity Technologies
7089
+ *
7090
+ * Group parser — port of `bc-envelope-pattern-rust`
7091
+ * `parse/meta/group_parser.rs`.
7092
+ *
7093
+ * Called from `parse_primary` after the opening `(` has been consumed.
7094
+ *
7095
+ * Mirrors Rust exactly:
7096
+ *
7097
+ * - Parse the inner expression with `parse_or`.
7098
+ * - Expect `)`. If missing, surface `ExpectedCloseParen`.
7099
+ * - Lookahead **once** for a quantifier suffix. If present, consume it
7100
+ * and wrap as `Pattern::repeat(inner, …)`. Otherwise return the inner
7101
+ * expression unchanged.
7102
+ *
7103
+ * The previous TS port wrapped every parenthesised expression in a
7104
+ * dedicated `GroupPattern` and applied quantifiers to bare primaries —
7105
+ * both broke `format(parse(s)) === s` round-tripping.
7106
+ *
7107
+ * @module envelope-pattern/parse/meta/group-parser
6454
7108
  */
6455
7109
  function parseGroup(lexer) {
6456
- const primary = parsePrimary(lexer);
6457
- if (!primary.ok) return primary;
7110
+ const inner = parseOr(lexer);
7111
+ if (!inner.ok) return inner;
7112
+ const close = lexer.next();
7113
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
7114
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
6458
7115
  const next = lexer.peekToken();
6459
- if (next === void 0) return primary;
6460
- const tokenType = next.token.type;
7116
+ if (next === void 0) return inner;
6461
7117
  let quantifier;
6462
- if (tokenType === "RepeatZeroOrMore") {
6463
- lexer.next();
6464
- quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrMore(_bcts_dcbor_pattern.Reluctance.Greedy);
6465
- } else if (tokenType === "RepeatZeroOrMoreLazy") {
6466
- lexer.next();
6467
- quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrMore(_bcts_dcbor_pattern.Reluctance.Lazy);
6468
- } else if (tokenType === "RepeatZeroOrMorePossessive") {
6469
- lexer.next();
6470
- quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrMore(_bcts_dcbor_pattern.Reluctance.Possessive);
6471
- } else if (tokenType === "RepeatOneOrMore") {
6472
- lexer.next();
6473
- quantifier = _bcts_dcbor_pattern.Quantifier.oneOrMore(_bcts_dcbor_pattern.Reluctance.Greedy);
6474
- } else if (tokenType === "RepeatOneOrMoreLazy") {
6475
- lexer.next();
6476
- quantifier = _bcts_dcbor_pattern.Quantifier.oneOrMore(_bcts_dcbor_pattern.Reluctance.Lazy);
6477
- } else if (tokenType === "RepeatOneOrMorePossessive") {
6478
- lexer.next();
6479
- quantifier = _bcts_dcbor_pattern.Quantifier.oneOrMore(_bcts_dcbor_pattern.Reluctance.Possessive);
6480
- } else if (tokenType === "RepeatZeroOrOne") {
6481
- lexer.next();
6482
- quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrOne(_bcts_dcbor_pattern.Reluctance.Greedy);
6483
- } else if (tokenType === "RepeatZeroOrOneLazy") {
6484
- lexer.next();
6485
- quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrOne(_bcts_dcbor_pattern.Reluctance.Lazy);
6486
- } else if (tokenType === "RepeatZeroOrOnePossessive") {
6487
- lexer.next();
6488
- quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrOne(_bcts_dcbor_pattern.Reluctance.Possessive);
6489
- } else if (tokenType === "Range") {
6490
- lexer.next();
7118
+ const tokenType = next.token.type;
7119
+ if (tokenType === "RepeatZeroOrMore") quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrMore(_bcts_dcbor_pattern.Reluctance.Greedy);
7120
+ else if (tokenType === "RepeatZeroOrMoreLazy") quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrMore(_bcts_dcbor_pattern.Reluctance.Lazy);
7121
+ else if (tokenType === "RepeatZeroOrMorePossessive") quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrMore(_bcts_dcbor_pattern.Reluctance.Possessive);
7122
+ else if (tokenType === "RepeatOneOrMore") quantifier = _bcts_dcbor_pattern.Quantifier.oneOrMore(_bcts_dcbor_pattern.Reluctance.Greedy);
7123
+ else if (tokenType === "RepeatOneOrMoreLazy") quantifier = _bcts_dcbor_pattern.Quantifier.oneOrMore(_bcts_dcbor_pattern.Reluctance.Lazy);
7124
+ else if (tokenType === "RepeatOneOrMorePossessive") quantifier = _bcts_dcbor_pattern.Quantifier.oneOrMore(_bcts_dcbor_pattern.Reluctance.Possessive);
7125
+ else if (tokenType === "RepeatZeroOrOne") quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrOne(_bcts_dcbor_pattern.Reluctance.Greedy);
7126
+ else if (tokenType === "RepeatZeroOrOneLazy") quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrOne(_bcts_dcbor_pattern.Reluctance.Lazy);
7127
+ else if (tokenType === "RepeatZeroOrOnePossessive") quantifier = _bcts_dcbor_pattern.Quantifier.zeroOrOne(_bcts_dcbor_pattern.Reluctance.Possessive);
7128
+ else if (tokenType === "Range") {
6491
7129
  if (!next.token.value.ok) return err(next.token.value.error);
6492
7130
  quantifier = next.token.value.value;
6493
- } else return primary;
6494
- return ok(repeat(primary.value, quantifier.min(), quantifier.max(), quantifier.reluctance()));
7131
+ } else return inner;
7132
+ lexer.next();
7133
+ return ok(repeat(inner.value, quantifier.min(), quantifier.max(), quantifier.reluctance()));
6495
7134
  }
7135
+ //#endregion
7136
+ //#region src/parse/meta/search-parser.ts
6496
7137
  /**
6497
- * Parse a primary expression (atoms and structure keywords).
7138
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7139
+ * Copyright © 2025-2026 Parity Technologies
7140
+ *
7141
+ * Search parser — port of `bc-envelope-pattern-rust`
7142
+ * `parse/meta/search_parser.rs`.
7143
+ *
7144
+ * @module envelope-pattern/parse/meta/search-parser
7145
+ */
7146
+ function parseSearch(lexer) {
7147
+ const open = lexer.next();
7148
+ if (open === void 0) return err(unexpectedEndOfInput());
7149
+ if (open.token.type !== "ParenOpen") return err(unexpectedToken(open.token, open.span));
7150
+ const inner = parseOr(lexer);
7151
+ if (!inner.ok) return inner;
7152
+ const close = lexer.next();
7153
+ if (close === void 0) return err(expectedCloseParen(lexer.span()));
7154
+ if (close.token.type !== "ParenClose") return err(unexpectedToken(close.token, close.span));
7155
+ return ok(search(inner.value));
7156
+ }
7157
+ //#endregion
7158
+ //#region src/parse/meta/primary-parser.ts
7159
+ /**
7160
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7161
+ * Copyright © 2025-2026 Parity Technologies
7162
+ *
7163
+ * Primary parser — port of `bc-envelope-pattern-rust`
7164
+ * `parse/meta/primary_parser.rs`.
7165
+ *
7166
+ * Dispatches on the next token to the appropriate leaf/structure/meta
7167
+ * parser. When a `(` is encountered the open paren is consumed here and
7168
+ * `parse_group` handles the rest (paren'd expression + optional
7169
+ * quantifier suffix).
7170
+ *
7171
+ * @module envelope-pattern/parse/meta/primary-parser
6498
7172
  */
6499
7173
  function parsePrimary(lexer) {
6500
7174
  const tokenResult = lexer.next();
@@ -6508,17 +7182,17 @@ function parsePrimary(lexer) {
6508
7182
  case "AssertionObj": return parseAssertionObj(lexer);
6509
7183
  case "Digest": return parseDigest(lexer);
6510
7184
  case "Obj": return parseObject(lexer);
6511
- case "Obscured": return ok(obscured());
6512
- case "Elided": return ok(elided());
6513
- case "Encrypted": return ok(encrypted());
6514
- case "Compressed": return ok(compressed());
7185
+ case "Obscured": return parseObscured(lexer);
7186
+ case "Elided": return parseElided(lexer);
7187
+ case "Encrypted": return parseEncrypted(lexer);
7188
+ case "Compressed": return parseCompressed(lexer);
6515
7189
  case "Pred": return parsePredicate(lexer);
6516
7190
  case "Subject": return parseSubject(lexer);
6517
- case "Wrapped": return ok(wrapped());
7191
+ case "Wrapped": return parseWrapped(lexer);
6518
7192
  case "Unwrap": return parseUnwrap(lexer);
6519
7193
  case "Leaf": return ok(leaf());
6520
7194
  case "GroupName": return parseCapture(lexer, token.name);
6521
- case "ParenOpen": return parseParenGroup(lexer);
7195
+ case "ParenOpen": return parseGroup(lexer);
6522
7196
  case "Cbor": return parseCbor(lexer);
6523
7197
  case "RepeatZeroOrMore": return ok(any());
6524
7198
  case "BoolKeyword": return ok(anyBool());
@@ -6581,6 +7255,7 @@ function parsePrimary(lexer) {
6581
7255
  return err(invalidRegex(span));
6582
7256
  }
6583
7257
  case "Null": return ok(nullPattern());
7258
+ case "Identifier": return err(unrecognizedToken(span));
6584
7259
  case "And":
6585
7260
  case "Or":
6586
7261
  case "Not":
@@ -6591,394 +7266,180 @@ function parsePrimary(lexer) {
6591
7266
  case "RepeatOneOrMoreLazy":
6592
7267
  case "RepeatOneOrMorePossessive":
6593
7268
  case "RepeatZeroOrOne":
6594
- case "RepeatZeroOrOneLazy":
6595
- case "RepeatZeroOrOnePossessive":
6596
- case "ParenClose":
6597
- case "BracketClose":
6598
- case "Comma":
6599
- case "Ellipsis":
6600
- case "Range":
6601
- case "Identifier": return err(unexpectedToken(token, span));
6602
- }
6603
- }
6604
- /**
6605
- * Parse a parenthesized group expression.
6606
- */
6607
- function parseParenGroup(lexer) {
6608
- const inner = parseOr(lexer);
6609
- if (!inner.ok) return inner;
6610
- if (lexer.next()?.token.type !== "ParenClose") return err({
6611
- type: "ExpectedCloseParen",
6612
- span: lexer.span()
6613
- });
6614
- return ok(group(inner.value));
6615
- }
6616
- /**
6617
- * Parse a capture group: @name pattern
6618
- */
6619
- function parseCapture(lexer, name) {
6620
- const inner = parseGroup(lexer);
6621
- if (!inner.ok) return inner;
6622
- return ok(capture(name, inner.value));
6623
- }
6624
- /**
6625
- * Parse a search pattern: search(pattern)
6626
- */
6627
- function parseSearch(lexer) {
6628
- if (lexer.next()?.token.type !== "ParenOpen") return err({
6629
- type: "ExpectedOpenParen",
6630
- span: lexer.span()
6631
- });
6632
- const inner = parseOr(lexer);
6633
- if (!inner.ok) return inner;
6634
- if (lexer.next()?.token.type !== "ParenClose") return err({
6635
- type: "ExpectedCloseParen",
6636
- span: lexer.span()
6637
- });
6638
- return ok(search(inner.value));
7269
+ case "RepeatZeroOrOneLazy":
7270
+ case "RepeatZeroOrOnePossessive":
7271
+ case "ParenClose":
7272
+ case "BracketClose":
7273
+ case "Comma":
7274
+ case "Ellipsis":
7275
+ case "Range": return err(unexpectedToken(token, span));
7276
+ }
6639
7277
  }
7278
+ //#endregion
7279
+ //#region src/parse/meta/and-parser.ts
6640
7280
  /**
6641
- * Parse number with possible range or comparison.
7281
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7282
+ * Copyright © 2025-2026 Parity Technologies
7283
+ *
7284
+ * And parser — port of `bc-envelope-pattern-rust`
7285
+ * `parse/meta/and_parser.rs`.
7286
+ *
7287
+ * Mirrors Rust: `parse_and` calls `parse_primary` (NOT `parse_not`); `!`
7288
+ * is handled at a higher precedence level by `parse_not`.
7289
+ *
7290
+ * @module envelope-pattern/parse/meta/and-parser
6642
7291
  */
6643
- function parseNumberRangeOrComparison(lexer, firstValue) {
6644
- const next = lexer.peekToken();
6645
- if (next === void 0) return ok(number(firstValue));
6646
- if (next.token.type === "Ellipsis") {
7292
+ function parseAnd(lexer) {
7293
+ const patterns = [];
7294
+ const first = parsePrimary(lexer);
7295
+ if (!first.ok) return first;
7296
+ patterns.push(first.value);
7297
+ while (true) {
7298
+ if (lexer.peekToken()?.token.type !== "And") break;
6647
7299
  lexer.next();
6648
- const endToken = lexer.next();
6649
- if (endToken === void 0) return err(unexpectedEndOfInput());
6650
- let endValue;
6651
- if (endToken.token.type === "UnsignedInteger" || endToken.token.type === "Integer") {
6652
- if (!endToken.token.value.ok) return err(endToken.token.value.error);
6653
- endValue = endToken.token.value.value;
6654
- } else if (endToken.token.type === "Float") {
6655
- if (!endToken.token.value.ok) return err(endToken.token.value.error);
6656
- endValue = endToken.token.value.value;
6657
- } else return err(unexpectedToken(endToken.token, endToken.span));
6658
- return ok(numberRange(firstValue, endValue));
7300
+ const nextExpr = parsePrimary(lexer);
7301
+ if (!nextExpr.ok) return nextExpr;
7302
+ patterns.push(nextExpr.value);
6659
7303
  }
6660
- return ok(number(firstValue));
7304
+ if (patterns.length === 1) return ok(patterns[0]);
7305
+ return ok(and(patterns));
6661
7306
  }
7307
+ //#endregion
7308
+ //#region src/parse/meta/not-parser.ts
6662
7309
  /**
6663
- * Parse comparison number: >=n, <=n, >n, <n
7310
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7311
+ * Copyright © 2025-2026 Parity Technologies
7312
+ *
7313
+ * Not parser — port of `bc-envelope-pattern-rust`
7314
+ * `parse/meta/not_parser.rs`.
7315
+ *
7316
+ * Mirrors Rust:
7317
+ * - On `!`, recurse into `parse_not` so chained negation parses as
7318
+ * `not(not(x))` rather than `not(group(x))`.
7319
+ * - Otherwise descend into `parse_and`.
7320
+ *
7321
+ * @module envelope-pattern/parse/meta/not-parser
6664
7322
  */
6665
- function parseComparisonNumber(lexer, op) {
6666
- const numToken = lexer.next();
6667
- if (numToken === void 0) return err(unexpectedEndOfInput());
6668
- let value;
6669
- if (numToken.token.type === "UnsignedInteger" || numToken.token.type === "Integer") {
6670
- if (!numToken.token.value.ok) return err(numToken.token.value.error);
6671
- value = numToken.token.value.value;
6672
- } else if (numToken.token.type === "Float") {
6673
- if (!numToken.token.value.ok) return err(numToken.token.value.error);
6674
- value = numToken.token.value.value;
6675
- } else return err(unexpectedToken(numToken.token, numToken.span));
6676
- switch (op) {
6677
- case ">=": return ok(patternLeaf(leafNumber(NumberPattern.greaterThanOrEqual(value))));
6678
- case "<=": return ok(patternLeaf(leafNumber(NumberPattern.lessThanOrEqual(value))));
6679
- case ">": return ok(numberGreaterThan(value));
6680
- case "<": return ok(numberLessThan(value));
6681
- default: return ok(number(value));
7323
+ function parseNot(lexer) {
7324
+ if (lexer.peekToken()?.token.type === "Not") {
7325
+ lexer.next();
7326
+ const inner = parseNot(lexer);
7327
+ if (!inner.ok) return inner;
7328
+ return ok(notMatching(inner.value));
6682
7329
  }
7330
+ return parseAnd(lexer);
6683
7331
  }
7332
+ //#endregion
7333
+ //#region src/parse/meta/traverse-parser.ts
6684
7334
  /**
6685
- * Parse an array pattern.
7335
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7336
+ * Copyright © 2025-2026 Parity Technologies
7337
+ *
7338
+ * Traverse parser — port of `bc-envelope-pattern-rust`
7339
+ * `parse/meta/traverse_parser.rs`.
7340
+ *
7341
+ * Note the precedence chain: `parse_or → parse_traverse → parse_not →
7342
+ * parse_and → parse_primary`. The earlier TS port had `parse_traverse`
7343
+ * call `parse_and` directly, which pushed `!` below `&` and
7344
+ * miscompiled `!a & b`.
7345
+ *
7346
+ * @module envelope-pattern/parse/meta/traverse-parser
6686
7347
  */
6687
- function parseArray(lexer) {
6688
- const first = lexer.peekToken();
6689
- if (first === void 0) return err(unexpectedEndOfInput());
6690
- if (first.token.type === "BracketClose") {
6691
- lexer.next();
6692
- return ok(patternLeaf(leafArray(ArrayPattern.count(0))));
6693
- }
6694
- if (first.token.type === "RepeatZeroOrMore") {
6695
- lexer.next();
6696
- if (lexer.next()?.token.type !== "BracketClose") return err({
6697
- type: "ExpectedCloseBracket",
6698
- span: lexer.span()
6699
- });
6700
- return ok(anyArray());
6701
- }
7348
+ function parseTraverse(lexer) {
6702
7349
  const patterns = [];
7350
+ const first = parseNot(lexer);
7351
+ if (!first.ok) return first;
7352
+ patterns.push(first.value);
6703
7353
  while (true) {
6704
- const next = lexer.peekToken();
6705
- if (next === void 0) return err(unexpectedEndOfInput());
6706
- if (next.token.type === "BracketClose") {
6707
- lexer.next();
6708
- break;
6709
- }
6710
- const pattern = parseOr(lexer);
6711
- if (!pattern.ok) return pattern;
6712
- patterns.push(pattern.value);
6713
- const afterPattern = lexer.peekToken();
6714
- if (afterPattern === void 0) return err(unexpectedEndOfInput());
6715
- if (afterPattern.token.type === "Comma") lexer.next();
6716
- else if (afterPattern.token.type !== "BracketClose") return err(unexpectedToken(afterPattern.token, afterPattern.span));
7354
+ if (lexer.peekToken()?.token.type !== "Traverse") break;
7355
+ lexer.next();
7356
+ const nextExpr = parseNot(lexer);
7357
+ if (!nextExpr.ok) return nextExpr;
7358
+ patterns.push(nextExpr.value);
6717
7359
  }
6718
- if (patterns.length === 0) return ok(patternLeaf(leafArray(ArrayPattern.count(0))));
6719
- return ok(patternLeaf(leafArray(ArrayPattern.withPatterns(patterns))));
6720
- }
6721
- /**
6722
- * Parse a tag pattern.
6723
- */
6724
- function parseTag(lexer) {
6725
- if (lexer.next()?.token.type !== "ParenOpen") return ok(anyTag());
6726
- const tagToken = lexer.next();
6727
- if (tagToken === void 0) return err(unexpectedEndOfInput());
6728
- if (tagToken.token.type !== "UnsignedInteger") return err(unexpectedToken(tagToken.token, tagToken.span));
6729
- if (!tagToken.token.value.ok) return err(tagToken.token.value.error);
6730
- if (lexer.next()?.token.type !== "ParenClose") return err({
6731
- type: "ExpectedCloseParen",
6732
- span: lexer.span()
6733
- });
6734
- return ok(anyTag());
7360
+ if (patterns.length === 1) return ok(patterns[0]);
7361
+ return ok(traverse(patterns));
6735
7362
  }
7363
+ //#endregion
7364
+ //#region src/parse/meta/or-parser.ts
6736
7365
  /**
6737
- * Parse date content from date'...' pattern.
7366
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7367
+ * Copyright © 2025-2026 Parity Technologies
7368
+ *
7369
+ * Or parser — port of `bc-envelope-pattern-rust` `parse/meta/or_parser.rs`.
7370
+ *
7371
+ * @module envelope-pattern/parse/meta/or-parser
6738
7372
  */
6739
- function parseDateContent(content, span) {
6740
- if (content.startsWith("/") && content.endsWith("/")) {
6741
- const regexStr = content.slice(1, -1);
6742
- try {
6743
- return ok(dateRegex(new RegExp(regexStr)));
6744
- } catch {
6745
- return err(invalidRegex(span));
6746
- }
6747
- }
6748
- const rangeIdx = content.indexOf("...");
6749
- if (rangeIdx !== -1) {
6750
- const left = content.slice(0, rangeIdx).trim();
6751
- const right = content.slice(rangeIdx + 3).trim();
6752
- if (left.length === 0 && right.length > 0) {
6753
- const parsed = Date.parse(right);
6754
- if (isNaN(parsed)) return err({
6755
- type: "InvalidDateFormat",
6756
- span
6757
- });
6758
- return ok(dateLatest(_bcts_dcbor.CborDate.fromDatetime(new Date(parsed))));
6759
- }
6760
- if (left.length > 0 && right.length === 0) {
6761
- const parsed = Date.parse(left);
6762
- if (isNaN(parsed)) return err({
6763
- type: "InvalidDateFormat",
6764
- span
6765
- });
6766
- return ok(dateEarliest(_bcts_dcbor.CborDate.fromDatetime(new Date(parsed))));
6767
- }
6768
- if (left.length > 0 && right.length > 0) {
6769
- const parsedStart = Date.parse(left);
6770
- const parsedEnd = Date.parse(right);
6771
- if (isNaN(parsedStart) || isNaN(parsedEnd)) return err({
6772
- type: "InvalidDateFormat",
6773
- span
6774
- });
6775
- return ok(dateRange(_bcts_dcbor.CborDate.fromDatetime(new Date(parsedStart)), _bcts_dcbor.CborDate.fromDatetime(new Date(parsedEnd))));
6776
- }
6777
- return err({
6778
- type: "InvalidDateFormat",
6779
- span
6780
- });
7373
+ function parseOr(lexer) {
7374
+ const patterns = [];
7375
+ const first = parseTraverse(lexer);
7376
+ if (!first.ok) return first;
7377
+ patterns.push(first.value);
7378
+ while (true) {
7379
+ if (lexer.peekToken()?.token.type !== "Or") break;
7380
+ lexer.next();
7381
+ const nextExpr = parseTraverse(lexer);
7382
+ if (!nextExpr.ok) return nextExpr;
7383
+ patterns.push(nextExpr.value);
6781
7384
  }
6782
- const parsed = Date.parse(content);
6783
- if (isNaN(parsed)) return err({
6784
- type: "InvalidDateFormat",
6785
- span
6786
- });
6787
- return ok(date(_bcts_dcbor.CborDate.fromDatetime(new Date(parsed))));
7385
+ if (patterns.length === 1) return ok(patterns[0]);
7386
+ return ok(or(patterns));
6788
7387
  }
7388
+ //#endregion
7389
+ //#region src/parse/index.ts
6789
7390
  /**
6790
- * Parse known value content from '...' pattern.
7391
+ * Copyright © 2023-2026 Blockchain Commons, LLC
7392
+ * Copyright © 2025-2026 Parity Technologies
7393
+ *
7394
+ *
7395
+ * @bcts/envelope-pattern - Parser entry point
7396
+ *
7397
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust parse/mod.rs.
7398
+ *
7399
+ * Recursive-descent parser for the Gordian Envelope pattern syntax. The
7400
+ * parsing rules live under `parse/leaf/`, `parse/meta/`, and
7401
+ * `parse/structure/`, mirroring the Rust crate's module layout.
7402
+ *
7403
+ * @module envelope-pattern/parse
6791
7404
  */
6792
- function parseKnownValueContent(content) {
6793
- const numValue = parseInt(content, 10);
6794
- if (!isNaN(numValue)) return ok(knownValue({ value: () => BigInt(numValue) }));
6795
- return ok(patternLeaf(leafKnownValue(KnownValuePattern.named(content))));
6796
- }
6797
7405
  /**
6798
- * Parse CBOR pattern.
7406
+ * Parse a pattern expression string into a Pattern.
6799
7407
  *
6800
- * Matches Rust parse_cbor: tries dcbor-pattern regex first (/keyword/),
6801
- * then CBOR diagnostic notation via parseDcborItemPartial, then falls
6802
- * back to parseOr for envelope pattern expressions.
7408
+ * Mirrors Rust `Pattern::parse`: tries envelope-pattern parsing first;
7409
+ * on failure falls back to dcbor-pattern parsing and converts the
7410
+ * result into an envelope pattern via the
7411
+ * `dcbor_integration::convert_dcbor_pattern_to_envelope_pattern` bridge.
6803
7412
  */
6804
- function parseCbor(lexer) {
6805
- if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyCbor());
6806
- lexer.next();
6807
- if (lexer.peek() === "/") {
6808
- const regexTokenResult = lexer.next();
6809
- if (regexTokenResult?.token.type === "Regex") {
6810
- const regexToken = regexTokenResult.token;
6811
- if (!regexToken.value.ok) return err(regexToken.value.error);
6812
- const keyword = regexToken.value.value;
6813
- const dcborResult = (0, _bcts_dcbor_pattern.parse)(keyword);
6814
- if (!dcborResult.ok) return err(unexpectedToken(regexToken, regexTokenResult.span));
6815
- if (lexer.next()?.token.type !== "ParenClose") return err({
6816
- type: "ExpectedCloseParen",
6817
- span: lexer.span()
6818
- });
6819
- return ok(cborPattern(dcborResult.value));
6820
- }
6821
- }
6822
- const cborResult = (0, _bcts_dcbor_parse.parseDcborItemPartial)(lexer.remainder());
6823
- if (cborResult.ok) {
6824
- const [cborData, consumed] = cborResult.value;
6825
- lexer.bump(consumed);
6826
- while (lexer.peek() === " " || lexer.peek() === " " || lexer.peek() === "\n") lexer.bump(1);
6827
- if (lexer.next()?.token.type !== "ParenClose") return err({
6828
- type: "ExpectedCloseParen",
6829
- span: lexer.span()
6830
- });
6831
- return ok(cborValue(cborData));
6832
- }
6833
- const inner = parseOr(lexer);
6834
- if (!inner.ok) return inner;
6835
- if (lexer.next()?.token.type !== "ParenClose") return err({
6836
- type: "ExpectedCloseParen",
6837
- span: lexer.span()
6838
- });
6839
- return inner;
6840
- }
6841
- function parseNode(lexer) {
6842
- if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyNode());
6843
- lexer.next();
6844
- const afterParen = lexer.peekToken();
6845
- if (afterParen?.token.type === "Range") {
6846
- lexer.next();
6847
- const rangeToken = afterParen.token;
6848
- if (!rangeToken.value.ok) return err(rangeToken.value.error);
6849
- const interval = rangeToken.value.value.interval();
6850
- if (lexer.next()?.token.type !== "ParenClose") return err({
6851
- type: "ExpectedCloseParen",
6852
- span: lexer.span()
6853
- });
6854
- return ok(patternStructure(structureNode(NodePattern.fromInterval(interval))));
6855
- }
6856
- const inner = parseOr(lexer);
6857
- if (!inner.ok) return inner;
6858
- if (lexer.next()?.token.type !== "ParenClose") return err({
6859
- type: "ExpectedCloseParen",
6860
- span: lexer.span()
6861
- });
6862
- return ok(patternStructure(structureNode(NodePattern.withSubject(inner.value))));
6863
- }
6864
- function parseAssertion(lexer) {
6865
- if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyAssertion());
6866
- lexer.next();
6867
- const pred = parseOr(lexer);
6868
- if (!pred.ok) return pred;
6869
- const comma = lexer.next();
6870
- if (comma?.token.type !== "Comma") return err(unexpectedToken(comma?.token ?? { type: "Null" }, comma?.span ?? lexer.span()));
6871
- const obj = parseOr(lexer);
6872
- if (!obj.ok) return obj;
6873
- if (lexer.next()?.token.type !== "ParenClose") return err({
6874
- type: "ExpectedCloseParen",
6875
- span: lexer.span()
6876
- });
6877
- return ok(patternStructure(structureAssertions(AssertionsPattern.withBoth(pred.value, obj.value))));
6878
- }
6879
- function parseAssertionPred(lexer) {
6880
- if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyAssertion());
6881
- lexer.next();
6882
- const inner = parseOr(lexer);
6883
- if (!inner.ok) return inner;
6884
- if (lexer.next()?.token.type !== "ParenClose") return err({
6885
- type: "ExpectedCloseParen",
6886
- span: lexer.span()
6887
- });
6888
- return ok(assertionWithPredicate(inner.value));
6889
- }
6890
- function parseAssertionObj(lexer) {
6891
- if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyAssertion());
6892
- lexer.next();
6893
- const inner = parseOr(lexer);
6894
- if (!inner.ok) return inner;
6895
- if (lexer.next()?.token.type !== "ParenClose") return err({
6896
- type: "ExpectedCloseParen",
6897
- span: lexer.span()
6898
- });
6899
- return ok(assertionWithObject(inner.value));
6900
- }
6901
- function parseDigest(lexer) {
6902
- if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(patternStructure(structureDigest(DigestPattern.any())));
6903
- lexer.next();
6904
- const digestToken = lexer.next();
6905
- if (digestToken === void 0) return err(unexpectedEndOfInput());
6906
- if (digestToken.token.type === "HexPattern") {
6907
- if (!digestToken.token.value.ok) return err(digestToken.token.value.error);
6908
- if (lexer.next()?.token.type !== "ParenClose") return err({
6909
- type: "ExpectedCloseParen",
6910
- span: lexer.span()
6911
- });
6912
- return ok(digestPrefix(digestToken.token.value.value));
6913
- }
6914
- if (digestToken.token.type === "Identifier") {
6915
- const hexStr = digestToken.token.value;
6916
- if (hexStr.length === 0 || hexStr.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(hexStr)) return err({
6917
- type: "InvalidHexString",
6918
- span: digestToken.span
6919
- });
6920
- const bytes = new Uint8Array(hexStr.length / 2);
6921
- for (let i = 0; i < hexStr.length; i += 2) bytes[i / 2] = Number.parseInt(hexStr.slice(i, i + 2), 16);
6922
- if (lexer.next()?.token.type !== "ParenClose") return err({
6923
- type: "ExpectedCloseParen",
6924
- span: lexer.span()
6925
- });
6926
- return ok(digestPrefix(bytes));
7413
+ function parse(input) {
7414
+ const lexer = new Lexer(input);
7415
+ const result = parseOr(lexer);
7416
+ if (!result.ok) {
7417
+ const dcborResult = (0, _bcts_dcbor_pattern.parse)(input);
7418
+ if (dcborResult.ok) return convertDcborPatternToEnvelopePattern(dcborResult.value);
7419
+ return result;
6927
7420
  }
6928
- return err(unexpectedToken(digestToken.token, digestToken.span));
6929
- }
6930
- function parseObject(lexer) {
6931
- if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyObject());
6932
- lexer.next();
6933
- const inner = parseOr(lexer);
6934
- if (!inner.ok) return inner;
6935
- if (lexer.next()?.token.type !== "ParenClose") return err({
6936
- type: "ExpectedCloseParen",
6937
- span: lexer.span()
6938
- });
6939
- return ok(object(inner.value));
6940
- }
6941
- function parsePredicate(lexer) {
6942
- if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anyPredicate());
6943
- lexer.next();
6944
- const inner = parseOr(lexer);
6945
- if (!inner.ok) return inner;
6946
- if (lexer.next()?.token.type !== "ParenClose") return err({
6947
- type: "ExpectedCloseParen",
6948
- span: lexer.span()
6949
- });
6950
- return ok(predicate(inner.value));
6951
- }
6952
- function parseSubject(lexer) {
6953
- if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(anySubject());
6954
- lexer.next();
6955
- const inner = parseOr(lexer);
6956
- if (!inner.ok) return inner;
6957
- if (lexer.next()?.token.type !== "ParenClose") return err({
6958
- type: "ExpectedCloseParen",
6959
- span: lexer.span()
6960
- });
6961
- return ok(subject(inner.value));
7421
+ const next = lexer.next();
7422
+ if (next !== void 0) return err(extraData(next.span));
7423
+ return result;
6962
7424
  }
6963
- function parseUnwrap(lexer) {
6964
- if (lexer.peekToken()?.token.type !== "ParenOpen") return ok(unwrapEnvelope());
6965
- lexer.next();
6966
- const inner = parseOr(lexer);
6967
- if (!inner.ok) return inner;
6968
- if (lexer.next()?.token.type !== "ParenClose") return err({
6969
- type: "ExpectedCloseParen",
6970
- span: lexer.span()
6971
- });
6972
- return ok(unwrapMatching(inner.value));
7425
+ /**
7426
+ * Parse a pattern, allowing extra data after the pattern.
7427
+ *
7428
+ * Returns the parsed pattern and the byte offset at which parsing
7429
+ * stopped, mirroring `Pattern::parse_partial` in spirit.
7430
+ */
7431
+ function parsePartial(input) {
7432
+ const lexer = new Lexer(input);
7433
+ const result = parseOr(lexer);
7434
+ if (!result.ok) return result;
7435
+ return ok([result.value, lexer.position]);
6973
7436
  }
6974
-
6975
7437
  //#endregion
6976
7438
  //#region src/index.ts
6977
7439
  /**
6978
7440
  * Package version.
6979
7441
  */
6980
7442
  const VERSION = "1.0.0-alpha.11";
6981
-
6982
7443
  //#endregion
6983
7444
  exports.AndPattern = AndPattern;
6984
7445
  exports.AnyPattern = AnyPattern;
@@ -6992,11 +7453,11 @@ exports.DatePattern = DatePattern;
6992
7453
  exports.DigestPattern = DigestPattern;
6993
7454
  exports.FormatPathsOptsBuilder = FormatPathsOptsBuilder;
6994
7455
  exports.GroupPattern = GroupPattern;
6995
- Object.defineProperty(exports, 'Interval', {
6996
- enumerable: true,
6997
- get: function () {
6998
- return _bcts_dcbor_pattern.Interval;
6999
- }
7456
+ Object.defineProperty(exports, "Interval", {
7457
+ enumerable: true,
7458
+ get: function() {
7459
+ return _bcts_dcbor_pattern.Interval;
7460
+ }
7000
7461
  });
7001
7462
  exports.KnownValuePattern = KnownValuePattern;
7002
7463
  exports.LeafStructurePattern = LeafStructurePattern;
@@ -7011,17 +7472,17 @@ exports.ObjectPattern = ObjectPattern;
7011
7472
  exports.ObscuredPattern = ObscuredPattern;
7012
7473
  exports.OrPattern = OrPattern;
7013
7474
  exports.PredicatePattern = PredicatePattern;
7014
- Object.defineProperty(exports, 'Quantifier', {
7015
- enumerable: true,
7016
- get: function () {
7017
- return _bcts_dcbor_pattern.Quantifier;
7018
- }
7475
+ Object.defineProperty(exports, "Quantifier", {
7476
+ enumerable: true,
7477
+ get: function() {
7478
+ return _bcts_dcbor_pattern.Quantifier;
7479
+ }
7019
7480
  });
7020
- Object.defineProperty(exports, 'Reluctance', {
7021
- enumerable: true,
7022
- get: function () {
7023
- return _bcts_dcbor_pattern.Reluctance;
7024
- }
7481
+ Object.defineProperty(exports, "Reluctance", {
7482
+ enumerable: true,
7483
+ get: function() {
7484
+ return _bcts_dcbor_pattern.Reluctance;
7485
+ }
7025
7486
  });
7026
7487
  exports.SearchPattern = SearchPattern;
7027
7488
  exports.SubjectPattern = SubjectPattern;
@@ -7166,6 +7627,7 @@ exports.registerAndPatternFactory = registerAndPatternFactory;
7166
7627
  exports.registerAnyPatternFactory = registerAnyPatternFactory;
7167
7628
  exports.registerArrayPatternFactory = registerArrayPatternFactory;
7168
7629
  exports.registerAssertionsPatternFactory = registerAssertionsPatternFactory;
7630
+ exports.registerAssertionsPatternToStringDispatch = registerAssertionsPatternToStringDispatch;
7169
7631
  exports.registerBoolPatternFactory = registerBoolPatternFactory;
7170
7632
  exports.registerByteStringPatternFactory = registerByteStringPatternFactory;
7171
7633
  exports.registerCBORPatternFactory = registerCBORPatternFactory;
@@ -7187,11 +7649,13 @@ exports.registerPatternDispatchFns = registerPatternDispatchFns;
7187
7649
  exports.registerPatternMatchFn = registerPatternMatchFn;
7188
7650
  exports.registerPredicatePatternFactory = registerPredicatePatternFactory;
7189
7651
  exports.registerSearchPatternFactory = registerSearchPatternFactory;
7652
+ exports.registerSubjectPatternDispatch = registerSubjectPatternDispatch;
7190
7653
  exports.registerSubjectPatternFactory = registerSubjectPatternFactory;
7191
7654
  exports.registerTaggedPatternFactory = registerTaggedPatternFactory;
7192
7655
  exports.registerTextPatternFactory = registerTextPatternFactory;
7193
7656
  exports.registerTraversePatternFactory = registerTraversePatternFactory;
7194
7657
  exports.registerVMPatternFunctions = registerVMPatternFunctions;
7658
+ exports.registerWrappedPatternAny = registerWrappedPatternAny;
7195
7659
  exports.registerWrappedPatternDispatch = registerWrappedPatternDispatch;
7196
7660
  exports.registerWrappedPatternFactory = registerWrappedPatternFactory;
7197
7661
  exports.repeat = repeat;
@@ -7230,4 +7694,5 @@ exports.unwrapEnvelope = unwrapEnvelope;
7230
7694
  exports.unwrapMatching = unwrapMatching;
7231
7695
  exports.unwrapOr = unwrapOr;
7232
7696
  exports.wrapped = wrapped;
7697
+
7233
7698
  //# sourceMappingURL=index.cjs.map