@bcts/envelope-pattern 1.0.0-alpha.12

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 (53) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +13 -0
  3. package/dist/index.cjs +6781 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +2628 -0
  6. package/dist/index.d.cts.map +1 -0
  7. package/dist/index.d.mts +2628 -0
  8. package/dist/index.d.mts.map +1 -0
  9. package/dist/index.iife.js +6781 -0
  10. package/dist/index.iife.js.map +1 -0
  11. package/dist/index.mjs +6545 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/package.json +77 -0
  14. package/src/error.ts +262 -0
  15. package/src/format.ts +375 -0
  16. package/src/index.ts +27 -0
  17. package/src/parse/index.ts +923 -0
  18. package/src/parse/token.ts +906 -0
  19. package/src/parse/utils.ts +339 -0
  20. package/src/pattern/index.ts +719 -0
  21. package/src/pattern/leaf/array-pattern.ts +273 -0
  22. package/src/pattern/leaf/bool-pattern.ts +140 -0
  23. package/src/pattern/leaf/byte-string-pattern.ts +172 -0
  24. package/src/pattern/leaf/cbor-pattern.ts +355 -0
  25. package/src/pattern/leaf/date-pattern.ts +178 -0
  26. package/src/pattern/leaf/index.ts +280 -0
  27. package/src/pattern/leaf/known-value-pattern.ts +192 -0
  28. package/src/pattern/leaf/map-pattern.ts +152 -0
  29. package/src/pattern/leaf/null-pattern.ts +110 -0
  30. package/src/pattern/leaf/number-pattern.ts +248 -0
  31. package/src/pattern/leaf/tagged-pattern.ts +228 -0
  32. package/src/pattern/leaf/text-pattern.ts +165 -0
  33. package/src/pattern/matcher.ts +88 -0
  34. package/src/pattern/meta/and-pattern.ts +109 -0
  35. package/src/pattern/meta/any-pattern.ts +81 -0
  36. package/src/pattern/meta/capture-pattern.ts +111 -0
  37. package/src/pattern/meta/group-pattern.ts +110 -0
  38. package/src/pattern/meta/index.ts +269 -0
  39. package/src/pattern/meta/not-pattern.ts +91 -0
  40. package/src/pattern/meta/or-pattern.ts +146 -0
  41. package/src/pattern/meta/search-pattern.ts +201 -0
  42. package/src/pattern/meta/traverse-pattern.ts +146 -0
  43. package/src/pattern/structure/assertions-pattern.ts +244 -0
  44. package/src/pattern/structure/digest-pattern.ts +225 -0
  45. package/src/pattern/structure/index.ts +272 -0
  46. package/src/pattern/structure/leaf-structure-pattern.ts +85 -0
  47. package/src/pattern/structure/node-pattern.ts +188 -0
  48. package/src/pattern/structure/object-pattern.ts +149 -0
  49. package/src/pattern/structure/obscured-pattern.ts +159 -0
  50. package/src/pattern/structure/predicate-pattern.ts +151 -0
  51. package/src/pattern/structure/subject-pattern.ts +152 -0
  52. package/src/pattern/structure/wrapped-pattern.ts +195 -0
  53. package/src/pattern/vm.ts +1021 -0
@@ -0,0 +1,272 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Structure patterns module
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust pattern/structure/mod.rs
5
+ *
6
+ * @module envelope-pattern/pattern/structure
7
+ */
8
+
9
+ import type { Envelope } from "@bcts/envelope";
10
+ import type { Path } from "../../format";
11
+ import type { Instr } from "../vm";
12
+ import type { Pattern } from "../index";
13
+
14
+ // Re-export all structure pattern types
15
+ export {
16
+ LeafStructurePattern,
17
+ registerLeafStructurePatternFactory,
18
+ } from "./leaf-structure-pattern";
19
+ export {
20
+ SubjectPattern,
21
+ type SubjectPatternType,
22
+ registerSubjectPatternFactory,
23
+ } from "./subject-pattern";
24
+ export {
25
+ PredicatePattern,
26
+ type PredicatePatternType,
27
+ registerPredicatePatternFactory,
28
+ } from "./predicate-pattern";
29
+ export {
30
+ ObjectPattern,
31
+ type ObjectPatternType,
32
+ registerObjectPatternFactory,
33
+ } from "./object-pattern";
34
+ export {
35
+ AssertionsPattern,
36
+ type AssertionsPatternType,
37
+ registerAssertionsPatternFactory,
38
+ } from "./assertions-pattern";
39
+ export {
40
+ DigestPattern,
41
+ type DigestPatternType,
42
+ registerDigestPatternFactory,
43
+ } from "./digest-pattern";
44
+ export { NodePattern, type NodePatternType, registerNodePatternFactory } from "./node-pattern";
45
+ export {
46
+ ObscuredPattern,
47
+ type ObscuredPatternType,
48
+ registerObscuredPatternFactory,
49
+ } from "./obscured-pattern";
50
+ export {
51
+ WrappedPattern,
52
+ type WrappedPatternType,
53
+ registerWrappedPatternFactory,
54
+ } from "./wrapped-pattern";
55
+
56
+ // Import concrete types for use in StructurePattern
57
+ import { type LeafStructurePattern } from "./leaf-structure-pattern";
58
+ import { type SubjectPattern } from "./subject-pattern";
59
+ import { type PredicatePattern } from "./predicate-pattern";
60
+ import { type ObjectPattern } from "./object-pattern";
61
+ import { type AssertionsPattern } from "./assertions-pattern";
62
+ import { type DigestPattern } from "./digest-pattern";
63
+ import { type NodePattern } from "./node-pattern";
64
+ import { type ObscuredPattern } from "./obscured-pattern";
65
+ import { type WrappedPattern } from "./wrapped-pattern";
66
+
67
+ /**
68
+ * Union type for all structure patterns.
69
+ *
70
+ * Corresponds to the Rust `StructurePattern` enum in pattern/structure/mod.rs
71
+ */
72
+ export type StructurePattern =
73
+ | { readonly type: "Leaf"; readonly pattern: LeafStructurePattern }
74
+ | { readonly type: "Subject"; readonly pattern: SubjectPattern }
75
+ | { readonly type: "Predicate"; readonly pattern: PredicatePattern }
76
+ | { readonly type: "Object"; readonly pattern: ObjectPattern }
77
+ | { readonly type: "Assertions"; readonly pattern: AssertionsPattern }
78
+ | { readonly type: "Digest"; readonly pattern: DigestPattern }
79
+ | { readonly type: "Node"; readonly pattern: NodePattern }
80
+ | { readonly type: "Obscured"; readonly pattern: ObscuredPattern }
81
+ | { readonly type: "Wrapped"; readonly pattern: WrappedPattern };
82
+
83
+ /**
84
+ * Creates a Leaf structure pattern.
85
+ */
86
+ export function structureLeaf(pattern: LeafStructurePattern): StructurePattern {
87
+ return { type: "Leaf", pattern };
88
+ }
89
+
90
+ /**
91
+ * Creates a Subject structure pattern.
92
+ */
93
+ export function structureSubject(pattern: SubjectPattern): StructurePattern {
94
+ return { type: "Subject", pattern };
95
+ }
96
+
97
+ /**
98
+ * Creates a Predicate structure pattern.
99
+ */
100
+ export function structurePredicate(pattern: PredicatePattern): StructurePattern {
101
+ return { type: "Predicate", pattern };
102
+ }
103
+
104
+ /**
105
+ * Creates an Object structure pattern.
106
+ */
107
+ export function structureObject(pattern: ObjectPattern): StructurePattern {
108
+ return { type: "Object", pattern };
109
+ }
110
+
111
+ /**
112
+ * Creates an Assertions structure pattern.
113
+ */
114
+ export function structureAssertions(pattern: AssertionsPattern): StructurePattern {
115
+ return { type: "Assertions", pattern };
116
+ }
117
+
118
+ /**
119
+ * Creates a Digest structure pattern.
120
+ */
121
+ export function structureDigest(pattern: DigestPattern): StructurePattern {
122
+ return { type: "Digest", pattern };
123
+ }
124
+
125
+ /**
126
+ * Creates a Node structure pattern.
127
+ */
128
+ export function structureNode(pattern: NodePattern): StructurePattern {
129
+ return { type: "Node", pattern };
130
+ }
131
+
132
+ /**
133
+ * Creates an Obscured structure pattern.
134
+ */
135
+ export function structureObscured(pattern: ObscuredPattern): StructurePattern {
136
+ return { type: "Obscured", pattern };
137
+ }
138
+
139
+ /**
140
+ * Creates a Wrapped structure pattern.
141
+ */
142
+ export function structureWrapped(pattern: WrappedPattern): StructurePattern {
143
+ return { type: "Wrapped", pattern };
144
+ }
145
+
146
+ /**
147
+ * Gets paths with captures for a structure pattern.
148
+ */
149
+ export function structurePatternPathsWithCaptures(
150
+ pattern: StructurePattern,
151
+ haystack: Envelope,
152
+ ): [Path[], Map<string, Path[]>] {
153
+ switch (pattern.type) {
154
+ case "Leaf":
155
+ return pattern.pattern.pathsWithCaptures(haystack);
156
+ case "Subject":
157
+ return pattern.pattern.pathsWithCaptures(haystack);
158
+ case "Predicate":
159
+ return pattern.pattern.pathsWithCaptures(haystack);
160
+ case "Object":
161
+ return pattern.pattern.pathsWithCaptures(haystack);
162
+ case "Assertions":
163
+ return pattern.pattern.pathsWithCaptures(haystack);
164
+ case "Digest":
165
+ return pattern.pattern.pathsWithCaptures(haystack);
166
+ case "Node":
167
+ return pattern.pattern.pathsWithCaptures(haystack);
168
+ case "Obscured":
169
+ return pattern.pattern.pathsWithCaptures(haystack);
170
+ case "Wrapped":
171
+ return pattern.pattern.pathsWithCaptures(haystack);
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Gets paths for a structure pattern.
177
+ */
178
+ export function structurePatternPaths(pattern: StructurePattern, haystack: Envelope): Path[] {
179
+ return structurePatternPathsWithCaptures(pattern, haystack)[0];
180
+ }
181
+
182
+ /**
183
+ * Compiles a structure pattern to bytecode.
184
+ */
185
+ export function structurePatternCompile(
186
+ pattern: StructurePattern,
187
+ code: Instr[],
188
+ literals: Pattern[],
189
+ captures: string[],
190
+ ): void {
191
+ switch (pattern.type) {
192
+ case "Leaf":
193
+ pattern.pattern.compile(code, literals, captures);
194
+ break;
195
+ case "Subject":
196
+ pattern.pattern.compile(code, literals, captures);
197
+ break;
198
+ case "Predicate":
199
+ pattern.pattern.compile(code, literals, captures);
200
+ break;
201
+ case "Object":
202
+ pattern.pattern.compile(code, literals, captures);
203
+ break;
204
+ case "Assertions":
205
+ pattern.pattern.compile(code, literals, captures);
206
+ break;
207
+ case "Digest":
208
+ pattern.pattern.compile(code, literals, captures);
209
+ break;
210
+ case "Node":
211
+ pattern.pattern.compile(code, literals, captures);
212
+ break;
213
+ case "Obscured":
214
+ pattern.pattern.compile(code, literals, captures);
215
+ break;
216
+ case "Wrapped":
217
+ pattern.pattern.compile(code, literals, captures);
218
+ break;
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Checks if a structure pattern is complex.
224
+ */
225
+ export function structurePatternIsComplex(pattern: StructurePattern): boolean {
226
+ switch (pattern.type) {
227
+ case "Leaf":
228
+ return pattern.pattern.isComplex();
229
+ case "Subject":
230
+ return pattern.pattern.isComplex();
231
+ case "Predicate":
232
+ return pattern.pattern.isComplex();
233
+ case "Object":
234
+ return pattern.pattern.isComplex();
235
+ case "Assertions":
236
+ return pattern.pattern.isComplex();
237
+ case "Digest":
238
+ return pattern.pattern.isComplex();
239
+ case "Node":
240
+ return pattern.pattern.isComplex();
241
+ case "Obscured":
242
+ return pattern.pattern.isComplex();
243
+ case "Wrapped":
244
+ return pattern.pattern.isComplex();
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Converts a structure pattern to string.
250
+ */
251
+ export function structurePatternToString(pattern: StructurePattern): string {
252
+ switch (pattern.type) {
253
+ case "Leaf":
254
+ return pattern.pattern.toString();
255
+ case "Subject":
256
+ return pattern.pattern.toString();
257
+ case "Predicate":
258
+ return pattern.pattern.toString();
259
+ case "Object":
260
+ return pattern.pattern.toString();
261
+ case "Assertions":
262
+ return pattern.pattern.toString();
263
+ case "Digest":
264
+ return pattern.pattern.toString();
265
+ case "Node":
266
+ return pattern.pattern.toString();
267
+ case "Obscured":
268
+ return pattern.pattern.toString();
269
+ case "Wrapped":
270
+ return pattern.pattern.toString();
271
+ }
272
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Leaf structure pattern matching
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust leaf_structure_pattern.rs
5
+ *
6
+ * @module envelope-pattern/pattern/structure/leaf-structure-pattern
7
+ */
8
+
9
+ import type { Envelope } from "@bcts/envelope";
10
+ import type { Path } from "../../format";
11
+ import type { Matcher } from "../matcher";
12
+ import { compileAsAtomic } from "../matcher";
13
+ import type { Instr } from "../vm";
14
+ import type { Pattern } from "../index";
15
+
16
+ // Forward declaration for Pattern factory
17
+ let createStructureLeafPattern: ((pattern: LeafStructurePattern) => Pattern) | undefined;
18
+
19
+ export function registerLeafStructurePatternFactory(
20
+ factory: (pattern: LeafStructurePattern) => Pattern,
21
+ ): void {
22
+ createStructureLeafPattern = factory;
23
+ }
24
+
25
+ /**
26
+ * Pattern for matching leaf envelopes (terminal nodes in the envelope tree).
27
+ *
28
+ * Corresponds to the Rust `LeafStructurePattern` struct in leaf_structure_pattern.rs
29
+ */
30
+ export class LeafStructurePattern implements Matcher {
31
+ private constructor() {
32
+ // Empty constructor - LeafStructurePattern is a singleton-like pattern with no state
33
+ }
34
+
35
+ /**
36
+ * Creates a new LeafStructurePattern.
37
+ */
38
+ static new(): LeafStructurePattern {
39
+ return new LeafStructurePattern();
40
+ }
41
+
42
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
43
+ const envCase = haystack.case();
44
+ const isLeafOrKnownValue = envCase.type === "leaf" || envCase.type === "knownValue";
45
+ const paths = isLeafOrKnownValue ? [[haystack]] : [];
46
+ return [paths, new Map<string, Path[]>()];
47
+ }
48
+
49
+ paths(haystack: Envelope): Path[] {
50
+ return this.pathsWithCaptures(haystack)[0];
51
+ }
52
+
53
+ matches(haystack: Envelope): boolean {
54
+ return this.paths(haystack).length > 0;
55
+ }
56
+
57
+ compile(code: Instr[], literals: Pattern[], captures: string[]): void {
58
+ if (createStructureLeafPattern === undefined) {
59
+ throw new Error("LeafStructurePattern factory not registered");
60
+ }
61
+ compileAsAtomic(createStructureLeafPattern(this), code, literals, captures);
62
+ }
63
+
64
+ isComplex(): boolean {
65
+ return false;
66
+ }
67
+
68
+ toString(): string {
69
+ return "leaf";
70
+ }
71
+
72
+ /**
73
+ * Equality comparison.
74
+ */
75
+ equals(_other: LeafStructurePattern): boolean {
76
+ return true; // All LeafStructurePattern instances are equal
77
+ }
78
+
79
+ /**
80
+ * Hash code for use in Maps/Sets.
81
+ */
82
+ hashCode(): number {
83
+ return 0;
84
+ }
85
+ }
@@ -0,0 +1,188 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Node pattern matching
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust node_pattern.rs
5
+ *
6
+ * @module envelope-pattern/pattern/structure/node-pattern
7
+ */
8
+
9
+ import type { Envelope } from "@bcts/envelope";
10
+ import { Interval } from "@bcts/dcbor-pattern";
11
+ import type { Path } from "../../format";
12
+ import type { Matcher } from "../matcher";
13
+ import { compileAsAtomic } from "../matcher";
14
+ import type { Instr } from "../vm";
15
+ import type { Pattern } from "../index";
16
+
17
+ // Forward declaration for Pattern factory
18
+ let createStructureNodePattern: ((pattern: NodePattern) => Pattern) | undefined;
19
+
20
+ export function registerNodePatternFactory(factory: (pattern: NodePattern) => Pattern): void {
21
+ createStructureNodePattern = factory;
22
+ }
23
+
24
+ /**
25
+ * Pattern type for node pattern matching.
26
+ *
27
+ * Corresponds to the Rust `NodePattern` enum in node_pattern.rs
28
+ */
29
+ export type NodePatternType =
30
+ | { readonly type: "Any" }
31
+ | { readonly type: "AssertionsInterval"; readonly interval: Interval }
32
+ | { readonly type: "WithSubject"; readonly subjectPattern: Pattern };
33
+
34
+ /**
35
+ * Pattern for matching node envelopes.
36
+ *
37
+ * Corresponds to the Rust `NodePattern` enum in node_pattern.rs
38
+ */
39
+ export class NodePattern implements Matcher {
40
+ readonly #pattern: NodePatternType;
41
+
42
+ private constructor(pattern: NodePatternType) {
43
+ this.#pattern = pattern;
44
+ }
45
+
46
+ /**
47
+ * Creates a new NodePattern that matches any node.
48
+ */
49
+ static any(): NodePattern {
50
+ return new NodePattern({ type: "Any" });
51
+ }
52
+
53
+ /**
54
+ * Creates a new NodePattern that matches a node with the specified count of assertions.
55
+ */
56
+ static interval(min: number, max?: number): NodePattern {
57
+ const interval = max !== undefined ? Interval.from(min, max) : Interval.atLeast(min);
58
+ return new NodePattern({ type: "AssertionsInterval", interval });
59
+ }
60
+
61
+ /**
62
+ * Creates a new NodePattern from an Interval.
63
+ */
64
+ static fromInterval(interval: Interval): NodePattern {
65
+ return new NodePattern({ type: "AssertionsInterval", interval });
66
+ }
67
+
68
+ /**
69
+ * Creates a new NodePattern with a subject pattern constraint.
70
+ */
71
+ static withSubject(subjectPattern: Pattern): NodePattern {
72
+ return new NodePattern({ type: "WithSubject", subjectPattern });
73
+ }
74
+
75
+ /**
76
+ * Gets the pattern type.
77
+ */
78
+ get patternType(): NodePatternType {
79
+ return this.#pattern;
80
+ }
81
+
82
+ /**
83
+ * Gets the subject pattern if this is a WithSubject type, undefined otherwise.
84
+ */
85
+ subjectPattern(): Pattern | undefined {
86
+ return this.#pattern.type === "WithSubject" ? this.#pattern.subjectPattern : undefined;
87
+ }
88
+
89
+ /**
90
+ * Gets the assertion patterns (empty array if none).
91
+ */
92
+ assertionPatterns(): Pattern[] {
93
+ // NodePattern doesn't support assertion patterns directly; return empty array
94
+ return [];
95
+ }
96
+
97
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
98
+ if (!haystack.isNode()) {
99
+ return [[], new Map<string, Path[]>()];
100
+ }
101
+
102
+ let isHit = false;
103
+
104
+ switch (this.#pattern.type) {
105
+ case "Any":
106
+ isHit = true;
107
+ break;
108
+ case "AssertionsInterval":
109
+ isHit = this.#pattern.interval.contains(haystack.assertions().length);
110
+ break;
111
+ case "WithSubject":
112
+ // For WithSubject, we match if the node exists (subject pattern matching done at higher level)
113
+ isHit = true;
114
+ break;
115
+ }
116
+
117
+ const paths = isHit ? [[haystack]] : [];
118
+ return [paths, new Map<string, Path[]>()];
119
+ }
120
+
121
+ paths(haystack: Envelope): Path[] {
122
+ return this.pathsWithCaptures(haystack)[0];
123
+ }
124
+
125
+ matches(haystack: Envelope): boolean {
126
+ return this.paths(haystack).length > 0;
127
+ }
128
+
129
+ compile(code: Instr[], literals: Pattern[], captures: string[]): void {
130
+ if (createStructureNodePattern === undefined) {
131
+ throw new Error("NodePattern factory not registered");
132
+ }
133
+ compileAsAtomic(createStructureNodePattern(this), code, literals, captures);
134
+ }
135
+
136
+ isComplex(): boolean {
137
+ return false;
138
+ }
139
+
140
+ toString(): string {
141
+ switch (this.#pattern.type) {
142
+ case "Any":
143
+ return "node";
144
+ case "AssertionsInterval":
145
+ return `node(${this.#pattern.interval.toString()})`;
146
+ case "WithSubject":
147
+ return `node(${(this.#pattern.subjectPattern as unknown as { toString(): string }).toString()})`;
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Equality comparison.
153
+ */
154
+ equals(other: NodePattern): boolean {
155
+ if (this.#pattern.type !== other.#pattern.type) {
156
+ return false;
157
+ }
158
+ switch (this.#pattern.type) {
159
+ case "Any":
160
+ return true;
161
+ case "AssertionsInterval":
162
+ return this.#pattern.interval.equals(
163
+ (other.#pattern as { type: "AssertionsInterval"; interval: Interval }).interval,
164
+ );
165
+ case "WithSubject":
166
+ // Simple reference equality for pattern (could be improved with deep equality)
167
+ return (
168
+ this.#pattern.subjectPattern ===
169
+ (other.#pattern as { type: "WithSubject"; subjectPattern: Pattern }).subjectPattern
170
+ );
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Hash code for use in Maps/Sets.
176
+ */
177
+ hashCode(): number {
178
+ switch (this.#pattern.type) {
179
+ case "Any":
180
+ return 0;
181
+ case "AssertionsInterval":
182
+ // Simple hash based on interval min/max
183
+ return this.#pattern.interval.min() * 31 + (this.#pattern.interval.max() ?? 0);
184
+ case "WithSubject":
185
+ return 1;
186
+ }
187
+ }
188
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Object pattern matching
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust object_pattern.rs
5
+ *
6
+ * @module envelope-pattern/pattern/structure/object-pattern
7
+ */
8
+
9
+ import type { Envelope } from "@bcts/envelope";
10
+ import type { Path } from "../../format";
11
+ import type { Matcher } from "../matcher";
12
+ import type { Instr } from "../vm";
13
+ import type { Pattern } from "../index";
14
+
15
+ // Forward declaration for Pattern factory
16
+ let createStructureObjectPattern: ((pattern: ObjectPattern) => Pattern) | undefined;
17
+
18
+ export function registerObjectPatternFactory(factory: (pattern: ObjectPattern) => Pattern): void {
19
+ createStructureObjectPattern = factory;
20
+ }
21
+
22
+ /**
23
+ * Pattern type for object pattern matching.
24
+ *
25
+ * Corresponds to the Rust `ObjectPattern` enum in object_pattern.rs
26
+ */
27
+ export type ObjectPatternType =
28
+ | { readonly type: "Any" }
29
+ | { readonly type: "Pattern"; readonly pattern: Pattern };
30
+
31
+ /**
32
+ * Pattern for matching objects in envelopes.
33
+ *
34
+ * Corresponds to the Rust `ObjectPattern` enum in object_pattern.rs
35
+ */
36
+ export class ObjectPattern implements Matcher {
37
+ readonly #pattern: ObjectPatternType;
38
+
39
+ private constructor(pattern: ObjectPatternType) {
40
+ this.#pattern = pattern;
41
+ }
42
+
43
+ /**
44
+ * Creates a new ObjectPattern that matches any object.
45
+ */
46
+ static any(): ObjectPattern {
47
+ return new ObjectPattern({ type: "Any" });
48
+ }
49
+
50
+ /**
51
+ * Creates a new ObjectPattern that matches objects matching the given pattern.
52
+ */
53
+ static pattern(pattern: Pattern): ObjectPattern {
54
+ return new ObjectPattern({ type: "Pattern", pattern });
55
+ }
56
+
57
+ /**
58
+ * Gets the pattern type.
59
+ */
60
+ get patternType(): ObjectPatternType {
61
+ return this.#pattern;
62
+ }
63
+
64
+ /**
65
+ * Gets the inner pattern if this is a Pattern type, undefined otherwise.
66
+ */
67
+ innerPattern(): Pattern | undefined {
68
+ return this.#pattern.type === "Pattern" ? this.#pattern.pattern : undefined;
69
+ }
70
+
71
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
72
+ const object = haystack.asObject?.();
73
+
74
+ if (object === undefined) {
75
+ return [[], new Map<string, Path[]>()];
76
+ }
77
+
78
+ let paths: Path[];
79
+
80
+ switch (this.#pattern.type) {
81
+ case "Any":
82
+ paths = [[object]];
83
+ break;
84
+ case "Pattern": {
85
+ const innerMatcher = this.#pattern.pattern as unknown as Matcher;
86
+ if (innerMatcher.matches(object)) {
87
+ paths = [[object]];
88
+ } else {
89
+ paths = [];
90
+ }
91
+ break;
92
+ }
93
+ }
94
+
95
+ return [paths, new Map<string, Path[]>()];
96
+ }
97
+
98
+ paths(haystack: Envelope): Path[] {
99
+ return this.pathsWithCaptures(haystack)[0];
100
+ }
101
+
102
+ matches(haystack: Envelope): boolean {
103
+ return this.paths(haystack).length > 0;
104
+ }
105
+
106
+ compile(code: Instr[], literals: Pattern[], _captures: string[]): void {
107
+ if (createStructureObjectPattern === undefined) {
108
+ throw new Error("ObjectPattern factory not registered");
109
+ }
110
+ const idx = literals.length;
111
+ literals.push(createStructureObjectPattern(this));
112
+ code.push({ type: "MatchStructure", literalIndex: idx });
113
+ }
114
+
115
+ isComplex(): boolean {
116
+ return false;
117
+ }
118
+
119
+ toString(): string {
120
+ switch (this.#pattern.type) {
121
+ case "Any":
122
+ return "obj";
123
+ case "Pattern":
124
+ return `obj(${(this.#pattern.pattern as unknown as { toString(): string }).toString()})`;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Equality comparison.
130
+ */
131
+ equals(other: ObjectPattern): boolean {
132
+ if (this.#pattern.type !== other.#pattern.type) {
133
+ return false;
134
+ }
135
+ if (this.#pattern.type === "Any") {
136
+ return true;
137
+ }
138
+ const thisPattern = (this.#pattern as { type: "Pattern"; pattern: Pattern }).pattern;
139
+ const otherPattern = (other.#pattern as { type: "Pattern"; pattern: Pattern }).pattern;
140
+ return thisPattern === otherPattern;
141
+ }
142
+
143
+ /**
144
+ * Hash code for use in Maps/Sets.
145
+ */
146
+ hashCode(): number {
147
+ return this.#pattern.type === "Any" ? 0 : 1;
148
+ }
149
+ }