@bcts/dcbor-pattern 1.0.0-alpha.11

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 (73) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +14 -0
  3. package/dist/index.cjs +6561 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +2732 -0
  6. package/dist/index.d.cts.map +1 -0
  7. package/dist/index.d.mts +2732 -0
  8. package/dist/index.d.mts.map +1 -0
  9. package/dist/index.iife.js +6562 -0
  10. package/dist/index.iife.js.map +1 -0
  11. package/dist/index.mjs +6244 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/package.json +85 -0
  14. package/src/error.ts +333 -0
  15. package/src/format.ts +299 -0
  16. package/src/index.ts +20 -0
  17. package/src/interval.ts +230 -0
  18. package/src/parse/index.ts +95 -0
  19. package/src/parse/meta/and-parser.ts +47 -0
  20. package/src/parse/meta/capture-parser.ts +56 -0
  21. package/src/parse/meta/index.ts +13 -0
  22. package/src/parse/meta/not-parser.ts +28 -0
  23. package/src/parse/meta/or-parser.ts +47 -0
  24. package/src/parse/meta/primary-parser.ts +420 -0
  25. package/src/parse/meta/repeat-parser.ts +133 -0
  26. package/src/parse/meta/search-parser.ts +56 -0
  27. package/src/parse/parse-registry.ts +31 -0
  28. package/src/parse/structure/array-parser.ts +210 -0
  29. package/src/parse/structure/index.ts +9 -0
  30. package/src/parse/structure/map-parser.ts +128 -0
  31. package/src/parse/structure/tagged-parser.ts +269 -0
  32. package/src/parse/token.ts +997 -0
  33. package/src/parse/value/bool-parser.ts +33 -0
  34. package/src/parse/value/bytestring-parser.ts +42 -0
  35. package/src/parse/value/date-parser.ts +24 -0
  36. package/src/parse/value/digest-parser.ts +24 -0
  37. package/src/parse/value/index.ts +14 -0
  38. package/src/parse/value/known-value-parser.ts +24 -0
  39. package/src/parse/value/null-parser.ts +19 -0
  40. package/src/parse/value/number-parser.ts +19 -0
  41. package/src/parse/value/text-parser.ts +43 -0
  42. package/src/pattern/index.ts +740 -0
  43. package/src/pattern/match-registry.ts +137 -0
  44. package/src/pattern/matcher.ts +388 -0
  45. package/src/pattern/meta/and-pattern.ts +56 -0
  46. package/src/pattern/meta/any-pattern.ts +43 -0
  47. package/src/pattern/meta/capture-pattern.ts +57 -0
  48. package/src/pattern/meta/index.ts +168 -0
  49. package/src/pattern/meta/not-pattern.ts +70 -0
  50. package/src/pattern/meta/or-pattern.ts +56 -0
  51. package/src/pattern/meta/repeat-pattern.ts +117 -0
  52. package/src/pattern/meta/search-pattern.ts +298 -0
  53. package/src/pattern/meta/sequence-pattern.ts +72 -0
  54. package/src/pattern/structure/array-pattern/assigner.ts +95 -0
  55. package/src/pattern/structure/array-pattern/backtrack.ts +240 -0
  56. package/src/pattern/structure/array-pattern/helpers.ts +140 -0
  57. package/src/pattern/structure/array-pattern/index.ts +502 -0
  58. package/src/pattern/structure/index.ts +122 -0
  59. package/src/pattern/structure/map-pattern.ts +255 -0
  60. package/src/pattern/structure/tagged-pattern.ts +190 -0
  61. package/src/pattern/value/bool-pattern.ts +67 -0
  62. package/src/pattern/value/bytes-utils.ts +48 -0
  63. package/src/pattern/value/bytestring-pattern.ts +111 -0
  64. package/src/pattern/value/date-pattern.ts +162 -0
  65. package/src/pattern/value/digest-pattern.ts +136 -0
  66. package/src/pattern/value/index.ts +168 -0
  67. package/src/pattern/value/known-value-pattern.ts +123 -0
  68. package/src/pattern/value/null-pattern.ts +46 -0
  69. package/src/pattern/value/number-pattern.ts +181 -0
  70. package/src/pattern/value/text-pattern.ts +82 -0
  71. package/src/pattern/vm.ts +619 -0
  72. package/src/quantifier.ts +185 -0
  73. package/src/reluctance.ts +65 -0
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Date pattern for dCBOR pattern matching.
3
+ *
4
+ * @module pattern/value/date-pattern
5
+ */
6
+
7
+ import type { Cbor } from "@bcts/dcbor";
8
+ import { CborDate, tagValue, isTagged } from "@bcts/dcbor";
9
+ import type { Path } from "../../format";
10
+
11
+ /**
12
+ * Pattern for matching date values in dCBOR.
13
+ * Dates in CBOR are represented as tagged values with tag 1.
14
+ */
15
+ export type DatePattern =
16
+ | { readonly variant: "Any" }
17
+ | { readonly variant: "Value"; readonly value: CborDate }
18
+ | {
19
+ readonly variant: "Range";
20
+ readonly min: CborDate;
21
+ readonly max: CborDate;
22
+ }
23
+ | { readonly variant: "Earliest"; readonly value: CborDate }
24
+ | { readonly variant: "Latest"; readonly value: CborDate }
25
+ | { readonly variant: "StringValue"; readonly value: string }
26
+ | { readonly variant: "Regex"; readonly pattern: RegExp };
27
+
28
+ /** CBOR tag for date (RFC 8943) */
29
+ const DATE_TAG = 1n;
30
+
31
+ /**
32
+ * Creates a DatePattern that matches any date.
33
+ */
34
+ export const datePatternAny = (): DatePattern => ({ variant: "Any" });
35
+
36
+ /**
37
+ * Creates a DatePattern that matches a specific date.
38
+ */
39
+ export const datePatternValue = (value: CborDate): DatePattern => ({
40
+ variant: "Value",
41
+ value,
42
+ });
43
+
44
+ /**
45
+ * Creates a DatePattern that matches dates within a range (inclusive).
46
+ */
47
+ export const datePatternRange = (min: CborDate, max: CborDate): DatePattern => ({
48
+ variant: "Range",
49
+ min,
50
+ max,
51
+ });
52
+
53
+ /**
54
+ * Creates a DatePattern that matches dates on or after the specified date.
55
+ */
56
+ export const datePatternEarliest = (value: CborDate): DatePattern => ({
57
+ variant: "Earliest",
58
+ value,
59
+ });
60
+
61
+ /**
62
+ * Creates a DatePattern that matches dates on or before the specified date.
63
+ */
64
+ export const datePatternLatest = (value: CborDate): DatePattern => ({
65
+ variant: "Latest",
66
+ value,
67
+ });
68
+
69
+ /**
70
+ * Creates a DatePattern that matches dates by their ISO-8601 string representation.
71
+ */
72
+ export const datePatternStringValue = (value: string): DatePattern => ({
73
+ variant: "StringValue",
74
+ value,
75
+ });
76
+
77
+ /**
78
+ * Creates a DatePattern that matches dates by regex on their ISO-8601 string.
79
+ */
80
+ export const datePatternRegex = (pattern: RegExp): DatePattern => ({
81
+ variant: "Regex",
82
+ pattern,
83
+ });
84
+
85
+ /**
86
+ * Extracts a CborDate from a tagged CBOR value if it's a date (tag 1).
87
+ */
88
+ const extractDate = (haystack: Cbor): CborDate | undefined => {
89
+ if (!isTagged(haystack)) {
90
+ return undefined;
91
+ }
92
+ const tag = tagValue(haystack);
93
+ if (tag !== DATE_TAG) {
94
+ return undefined;
95
+ }
96
+ try {
97
+ return CborDate.fromTaggedCbor(haystack);
98
+ } catch {
99
+ return undefined;
100
+ }
101
+ };
102
+
103
+ /**
104
+ * Tests if a CBOR value matches this date pattern.
105
+ */
106
+ export const datePatternMatches = (pattern: DatePattern, haystack: Cbor): boolean => {
107
+ const date = extractDate(haystack);
108
+ if (date === undefined) {
109
+ return false;
110
+ }
111
+
112
+ switch (pattern.variant) {
113
+ case "Any":
114
+ return true;
115
+ case "Value":
116
+ return date.timestamp() === pattern.value.timestamp();
117
+ case "Range":
118
+ return (
119
+ date.timestamp() >= pattern.min.timestamp() && date.timestamp() <= pattern.max.timestamp()
120
+ );
121
+ case "Earliest":
122
+ return date.timestamp() >= pattern.value.timestamp();
123
+ case "Latest":
124
+ return date.timestamp() <= pattern.value.timestamp();
125
+ case "StringValue":
126
+ return date.toString() === pattern.value;
127
+ case "Regex":
128
+ return pattern.pattern.test(date.toString());
129
+ }
130
+ };
131
+
132
+ /**
133
+ * Returns paths to matching date values.
134
+ */
135
+ export const datePatternPaths = (pattern: DatePattern, haystack: Cbor): Path[] => {
136
+ if (datePatternMatches(pattern, haystack)) {
137
+ return [[haystack]];
138
+ }
139
+ return [];
140
+ };
141
+
142
+ /**
143
+ * Formats a DatePattern as a string.
144
+ */
145
+ export const datePatternDisplay = (pattern: DatePattern): string => {
146
+ switch (pattern.variant) {
147
+ case "Any":
148
+ return "date";
149
+ case "Value":
150
+ return `date'${pattern.value.toString()}'`;
151
+ case "Range":
152
+ return `date'${pattern.min.toString()}...${pattern.max.toString()}'`;
153
+ case "Earliest":
154
+ return `date'${pattern.value.toString()}...'`;
155
+ case "Latest":
156
+ return `date'...${pattern.value.toString()}'`;
157
+ case "StringValue":
158
+ return `date'${pattern.value}'`;
159
+ case "Regex":
160
+ return `date'/${pattern.pattern.source}/'`;
161
+ }
162
+ };
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Digest pattern for dCBOR pattern matching.
3
+ *
4
+ * @module pattern/value/digest-pattern
5
+ */
6
+
7
+ import type { Cbor } from "@bcts/dcbor";
8
+ import { tagValue, isTagged, tagContent, asBytes, bytesToHex } from "@bcts/dcbor";
9
+ import type { Digest } from "@bcts/components";
10
+ import type { Path } from "../../format";
11
+ import { bytesEqual, bytesStartsWith } from "./bytes-utils";
12
+
13
+ /**
14
+ * Pattern for matching digest values in dCBOR.
15
+ * Digests are represented as tagged values with tag 40001.
16
+ *
17
+ * Note: The BinaryRegex variant uses a RegExp that matches against the
18
+ * hex-encoded string representation of the digest bytes. This is a known
19
+ * difference from the Rust implementation which uses regex::bytes::Regex.
20
+ */
21
+ export type DigestPattern =
22
+ | { readonly variant: "Any" }
23
+ | { readonly variant: "Value"; readonly value: Digest }
24
+ | { readonly variant: "Prefix"; readonly prefix: Uint8Array }
25
+ | { readonly variant: "BinaryRegex"; readonly pattern: RegExp };
26
+
27
+ /** CBOR tag for digest (BCR-2021-002) */
28
+ const DIGEST_TAG = 40001n;
29
+
30
+ /** Expected size of a SHA-256 digest */
31
+ const DIGEST_SIZE = 32;
32
+
33
+ /**
34
+ * Creates a DigestPattern that matches any digest.
35
+ */
36
+ export const digestPatternAny = (): DigestPattern => ({ variant: "Any" });
37
+
38
+ /**
39
+ * Creates a DigestPattern that matches a specific digest.
40
+ */
41
+ export const digestPatternValue = (value: Digest): DigestPattern => ({
42
+ variant: "Value",
43
+ value,
44
+ });
45
+
46
+ /**
47
+ * Creates a DigestPattern that matches digests with a prefix.
48
+ */
49
+ export const digestPatternPrefix = (prefix: Uint8Array): DigestPattern => ({
50
+ variant: "Prefix",
51
+ prefix,
52
+ });
53
+
54
+ /**
55
+ * Creates a DigestPattern that matches digests by binary regex.
56
+ *
57
+ * Note: In TypeScript, this matches against the hex-encoded representation
58
+ * of the digest bytes.
59
+ */
60
+ export const digestPatternBinaryRegex = (pattern: RegExp): DigestPattern => ({
61
+ variant: "BinaryRegex",
62
+ pattern,
63
+ });
64
+
65
+ /**
66
+ * Extracts digest bytes from a tagged CBOR value if it's a digest (tag 40001).
67
+ */
68
+ const extractDigestBytes = (haystack: Cbor): Uint8Array | undefined => {
69
+ if (!isTagged(haystack)) {
70
+ return undefined;
71
+ }
72
+ const tag = tagValue(haystack);
73
+ if (tag !== DIGEST_TAG) {
74
+ return undefined;
75
+ }
76
+ const content = tagContent(haystack);
77
+ if (content === undefined) {
78
+ return undefined;
79
+ }
80
+ const bytes = asBytes(content);
81
+ if (bytes?.length !== DIGEST_SIZE) {
82
+ return undefined;
83
+ }
84
+ return bytes;
85
+ };
86
+
87
+ /**
88
+ * Tests if a CBOR value matches this digest pattern.
89
+ */
90
+ export const digestPatternMatches = (pattern: DigestPattern, haystack: Cbor): boolean => {
91
+ const digestBytes = extractDigestBytes(haystack);
92
+ if (digestBytes === undefined) {
93
+ return false;
94
+ }
95
+
96
+ switch (pattern.variant) {
97
+ case "Any":
98
+ return true;
99
+ case "Value":
100
+ return bytesEqual(digestBytes, pattern.value.data());
101
+ case "Prefix":
102
+ return bytesStartsWith(digestBytes, pattern.prefix);
103
+ case "BinaryRegex": {
104
+ // Convert bytes to hex string for regex matching
105
+ const hexString = bytesToHex(digestBytes);
106
+ return pattern.pattern.test(hexString);
107
+ }
108
+ }
109
+ };
110
+
111
+ /**
112
+ * Returns paths to matching digest values.
113
+ */
114
+ export const digestPatternPaths = (pattern: DigestPattern, haystack: Cbor): Path[] => {
115
+ if (digestPatternMatches(pattern, haystack)) {
116
+ return [[haystack]];
117
+ }
118
+ return [];
119
+ };
120
+
121
+ /**
122
+ * Formats a DigestPattern as a string.
123
+ */
124
+ export const digestPatternDisplay = (pattern: DigestPattern): string => {
125
+ switch (pattern.variant) {
126
+ case "Any":
127
+ return "digest";
128
+ case "Value":
129
+ // Use UR string if available, otherwise hex
130
+ return `digest'${bytesToHex(pattern.value.data())}'`;
131
+ case "Prefix":
132
+ return `digest'${bytesToHex(pattern.prefix)}'`;
133
+ case "BinaryRegex":
134
+ return `digest'/${pattern.pattern.source}/'`;
135
+ }
136
+ };
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Value patterns for dCBOR pattern matching.
3
+ *
4
+ * @module pattern/value
5
+ */
6
+
7
+ export * from "./bool-pattern";
8
+ export * from "./null-pattern";
9
+ export * from "./number-pattern";
10
+ export * from "./text-pattern";
11
+ export * from "./bytestring-pattern";
12
+ export * from "./date-pattern";
13
+ export * from "./digest-pattern";
14
+ export * from "./known-value-pattern";
15
+
16
+ import type { Cbor } from "@bcts/dcbor";
17
+ import type { Path } from "../../format";
18
+
19
+ import { type BoolPattern, boolPatternPaths, boolPatternDisplay } from "./bool-pattern";
20
+ import { type NullPattern, nullPatternPaths, nullPatternDisplay } from "./null-pattern";
21
+ import { type NumberPattern, numberPatternPaths, numberPatternDisplay } from "./number-pattern";
22
+ import { type TextPattern, textPatternPaths, textPatternDisplay } from "./text-pattern";
23
+ import {
24
+ type ByteStringPattern,
25
+ byteStringPatternPaths,
26
+ byteStringPatternDisplay,
27
+ } from "./bytestring-pattern";
28
+ import { type DatePattern, datePatternPaths, datePatternDisplay } from "./date-pattern";
29
+ import { type DigestPattern, digestPatternPaths, digestPatternDisplay } from "./digest-pattern";
30
+ import {
31
+ type KnownValuePattern,
32
+ knownValuePatternPaths,
33
+ knownValuePatternDisplay,
34
+ } from "./known-value-pattern";
35
+
36
+ /**
37
+ * Union of all value pattern types.
38
+ */
39
+ export type ValuePattern =
40
+ | { readonly type: "Bool"; readonly pattern: BoolPattern }
41
+ | { readonly type: "Null"; readonly pattern: NullPattern }
42
+ | { readonly type: "Number"; readonly pattern: NumberPattern }
43
+ | { readonly type: "Text"; readonly pattern: TextPattern }
44
+ | { readonly type: "ByteString"; readonly pattern: ByteStringPattern }
45
+ | { readonly type: "Date"; readonly pattern: DatePattern }
46
+ | { readonly type: "Digest"; readonly pattern: DigestPattern }
47
+ | { readonly type: "KnownValue"; readonly pattern: KnownValuePattern };
48
+
49
+ /**
50
+ * Returns paths to matching values for a ValuePattern.
51
+ */
52
+ export const valuePatternPaths = (pattern: ValuePattern, haystack: Cbor): Path[] => {
53
+ switch (pattern.type) {
54
+ case "Bool":
55
+ return boolPatternPaths(pattern.pattern, haystack);
56
+ case "Null":
57
+ return nullPatternPaths(pattern.pattern, haystack);
58
+ case "Number":
59
+ return numberPatternPaths(pattern.pattern, haystack);
60
+ case "Text":
61
+ return textPatternPaths(pattern.pattern, haystack);
62
+ case "ByteString":
63
+ return byteStringPatternPaths(pattern.pattern, haystack);
64
+ case "Date":
65
+ return datePatternPaths(pattern.pattern, haystack);
66
+ case "Digest":
67
+ return digestPatternPaths(pattern.pattern, haystack);
68
+ case "KnownValue":
69
+ return knownValuePatternPaths(pattern.pattern, haystack);
70
+ }
71
+ };
72
+
73
+ /**
74
+ * Tests if a CBOR value matches a ValuePattern.
75
+ */
76
+ export const valuePatternMatches = (pattern: ValuePattern, haystack: Cbor): boolean => {
77
+ return valuePatternPaths(pattern, haystack).length > 0;
78
+ };
79
+
80
+ /**
81
+ * Formats a ValuePattern as a string.
82
+ */
83
+ export const valuePatternDisplay = (pattern: ValuePattern): string => {
84
+ switch (pattern.type) {
85
+ case "Bool":
86
+ return boolPatternDisplay(pattern.pattern);
87
+ case "Null":
88
+ return nullPatternDisplay(pattern.pattern);
89
+ case "Number":
90
+ return numberPatternDisplay(pattern.pattern);
91
+ case "Text":
92
+ return textPatternDisplay(pattern.pattern);
93
+ case "ByteString":
94
+ return byteStringPatternDisplay(pattern.pattern);
95
+ case "Date":
96
+ return datePatternDisplay(pattern.pattern);
97
+ case "Digest":
98
+ return digestPatternDisplay(pattern.pattern);
99
+ case "KnownValue":
100
+ return knownValuePatternDisplay(pattern.pattern);
101
+ }
102
+ };
103
+
104
+ // Convenience constructors for ValuePattern
105
+
106
+ /**
107
+ * Creates a Bool ValuePattern.
108
+ */
109
+ export const valueBool = (pattern: BoolPattern): ValuePattern => ({
110
+ type: "Bool",
111
+ pattern,
112
+ });
113
+
114
+ /**
115
+ * Creates a Null ValuePattern.
116
+ */
117
+ export const valueNull = (pattern: NullPattern): ValuePattern => ({
118
+ type: "Null",
119
+ pattern,
120
+ });
121
+
122
+ /**
123
+ * Creates a Number ValuePattern.
124
+ */
125
+ export const valueNumber = (pattern: NumberPattern): ValuePattern => ({
126
+ type: "Number",
127
+ pattern,
128
+ });
129
+
130
+ /**
131
+ * Creates a Text ValuePattern.
132
+ */
133
+ export const valueText = (pattern: TextPattern): ValuePattern => ({
134
+ type: "Text",
135
+ pattern,
136
+ });
137
+
138
+ /**
139
+ * Creates a ByteString ValuePattern.
140
+ */
141
+ export const valueByteString = (pattern: ByteStringPattern): ValuePattern => ({
142
+ type: "ByteString",
143
+ pattern,
144
+ });
145
+
146
+ /**
147
+ * Creates a Date ValuePattern.
148
+ */
149
+ export const valueDate = (pattern: DatePattern): ValuePattern => ({
150
+ type: "Date",
151
+ pattern,
152
+ });
153
+
154
+ /**
155
+ * Creates a Digest ValuePattern.
156
+ */
157
+ export const valueDigest = (pattern: DigestPattern): ValuePattern => ({
158
+ type: "Digest",
159
+ pattern,
160
+ });
161
+
162
+ /**
163
+ * Creates a KnownValue ValuePattern.
164
+ */
165
+ export const valueKnownValue = (pattern: KnownValuePattern): ValuePattern => ({
166
+ type: "KnownValue",
167
+ pattern,
168
+ });
@@ -0,0 +1,123 @@
1
+ /**
2
+ * KnownValue pattern for dCBOR pattern matching.
3
+ *
4
+ * @module pattern/value/known-value-pattern
5
+ */
6
+
7
+ import type { Cbor } from "@bcts/dcbor";
8
+ import { tagValue, isTagged, tagContent, asUnsigned } from "@bcts/dcbor";
9
+ import { KnownValue, KNOWN_VALUE_TAG } from "@bcts/known-values";
10
+ import type { Path } from "../../format";
11
+
12
+ /**
13
+ * Pattern for matching known values in dCBOR.
14
+ * Known values are represented as tagged values with tag 40000.
15
+ */
16
+ export type KnownValuePattern =
17
+ | { readonly variant: "Any" }
18
+ | { readonly variant: "Value"; readonly value: KnownValue }
19
+ | { readonly variant: "Named"; readonly name: string }
20
+ | { readonly variant: "Regex"; readonly pattern: RegExp };
21
+
22
+ /**
23
+ * Creates a KnownValuePattern that matches any known value.
24
+ */
25
+ export const knownValuePatternAny = (): KnownValuePattern => ({
26
+ variant: "Any",
27
+ });
28
+
29
+ /**
30
+ * Creates a KnownValuePattern that matches a specific known value.
31
+ */
32
+ export const knownValuePatternValue = (value: KnownValue): KnownValuePattern => ({
33
+ variant: "Value",
34
+ value,
35
+ });
36
+
37
+ /**
38
+ * Creates a KnownValuePattern that matches a known value by name.
39
+ */
40
+ export const knownValuePatternNamed = (name: string): KnownValuePattern => ({
41
+ variant: "Named",
42
+ name,
43
+ });
44
+
45
+ /**
46
+ * Creates a KnownValuePattern that matches known values by regex on name.
47
+ */
48
+ export const knownValuePatternRegex = (pattern: RegExp): KnownValuePattern => ({
49
+ variant: "Regex",
50
+ pattern,
51
+ });
52
+
53
+ /**
54
+ * Extracts a KnownValue from a tagged CBOR value if it's a known value (tag 40000).
55
+ */
56
+ const extractKnownValue = (haystack: Cbor): KnownValue | undefined => {
57
+ if (!isTagged(haystack)) {
58
+ return undefined;
59
+ }
60
+ const tag = tagValue(haystack);
61
+ if (tag !== KNOWN_VALUE_TAG.value) {
62
+ return undefined;
63
+ }
64
+ const content = tagContent(haystack);
65
+ if (content === undefined) {
66
+ return undefined;
67
+ }
68
+ const value = asUnsigned(content);
69
+ if (value === undefined) {
70
+ return undefined;
71
+ }
72
+ return new KnownValue(value);
73
+ };
74
+
75
+ /**
76
+ * Tests if a CBOR value matches this known value pattern.
77
+ */
78
+ export const knownValuePatternMatches = (pattern: KnownValuePattern, haystack: Cbor): boolean => {
79
+ const knownValue = extractKnownValue(haystack);
80
+ if (knownValue === undefined) {
81
+ return false;
82
+ }
83
+
84
+ switch (pattern.variant) {
85
+ case "Any":
86
+ return true;
87
+ case "Value":
88
+ return knownValue.valueBigInt() === pattern.value.valueBigInt();
89
+ case "Named": {
90
+ // Look up the known value by name and compare
91
+ // KnownValue has a name method that we can compare
92
+ return knownValue.name() === pattern.name;
93
+ }
94
+ case "Regex":
95
+ return pattern.pattern.test(knownValue.name());
96
+ }
97
+ };
98
+
99
+ /**
100
+ * Returns paths to matching known values.
101
+ */
102
+ export const knownValuePatternPaths = (pattern: KnownValuePattern, haystack: Cbor): Path[] => {
103
+ if (knownValuePatternMatches(pattern, haystack)) {
104
+ return [[haystack]];
105
+ }
106
+ return [];
107
+ };
108
+
109
+ /**
110
+ * Formats a KnownValuePattern as a string.
111
+ */
112
+ export const knownValuePatternDisplay = (pattern: KnownValuePattern): string => {
113
+ switch (pattern.variant) {
114
+ case "Any":
115
+ return "known";
116
+ case "Value":
117
+ return `'${pattern.value.name()}'`;
118
+ case "Named":
119
+ return `'${pattern.name}'`;
120
+ case "Regex":
121
+ return `'/${pattern.pattern.source}/'`;
122
+ }
123
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Null pattern for dCBOR pattern matching.
3
+ *
4
+ * @module pattern/value/null-pattern
5
+ */
6
+
7
+ import type { Cbor } from "@bcts/dcbor";
8
+ import { isNull } from "@bcts/dcbor";
9
+ import type { Path } from "../../format";
10
+
11
+ /**
12
+ * Pattern for matching null values in dCBOR.
13
+ * This is a unit type - there's only one way to match null.
14
+ */
15
+ export interface NullPattern {
16
+ readonly variant: "Null";
17
+ }
18
+
19
+ /**
20
+ * Creates a NullPattern.
21
+ */
22
+ export const nullPattern = (): NullPattern => ({ variant: "Null" });
23
+
24
+ /**
25
+ * Tests if a CBOR value matches the null pattern.
26
+ */
27
+ export const nullPatternMatches = (_pattern: NullPattern, haystack: Cbor): boolean => {
28
+ return isNull(haystack);
29
+ };
30
+
31
+ /**
32
+ * Returns paths to matching null values.
33
+ */
34
+ export const nullPatternPaths = (pattern: NullPattern, haystack: Cbor): Path[] => {
35
+ if (nullPatternMatches(pattern, haystack)) {
36
+ return [[haystack]];
37
+ }
38
+ return [];
39
+ };
40
+
41
+ /**
42
+ * Formats a NullPattern as a string.
43
+ */
44
+ export const nullPatternDisplay = (_pattern: NullPattern): string => {
45
+ return "null";
46
+ };