@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.
- package/LICENSE +48 -0
- package/README.md +13 -0
- package/dist/index.cjs +6781 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2628 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +2628 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.iife.js +6781 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.mjs +6545 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +77 -0
- package/src/error.ts +262 -0
- package/src/format.ts +375 -0
- package/src/index.ts +27 -0
- package/src/parse/index.ts +923 -0
- package/src/parse/token.ts +906 -0
- package/src/parse/utils.ts +339 -0
- package/src/pattern/index.ts +719 -0
- package/src/pattern/leaf/array-pattern.ts +273 -0
- package/src/pattern/leaf/bool-pattern.ts +140 -0
- package/src/pattern/leaf/byte-string-pattern.ts +172 -0
- package/src/pattern/leaf/cbor-pattern.ts +355 -0
- package/src/pattern/leaf/date-pattern.ts +178 -0
- package/src/pattern/leaf/index.ts +280 -0
- package/src/pattern/leaf/known-value-pattern.ts +192 -0
- package/src/pattern/leaf/map-pattern.ts +152 -0
- package/src/pattern/leaf/null-pattern.ts +110 -0
- package/src/pattern/leaf/number-pattern.ts +248 -0
- package/src/pattern/leaf/tagged-pattern.ts +228 -0
- package/src/pattern/leaf/text-pattern.ts +165 -0
- package/src/pattern/matcher.ts +88 -0
- package/src/pattern/meta/and-pattern.ts +109 -0
- package/src/pattern/meta/any-pattern.ts +81 -0
- package/src/pattern/meta/capture-pattern.ts +111 -0
- package/src/pattern/meta/group-pattern.ts +110 -0
- package/src/pattern/meta/index.ts +269 -0
- package/src/pattern/meta/not-pattern.ts +91 -0
- package/src/pattern/meta/or-pattern.ts +146 -0
- package/src/pattern/meta/search-pattern.ts +201 -0
- package/src/pattern/meta/traverse-pattern.ts +146 -0
- package/src/pattern/structure/assertions-pattern.ts +244 -0
- package/src/pattern/structure/digest-pattern.ts +225 -0
- package/src/pattern/structure/index.ts +272 -0
- package/src/pattern/structure/leaf-structure-pattern.ts +85 -0
- package/src/pattern/structure/node-pattern.ts +188 -0
- package/src/pattern/structure/object-pattern.ts +149 -0
- package/src/pattern/structure/obscured-pattern.ts +159 -0
- package/src/pattern/structure/predicate-pattern.ts +151 -0
- package/src/pattern/structure/subject-pattern.ts +152 -0
- package/src/pattern/structure/wrapped-pattern.ts +195 -0
- package/src/pattern/vm.ts +1021 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bcts/envelope-pattern - CBOR pattern matching
|
|
3
|
+
*
|
|
4
|
+
* This is a 1:1 TypeScript port of bc-envelope-pattern-rust cbor_pattern.rs
|
|
5
|
+
*
|
|
6
|
+
* @module envelope-pattern/pattern/leaf/cbor-pattern
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Envelope } from "@bcts/envelope";
|
|
10
|
+
import type { Cbor } from "@bcts/dcbor";
|
|
11
|
+
import { cbor as toCbor, type CborInput } from "@bcts/dcbor";
|
|
12
|
+
import {
|
|
13
|
+
type Pattern as DCBORPattern,
|
|
14
|
+
patternPathsWithCaptures as dcborPatternPathsWithCaptures,
|
|
15
|
+
patternDisplay as dcborPatternDisplay,
|
|
16
|
+
} from "@bcts/dcbor-pattern";
|
|
17
|
+
import type { Path } from "../../format";
|
|
18
|
+
import type { Matcher } from "../matcher";
|
|
19
|
+
import { compileAsAtomic } from "../matcher";
|
|
20
|
+
import type { Instr } from "../vm";
|
|
21
|
+
import type { Pattern } from "../index";
|
|
22
|
+
|
|
23
|
+
// Forward declaration for Pattern factory
|
|
24
|
+
let createLeafCBORPattern: ((pattern: CBORPattern) => Pattern) | undefined;
|
|
25
|
+
|
|
26
|
+
export function registerCBORPatternFactory(factory: (pattern: CBORPattern) => Pattern): void {
|
|
27
|
+
createLeafCBORPattern = factory;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Pattern type for CBOR pattern matching.
|
|
32
|
+
*
|
|
33
|
+
* Corresponds to the Rust `CBORPattern` enum in cbor_pattern.rs
|
|
34
|
+
*/
|
|
35
|
+
export type CBORPatternType =
|
|
36
|
+
| { readonly type: "Any" }
|
|
37
|
+
| { readonly type: "Value"; readonly cbor: Cbor }
|
|
38
|
+
| { readonly type: "Pattern"; readonly pattern: DCBORPattern };
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Pattern for matching CBOR values with support for exact values and advanced pattern matching.
|
|
42
|
+
*
|
|
43
|
+
* Corresponds to the Rust `CBORPattern` enum in cbor_pattern.rs
|
|
44
|
+
*/
|
|
45
|
+
export class CBORPattern implements Matcher {
|
|
46
|
+
readonly #pattern: CBORPatternType;
|
|
47
|
+
|
|
48
|
+
private constructor(pattern: CBORPatternType) {
|
|
49
|
+
this.#pattern = pattern;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Creates a new CBORPattern that matches any CBOR value.
|
|
54
|
+
*/
|
|
55
|
+
static any(): CBORPattern {
|
|
56
|
+
return new CBORPattern({ type: "Any" });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Creates a new CBORPattern that matches a specific CBOR value.
|
|
61
|
+
*/
|
|
62
|
+
static value(value: CborInput): CBORPattern {
|
|
63
|
+
return new CBORPattern({ type: "Value", cbor: toCbor(value) });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Creates a new CBORPattern that matches CBOR values using dcbor-pattern expressions.
|
|
68
|
+
*/
|
|
69
|
+
static pattern(dcborPattern: DCBORPattern): CBORPattern {
|
|
70
|
+
return new CBORPattern({ type: "Pattern", pattern: dcborPattern });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Creates a new CBORPattern from a dcbor-pattern Pattern.
|
|
75
|
+
*/
|
|
76
|
+
static fromDcborPattern(dcborPattern: DCBORPattern): CBORPattern {
|
|
77
|
+
return new CBORPattern({ type: "Pattern", pattern: dcborPattern });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Gets the pattern type.
|
|
82
|
+
*/
|
|
83
|
+
get pattern(): CBORPatternType {
|
|
84
|
+
return this.#pattern;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Convert dcbor captures to envelope captures.
|
|
89
|
+
*/
|
|
90
|
+
#convertDcborCapturesToEnvelopeCaptures(
|
|
91
|
+
dcborCaptures: Map<string, Cbor[][]>,
|
|
92
|
+
baseEnvelope: Envelope,
|
|
93
|
+
baseCbor: Cbor,
|
|
94
|
+
): Map<string, Path[]> {
|
|
95
|
+
const envelopeCaptures = new Map<string, Path[]>();
|
|
96
|
+
|
|
97
|
+
for (const [captureName, dcborCapturePaths] of dcborCaptures) {
|
|
98
|
+
const envelopeCapturePaths: Path[] = dcborCapturePaths.map((dcborPath) =>
|
|
99
|
+
this.#convertDcborPathToEnvelopePath(dcborPath, baseEnvelope, baseCbor),
|
|
100
|
+
);
|
|
101
|
+
envelopeCaptures.set(captureName, envelopeCapturePaths);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return envelopeCaptures;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Convert a single dcbor path to an envelope path.
|
|
109
|
+
*/
|
|
110
|
+
#convertDcborPathToEnvelopePath(
|
|
111
|
+
dcborPath: Cbor[],
|
|
112
|
+
baseEnvelope: Envelope,
|
|
113
|
+
baseCbor: Cbor,
|
|
114
|
+
): Envelope[] {
|
|
115
|
+
const envelopePath: Envelope[] = [baseEnvelope];
|
|
116
|
+
|
|
117
|
+
// Skip first element if it matches the base envelope's CBOR content (compare by diagnostic)
|
|
118
|
+
const skipFirst =
|
|
119
|
+
dcborPath.length > 0 && dcborPath[0]?.toDiagnostic() === baseCbor.toDiagnostic();
|
|
120
|
+
|
|
121
|
+
const elementsToAdd = skipFirst ? dcborPath.slice(1) : dcborPath;
|
|
122
|
+
|
|
123
|
+
for (const cborElement of elementsToAdd) {
|
|
124
|
+
// Use newLeaf to create envelope from CBOR value
|
|
125
|
+
envelopePath.push(Envelope.newLeaf(cborElement));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return envelopePath;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Collect capture names from a dcbor pattern.
|
|
133
|
+
*/
|
|
134
|
+
#collectDcborCaptureNames(dcborPattern: DCBORPattern, names: string[]): void {
|
|
135
|
+
// Parse the pattern string to extract capture names
|
|
136
|
+
const patternStr = dcborPatternDisplay(dcborPattern);
|
|
137
|
+
|
|
138
|
+
// Simple parsing to find @name( patterns
|
|
139
|
+
let i = 0;
|
|
140
|
+
while (i < patternStr.length) {
|
|
141
|
+
if (patternStr[i] === "@") {
|
|
142
|
+
i++;
|
|
143
|
+
let name = "";
|
|
144
|
+
// Collect characters until we hit '('
|
|
145
|
+
while (i < patternStr.length && patternStr[i] !== "(") {
|
|
146
|
+
name += patternStr[i];
|
|
147
|
+
i++;
|
|
148
|
+
}
|
|
149
|
+
if (name.length > 0 && !names.includes(name)) {
|
|
150
|
+
names.push(name);
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
i++;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
159
|
+
const envCase = haystack.case();
|
|
160
|
+
|
|
161
|
+
// Special case for KnownValue envelope
|
|
162
|
+
if (envCase.type === "knownValue") {
|
|
163
|
+
const knownValue = envCase.value;
|
|
164
|
+
const knownValueCbor = knownValue.taggedCbor();
|
|
165
|
+
|
|
166
|
+
switch (this.#pattern.type) {
|
|
167
|
+
case "Any":
|
|
168
|
+
return [[[haystack]], new Map<string, Path[]>()];
|
|
169
|
+
case "Value": {
|
|
170
|
+
// Compare using diagnostic representation
|
|
171
|
+
if (knownValueCbor.toDiagnostic() === this.#pattern.cbor.toDiagnostic()) {
|
|
172
|
+
return [[[haystack]], new Map<string, Path[]>()];
|
|
173
|
+
}
|
|
174
|
+
return [[], new Map<string, Path[]>()];
|
|
175
|
+
}
|
|
176
|
+
case "Pattern": {
|
|
177
|
+
const { paths: dcborPaths, captures: dcborCaptures } = dcborPatternPathsWithCaptures(
|
|
178
|
+
this.#pattern.pattern,
|
|
179
|
+
knownValueCbor,
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
if (dcborPaths.length > 0) {
|
|
183
|
+
const basePath: Path = [haystack];
|
|
184
|
+
const envelopePaths: Path[] = dcborPaths.map((dcborPath: Cbor[]) => {
|
|
185
|
+
const extendedPath = [...basePath];
|
|
186
|
+
// Skip the first element as it represents the root CBOR
|
|
187
|
+
for (let i = 1; i < dcborPath.length; i++) {
|
|
188
|
+
const elem = dcborPath[i];
|
|
189
|
+
if (elem !== undefined) {
|
|
190
|
+
extendedPath.push(Envelope.newLeaf(elem));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return extendedPath;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const envelopeCaptures = this.#convertDcborCapturesToEnvelopeCaptures(
|
|
197
|
+
dcborCaptures,
|
|
198
|
+
haystack,
|
|
199
|
+
knownValueCbor,
|
|
200
|
+
);
|
|
201
|
+
return [envelopePaths, envelopeCaptures];
|
|
202
|
+
}
|
|
203
|
+
return [[], new Map<string, Path[]>()];
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Standard case for CBOR leaf
|
|
209
|
+
const leafCbor = haystack.asLeaf();
|
|
210
|
+
if (leafCbor === undefined) {
|
|
211
|
+
return [[], new Map<string, Path[]>()];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
switch (this.#pattern.type) {
|
|
215
|
+
case "Any":
|
|
216
|
+
return [[[haystack]], new Map<string, Path[]>()];
|
|
217
|
+
|
|
218
|
+
case "Value":
|
|
219
|
+
// Compare using diagnostic representation
|
|
220
|
+
if (leafCbor.toDiagnostic() === this.#pattern.cbor.toDiagnostic()) {
|
|
221
|
+
return [[[haystack]], new Map<string, Path[]>()];
|
|
222
|
+
}
|
|
223
|
+
return [[], new Map<string, Path[]>()];
|
|
224
|
+
|
|
225
|
+
case "Pattern": {
|
|
226
|
+
const { paths: dcborPaths, captures: dcborCaptures } = dcborPatternPathsWithCaptures(
|
|
227
|
+
this.#pattern.pattern,
|
|
228
|
+
leafCbor,
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
if (dcborPaths.length > 0) {
|
|
232
|
+
const basePath: Path = [haystack];
|
|
233
|
+
|
|
234
|
+
const envelopePaths: Path[] = dcborPaths.map((dcborPath: Cbor[]) => {
|
|
235
|
+
const extendedPath = [...basePath];
|
|
236
|
+
// Skip the first element only if it exactly matches our root CBOR
|
|
237
|
+
const skipFirst =
|
|
238
|
+
dcborPath.length > 0 && dcborPath[0]?.toDiagnostic() === leafCbor.toDiagnostic();
|
|
239
|
+
|
|
240
|
+
const elementsToAdd = skipFirst ? dcborPath.slice(1) : dcborPath;
|
|
241
|
+
|
|
242
|
+
for (const cborElement of elementsToAdd) {
|
|
243
|
+
extendedPath.push(Envelope.newLeaf(cborElement));
|
|
244
|
+
}
|
|
245
|
+
return extendedPath;
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const envelopeCaptures = this.#convertDcborCapturesToEnvelopeCaptures(
|
|
249
|
+
dcborCaptures,
|
|
250
|
+
haystack,
|
|
251
|
+
leafCbor,
|
|
252
|
+
);
|
|
253
|
+
return [envelopePaths, envelopeCaptures];
|
|
254
|
+
}
|
|
255
|
+
return [[], new Map<string, Path[]>()];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
paths(haystack: Envelope): Path[] {
|
|
261
|
+
return this.pathsWithCaptures(haystack)[0];
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
matches(haystack: Envelope): boolean {
|
|
265
|
+
return this.paths(haystack).length > 0;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
compile(code: Instr[], literals: Pattern[], captures: string[]): void {
|
|
269
|
+
// Register any capture names from this CBOR pattern
|
|
270
|
+
if (this.#pattern.type === "Pattern") {
|
|
271
|
+
const captureNames: string[] = [];
|
|
272
|
+
this.#collectDcborCaptureNames(this.#pattern.pattern, captureNames);
|
|
273
|
+
for (const name of captureNames) {
|
|
274
|
+
if (!captures.includes(name)) {
|
|
275
|
+
captures.push(name);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (createLeafCBORPattern === undefined) {
|
|
281
|
+
throw new Error("CBORPattern factory not registered");
|
|
282
|
+
}
|
|
283
|
+
compileAsAtomic(createLeafCBORPattern(this), code, literals, captures);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
isComplex(): boolean {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
toString(): string {
|
|
291
|
+
switch (this.#pattern.type) {
|
|
292
|
+
case "Any":
|
|
293
|
+
return "cbor";
|
|
294
|
+
case "Value":
|
|
295
|
+
return `cbor(${this.#pattern.cbor.toDiagnostic()})`;
|
|
296
|
+
case "Pattern":
|
|
297
|
+
return `cbor(/${dcborPatternDisplay(this.#pattern.pattern)}/)`;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Equality comparison.
|
|
303
|
+
*/
|
|
304
|
+
equals(other: CBORPattern): boolean {
|
|
305
|
+
if (this.#pattern.type !== other.#pattern.type) {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
switch (this.#pattern.type) {
|
|
309
|
+
case "Any":
|
|
310
|
+
return true;
|
|
311
|
+
case "Value":
|
|
312
|
+
// Compare using diagnostic representation
|
|
313
|
+
return (
|
|
314
|
+
this.#pattern.cbor.toDiagnostic() ===
|
|
315
|
+
(other.#pattern as { type: "Value"; cbor: Cbor }).cbor.toDiagnostic()
|
|
316
|
+
);
|
|
317
|
+
case "Pattern":
|
|
318
|
+
// Compare using display representation
|
|
319
|
+
return (
|
|
320
|
+
dcborPatternDisplay(this.#pattern.pattern) ===
|
|
321
|
+
dcborPatternDisplay(
|
|
322
|
+
(other.#pattern as { type: "Pattern"; pattern: DCBORPattern }).pattern,
|
|
323
|
+
)
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Hash code for use in Maps/Sets.
|
|
330
|
+
*/
|
|
331
|
+
hashCode(): number {
|
|
332
|
+
switch (this.#pattern.type) {
|
|
333
|
+
case "Any":
|
|
334
|
+
return 0;
|
|
335
|
+
case "Value":
|
|
336
|
+
// Simple hash based on diagnostic string
|
|
337
|
+
return simpleStringHash(this.#pattern.cbor.toDiagnostic());
|
|
338
|
+
case "Pattern":
|
|
339
|
+
// Simple hash based on display string
|
|
340
|
+
return simpleStringHash(dcborPatternDisplay(this.#pattern.pattern));
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Simple string hash function for hashCode implementations.
|
|
347
|
+
*/
|
|
348
|
+
function simpleStringHash(str: string): number {
|
|
349
|
+
let hash = 0;
|
|
350
|
+
for (const char of str) {
|
|
351
|
+
hash = (hash << 5) - hash + char.charCodeAt(0);
|
|
352
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
353
|
+
}
|
|
354
|
+
return hash;
|
|
355
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bcts/envelope-pattern - Date pattern matching
|
|
3
|
+
*
|
|
4
|
+
* This is a 1:1 TypeScript port of bc-envelope-pattern-rust date_pattern.rs
|
|
5
|
+
*
|
|
6
|
+
* @module envelope-pattern/pattern/leaf/date-pattern
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Envelope } from "@bcts/envelope";
|
|
10
|
+
import type { CborDate } from "@bcts/dcbor";
|
|
11
|
+
import {
|
|
12
|
+
type DatePattern as DCBORDatePattern,
|
|
13
|
+
datePatternAny,
|
|
14
|
+
datePatternValue,
|
|
15
|
+
datePatternRange,
|
|
16
|
+
datePatternEarliest,
|
|
17
|
+
datePatternLatest,
|
|
18
|
+
datePatternStringValue,
|
|
19
|
+
datePatternRegex,
|
|
20
|
+
datePatternPaths as dcborDatePatternPaths,
|
|
21
|
+
datePatternDisplay,
|
|
22
|
+
} from "@bcts/dcbor-pattern";
|
|
23
|
+
import type { Path } from "../../format";
|
|
24
|
+
import type { Matcher } from "../matcher";
|
|
25
|
+
import { compileAsAtomic } from "../matcher";
|
|
26
|
+
import type { Instr } from "../vm";
|
|
27
|
+
import type { Pattern } from "../index";
|
|
28
|
+
|
|
29
|
+
// Forward declaration for Pattern factory
|
|
30
|
+
let createLeafDatePattern: ((pattern: DatePattern) => Pattern) | undefined;
|
|
31
|
+
|
|
32
|
+
export function registerDatePatternFactory(factory: (pattern: DatePattern) => Pattern): void {
|
|
33
|
+
createLeafDatePattern = factory;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Pattern for matching date values.
|
|
38
|
+
*
|
|
39
|
+
* This is a wrapper around dcbor_pattern::DatePattern that provides
|
|
40
|
+
* envelope-specific integration.
|
|
41
|
+
*
|
|
42
|
+
* Corresponds to the Rust `DatePattern` struct in date_pattern.rs
|
|
43
|
+
*/
|
|
44
|
+
export class DatePattern implements Matcher {
|
|
45
|
+
readonly #inner: DCBORDatePattern;
|
|
46
|
+
|
|
47
|
+
private constructor(inner: DCBORDatePattern) {
|
|
48
|
+
this.#inner = inner;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new DatePattern that matches any date.
|
|
53
|
+
*/
|
|
54
|
+
static any(): DatePattern {
|
|
55
|
+
return new DatePattern(datePatternAny());
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Creates a new DatePattern that matches the specific date.
|
|
60
|
+
*/
|
|
61
|
+
static value(date: CborDate): DatePattern {
|
|
62
|
+
return new DatePattern(datePatternValue(date));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Creates a new DatePattern that matches dates within a range (inclusive).
|
|
67
|
+
*/
|
|
68
|
+
static range(start: CborDate, end: CborDate): DatePattern {
|
|
69
|
+
return new DatePattern(datePatternRange(start, end));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Creates a new DatePattern that matches dates on or after the specified date.
|
|
74
|
+
*/
|
|
75
|
+
static earliest(date: CborDate): DatePattern {
|
|
76
|
+
return new DatePattern(datePatternEarliest(date));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Creates a new DatePattern that matches dates on or before the specified date.
|
|
81
|
+
*/
|
|
82
|
+
static latest(date: CborDate): DatePattern {
|
|
83
|
+
return new DatePattern(datePatternLatest(date));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Creates a new DatePattern that matches dates by their ISO-8601 string representation.
|
|
88
|
+
*/
|
|
89
|
+
static string(isoString: string): DatePattern {
|
|
90
|
+
return new DatePattern(datePatternStringValue(isoString));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Creates a new DatePattern that matches dates whose ISO-8601 string representation
|
|
95
|
+
* matches the given regular expression.
|
|
96
|
+
*/
|
|
97
|
+
static regex(pattern: RegExp): DatePattern {
|
|
98
|
+
return new DatePattern(datePatternRegex(pattern));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Creates a new DatePattern from a dcbor-pattern DatePattern.
|
|
103
|
+
*/
|
|
104
|
+
static fromDcborPattern(dcborPattern: DCBORDatePattern): DatePattern {
|
|
105
|
+
return new DatePattern(dcborPattern);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Gets the underlying dcbor-pattern DatePattern.
|
|
110
|
+
*/
|
|
111
|
+
get inner(): DCBORDatePattern {
|
|
112
|
+
return this.#inner;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
116
|
+
// For leaf envelopes, extract the CBOR and delegate to dcbor-pattern
|
|
117
|
+
const cbor = haystack.asLeaf();
|
|
118
|
+
if (cbor !== undefined) {
|
|
119
|
+
// Delegate to dcbor-pattern for CBOR matching
|
|
120
|
+
const dcborPaths = dcborDatePatternPaths(this.#inner, cbor);
|
|
121
|
+
|
|
122
|
+
// For simple leaf patterns, if dcbor-pattern found matches, return the envelope
|
|
123
|
+
if (dcborPaths.length > 0) {
|
|
124
|
+
const envelopePaths: Path[] = [[haystack]];
|
|
125
|
+
return [envelopePaths, new Map<string, Path[]>()];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return [[], new Map<string, Path[]>()];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
paths(haystack: Envelope): Path[] {
|
|
133
|
+
return this.pathsWithCaptures(haystack)[0];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
matches(haystack: Envelope): boolean {
|
|
137
|
+
return this.paths(haystack).length > 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
compile(code: Instr[], literals: Pattern[], captures: string[]): void {
|
|
141
|
+
if (createLeafDatePattern === undefined) {
|
|
142
|
+
throw new Error("DatePattern factory not registered");
|
|
143
|
+
}
|
|
144
|
+
compileAsAtomic(createLeafDatePattern(this), code, literals, captures);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
isComplex(): boolean {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
toString(): string {
|
|
152
|
+
return datePatternDisplay(this.#inner);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Equality comparison.
|
|
157
|
+
*/
|
|
158
|
+
equals(other: DatePattern): boolean {
|
|
159
|
+
if (this.#inner.variant !== other.#inner.variant) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
// Simplified equality - compare variant names
|
|
163
|
+
return JSON.stringify(this.#inner) === JSON.stringify(other.#inner);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Hash code for use in Maps/Sets.
|
|
168
|
+
*/
|
|
169
|
+
hashCode(): number {
|
|
170
|
+
// Simple hash based on variant
|
|
171
|
+
let hash = 0;
|
|
172
|
+
const str = this.#inner.variant;
|
|
173
|
+
for (let i = 0; i < str.length; i++) {
|
|
174
|
+
hash = hash * 31 + str.charCodeAt(i);
|
|
175
|
+
}
|
|
176
|
+
return hash;
|
|
177
|
+
}
|
|
178
|
+
}
|