@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
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@bcts/dcbor-pattern",
3
+ "version": "1.0.0-alpha.11",
4
+ "type": "module",
5
+ "description": "Pattern matching for dCBOR (Deterministic CBOR) for TypeScript",
6
+ "license": "BSD-2-Clause-Patent",
7
+ "contributors": [
8
+ {
9
+ "name": "Leonardo Custodio",
10
+ "email": "leonardo.custodio@parity.io",
11
+ "url": "https://github.com/leonardocustodio"
12
+ },
13
+ {
14
+ "name": "Karim Jedda",
15
+ "email": "karim@parity.io",
16
+ "url": "https://github.com/KarimJedda"
17
+ }
18
+ ],
19
+ "homepage": "https://bcts.dev",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/leonardocustodio/bcts.git",
23
+ "directory": "packages/dcbor-pattern"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/leonardocustodio/bcts/issues"
27
+ },
28
+ "main": "dist/index.cjs",
29
+ "module": "dist/index.mjs",
30
+ "types": "dist/index.d.mts",
31
+ "browser": "dist/index.iife.js",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.mts",
35
+ "import": "./dist/index.mjs",
36
+ "require": "./dist/index.cjs",
37
+ "default": "./dist/index.mjs"
38
+ }
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "src",
43
+ "README.md"
44
+ ],
45
+ "scripts": {
46
+ "build": "tsdown",
47
+ "dev": "tsdown --watch",
48
+ "test": "vitest run",
49
+ "test:watch": "vitest",
50
+ "lint": "eslint 'src/**/*.ts' 'tests/**/*.ts'",
51
+ "lint:fix": "eslint 'src/**/*.ts' 'tests/**/*.ts' --fix",
52
+ "typecheck": "tsc --noEmit",
53
+ "clean": "rm -rf dist",
54
+ "docs": "typedoc",
55
+ "prepublishOnly": "npm run clean && npm run build && npm test"
56
+ },
57
+ "keywords": [
58
+ "cbor",
59
+ "dcbor",
60
+ "pattern",
61
+ "matching",
62
+ "blockchain-commons",
63
+ "query",
64
+ "search"
65
+ ],
66
+ "engines": {
67
+ "node": ">=18.0.0"
68
+ },
69
+ "devDependencies": {
70
+ "@bcts/eslint": "workspace:*",
71
+ "@bcts/tsconfig": "workspace:*",
72
+ "@types/node": "^25.0.3",
73
+ "eslint": "^9.39.2",
74
+ "tsdown": "^0.18.3",
75
+ "typedoc": "^0.28.15",
76
+ "typescript": "^5.9.3",
77
+ "vitest": "^4.0.16"
78
+ },
79
+ "dependencies": {
80
+ "@bcts/dcbor": "workspace:*",
81
+ "@bcts/components": "workspace:*",
82
+ "@bcts/tags": "workspace:*",
83
+ "@bcts/known-values": "workspace:*"
84
+ }
85
+ }
package/src/error.ts ADDED
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Error types for dCBOR pattern parsing.
3
+ *
4
+ * This module provides error handling utilities for the dCBOR pattern
5
+ * matching system, including a discriminated union Error type and
6
+ * a Result type for type-safe error handling.
7
+ *
8
+ * @module error
9
+ */
10
+
11
+ import type { Token } from "./parse/token";
12
+
13
+ /**
14
+ * Represents a span in the input string, indicating position for error reporting.
15
+ */
16
+ export interface Span {
17
+ readonly start: number;
18
+ readonly end: number;
19
+ }
20
+
21
+ /**
22
+ * Creates a new Span.
23
+ */
24
+ export const span = (start: number, end: number): Span => ({ start, end });
25
+
26
+ /**
27
+ * Errors that can occur during parsing of dCBOR patterns.
28
+ *
29
+ * This is a discriminated union type matching the Rust Error enum.
30
+ */
31
+ export type Error =
32
+ | { readonly type: "EmptyInput" }
33
+ | { readonly type: "UnexpectedEndOfInput" }
34
+ | { readonly type: "ExtraData"; readonly span: Span }
35
+ | { readonly type: "UnexpectedToken"; readonly token: Token; readonly span: Span }
36
+ | { readonly type: "UnrecognizedToken"; readonly span: Span }
37
+ | { readonly type: "InvalidRegex"; readonly span: Span }
38
+ | { readonly type: "UnterminatedRegex"; readonly span: Span }
39
+ | { readonly type: "UnterminatedString"; readonly span: Span }
40
+ | { readonly type: "InvalidRange"; readonly span: Span }
41
+ | { readonly type: "InvalidHexString"; readonly span: Span }
42
+ | { readonly type: "UnterminatedHexString"; readonly span: Span }
43
+ | { readonly type: "InvalidDateFormat"; readonly span: Span }
44
+ | { readonly type: "InvalidNumberFormat"; readonly span: Span }
45
+ | { readonly type: "InvalidUr"; readonly message: string; readonly span: Span }
46
+ | { readonly type: "ExpectedOpenParen"; readonly span: Span }
47
+ | { readonly type: "ExpectedCloseParen"; readonly span: Span }
48
+ | { readonly type: "ExpectedCloseBracket"; readonly span: Span }
49
+ | { readonly type: "ExpectedCloseBrace"; readonly span: Span }
50
+ | { readonly type: "ExpectedColon"; readonly span: Span }
51
+ | { readonly type: "ExpectedPattern"; readonly span: Span }
52
+ | { readonly type: "UnmatchedParentheses"; readonly span: Span }
53
+ | { readonly type: "UnmatchedBraces"; readonly span: Span }
54
+ | { readonly type: "InvalidCaptureGroupName"; readonly name: string; readonly span: Span }
55
+ | { readonly type: "InvalidDigestPattern"; readonly message: string; readonly span: Span }
56
+ | { readonly type: "UnterminatedDigestQuoted"; readonly span: Span }
57
+ | { readonly type: "UnterminatedDateQuoted"; readonly span: Span }
58
+ | { readonly type: "InvalidDigest"; readonly span: Span }
59
+ | { readonly type: "InvalidDate"; readonly span: Span }
60
+ | { readonly type: "Unknown" };
61
+
62
+ /**
63
+ * A Result type specialized for dCBOR pattern parsing.
64
+ * Matches Rust's Result<T, Error> pattern.
65
+ */
66
+ export type Result<T> =
67
+ | { readonly ok: true; readonly value: T }
68
+ | { readonly ok: false; readonly error: Error };
69
+
70
+ /**
71
+ * Creates a successful Result.
72
+ */
73
+ export const Ok = <T>(value: T): Result<T> => ({ ok: true, value });
74
+
75
+ /**
76
+ * Creates a failed Result.
77
+ */
78
+ export const Err = <T>(error: Error): Result<T> => ({ ok: false, error });
79
+
80
+ /**
81
+ * Unwraps a Result, throwing an error if it's not Ok.
82
+ */
83
+ export const unwrap = <T>(result: Result<T>): T => {
84
+ if (result.ok) {
85
+ return result.value;
86
+ }
87
+ throw new PatternError(result.error);
88
+ };
89
+
90
+ /**
91
+ * Unwraps a Result, returning the default value if it's an error.
92
+ */
93
+ export const unwrapOr = <T>(result: Result<T>, defaultValue: T): T => {
94
+ if (result.ok) {
95
+ return result.value;
96
+ }
97
+ return defaultValue;
98
+ };
99
+
100
+ /**
101
+ * Maps a Result's value if it's Ok.
102
+ */
103
+ export const map = <T, U>(result: Result<T>, fn: (value: T) => U): Result<U> => {
104
+ if (result.ok) {
105
+ return Ok(fn(result.value));
106
+ }
107
+ return result as Result<U>;
108
+ };
109
+
110
+ /**
111
+ * Converts an Error to a human-readable string.
112
+ */
113
+ export const errorToString = (error: Error): string => {
114
+ switch (error.type) {
115
+ case "EmptyInput":
116
+ return "Empty input";
117
+ case "UnexpectedEndOfInput":
118
+ return "Unexpected end of input";
119
+ case "ExtraData":
120
+ return `Extra data at end of input at ${error.span.start}..${error.span.end}`;
121
+ case "UnexpectedToken":
122
+ return `Unexpected token at ${error.span.start}..${error.span.end}`;
123
+ case "UnrecognizedToken":
124
+ return `Unrecognized token at position ${error.span.start}..${error.span.end}`;
125
+ case "InvalidRegex":
126
+ return `Invalid regex pattern at ${error.span.start}..${error.span.end}`;
127
+ case "UnterminatedRegex":
128
+ return `Unterminated regex pattern at ${error.span.start}..${error.span.end}`;
129
+ case "UnterminatedString":
130
+ return `Unterminated string literal at ${error.span.start}..${error.span.end}`;
131
+ case "InvalidRange":
132
+ return `Invalid range at ${error.span.start}..${error.span.end}`;
133
+ case "InvalidHexString":
134
+ return `Invalid hex string at ${error.span.start}..${error.span.end}`;
135
+ case "UnterminatedHexString":
136
+ return `Unterminated hex string at ${error.span.start}..${error.span.end}`;
137
+ case "InvalidDateFormat":
138
+ return `Invalid date format at ${error.span.start}..${error.span.end}`;
139
+ case "InvalidNumberFormat":
140
+ return `Invalid number format at ${error.span.start}..${error.span.end}`;
141
+ case "InvalidUr":
142
+ return `Invalid UR: ${error.message} at ${error.span.start}..${error.span.end}`;
143
+ case "ExpectedOpenParen":
144
+ return `Expected opening parenthesis at ${error.span.start}..${error.span.end}`;
145
+ case "ExpectedCloseParen":
146
+ return `Expected closing parenthesis at ${error.span.start}..${error.span.end}`;
147
+ case "ExpectedCloseBracket":
148
+ return `Expected closing bracket at ${error.span.start}..${error.span.end}`;
149
+ case "ExpectedCloseBrace":
150
+ return `Expected closing brace at ${error.span.start}..${error.span.end}`;
151
+ case "ExpectedColon":
152
+ return `Expected colon at ${error.span.start}..${error.span.end}`;
153
+ case "ExpectedPattern":
154
+ return `Expected pattern after operator at ${error.span.start}..${error.span.end}`;
155
+ case "UnmatchedParentheses":
156
+ return `Unmatched parentheses at ${error.span.start}..${error.span.end}`;
157
+ case "UnmatchedBraces":
158
+ return `Unmatched braces at ${error.span.start}..${error.span.end}`;
159
+ case "InvalidCaptureGroupName":
160
+ return `Invalid capture group name '${error.name}' at ${error.span.start}..${error.span.end}`;
161
+ case "InvalidDigestPattern":
162
+ return `Invalid digest pattern: ${error.message} at ${error.span.start}..${error.span.end}`;
163
+ case "UnterminatedDigestQuoted":
164
+ return `Unterminated digest quoted pattern at ${error.span.start}..${error.span.end}`;
165
+ case "UnterminatedDateQuoted":
166
+ return `Unterminated date quoted pattern at ${error.span.start}..${error.span.end}`;
167
+ case "InvalidDigest":
168
+ return `Invalid digest at ${error.span.start}..${error.span.end}`;
169
+ case "InvalidDate":
170
+ return `Invalid date at ${error.span.start}..${error.span.end}`;
171
+ case "Unknown":
172
+ return "Unknown error";
173
+ }
174
+ };
175
+
176
+ /**
177
+ * Adjusts the span of an error by adding the given offset to both start and end positions.
178
+ * Returns a new error with adjusted span, or the original error if it has no span.
179
+ */
180
+ export const adjustSpan = (error: Error, offset: number): Error => {
181
+ switch (error.type) {
182
+ case "ExtraData":
183
+ return { type: "ExtraData", span: span(offset + error.span.start, offset + error.span.end) };
184
+ case "UnexpectedToken":
185
+ return {
186
+ type: "UnexpectedToken",
187
+ token: error.token,
188
+ span: span(offset + error.span.start, offset + error.span.end),
189
+ };
190
+ case "UnrecognizedToken":
191
+ return {
192
+ type: "UnrecognizedToken",
193
+ span: span(offset + error.span.start, offset + error.span.end),
194
+ };
195
+ case "InvalidRegex":
196
+ return {
197
+ type: "InvalidRegex",
198
+ span: span(offset + error.span.start, offset + error.span.end),
199
+ };
200
+ case "UnterminatedRegex":
201
+ return {
202
+ type: "UnterminatedRegex",
203
+ span: span(offset + error.span.start, offset + error.span.end),
204
+ };
205
+ case "UnterminatedString":
206
+ return {
207
+ type: "UnterminatedString",
208
+ span: span(offset + error.span.start, offset + error.span.end),
209
+ };
210
+ case "InvalidRange":
211
+ return {
212
+ type: "InvalidRange",
213
+ span: span(offset + error.span.start, offset + error.span.end),
214
+ };
215
+ case "InvalidHexString":
216
+ return {
217
+ type: "InvalidHexString",
218
+ span: span(offset + error.span.start, offset + error.span.end),
219
+ };
220
+ case "UnterminatedHexString":
221
+ return {
222
+ type: "UnterminatedHexString",
223
+ span: span(offset + error.span.start, offset + error.span.end),
224
+ };
225
+ case "InvalidDateFormat":
226
+ return {
227
+ type: "InvalidDateFormat",
228
+ span: span(offset + error.span.start, offset + error.span.end),
229
+ };
230
+ case "InvalidNumberFormat":
231
+ return {
232
+ type: "InvalidNumberFormat",
233
+ span: span(offset + error.span.start, offset + error.span.end),
234
+ };
235
+ case "InvalidUr":
236
+ return {
237
+ type: "InvalidUr",
238
+ message: error.message,
239
+ span: span(offset + error.span.start, offset + error.span.end),
240
+ };
241
+ case "ExpectedOpenParen":
242
+ return {
243
+ type: "ExpectedOpenParen",
244
+ span: span(offset + error.span.start, offset + error.span.end),
245
+ };
246
+ case "ExpectedCloseParen":
247
+ return {
248
+ type: "ExpectedCloseParen",
249
+ span: span(offset + error.span.start, offset + error.span.end),
250
+ };
251
+ case "ExpectedCloseBracket":
252
+ return {
253
+ type: "ExpectedCloseBracket",
254
+ span: span(offset + error.span.start, offset + error.span.end),
255
+ };
256
+ case "ExpectedCloseBrace":
257
+ return {
258
+ type: "ExpectedCloseBrace",
259
+ span: span(offset + error.span.start, offset + error.span.end),
260
+ };
261
+ case "ExpectedColon":
262
+ return {
263
+ type: "ExpectedColon",
264
+ span: span(offset + error.span.start, offset + error.span.end),
265
+ };
266
+ case "ExpectedPattern":
267
+ return {
268
+ type: "ExpectedPattern",
269
+ span: span(offset + error.span.start, offset + error.span.end),
270
+ };
271
+ case "UnmatchedParentheses":
272
+ return {
273
+ type: "UnmatchedParentheses",
274
+ span: span(offset + error.span.start, offset + error.span.end),
275
+ };
276
+ case "UnmatchedBraces":
277
+ return {
278
+ type: "UnmatchedBraces",
279
+ span: span(offset + error.span.start, offset + error.span.end),
280
+ };
281
+ case "InvalidCaptureGroupName":
282
+ return {
283
+ type: "InvalidCaptureGroupName",
284
+ name: error.name,
285
+ span: span(offset + error.span.start, offset + error.span.end),
286
+ };
287
+ case "InvalidDigestPattern":
288
+ return {
289
+ type: "InvalidDigestPattern",
290
+ message: error.message,
291
+ span: span(offset + error.span.start, offset + error.span.end),
292
+ };
293
+ case "UnterminatedDigestQuoted":
294
+ return {
295
+ type: "UnterminatedDigestQuoted",
296
+ span: span(offset + error.span.start, offset + error.span.end),
297
+ };
298
+ case "UnterminatedDateQuoted":
299
+ return {
300
+ type: "UnterminatedDateQuoted",
301
+ span: span(offset + error.span.start, offset + error.span.end),
302
+ };
303
+ case "InvalidDigest":
304
+ return {
305
+ type: "InvalidDigest",
306
+ span: span(offset + error.span.start, offset + error.span.end),
307
+ };
308
+ case "InvalidDate":
309
+ return {
310
+ type: "InvalidDate",
311
+ span: span(offset + error.span.start, offset + error.span.end),
312
+ };
313
+ // For errors without spans, return them as-is
314
+ case "EmptyInput":
315
+ case "UnexpectedEndOfInput":
316
+ case "Unknown":
317
+ return error;
318
+ }
319
+ };
320
+
321
+ /**
322
+ * JavaScript Error class wrapper for PatternError.
323
+ * Provides stack traces and works with try/catch blocks.
324
+ */
325
+ export class PatternError extends globalThis.Error {
326
+ public readonly errorType: Error;
327
+
328
+ constructor(errorType: Error, message?: string) {
329
+ super(message ?? errorToString(errorType));
330
+ this.name = "PatternError";
331
+ this.errorType = errorType;
332
+ }
333
+ }