@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.
- package/README.md +1 -1
- package/dist/index.cjs +1992 -1714
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +147 -31
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +147 -31
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +1984 -1707
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +1966 -1698
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
- package/src/format.ts +32 -13
- package/src/parse/index.ts +138 -5
- package/src/parse/token.ts +59 -58
- package/src/pattern/index.ts +110 -2
- package/src/pattern/leaf/array-pattern.ts +26 -26
- package/src/pattern/leaf/bool-pattern.ts +12 -12
- package/src/pattern/leaf/byte-string-pattern.ts +15 -15
- package/src/pattern/leaf/cbor-pattern.ts +31 -31
- package/src/pattern/leaf/date-pattern.ts +9 -9
- package/src/pattern/leaf/index.ts +1 -2
- package/src/pattern/leaf/known-value-pattern.ts +21 -20
- package/src/pattern/leaf/map-pattern.ts +14 -14
- package/src/pattern/leaf/null-pattern.ts +8 -8
- package/src/pattern/leaf/number-pattern.ts +20 -20
- package/src/pattern/leaf/tagged-pattern.ts +20 -20
- package/src/pattern/leaf/text-pattern.ts +14 -14
- package/src/pattern/matcher.ts +88 -3
- package/src/pattern/meta/and-pattern.ts +19 -18
- package/src/pattern/meta/capture-pattern.ts +16 -17
- package/src/pattern/meta/group-pattern.ts +20 -17
- package/src/pattern/meta/not-pattern.ts +9 -8
- package/src/pattern/meta/or-pattern.ts +30 -25
- package/src/pattern/meta/search-pattern.ts +17 -17
- package/src/pattern/meta/traverse-pattern.ts +42 -18
- package/src/pattern/structure/assertions-pattern.ts +31 -32
- package/src/pattern/structure/digest-pattern.ts +23 -23
- package/src/pattern/structure/index.ts +1 -0
- package/src/pattern/structure/node-pattern.ts +17 -17
- package/src/pattern/structure/object-pattern.ts +14 -15
- package/src/pattern/structure/obscured-pattern.ts +7 -7
- package/src/pattern/structure/predicate-pattern.ts +14 -15
- package/src/pattern/structure/subject-pattern.ts +16 -17
- package/src/pattern/structure/wrapped-pattern.ts +40 -19
- package/src/pattern/vm.ts +12 -11
package/src/pattern/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
|
|
20
20
|
import type { Path } from "../format";
|
|
21
21
|
import type { Instr } from "./vm";
|
|
22
|
+
import { compile, run } from "./vm";
|
|
22
23
|
|
|
23
24
|
// Re-export sub-modules
|
|
24
25
|
export * from "./leaf";
|
|
@@ -104,6 +105,7 @@ import {
|
|
|
104
105
|
registerNodePatternFactory,
|
|
105
106
|
registerObscuredPatternFactory,
|
|
106
107
|
registerWrappedPatternFactory,
|
|
108
|
+
registerWrappedPatternDispatch,
|
|
107
109
|
} from "./structure";
|
|
108
110
|
|
|
109
111
|
// Import meta patterns
|
|
@@ -176,13 +178,57 @@ export function patternMeta(meta: MetaPattern): Pattern {
|
|
|
176
178
|
// Pattern Matcher Implementation
|
|
177
179
|
// ============================================================================
|
|
178
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Check if a pattern requires the VM for execution.
|
|
183
|
+
* Patterns containing Group (repeat), Traverse, or Search require compilation.
|
|
184
|
+
*/
|
|
185
|
+
function patternNeedsVM(pattern: Pattern): boolean {
|
|
186
|
+
switch (pattern.type) {
|
|
187
|
+
case "Leaf":
|
|
188
|
+
case "Structure":
|
|
189
|
+
return false;
|
|
190
|
+
case "Meta":
|
|
191
|
+
return metaPatternNeedsVM(pattern.pattern);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function metaPatternNeedsVM(pattern: MetaPattern): boolean {
|
|
196
|
+
switch (pattern.type) {
|
|
197
|
+
case "Any":
|
|
198
|
+
return false;
|
|
199
|
+
case "And":
|
|
200
|
+
return pattern.pattern.patterns().some(patternNeedsVM);
|
|
201
|
+
case "Or":
|
|
202
|
+
return pattern.pattern.patterns().some(patternNeedsVM);
|
|
203
|
+
case "Not":
|
|
204
|
+
return patternNeedsVM(pattern.pattern.pattern());
|
|
205
|
+
case "Capture":
|
|
206
|
+
return patternNeedsVM(pattern.pattern.pattern());
|
|
207
|
+
case "Search":
|
|
208
|
+
case "Traverse":
|
|
209
|
+
return true;
|
|
210
|
+
case "Group": {
|
|
211
|
+
// Group with exactly(1) is simple pass-through, doesn't need VM
|
|
212
|
+
const q = pattern.pattern.quantifier();
|
|
213
|
+
if (q.min() === 1 && q.max() === 1) {
|
|
214
|
+
return patternNeedsVM(pattern.pattern.pattern());
|
|
215
|
+
}
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
179
221
|
/**
|
|
180
222
|
* Gets paths with captures for a pattern.
|
|
223
|
+
* Routes through the VM for complex patterns that require compilation.
|
|
181
224
|
*/
|
|
182
225
|
export function patternPathsWithCaptures(
|
|
183
226
|
pattern: Pattern,
|
|
184
227
|
haystack: Envelope,
|
|
185
228
|
): [Path[], Map<string, Path[]>] {
|
|
229
|
+
if (patternNeedsVM(pattern)) {
|
|
230
|
+
return patternPathsWithCapturesViaVM(pattern, haystack);
|
|
231
|
+
}
|
|
186
232
|
switch (pattern.type) {
|
|
187
233
|
case "Leaf":
|
|
188
234
|
return leafPatternPathsWithCaptures(pattern.pattern, haystack);
|
|
@@ -193,6 +239,31 @@ export function patternPathsWithCaptures(
|
|
|
193
239
|
}
|
|
194
240
|
}
|
|
195
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Execute a pattern through the VM, merging results.
|
|
244
|
+
*/
|
|
245
|
+
function patternPathsWithCapturesViaVM(
|
|
246
|
+
pattern: Pattern,
|
|
247
|
+
haystack: Envelope,
|
|
248
|
+
): [Path[], Map<string, Path[]>] {
|
|
249
|
+
const prog = compile(pattern);
|
|
250
|
+
const results = run(prog, haystack);
|
|
251
|
+
|
|
252
|
+
const allPaths: Path[] = [];
|
|
253
|
+
const mergedCaptures = new Map<string, Path[]>();
|
|
254
|
+
|
|
255
|
+
for (const [path, captures] of results) {
|
|
256
|
+
allPaths.push(path);
|
|
257
|
+
for (const [name, paths] of captures) {
|
|
258
|
+
const existing = mergedCaptures.get(name) ?? [];
|
|
259
|
+
existing.push(...paths);
|
|
260
|
+
mergedCaptures.set(name, existing);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return [allPaths, mergedCaptures];
|
|
265
|
+
}
|
|
266
|
+
|
|
196
267
|
/**
|
|
197
268
|
* Gets paths for a pattern.
|
|
198
269
|
*/
|
|
@@ -347,6 +418,27 @@ export function dateRange(earliest: CborDate, latest: CborDate): Pattern {
|
|
|
347
418
|
return patternLeaf(leafDate(DatePattern.range(earliest, latest)));
|
|
348
419
|
}
|
|
349
420
|
|
|
421
|
+
/**
|
|
422
|
+
* Creates a new Pattern that matches Date values on or after the specified date.
|
|
423
|
+
*/
|
|
424
|
+
export function dateEarliest(d: CborDate): Pattern {
|
|
425
|
+
return patternLeaf(leafDate(DatePattern.earliest(d)));
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Creates a new Pattern that matches Date values on or before the specified date.
|
|
430
|
+
*/
|
|
431
|
+
export function dateLatest(d: CborDate): Pattern {
|
|
432
|
+
return patternLeaf(leafDate(DatePattern.latest(d)));
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Creates a new Pattern that matches Date values whose ISO-8601 string matches the regex.
|
|
437
|
+
*/
|
|
438
|
+
export function dateRegex(pattern: RegExp): Pattern {
|
|
439
|
+
return patternLeaf(leafDate(DatePattern.regex(pattern)));
|
|
440
|
+
}
|
|
441
|
+
|
|
350
442
|
/**
|
|
351
443
|
* Creates a new Pattern that matches any number value.
|
|
352
444
|
*/
|
|
@@ -700,6 +792,11 @@ function registerAllFactories(): void {
|
|
|
700
792
|
registerNodePatternFactory((p) => patternStructure(structureNode(p)));
|
|
701
793
|
registerObscuredPatternFactory((p) => patternStructure(structureObscured(p)));
|
|
702
794
|
registerWrappedPatternFactory((p) => patternStructure(structureWrapped(p)));
|
|
795
|
+
registerWrappedPatternDispatch({
|
|
796
|
+
pathsWithCaptures: patternPathsWithCaptures,
|
|
797
|
+
compile: patternCompile,
|
|
798
|
+
toString: patternToString,
|
|
799
|
+
});
|
|
703
800
|
|
|
704
801
|
// Meta pattern factories
|
|
705
802
|
registerAnyPatternFactory((p) => patternMeta(metaAny(p)));
|
|
@@ -719,6 +816,17 @@ registerAllFactories();
|
|
|
719
816
|
import { registerVMPatternFunctions } from "./vm";
|
|
720
817
|
registerVMPatternFunctions(patternPathsWithCaptures, patternMatches, patternPaths);
|
|
721
818
|
|
|
722
|
-
// Register pattern
|
|
723
|
-
import { registerPatternMatchFn } from "./matcher";
|
|
819
|
+
// Register pattern dispatch functions for meta patterns
|
|
820
|
+
import { registerPatternMatchFn, registerPatternDispatchFns } from "./matcher";
|
|
724
821
|
registerPatternMatchFn(patternMatches);
|
|
822
|
+
registerPatternDispatchFns({
|
|
823
|
+
pathsWithCaptures: patternPathsWithCaptures,
|
|
824
|
+
paths: patternPaths,
|
|
825
|
+
compile: patternCompile,
|
|
826
|
+
isComplex: patternIsComplex,
|
|
827
|
+
toString: patternToString,
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
// Register traverse dispatch functions to resolve circular dependencies
|
|
831
|
+
import { registerTraverseDispatchFunctions } from "./meta/traverse-pattern";
|
|
832
|
+
registerTraverseDispatchFunctions(patternPathsWithCaptures, patternCompile, patternIsComplex);
|
|
@@ -44,10 +44,10 @@ export type ArrayPatternType =
|
|
|
44
44
|
* Corresponds to the Rust `ArrayPattern` struct in array_pattern.rs
|
|
45
45
|
*/
|
|
46
46
|
export class ArrayPattern implements Matcher {
|
|
47
|
-
readonly
|
|
47
|
+
private readonly _pattern: ArrayPatternType;
|
|
48
48
|
|
|
49
49
|
private constructor(pattern: ArrayPatternType) {
|
|
50
|
-
this
|
|
50
|
+
this._pattern = pattern;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/**
|
|
@@ -93,12 +93,12 @@ export class ArrayPattern implements Matcher {
|
|
|
93
93
|
* Gets the pattern type.
|
|
94
94
|
*/
|
|
95
95
|
get pattern(): ArrayPatternType {
|
|
96
|
-
return this
|
|
96
|
+
return this._pattern;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
100
100
|
// Try to extract CBOR from the envelope
|
|
101
|
-
const cbor = haystack.asLeaf();
|
|
101
|
+
const cbor = haystack.subject().asLeaf();
|
|
102
102
|
if (cbor === undefined) {
|
|
103
103
|
return [[], new Map<string, Path[]>()];
|
|
104
104
|
}
|
|
@@ -109,13 +109,13 @@ export class ArrayPattern implements Matcher {
|
|
|
109
109
|
return [[], new Map<string, Path[]>()];
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
switch (this
|
|
112
|
+
switch (this._pattern.type) {
|
|
113
113
|
case "Any":
|
|
114
114
|
return [[[haystack]], new Map<string, Path[]>()];
|
|
115
115
|
|
|
116
116
|
case "Interval": {
|
|
117
117
|
const length = array.length;
|
|
118
|
-
if (this
|
|
118
|
+
if (this._pattern.interval.contains(length)) {
|
|
119
119
|
return [[[haystack]], new Map<string, Path[]>()];
|
|
120
120
|
}
|
|
121
121
|
return [[], new Map<string, Path[]>()];
|
|
@@ -124,7 +124,7 @@ export class ArrayPattern implements Matcher {
|
|
|
124
124
|
case "DCBORPattern": {
|
|
125
125
|
// Delegate to dcbor-pattern for matching
|
|
126
126
|
const { paths: dcborPaths, captures: dcborCaptures } = dcborPatternPathsWithCaptures(
|
|
127
|
-
this
|
|
127
|
+
this._pattern.pattern,
|
|
128
128
|
cbor,
|
|
129
129
|
);
|
|
130
130
|
|
|
@@ -167,7 +167,7 @@ export class ArrayPattern implements Matcher {
|
|
|
167
167
|
case "WithPatterns":
|
|
168
168
|
// For envelope patterns, match if array length equals patterns count
|
|
169
169
|
// Full element-by-element matching would require additional implementation
|
|
170
|
-
if (array.length === this
|
|
170
|
+
if (array.length === this._pattern.patterns.length) {
|
|
171
171
|
return [[[haystack]], new Map<string, Path[]>()];
|
|
172
172
|
}
|
|
173
173
|
return [[], new Map<string, Path[]>()];
|
|
@@ -194,15 +194,15 @@ export class ArrayPattern implements Matcher {
|
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
toString(): string {
|
|
197
|
-
switch (this
|
|
197
|
+
switch (this._pattern.type) {
|
|
198
198
|
case "Any":
|
|
199
199
|
return "[*]";
|
|
200
200
|
case "Interval":
|
|
201
|
-
return `[{${this
|
|
201
|
+
return `[{${this._pattern.interval.toString()}}]`;
|
|
202
202
|
case "DCBORPattern":
|
|
203
|
-
return dcborPatternDisplay(this
|
|
203
|
+
return dcborPatternDisplay(this._pattern.pattern);
|
|
204
204
|
case "WithPatterns":
|
|
205
|
-
return `[${this
|
|
205
|
+
return `[${this._pattern.patterns.map(String).join(", ")}]`;
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
@@ -210,30 +210,30 @@ export class ArrayPattern implements Matcher {
|
|
|
210
210
|
* Equality comparison.
|
|
211
211
|
*/
|
|
212
212
|
equals(other: ArrayPattern): boolean {
|
|
213
|
-
if (this
|
|
213
|
+
if (this._pattern.type !== other._pattern.type) {
|
|
214
214
|
return false;
|
|
215
215
|
}
|
|
216
|
-
switch (this
|
|
216
|
+
switch (this._pattern.type) {
|
|
217
217
|
case "Any":
|
|
218
218
|
return true;
|
|
219
219
|
case "Interval":
|
|
220
|
-
return this
|
|
221
|
-
(other
|
|
220
|
+
return this._pattern.interval.equals(
|
|
221
|
+
(other._pattern as { type: "Interval"; interval: Interval }).interval,
|
|
222
222
|
);
|
|
223
223
|
case "DCBORPattern":
|
|
224
224
|
// Compare using display representation
|
|
225
225
|
return (
|
|
226
|
-
dcborPatternDisplay(this
|
|
226
|
+
dcborPatternDisplay(this._pattern.pattern) ===
|
|
227
227
|
dcborPatternDisplay(
|
|
228
|
-
(other
|
|
228
|
+
(other._pattern as { type: "DCBORPattern"; pattern: DCBORPattern }).pattern,
|
|
229
229
|
)
|
|
230
230
|
);
|
|
231
231
|
case "WithPatterns": {
|
|
232
|
-
const otherPatterns = (other
|
|
232
|
+
const otherPatterns = (other._pattern as { type: "WithPatterns"; patterns: Pattern[] })
|
|
233
233
|
.patterns;
|
|
234
|
-
if (this
|
|
235
|
-
for (let i = 0; i < this
|
|
236
|
-
if (this
|
|
234
|
+
if (this._pattern.patterns.length !== otherPatterns.length) return false;
|
|
235
|
+
for (let i = 0; i < this._pattern.patterns.length; i++) {
|
|
236
|
+
if (this._pattern.patterns[i] !== otherPatterns[i]) return false;
|
|
237
237
|
}
|
|
238
238
|
return true;
|
|
239
239
|
}
|
|
@@ -244,17 +244,17 @@ export class ArrayPattern implements Matcher {
|
|
|
244
244
|
* Hash code for use in Maps/Sets.
|
|
245
245
|
*/
|
|
246
246
|
hashCode(): number {
|
|
247
|
-
switch (this
|
|
247
|
+
switch (this._pattern.type) {
|
|
248
248
|
case "Any":
|
|
249
249
|
return 0;
|
|
250
250
|
case "Interval":
|
|
251
251
|
// Simple hash based on min/max
|
|
252
|
-
return this
|
|
252
|
+
return this._pattern.interval.min() * 31 + (this._pattern.interval.max() ?? 0);
|
|
253
253
|
case "DCBORPattern":
|
|
254
254
|
// Simple hash based on display string
|
|
255
|
-
return simpleStringHash(dcborPatternDisplay(this
|
|
255
|
+
return simpleStringHash(dcborPatternDisplay(this._pattern.pattern));
|
|
256
256
|
case "WithPatterns":
|
|
257
|
-
return this
|
|
257
|
+
return this._pattern.patterns.length;
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
}
|
|
@@ -36,10 +36,10 @@ export function registerBoolPatternFactory(factory: (pattern: BoolPattern) => Pa
|
|
|
36
36
|
* Corresponds to the Rust `BoolPattern` struct in bool_pattern.rs
|
|
37
37
|
*/
|
|
38
38
|
export class BoolPattern implements Matcher {
|
|
39
|
-
readonly
|
|
39
|
+
private readonly _inner: DCBORBoolPattern;
|
|
40
40
|
|
|
41
41
|
private constructor(inner: DCBORBoolPattern) {
|
|
42
|
-
this
|
|
42
|
+
this._inner = inner;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -67,15 +67,15 @@ export class BoolPattern implements Matcher {
|
|
|
67
67
|
* Gets the underlying dcbor-pattern BoolPattern.
|
|
68
68
|
*/
|
|
69
69
|
get inner(): DCBORBoolPattern {
|
|
70
|
-
return this
|
|
70
|
+
return this._inner;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
74
74
|
// For leaf envelopes, extract the CBOR and delegate to dcbor-pattern
|
|
75
|
-
const cbor = haystack.asLeaf();
|
|
75
|
+
const cbor = haystack.subject().asLeaf();
|
|
76
76
|
if (cbor !== undefined) {
|
|
77
77
|
// Delegate to dcbor-pattern for CBOR matching
|
|
78
|
-
const dcborPaths = dcborBoolPatternPaths(this
|
|
78
|
+
const dcborPaths = dcborBoolPatternPaths(this._inner, cbor);
|
|
79
79
|
|
|
80
80
|
// For simple leaf patterns, if dcbor-pattern found matches, return the envelope
|
|
81
81
|
if (dcborPaths.length > 0) {
|
|
@@ -109,7 +109,7 @@ export class BoolPattern implements Matcher {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
toString(): string {
|
|
112
|
-
return boolPatternDisplay(this
|
|
112
|
+
return boolPatternDisplay(this._inner);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/**
|
|
@@ -117,11 +117,11 @@ export class BoolPattern implements Matcher {
|
|
|
117
117
|
*/
|
|
118
118
|
equals(other: BoolPattern): boolean {
|
|
119
119
|
// Compare by variant and value
|
|
120
|
-
if (this
|
|
120
|
+
if (this._inner.variant !== other._inner.variant) {
|
|
121
121
|
return false;
|
|
122
122
|
}
|
|
123
|
-
if (this
|
|
124
|
-
return this
|
|
123
|
+
if (this._inner.variant === "Value" && other._inner.variant === "Value") {
|
|
124
|
+
return this._inner.value === other._inner.value;
|
|
125
125
|
}
|
|
126
126
|
return true;
|
|
127
127
|
}
|
|
@@ -131,9 +131,9 @@ export class BoolPattern implements Matcher {
|
|
|
131
131
|
*/
|
|
132
132
|
hashCode(): number {
|
|
133
133
|
// Simple hash based on variant and value
|
|
134
|
-
let hash = this
|
|
135
|
-
if (this
|
|
136
|
-
hash = hash * 31 + (this
|
|
134
|
+
let hash = this._inner.variant === "Any" ? 0 : 1;
|
|
135
|
+
if (this._inner.variant === "Value") {
|
|
136
|
+
hash = hash * 31 + (this._inner.value ? 1 : 0);
|
|
137
137
|
}
|
|
138
138
|
return hash;
|
|
139
139
|
}
|
|
@@ -39,10 +39,10 @@ export function registerByteStringPatternFactory(
|
|
|
39
39
|
* Corresponds to the Rust `ByteStringPattern` struct in byte_string_pattern.rs
|
|
40
40
|
*/
|
|
41
41
|
export class ByteStringPattern implements Matcher {
|
|
42
|
-
readonly
|
|
42
|
+
private readonly _inner: DCBORByteStringPattern;
|
|
43
43
|
|
|
44
44
|
private constructor(inner: DCBORByteStringPattern) {
|
|
45
|
-
this
|
|
45
|
+
this._inner = inner;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
@@ -77,15 +77,15 @@ export class ByteStringPattern implements Matcher {
|
|
|
77
77
|
* Gets the underlying dcbor-pattern ByteStringPattern.
|
|
78
78
|
*/
|
|
79
79
|
get inner(): DCBORByteStringPattern {
|
|
80
|
-
return this
|
|
80
|
+
return this._inner;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
84
84
|
// For leaf envelopes, extract the CBOR and delegate to dcbor-pattern
|
|
85
|
-
const cbor = haystack.asLeaf();
|
|
85
|
+
const cbor = haystack.subject().asLeaf();
|
|
86
86
|
if (cbor !== undefined) {
|
|
87
87
|
// Delegate to dcbor-pattern for CBOR matching
|
|
88
|
-
const dcborPaths = dcborByteStringPatternPaths(this
|
|
88
|
+
const dcborPaths = dcborByteStringPatternPaths(this._inner, cbor);
|
|
89
89
|
|
|
90
90
|
// For simple leaf patterns, if dcbor-pattern found matches, return the envelope
|
|
91
91
|
if (dcborPaths.length > 0) {
|
|
@@ -117,22 +117,22 @@ export class ByteStringPattern implements Matcher {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
toString(): string {
|
|
120
|
-
return byteStringPatternDisplay(this
|
|
120
|
+
return byteStringPatternDisplay(this._inner);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
124
|
* Equality comparison.
|
|
125
125
|
*/
|
|
126
126
|
equals(other: ByteStringPattern): boolean {
|
|
127
|
-
if (this
|
|
127
|
+
if (this._inner.variant !== other._inner.variant) {
|
|
128
128
|
return false;
|
|
129
129
|
}
|
|
130
|
-
switch (this
|
|
130
|
+
switch (this._inner.variant) {
|
|
131
131
|
case "Any":
|
|
132
132
|
return true;
|
|
133
133
|
case "Value": {
|
|
134
|
-
const a = (this
|
|
135
|
-
const b = (other
|
|
134
|
+
const a = (this._inner as { value: Uint8Array }).value;
|
|
135
|
+
const b = (other._inner as { value: Uint8Array }).value;
|
|
136
136
|
if (a.length !== b.length) return false;
|
|
137
137
|
for (let i = 0; i < a.length; i++) {
|
|
138
138
|
if (a[i] !== b[i]) return false;
|
|
@@ -141,8 +141,8 @@ export class ByteStringPattern implements Matcher {
|
|
|
141
141
|
}
|
|
142
142
|
case "BinaryRegex":
|
|
143
143
|
return (
|
|
144
|
-
(this
|
|
145
|
-
(other
|
|
144
|
+
(this._inner as { pattern: RegExp }).pattern.source ===
|
|
145
|
+
(other._inner as { pattern: RegExp }).pattern.source
|
|
146
146
|
);
|
|
147
147
|
}
|
|
148
148
|
}
|
|
@@ -152,19 +152,19 @@ export class ByteStringPattern implements Matcher {
|
|
|
152
152
|
*/
|
|
153
153
|
hashCode(): number {
|
|
154
154
|
let hash = 0;
|
|
155
|
-
switch (this
|
|
155
|
+
switch (this._inner.variant) {
|
|
156
156
|
case "Any":
|
|
157
157
|
hash = 1;
|
|
158
158
|
break;
|
|
159
159
|
case "Value": {
|
|
160
|
-
const val = (this
|
|
160
|
+
const val = (this._inner as { value: Uint8Array }).value;
|
|
161
161
|
for (const byte of val) {
|
|
162
162
|
hash = hash * 31 + byte;
|
|
163
163
|
}
|
|
164
164
|
break;
|
|
165
165
|
}
|
|
166
166
|
case "BinaryRegex":
|
|
167
|
-
hash = 3 * 31 + (this
|
|
167
|
+
hash = 3 * 31 + (this._inner as { pattern: RegExp }).pattern.source.length;
|
|
168
168
|
break;
|
|
169
169
|
}
|
|
170
170
|
return hash;
|
|
@@ -43,10 +43,10 @@ export type CBORPatternType =
|
|
|
43
43
|
* Corresponds to the Rust `CBORPattern` enum in cbor_pattern.rs
|
|
44
44
|
*/
|
|
45
45
|
export class CBORPattern implements Matcher {
|
|
46
|
-
readonly
|
|
46
|
+
private readonly _pattern: CBORPatternType;
|
|
47
47
|
|
|
48
48
|
private constructor(pattern: CBORPatternType) {
|
|
49
|
-
this
|
|
49
|
+
this._pattern = pattern;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
@@ -81,13 +81,13 @@ export class CBORPattern implements Matcher {
|
|
|
81
81
|
* Gets the pattern type.
|
|
82
82
|
*/
|
|
83
83
|
get pattern(): CBORPatternType {
|
|
84
|
-
return this
|
|
84
|
+
return this._pattern;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
88
|
* Convert dcbor captures to envelope captures.
|
|
89
89
|
*/
|
|
90
|
-
|
|
90
|
+
private _convertDcborCapturesToEnvelopeCaptures(
|
|
91
91
|
dcborCaptures: Map<string, Cbor[][]>,
|
|
92
92
|
baseEnvelope: Envelope,
|
|
93
93
|
baseCbor: Cbor,
|
|
@@ -96,7 +96,7 @@ export class CBORPattern implements Matcher {
|
|
|
96
96
|
|
|
97
97
|
for (const [captureName, dcborCapturePaths] of dcborCaptures) {
|
|
98
98
|
const envelopeCapturePaths: Path[] = dcborCapturePaths.map((dcborPath) =>
|
|
99
|
-
this
|
|
99
|
+
this._convertDcborPathToEnvelopePath(dcborPath, baseEnvelope, baseCbor),
|
|
100
100
|
);
|
|
101
101
|
envelopeCaptures.set(captureName, envelopeCapturePaths);
|
|
102
102
|
}
|
|
@@ -107,7 +107,7 @@ export class CBORPattern implements Matcher {
|
|
|
107
107
|
/**
|
|
108
108
|
* Convert a single dcbor path to an envelope path.
|
|
109
109
|
*/
|
|
110
|
-
|
|
110
|
+
private _convertDcborPathToEnvelopePath(
|
|
111
111
|
dcborPath: Cbor[],
|
|
112
112
|
baseEnvelope: Envelope,
|
|
113
113
|
baseCbor: Cbor,
|
|
@@ -131,7 +131,7 @@ export class CBORPattern implements Matcher {
|
|
|
131
131
|
/**
|
|
132
132
|
* Collect capture names from a dcbor pattern.
|
|
133
133
|
*/
|
|
134
|
-
|
|
134
|
+
private _collectDcborCaptureNames(dcborPattern: DCBORPattern, names: string[]): void {
|
|
135
135
|
// Parse the pattern string to extract capture names
|
|
136
136
|
const patternStr = dcborPatternDisplay(dcborPattern);
|
|
137
137
|
|
|
@@ -156,26 +156,26 @@ export class CBORPattern implements Matcher {
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
159
|
-
const envCase = haystack.case();
|
|
159
|
+
const envCase = haystack.subject().case();
|
|
160
160
|
|
|
161
161
|
// Special case for KnownValue envelope
|
|
162
162
|
if (envCase.type === "knownValue") {
|
|
163
163
|
const knownValue = envCase.value;
|
|
164
164
|
const knownValueCbor = knownValue.taggedCbor();
|
|
165
165
|
|
|
166
|
-
switch (this
|
|
166
|
+
switch (this._pattern.type) {
|
|
167
167
|
case "Any":
|
|
168
168
|
return [[[haystack]], new Map<string, Path[]>()];
|
|
169
169
|
case "Value": {
|
|
170
170
|
// Compare using diagnostic representation
|
|
171
|
-
if (knownValueCbor.toDiagnostic() === this
|
|
171
|
+
if (knownValueCbor.toDiagnostic() === this._pattern.cbor.toDiagnostic()) {
|
|
172
172
|
return [[[haystack]], new Map<string, Path[]>()];
|
|
173
173
|
}
|
|
174
174
|
return [[], new Map<string, Path[]>()];
|
|
175
175
|
}
|
|
176
176
|
case "Pattern": {
|
|
177
177
|
const { paths: dcborPaths, captures: dcborCaptures } = dcborPatternPathsWithCaptures(
|
|
178
|
-
this
|
|
178
|
+
this._pattern.pattern,
|
|
179
179
|
knownValueCbor,
|
|
180
180
|
);
|
|
181
181
|
|
|
@@ -193,7 +193,7 @@ export class CBORPattern implements Matcher {
|
|
|
193
193
|
return extendedPath;
|
|
194
194
|
});
|
|
195
195
|
|
|
196
|
-
const envelopeCaptures = this
|
|
196
|
+
const envelopeCaptures = this._convertDcborCapturesToEnvelopeCaptures(
|
|
197
197
|
dcborCaptures,
|
|
198
198
|
haystack,
|
|
199
199
|
knownValueCbor,
|
|
@@ -206,25 +206,25 @@ export class CBORPattern implements Matcher {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
// Standard case for CBOR leaf
|
|
209
|
-
const leafCbor = haystack.asLeaf();
|
|
209
|
+
const leafCbor = haystack.subject().asLeaf();
|
|
210
210
|
if (leafCbor === undefined) {
|
|
211
211
|
return [[], new Map<string, Path[]>()];
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
switch (this
|
|
214
|
+
switch (this._pattern.type) {
|
|
215
215
|
case "Any":
|
|
216
216
|
return [[[haystack]], new Map<string, Path[]>()];
|
|
217
217
|
|
|
218
218
|
case "Value":
|
|
219
219
|
// Compare using diagnostic representation
|
|
220
|
-
if (leafCbor.toDiagnostic() === this
|
|
220
|
+
if (leafCbor.toDiagnostic() === this._pattern.cbor.toDiagnostic()) {
|
|
221
221
|
return [[[haystack]], new Map<string, Path[]>()];
|
|
222
222
|
}
|
|
223
223
|
return [[], new Map<string, Path[]>()];
|
|
224
224
|
|
|
225
225
|
case "Pattern": {
|
|
226
226
|
const { paths: dcborPaths, captures: dcborCaptures } = dcborPatternPathsWithCaptures(
|
|
227
|
-
this
|
|
227
|
+
this._pattern.pattern,
|
|
228
228
|
leafCbor,
|
|
229
229
|
);
|
|
230
230
|
|
|
@@ -245,7 +245,7 @@ export class CBORPattern implements Matcher {
|
|
|
245
245
|
return extendedPath;
|
|
246
246
|
});
|
|
247
247
|
|
|
248
|
-
const envelopeCaptures = this
|
|
248
|
+
const envelopeCaptures = this._convertDcborCapturesToEnvelopeCaptures(
|
|
249
249
|
dcborCaptures,
|
|
250
250
|
haystack,
|
|
251
251
|
leafCbor,
|
|
@@ -267,9 +267,9 @@ export class CBORPattern implements Matcher {
|
|
|
267
267
|
|
|
268
268
|
compile(code: Instr[], literals: Pattern[], captures: string[]): void {
|
|
269
269
|
// Register any capture names from this CBOR pattern
|
|
270
|
-
if (this
|
|
270
|
+
if (this._pattern.type === "Pattern") {
|
|
271
271
|
const captureNames: string[] = [];
|
|
272
|
-
this
|
|
272
|
+
this._collectDcborCaptureNames(this._pattern.pattern, captureNames);
|
|
273
273
|
for (const name of captureNames) {
|
|
274
274
|
if (!captures.includes(name)) {
|
|
275
275
|
captures.push(name);
|
|
@@ -288,13 +288,13 @@ export class CBORPattern implements Matcher {
|
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
toString(): string {
|
|
291
|
-
switch (this
|
|
291
|
+
switch (this._pattern.type) {
|
|
292
292
|
case "Any":
|
|
293
293
|
return "cbor";
|
|
294
294
|
case "Value":
|
|
295
|
-
return `cbor(${this
|
|
295
|
+
return `cbor(${this._pattern.cbor.toDiagnostic()})`;
|
|
296
296
|
case "Pattern":
|
|
297
|
-
return `cbor(/${dcborPatternDisplay(this
|
|
297
|
+
return `cbor(/${dcborPatternDisplay(this._pattern.pattern)}/)`;
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
|
|
@@ -302,24 +302,24 @@ export class CBORPattern implements Matcher {
|
|
|
302
302
|
* Equality comparison.
|
|
303
303
|
*/
|
|
304
304
|
equals(other: CBORPattern): boolean {
|
|
305
|
-
if (this
|
|
305
|
+
if (this._pattern.type !== other._pattern.type) {
|
|
306
306
|
return false;
|
|
307
307
|
}
|
|
308
|
-
switch (this
|
|
308
|
+
switch (this._pattern.type) {
|
|
309
309
|
case "Any":
|
|
310
310
|
return true;
|
|
311
311
|
case "Value":
|
|
312
312
|
// Compare using diagnostic representation
|
|
313
313
|
return (
|
|
314
|
-
this
|
|
315
|
-
(other
|
|
314
|
+
this._pattern.cbor.toDiagnostic() ===
|
|
315
|
+
(other._pattern as { type: "Value"; cbor: Cbor }).cbor.toDiagnostic()
|
|
316
316
|
);
|
|
317
317
|
case "Pattern":
|
|
318
318
|
// Compare using display representation
|
|
319
319
|
return (
|
|
320
|
-
dcborPatternDisplay(this
|
|
320
|
+
dcborPatternDisplay(this._pattern.pattern) ===
|
|
321
321
|
dcborPatternDisplay(
|
|
322
|
-
(other
|
|
322
|
+
(other._pattern as { type: "Pattern"; pattern: DCBORPattern }).pattern,
|
|
323
323
|
)
|
|
324
324
|
);
|
|
325
325
|
}
|
|
@@ -329,15 +329,15 @@ export class CBORPattern implements Matcher {
|
|
|
329
329
|
* Hash code for use in Maps/Sets.
|
|
330
330
|
*/
|
|
331
331
|
hashCode(): number {
|
|
332
|
-
switch (this
|
|
332
|
+
switch (this._pattern.type) {
|
|
333
333
|
case "Any":
|
|
334
334
|
return 0;
|
|
335
335
|
case "Value":
|
|
336
336
|
// Simple hash based on diagnostic string
|
|
337
|
-
return simpleStringHash(this
|
|
337
|
+
return simpleStringHash(this._pattern.cbor.toDiagnostic());
|
|
338
338
|
case "Pattern":
|
|
339
339
|
// Simple hash based on display string
|
|
340
|
-
return simpleStringHash(dcborPatternDisplay(this
|
|
340
|
+
return simpleStringHash(dcborPatternDisplay(this._pattern.pattern));
|
|
341
341
|
}
|
|
342
342
|
}
|
|
343
343
|
}
|