@bcts/envelope-pattern 1.0.0-alpha.16 → 1.0.0-alpha.18

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 (46) hide show
  1. package/README.md +1 -1
  2. package/dist/index.cjs +1992 -1714
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +147 -31
  5. package/dist/index.d.cts.map +1 -1
  6. package/dist/index.d.mts +147 -31
  7. package/dist/index.d.mts.map +1 -1
  8. package/dist/index.iife.js +1984 -1707
  9. package/dist/index.iife.js.map +1 -1
  10. package/dist/index.mjs +1966 -1698
  11. package/dist/index.mjs.map +1 -1
  12. package/package.json +9 -9
  13. package/src/format.ts +32 -13
  14. package/src/parse/index.ts +138 -5
  15. package/src/parse/token.ts +59 -58
  16. package/src/pattern/index.ts +110 -2
  17. package/src/pattern/leaf/array-pattern.ts +26 -26
  18. package/src/pattern/leaf/bool-pattern.ts +12 -12
  19. package/src/pattern/leaf/byte-string-pattern.ts +15 -15
  20. package/src/pattern/leaf/cbor-pattern.ts +31 -31
  21. package/src/pattern/leaf/date-pattern.ts +9 -9
  22. package/src/pattern/leaf/index.ts +1 -2
  23. package/src/pattern/leaf/known-value-pattern.ts +21 -20
  24. package/src/pattern/leaf/map-pattern.ts +14 -14
  25. package/src/pattern/leaf/null-pattern.ts +8 -8
  26. package/src/pattern/leaf/number-pattern.ts +20 -20
  27. package/src/pattern/leaf/tagged-pattern.ts +20 -20
  28. package/src/pattern/leaf/text-pattern.ts +14 -14
  29. package/src/pattern/matcher.ts +88 -3
  30. package/src/pattern/meta/and-pattern.ts +19 -18
  31. package/src/pattern/meta/capture-pattern.ts +16 -17
  32. package/src/pattern/meta/group-pattern.ts +20 -17
  33. package/src/pattern/meta/not-pattern.ts +9 -8
  34. package/src/pattern/meta/or-pattern.ts +30 -25
  35. package/src/pattern/meta/search-pattern.ts +17 -17
  36. package/src/pattern/meta/traverse-pattern.ts +42 -18
  37. package/src/pattern/structure/assertions-pattern.ts +31 -32
  38. package/src/pattern/structure/digest-pattern.ts +23 -23
  39. package/src/pattern/structure/index.ts +1 -0
  40. package/src/pattern/structure/node-pattern.ts +17 -17
  41. package/src/pattern/structure/object-pattern.ts +14 -15
  42. package/src/pattern/structure/obscured-pattern.ts +7 -7
  43. package/src/pattern/structure/predicate-pattern.ts +14 -15
  44. package/src/pattern/structure/subject-pattern.ts +16 -17
  45. package/src/pattern/structure/wrapped-pattern.ts +40 -19
  46. package/src/pattern/vm.ts +12 -11
@@ -8,9 +8,10 @@
8
8
 
9
9
  import type { Envelope } from "@bcts/envelope";
10
10
  import type { Path } from "../../format";
11
- import type { Matcher } from "../matcher";
11
+ import { dispatchPaths, dispatchPatternToString } from "../matcher";
12
12
  import type { Instr } from "../vm";
13
13
  import type { Pattern } from "../index";
14
+ import type { Matcher } from "../matcher";
14
15
 
15
16
  // Forward declaration for Pattern factory (used for late binding)
16
17
  export let createMetaSearchPattern: ((pattern: SearchPattern) => Pattern) | undefined;
@@ -25,10 +26,10 @@ export function registerSearchPatternFactory(factory: (pattern: SearchPattern) =
25
26
  * Corresponds to the Rust `SearchPattern` struct in search_pattern.rs
26
27
  */
27
28
  export class SearchPattern implements Matcher {
28
- readonly #pattern: Pattern;
29
+ private readonly _pattern: Pattern;
29
30
 
30
31
  private constructor(pattern: Pattern) {
31
- this.#pattern = pattern;
32
+ this._pattern = pattern;
32
33
  }
33
34
 
34
35
  /**
@@ -42,20 +43,19 @@ export class SearchPattern implements Matcher {
42
43
  * Gets the inner pattern.
43
44
  */
44
45
  pattern(): Pattern {
45
- return this.#pattern;
46
+ return this._pattern;
46
47
  }
47
48
 
48
49
  pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
49
50
  const resultPaths: Path[] = [];
50
- const matcher = this.#pattern as unknown as Matcher;
51
51
 
52
52
  // Walk the envelope tree
53
- this.#walkEnvelope(haystack, [], (currentEnvelope, pathToCurrent) => {
53
+ this._walkEnvelope(haystack, [], (currentEnvelope, pathToCurrent) => {
54
54
  // Create the path to this node
55
55
  const newPath: Envelope[] = [...pathToCurrent, currentEnvelope];
56
56
 
57
57
  // Test the pattern against this node
58
- const patternPaths = matcher.paths(currentEnvelope);
58
+ const patternPaths = dispatchPaths(this._pattern, currentEnvelope);
59
59
 
60
60
  // If the pattern matches, emit the full paths
61
61
  for (const patternPath of patternPaths) {
@@ -92,7 +92,7 @@ export class SearchPattern implements Matcher {
92
92
  /**
93
93
  * Walk the envelope tree recursively.
94
94
  */
95
- #walkEnvelope(
95
+ private _walkEnvelope(
96
96
  envelope: Envelope,
97
97
  pathToCurrent: Envelope[],
98
98
  visitor: (envelope: Envelope, path: Envelope[]) => void,
@@ -106,24 +106,24 @@ export class SearchPattern implements Matcher {
106
106
 
107
107
  // Walk subject if it's different from this envelope
108
108
  if (!subject.digest().equals(envelope.digest())) {
109
- this.#walkEnvelope(subject, newPath, visitor);
109
+ this._walkEnvelope(subject, newPath, visitor);
110
110
  }
111
111
 
112
112
  // Walk assertions
113
113
  for (const assertion of envelope.assertions()) {
114
- this.#walkEnvelope(assertion, newPath, visitor);
114
+ this._walkEnvelope(assertion, newPath, visitor);
115
115
 
116
116
  // Walk predicate and object if available
117
117
  const predicate = assertion.asPredicate?.();
118
118
  if (predicate !== undefined) {
119
119
  const assertionPath = [...newPath, assertion];
120
- this.#walkEnvelope(predicate, assertionPath, visitor);
120
+ this._walkEnvelope(predicate, assertionPath, visitor);
121
121
  }
122
122
 
123
123
  const object = assertion.asObject?.();
124
124
  if (object !== undefined) {
125
125
  const assertionPath = [...newPath, assertion];
126
- this.#walkEnvelope(object, assertionPath, visitor);
126
+ this._walkEnvelope(object, assertionPath, visitor);
127
127
  }
128
128
  }
129
129
 
@@ -131,7 +131,7 @@ export class SearchPattern implements Matcher {
131
131
  if (subject.isWrapped()) {
132
132
  const unwrapped = subject.tryUnwrap?.();
133
133
  if (unwrapped !== undefined) {
134
- this.#walkEnvelope(unwrapped, newPath, visitor);
134
+ this._walkEnvelope(unwrapped, newPath, visitor);
135
135
  }
136
136
  }
137
137
  }
@@ -146,11 +146,11 @@ export class SearchPattern implements Matcher {
146
146
 
147
147
  compile(code: Instr[], literals: Pattern[], captures: string[]): void {
148
148
  const idx = literals.length;
149
- literals.push(this.#pattern);
149
+ literals.push(this._pattern);
150
150
 
151
151
  // Collect capture names from inner pattern
152
152
  const innerNames: string[] = [];
153
- collectCaptureNames(this.#pattern, innerNames);
153
+ collectCaptureNames(this._pattern, innerNames);
154
154
 
155
155
  const captureMap: [string, number][] = [];
156
156
  for (const name of innerNames) {
@@ -170,14 +170,14 @@ export class SearchPattern implements Matcher {
170
170
  }
171
171
 
172
172
  toString(): string {
173
- return `search(${(this.#pattern as unknown as { toString(): string }).toString()})`;
173
+ return `search(${dispatchPatternToString(this._pattern)})`;
174
174
  }
175
175
 
176
176
  /**
177
177
  * Equality comparison.
178
178
  */
179
179
  equals(other: SearchPattern): boolean {
180
- return this.#pattern === other.#pattern;
180
+ return this._pattern === other._pattern;
181
181
  }
182
182
 
183
183
  /**
@@ -21,18 +21,37 @@ export function registerTraversePatternFactory(
21
21
  createMetaTraversePattern = factory;
22
22
  }
23
23
 
24
+ // Late-binding dispatch functions to avoid circular dependency with Pattern
25
+ let _patternPathsWithCaptures:
26
+ | ((pattern: Pattern, haystack: Envelope) => [Path[], Map<string, Path[]>])
27
+ | undefined;
28
+ let _patternCompile:
29
+ | ((pattern: Pattern, code: Instr[], literals: Pattern[], captures: string[]) => void)
30
+ | undefined;
31
+ let _patternIsComplex: ((pattern: Pattern) => boolean) | undefined;
32
+
33
+ export function registerTraverseDispatchFunctions(
34
+ pathsWithCaptures: (pattern: Pattern, haystack: Envelope) => [Path[], Map<string, Path[]>],
35
+ compile: (pattern: Pattern, code: Instr[], literals: Pattern[], captures: string[]) => void,
36
+ isComplex: (pattern: Pattern) => boolean,
37
+ ): void {
38
+ _patternPathsWithCaptures = pathsWithCaptures;
39
+ _patternCompile = compile;
40
+ _patternIsComplex = isComplex;
41
+ }
42
+
24
43
  /**
25
44
  * A pattern that matches a traversal order of patterns.
26
45
  *
27
46
  * Corresponds to the Rust `TraversePattern` struct in traverse_pattern.rs
28
47
  */
29
48
  export class TraversePattern implements Matcher {
30
- readonly #first: Pattern;
31
- readonly #rest: TraversePattern | undefined;
49
+ private readonly _first: Pattern;
50
+ private readonly _rest: TraversePattern | undefined;
32
51
 
33
52
  private constructor(first: Pattern, rest: TraversePattern | undefined) {
34
- this.#first = first;
35
- this.#rest = rest;
53
+ this._first = first;
54
+ this._rest = rest;
36
55
  }
37
56
 
38
57
  /**
@@ -53,19 +72,21 @@ export class TraversePattern implements Matcher {
53
72
  * Gets all patterns in this traversal.
54
73
  */
55
74
  patterns(): Pattern[] {
56
- const result: Pattern[] = [this.#first];
57
- if (this.#rest !== undefined) {
58
- result.push(...this.#rest.patterns());
75
+ const result: Pattern[] = [this._first];
76
+ if (this._rest !== undefined) {
77
+ result.push(...this._rest.patterns());
59
78
  }
60
79
  return result;
61
80
  }
62
81
 
63
82
  pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
64
- const firstMatcher = this.#first as unknown as Matcher;
65
- const headPaths = firstMatcher.paths(haystack);
83
+ if (_patternPathsWithCaptures === undefined) {
84
+ throw new Error("TraversePattern dispatch functions not registered");
85
+ }
86
+ const headPaths = _patternPathsWithCaptures(this._first, haystack)[0];
66
87
 
67
88
  // If there's no further traversal, return head paths
68
- if (this.#rest === undefined) {
89
+ if (this._rest === undefined) {
69
90
  return [headPaths, new Map<string, Path[]>()];
70
91
  }
71
92
 
@@ -74,7 +95,7 @@ export class TraversePattern implements Matcher {
74
95
  const lastEnv = path[path.length - 1];
75
96
  if (lastEnv !== undefined) {
76
97
  // Recursively match the rest of the traversal
77
- const tailPaths = this.#rest.paths(lastEnv);
98
+ const tailPaths = this._rest.paths(lastEnv);
78
99
  for (const tailPath of tailPaths) {
79
100
  const combined = [...path, ...tailPath];
80
101
  result.push(combined);
@@ -94,24 +115,27 @@ export class TraversePattern implements Matcher {
94
115
  }
95
116
 
96
117
  compile(code: Instr[], literals: Pattern[], captures: string[]): void {
118
+ if (_patternCompile === undefined) {
119
+ throw new Error("TraversePattern dispatch functions not registered");
120
+ }
97
121
  // Compile the first pattern
98
- const firstMatcher = this.#first as unknown as Matcher;
99
- firstMatcher.compile(code, literals, captures);
122
+ _patternCompile(this._first, code, literals, captures);
100
123
 
101
- if (this.#rest !== undefined) {
124
+ if (this._rest !== undefined) {
102
125
  // Save the current path and switch to last envelope
103
126
  code.push({ type: "ExtendTraversal" });
104
127
  // Compile the rest of the traversal
105
- this.#rest.compile(code, literals, captures);
128
+ this._rest.compile(code, literals, captures);
106
129
  // Combine the paths correctly
107
130
  code.push({ type: "CombineTraversal" });
108
131
  }
109
132
  }
110
133
 
111
134
  isComplex(): boolean {
112
- // A traversal is complex if `first` is complex, or it has more than one pattern
113
- const firstMatcher = this.#first as unknown as Matcher;
114
- return firstMatcher.isComplex() || this.#rest !== undefined;
135
+ if (_patternIsComplex === undefined) {
136
+ throw new Error("TraversePattern dispatch functions not registered");
137
+ }
138
+ return _patternIsComplex(this._first) || this._rest !== undefined;
115
139
  }
116
140
 
117
141
  toString(): string {
@@ -8,7 +8,7 @@
8
8
 
9
9
  import type { Envelope } from "@bcts/envelope";
10
10
  import type { Path } from "../../format";
11
- import type { Matcher } from "../matcher";
11
+ import { matchPattern, type Matcher } from "../matcher";
12
12
  import type { Instr } from "../vm";
13
13
  import type { Pattern } from "../index";
14
14
 
@@ -42,10 +42,10 @@ export type AssertionsPatternType =
42
42
  * Corresponds to the Rust `AssertionsPattern` enum in assertions_pattern.rs
43
43
  */
44
44
  export class AssertionsPattern implements Matcher {
45
- readonly #pattern: AssertionsPatternType;
45
+ private readonly _pattern: AssertionsPatternType;
46
46
 
47
47
  private constructor(pattern: AssertionsPatternType) {
48
- this.#pattern = pattern;
48
+ this._pattern = pattern;
49
49
  }
50
50
 
51
51
  /**
@@ -83,18 +83,18 @@ export class AssertionsPattern implements Matcher {
83
83
  * Gets the pattern type.
84
84
  */
85
85
  get patternType(): AssertionsPatternType {
86
- return this.#pattern;
86
+ return this._pattern;
87
87
  }
88
88
 
89
89
  /**
90
90
  * Gets the predicate pattern if this has one, undefined otherwise.
91
91
  */
92
92
  predicatePattern(): Pattern | undefined {
93
- if (this.#pattern.type === "WithPredicate") {
94
- return this.#pattern.pattern;
93
+ if (this._pattern.type === "WithPredicate") {
94
+ return this._pattern.pattern;
95
95
  }
96
- if (this.#pattern.type === "WithBoth") {
97
- return this.#pattern.predicatePattern;
96
+ if (this._pattern.type === "WithBoth") {
97
+ return this._pattern.predicatePattern;
98
98
  }
99
99
  return undefined;
100
100
  }
@@ -103,11 +103,11 @@ export class AssertionsPattern implements Matcher {
103
103
  * Gets the object pattern if this has one, undefined otherwise.
104
104
  */
105
105
  objectPattern(): Pattern | undefined {
106
- if (this.#pattern.type === "WithObject") {
107
- return this.#pattern.pattern;
106
+ if (this._pattern.type === "WithObject") {
107
+ return this._pattern.pattern;
108
108
  }
109
- if (this.#pattern.type === "WithBoth") {
110
- return this.#pattern.objectPattern;
109
+ if (this._pattern.type === "WithBoth") {
110
+ return this._pattern.objectPattern;
111
111
  }
112
112
  return undefined;
113
113
  }
@@ -116,15 +116,14 @@ export class AssertionsPattern implements Matcher {
116
116
  const paths: Path[] = [];
117
117
 
118
118
  for (const assertion of haystack.assertions()) {
119
- switch (this.#pattern.type) {
119
+ switch (this._pattern.type) {
120
120
  case "Any":
121
121
  paths.push([assertion]);
122
122
  break;
123
123
  case "WithPredicate": {
124
124
  const predicate = assertion.asPredicate?.();
125
125
  if (predicate !== undefined) {
126
- const innerMatcher = this.#pattern.pattern as unknown as Matcher;
127
- if (innerMatcher.matches(predicate)) {
126
+ if (matchPattern(this._pattern.pattern, predicate)) {
128
127
  paths.push([assertion]);
129
128
  }
130
129
  }
@@ -133,8 +132,7 @@ export class AssertionsPattern implements Matcher {
133
132
  case "WithObject": {
134
133
  const object = assertion.asObject?.();
135
134
  if (object !== undefined) {
136
- const innerMatcher = this.#pattern.pattern as unknown as Matcher;
137
- if (innerMatcher.matches(object)) {
135
+ if (matchPattern(this._pattern.pattern, object)) {
138
136
  paths.push([assertion]);
139
137
  }
140
138
  }
@@ -144,9 +142,10 @@ export class AssertionsPattern implements Matcher {
144
142
  const predicate = assertion.asPredicate?.();
145
143
  const object = assertion.asObject?.();
146
144
  if (predicate !== undefined && object !== undefined) {
147
- const predMatcher = this.#pattern.predicatePattern as unknown as Matcher;
148
- const objMatcher = this.#pattern.objectPattern as unknown as Matcher;
149
- if (predMatcher.matches(predicate) && objMatcher.matches(object)) {
145
+ if (
146
+ matchPattern(this._pattern.predicatePattern, predicate) &&
147
+ matchPattern(this._pattern.objectPattern, object)
148
+ ) {
150
149
  paths.push([assertion]);
151
150
  }
152
151
  }
@@ -180,15 +179,15 @@ export class AssertionsPattern implements Matcher {
180
179
  }
181
180
 
182
181
  toString(): string {
183
- switch (this.#pattern.type) {
182
+ switch (this._pattern.type) {
184
183
  case "Any":
185
184
  return "assert";
186
185
  case "WithPredicate":
187
- return `assertpred(${(this.#pattern.pattern as unknown as { toString(): string }).toString()})`;
186
+ return `assertpred(${(this._pattern.pattern as unknown as { toString(): string }).toString()})`;
188
187
  case "WithObject":
189
- return `assertobj(${(this.#pattern.pattern as unknown as { toString(): string }).toString()})`;
188
+ return `assertobj(${(this._pattern.pattern as unknown as { toString(): string }).toString()})`;
190
189
  case "WithBoth":
191
- return `assert(${(this.#pattern.predicatePattern as unknown as { toString(): string }).toString()}, ${(this.#pattern.objectPattern as unknown as { toString(): string }).toString()})`;
190
+ return `assert(${(this._pattern.predicatePattern as unknown as { toString(): string }).toString()}, ${(this._pattern.objectPattern as unknown as { toString(): string }).toString()})`;
192
191
  }
193
192
  }
194
193
 
@@ -196,31 +195,31 @@ export class AssertionsPattern implements Matcher {
196
195
  * Equality comparison.
197
196
  */
198
197
  equals(other: AssertionsPattern): boolean {
199
- if (this.#pattern.type !== other.#pattern.type) {
198
+ if (this._pattern.type !== other._pattern.type) {
200
199
  return false;
201
200
  }
202
- switch (this.#pattern.type) {
201
+ switch (this._pattern.type) {
203
202
  case "Any":
204
203
  return true;
205
204
  case "WithPredicate":
206
205
  case "WithObject": {
207
206
  const thisPattern = (
208
- this.#pattern as { type: "WithPredicate" | "WithObject"; pattern: Pattern }
207
+ this._pattern as { type: "WithPredicate" | "WithObject"; pattern: Pattern }
209
208
  ).pattern;
210
209
  const otherPattern = (
211
- other.#pattern as { type: "WithPredicate" | "WithObject"; pattern: Pattern }
210
+ other._pattern as { type: "WithPredicate" | "WithObject"; pattern: Pattern }
212
211
  ).pattern;
213
212
  return thisPattern === otherPattern;
214
213
  }
215
214
  case "WithBoth": {
216
- const otherBoth = other.#pattern as {
215
+ const otherBoth = other._pattern as {
217
216
  type: "WithBoth";
218
217
  predicatePattern: Pattern;
219
218
  objectPattern: Pattern;
220
219
  };
221
220
  return (
222
- this.#pattern.predicatePattern === otherBoth.predicatePattern &&
223
- this.#pattern.objectPattern === otherBoth.objectPattern
221
+ this._pattern.predicatePattern === otherBoth.predicatePattern &&
222
+ this._pattern.objectPattern === otherBoth.objectPattern
224
223
  );
225
224
  }
226
225
  }
@@ -230,7 +229,7 @@ export class AssertionsPattern implements Matcher {
230
229
  * Hash code for use in Maps/Sets.
231
230
  */
232
231
  hashCode(): number {
233
- switch (this.#pattern.type) {
232
+ switch (this._pattern.type) {
234
233
  case "Any":
235
234
  return 0;
236
235
  case "WithPredicate":
@@ -49,10 +49,10 @@ export type DigestPatternType =
49
49
  * Corresponds to the Rust `DigestPattern` enum in digest_pattern.rs
50
50
  */
51
51
  export class DigestPattern implements Matcher {
52
- readonly #pattern: DigestPatternType;
52
+ private readonly _pattern: DigestPatternType;
53
53
 
54
54
  private constructor(pattern: DigestPatternType) {
55
- this.#pattern = pattern;
55
+ this._pattern = pattern;
56
56
  }
57
57
 
58
58
  /**
@@ -87,7 +87,7 @@ export class DigestPattern implements Matcher {
87
87
  * Gets the pattern type.
88
88
  */
89
89
  get patternType(): DigestPatternType {
90
- return this.#pattern;
90
+ return this._pattern;
91
91
  }
92
92
 
93
93
  pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
@@ -95,16 +95,16 @@ export class DigestPattern implements Matcher {
95
95
  const digestData = digest.data();
96
96
  let isHit = false;
97
97
 
98
- switch (this.#pattern.type) {
98
+ switch (this._pattern.type) {
99
99
  case "Any":
100
100
  // Any digest matches - every envelope has a digest
101
101
  isHit = true;
102
102
  break;
103
103
  case "Digest":
104
- isHit = digest.equals(this.#pattern.digest);
104
+ isHit = digest.equals(this._pattern.digest);
105
105
  break;
106
106
  case "Prefix": {
107
- const prefix = this.#pattern.prefix;
107
+ const prefix = this._pattern.prefix;
108
108
  if (digestData.length >= prefix.length) {
109
109
  isHit = true;
110
110
  for (let i = 0; i < prefix.length; i++) {
@@ -118,7 +118,7 @@ export class DigestPattern implements Matcher {
118
118
  }
119
119
  case "BinaryRegex": {
120
120
  const latin1 = bytesToLatin1(digestData);
121
- isHit = this.#pattern.regex.test(latin1);
121
+ isHit = this._pattern.regex.test(latin1);
122
122
  break;
123
123
  }
124
124
  }
@@ -147,15 +147,15 @@ export class DigestPattern implements Matcher {
147
147
  }
148
148
 
149
149
  toString(): string {
150
- switch (this.#pattern.type) {
150
+ switch (this._pattern.type) {
151
151
  case "Any":
152
152
  return "digest";
153
153
  case "Digest":
154
- return `digest(${this.#pattern.digest.hex()})`;
154
+ return `digest(${this._pattern.digest.hex()})`;
155
155
  case "Prefix":
156
- return `digest(${bytesToHex(this.#pattern.prefix)})`;
156
+ return `digest(${bytesToHex(this._pattern.prefix)})`;
157
157
  case "BinaryRegex":
158
- return `digest(/${this.#pattern.regex.source}/)`;
158
+ return `digest(/${this._pattern.regex.source}/)`;
159
159
  }
160
160
  }
161
161
 
@@ -163,19 +163,19 @@ export class DigestPattern implements Matcher {
163
163
  * Equality comparison.
164
164
  */
165
165
  equals(other: DigestPattern): boolean {
166
- if (this.#pattern.type !== other.#pattern.type) {
166
+ if (this._pattern.type !== other._pattern.type) {
167
167
  return false;
168
168
  }
169
- switch (this.#pattern.type) {
169
+ switch (this._pattern.type) {
170
170
  case "Any":
171
171
  return true;
172
172
  case "Digest":
173
- return this.#pattern.digest.equals(
174
- (other.#pattern as { type: "Digest"; digest: Digest }).digest,
173
+ return this._pattern.digest.equals(
174
+ (other._pattern as { type: "Digest"; digest: Digest }).digest,
175
175
  );
176
176
  case "Prefix": {
177
- const thisPrefix = this.#pattern.prefix;
178
- const otherPrefix = (other.#pattern as { type: "Prefix"; prefix: Uint8Array }).prefix;
177
+ const thisPrefix = this._pattern.prefix;
178
+ const otherPrefix = (other._pattern as { type: "Prefix"; prefix: Uint8Array }).prefix;
179
179
  if (thisPrefix.length !== otherPrefix.length) return false;
180
180
  for (let i = 0; i < thisPrefix.length; i++) {
181
181
  if (thisPrefix[i] !== otherPrefix[i]) return false;
@@ -184,8 +184,8 @@ export class DigestPattern implements Matcher {
184
184
  }
185
185
  case "BinaryRegex":
186
186
  return (
187
- this.#pattern.regex.source ===
188
- (other.#pattern as { type: "BinaryRegex"; regex: RegExp }).regex.source
187
+ this._pattern.regex.source ===
188
+ (other._pattern as { type: "BinaryRegex"; regex: RegExp }).regex.source
189
189
  );
190
190
  }
191
191
  }
@@ -194,12 +194,12 @@ export class DigestPattern implements Matcher {
194
194
  * Hash code for use in Maps/Sets.
195
195
  */
196
196
  hashCode(): number {
197
- switch (this.#pattern.type) {
197
+ switch (this._pattern.type) {
198
198
  case "Any":
199
199
  return 0;
200
200
  case "Digest": {
201
201
  // Hash based on first few bytes of digest
202
- const data = this.#pattern.digest.data().slice(0, 8);
202
+ const data = this._pattern.digest.data().slice(0, 8);
203
203
  let hash = 0;
204
204
  for (const byte of data) {
205
205
  hash = (hash * 31 + byte) | 0;
@@ -208,14 +208,14 @@ export class DigestPattern implements Matcher {
208
208
  }
209
209
  case "Prefix": {
210
210
  let hash = 0;
211
- for (const byte of this.#pattern.prefix) {
211
+ for (const byte of this._pattern.prefix) {
212
212
  hash = (hash * 31 + byte) | 0;
213
213
  }
214
214
  return hash;
215
215
  }
216
216
  case "BinaryRegex": {
217
217
  let hash = 0;
218
- for (const char of this.#pattern.regex.source) {
218
+ for (const char of this._pattern.regex.source) {
219
219
  hash = (hash * 31 + char.charCodeAt(0)) | 0;
220
220
  }
221
221
  return hash;
@@ -51,6 +51,7 @@ export {
51
51
  WrappedPattern,
52
52
  type WrappedPatternType,
53
53
  registerWrappedPatternFactory,
54
+ registerWrappedPatternDispatch,
54
55
  } from "./wrapped-pattern";
55
56
 
56
57
  // Import concrete types for use in StructurePattern
@@ -37,10 +37,10 @@ export type NodePatternType =
37
37
  * Corresponds to the Rust `NodePattern` enum in node_pattern.rs
38
38
  */
39
39
  export class NodePattern implements Matcher {
40
- readonly #pattern: NodePatternType;
40
+ private readonly _pattern: NodePatternType;
41
41
 
42
42
  private constructor(pattern: NodePatternType) {
43
- this.#pattern = pattern;
43
+ this._pattern = pattern;
44
44
  }
45
45
 
46
46
  /**
@@ -76,14 +76,14 @@ export class NodePattern implements Matcher {
76
76
  * Gets the pattern type.
77
77
  */
78
78
  get patternType(): NodePatternType {
79
- return this.#pattern;
79
+ return this._pattern;
80
80
  }
81
81
 
82
82
  /**
83
83
  * Gets the subject pattern if this is a WithSubject type, undefined otherwise.
84
84
  */
85
85
  subjectPattern(): Pattern | undefined {
86
- return this.#pattern.type === "WithSubject" ? this.#pattern.subjectPattern : undefined;
86
+ return this._pattern.type === "WithSubject" ? this._pattern.subjectPattern : undefined;
87
87
  }
88
88
 
89
89
  /**
@@ -101,12 +101,12 @@ export class NodePattern implements Matcher {
101
101
 
102
102
  let isHit = false;
103
103
 
104
- switch (this.#pattern.type) {
104
+ switch (this._pattern.type) {
105
105
  case "Any":
106
106
  isHit = true;
107
107
  break;
108
108
  case "AssertionsInterval":
109
- isHit = this.#pattern.interval.contains(haystack.assertions().length);
109
+ isHit = this._pattern.interval.contains(haystack.assertions().length);
110
110
  break;
111
111
  case "WithSubject":
112
112
  // For WithSubject, we match if the node exists (subject pattern matching done at higher level)
@@ -138,13 +138,13 @@ export class NodePattern implements Matcher {
138
138
  }
139
139
 
140
140
  toString(): string {
141
- switch (this.#pattern.type) {
141
+ switch (this._pattern.type) {
142
142
  case "Any":
143
143
  return "node";
144
144
  case "AssertionsInterval":
145
- return `node(${this.#pattern.interval.toString()})`;
145
+ return `node(${this._pattern.interval.toString()})`;
146
146
  case "WithSubject":
147
- return `node(${(this.#pattern.subjectPattern as unknown as { toString(): string }).toString()})`;
147
+ return `node(${(this._pattern.subjectPattern as unknown as { toString(): string }).toString()})`;
148
148
  }
149
149
  }
150
150
 
@@ -152,21 +152,21 @@ export class NodePattern implements Matcher {
152
152
  * Equality comparison.
153
153
  */
154
154
  equals(other: NodePattern): boolean {
155
- if (this.#pattern.type !== other.#pattern.type) {
155
+ if (this._pattern.type !== other._pattern.type) {
156
156
  return false;
157
157
  }
158
- switch (this.#pattern.type) {
158
+ switch (this._pattern.type) {
159
159
  case "Any":
160
160
  return true;
161
161
  case "AssertionsInterval":
162
- return this.#pattern.interval.equals(
163
- (other.#pattern as { type: "AssertionsInterval"; interval: Interval }).interval,
162
+ return this._pattern.interval.equals(
163
+ (other._pattern as { type: "AssertionsInterval"; interval: Interval }).interval,
164
164
  );
165
165
  case "WithSubject":
166
166
  // Simple reference equality for pattern (could be improved with deep equality)
167
167
  return (
168
- this.#pattern.subjectPattern ===
169
- (other.#pattern as { type: "WithSubject"; subjectPattern: Pattern }).subjectPattern
168
+ this._pattern.subjectPattern ===
169
+ (other._pattern as { type: "WithSubject"; subjectPattern: Pattern }).subjectPattern
170
170
  );
171
171
  }
172
172
  }
@@ -175,12 +175,12 @@ export class NodePattern implements Matcher {
175
175
  * Hash code for use in Maps/Sets.
176
176
  */
177
177
  hashCode(): number {
178
- switch (this.#pattern.type) {
178
+ switch (this._pattern.type) {
179
179
  case "Any":
180
180
  return 0;
181
181
  case "AssertionsInterval":
182
182
  // Simple hash based on interval min/max
183
- return this.#pattern.interval.min() * 31 + (this.#pattern.interval.max() ?? 0);
183
+ return this._pattern.interval.min() * 31 + (this._pattern.interval.max() ?? 0);
184
184
  case "WithSubject":
185
185
  return 1;
186
186
  }