@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
@@ -12,7 +12,7 @@
12
12
 
13
13
  import type { Envelope } from "@bcts/envelope";
14
14
  import type { Path } from "../../format";
15
- import { matchPattern, type Matcher } from "../matcher";
15
+ import { dispatchPatternToString, matchPattern, type Matcher } from "../matcher";
16
16
  import type { Instr } from "../vm";
17
17
  import type { Pattern } from "../index";
18
18
 
@@ -126,7 +126,7 @@ export class PredicatePattern implements Matcher {
126
126
  case "Any":
127
127
  return "pred";
128
128
  case "Pattern":
129
- return `pred(${(this._pattern.pattern as unknown as { toString(): string }).toString()})`;
129
+ return `pred(${dispatchPatternToString(this._pattern.pattern)})`;
130
130
  }
131
131
  }
132
132
 
@@ -19,10 +19,28 @@ import type { Pattern } from "../index";
19
19
  // Forward declaration for Pattern factory (used for late binding)
20
20
  export let createStructureSubjectPattern: ((pattern: SubjectPattern) => Pattern) | undefined;
21
21
 
22
+ // Forward declaration for top-level pattern compile/toString dispatch.
23
+ // Mirrors Rust `pat.compile(code, lits, caps)` on the top-level `Pattern`
24
+ // enum — the TS port can't call methods on the tagged-union value, so we
25
+ // register the compile dispatcher (which lives in `pattern/index.ts`)
26
+ // during module initialisation.
27
+ let dispatchPatternCompile:
28
+ | ((pattern: Pattern, code: Instr[], literals: Pattern[], captures: string[]) => void)
29
+ | undefined;
30
+ let dispatchPatternToString: ((pattern: Pattern) => string) | undefined;
31
+
22
32
  export function registerSubjectPatternFactory(factory: (pattern: SubjectPattern) => Pattern): void {
23
33
  createStructureSubjectPattern = factory;
24
34
  }
25
35
 
36
+ export function registerSubjectPatternDispatch(dispatch: {
37
+ compile: (pattern: Pattern, code: Instr[], literals: Pattern[], captures: string[]) => void;
38
+ toString: (pattern: Pattern) => string;
39
+ }): void {
40
+ dispatchPatternCompile = dispatch.compile;
41
+ dispatchPatternToString = dispatch.toString;
42
+ }
43
+
26
44
  /**
27
45
  * Pattern type for subject pattern matching.
28
46
  *
@@ -106,14 +124,20 @@ export class SubjectPattern implements Matcher {
106
124
  case "Any":
107
125
  code.push({ type: "NavigateSubject" });
108
126
  break;
109
- case "Pattern":
127
+ case "Pattern": {
128
+ if (dispatchPatternCompile === undefined) {
129
+ throw new Error(
130
+ "SubjectPattern.compile requires the top-level Pattern compile dispatch; not registered",
131
+ );
132
+ }
110
133
  // Navigate to the subject first
111
134
  code.push({ type: "NavigateSubject" });
112
135
  // Save the path and run the inner pattern relative to the subject
113
136
  code.push({ type: "ExtendTraversal" });
114
- (this._pattern.pattern as unknown as Matcher).compile(code, literals, captures);
137
+ dispatchPatternCompile(this._pattern.pattern, code, literals, captures);
115
138
  code.push({ type: "CombineTraversal" });
116
139
  break;
140
+ }
117
141
  }
118
142
  }
119
143
 
@@ -125,8 +149,11 @@ export class SubjectPattern implements Matcher {
125
149
  switch (this._pattern.type) {
126
150
  case "Any":
127
151
  return "subj";
128
- case "Pattern":
129
- return `subj(${(this._pattern.pattern as unknown as { toString(): string }).toString()})`;
152
+ case "Pattern": {
153
+ const fmt = dispatchPatternToString;
154
+ const inner = fmt !== undefined ? fmt(this._pattern.pattern) : "?";
155
+ return `subj(${inner})`;
156
+ }
130
157
  }
131
158
  }
132
159
 
@@ -19,6 +19,12 @@ import type { Pattern } from "../index";
19
19
  // Forward declaration for Pattern factory
20
20
  let createStructureWrappedPattern: ((pattern: WrappedPattern) => Pattern) | undefined;
21
21
 
22
+ // Forward declaration for `Pattern::any()` so that
23
+ // `WrappedPattern.unwrap()` can mirror Rust's
24
+ // `Self::unwrap_matching(Pattern::any())` factory exactly. Resolved during
25
+ // pattern-module registration to avoid the circular import.
26
+ let createAnyPattern: (() => Pattern) | undefined;
27
+
22
28
  // Forward declaration for pattern dispatch (avoids circular imports)
23
29
  let dispatchPatternPathsWithCaptures:
24
30
  | ((pattern: Pattern, haystack: Envelope) => [Path[], Map<string, Path[]>])
@@ -32,6 +38,10 @@ export function registerWrappedPatternFactory(factory: (pattern: WrappedPattern)
32
38
  createStructureWrappedPattern = factory;
33
39
  }
34
40
 
41
+ export function registerWrappedPatternAny(factory: () => Pattern): void {
42
+ createAnyPattern = factory;
43
+ }
44
+
35
45
  export function registerWrappedPatternDispatch(dispatch: {
36
46
  pathsWithCaptures: (pattern: Pattern, haystack: Envelope) => [Path[], Map<string, Path[]>];
37
47
  compile: (pattern: Pattern, code: Instr[], literals: Pattern[], captures: string[]) => void;
@@ -80,12 +90,17 @@ export class WrappedPattern implements Matcher {
80
90
 
81
91
  /**
82
92
  * Creates a new WrappedPattern that matches any wrapped envelope and descends into it.
83
- * Note: This requires Pattern.any() to be available, so it's set up during registration.
93
+ *
94
+ * Mirrors Rust `WrappedPattern::unwrap()` which delegates to
95
+ * `Self::unwrap_matching(Pattern::any())`. The `any` factory is wired in
96
+ * during module-load registration to break the circular import on the
97
+ * top-level `Pattern` type.
84
98
  */
85
99
  static unwrap(): WrappedPattern {
86
- // This will be filled in when Pattern.any() is available
87
- // For now, create a placeholder that will be replaced
88
- return new WrappedPattern({ type: "Any" }); // Will be overwritten
100
+ if (createAnyPattern === undefined) {
101
+ throw new Error("WrappedPattern.unwrap() requires Pattern.any factory; not registered");
102
+ }
103
+ return WrappedPattern.unwrapMatching(createAnyPattern());
89
104
  }
90
105
 
91
106
  /**
@@ -184,13 +199,17 @@ export class WrappedPattern implements Matcher {
184
199
  case "Any":
185
200
  return "wrapped";
186
201
  case "Unwrap": {
187
- const patternStr =
188
- dispatchPatternToString !== undefined
189
- ? dispatchPatternToString(this._pattern.pattern)
190
- : "*";
191
- if (patternStr === "*") {
202
+ // Rust collapses `Unwrap(Pattern::any())` to the bare keyword
203
+ // `unwrap`. We detect the "any" pattern by inspecting the tagged
204
+ // union shape rather than by string compare so this stays correct
205
+ // if `Pattern::any()`'s display ever changes.
206
+ const inner = this._pattern.pattern;
207
+ const isAny = inner.type === "Meta" && inner.pattern.type === "Any";
208
+ if (isAny) {
192
209
  return "unwrap";
193
210
  }
211
+ const patternStr =
212
+ dispatchPatternToString !== undefined ? dispatchPatternToString(inner) : "?";
194
213
  return `unwrap(${patternStr})`;
195
214
  }
196
215
  }
package/src/pattern/vm.ts CHANGED
@@ -86,10 +86,10 @@ export function axisChildren(axis: Axis, env: Envelope): [Envelope, EdgeType][]
86
86
  if (envCase.type === "node") {
87
87
  const subject = envCase.subject;
88
88
  if (subject.isWrapped()) {
89
- const unwrapped = subject.unwrap();
90
- if (unwrapped !== undefined) {
91
- return [[unwrapped, "Content"]];
92
- }
89
+ // Mirror Rust `subject.try_unwrap().unwrap()`: the "is wrapped"
90
+ // check above already guarantees `tryUnwrap` won't throw.
91
+ const unwrapped = subject.tryUnwrap();
92
+ return [[unwrapped, "Content"]];
93
93
  }
94
94
  } else if (envCase.type === "wrapped") {
95
95
  return [[envCase.envelope, "Content"]];