@bcts/envelope-pattern 1.0.0-alpha.12 → 1.0.0-alpha.14
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 +162 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +23 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +162 -9
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +160 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -9
- package/src/parse/utils.ts +13 -14
- package/src/pattern/dcbor-integration.ts +208 -0
- package/src/pattern/index.ts +5 -0
- package/src/pattern/matcher.ts +31 -0
- package/src/pattern/meta/and-pattern.ts +2 -5
- package/src/pattern/meta/not-pattern.ts +2 -3
- package/src/pattern/meta/or-pattern.ts +2 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bcts/envelope-pattern",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Pattern matching for Gordian Envelope structures",
|
|
6
6
|
"license": "BSD-2-Clause-Patent",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"node": ">=18.0.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@bcts/eslint": "
|
|
62
|
-
"@bcts/tsconfig": "
|
|
61
|
+
"@bcts/eslint": "^0.1.0",
|
|
62
|
+
"@bcts/tsconfig": "^0.1.0",
|
|
63
63
|
"eslint": "^9.39.2",
|
|
64
64
|
"tsdown": "^0.18.3",
|
|
65
65
|
"typedoc": "^0.28.15",
|
|
@@ -67,11 +67,10 @@
|
|
|
67
67
|
"vitest": "^4.0.16"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@bcts/dcbor": "
|
|
71
|
-
"@bcts/dcbor-
|
|
72
|
-
"@bcts/
|
|
73
|
-
"@bcts/
|
|
74
|
-
"@bcts/
|
|
75
|
-
"@bcts/known-values": "workspace:*"
|
|
70
|
+
"@bcts/dcbor": "^1.0.0-alpha.14",
|
|
71
|
+
"@bcts/dcbor-parse": "^1.0.0-alpha.14",
|
|
72
|
+
"@bcts/dcbor-pattern": "^1.0.0-alpha.14",
|
|
73
|
+
"@bcts/envelope": "^1.0.0-alpha.14",
|
|
74
|
+
"@bcts/known-values": "^1.0.0-alpha.14"
|
|
76
75
|
}
|
|
77
76
|
}
|
package/src/parse/utils.ts
CHANGED
|
@@ -7,13 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { Cbor } from "@bcts/dcbor";
|
|
10
|
+
import { parseDcborItemPartial } from "@bcts/dcbor-parse";
|
|
10
11
|
import { type Pattern as DCBORPattern, parse as parseDcborPattern } from "@bcts/dcbor-pattern";
|
|
11
|
-
|
|
12
|
-
// Stub for cborFromDiagnostic - not implemented in dcbor yet
|
|
13
|
-
function cborFromDiagnostic(_src: string): { ok: true; value: Cbor } | { ok: false } {
|
|
14
|
-
// TODO: Implement when dcbor adds diagnostic notation parsing
|
|
15
|
-
return { ok: false };
|
|
16
|
-
}
|
|
17
12
|
import {
|
|
18
13
|
type Result,
|
|
19
14
|
ok,
|
|
@@ -175,20 +170,24 @@ export function parseCborInner(src: string): Result<[Pattern, number]> {
|
|
|
175
170
|
|
|
176
171
|
// Check if this is a UR (ur:type/value)
|
|
177
172
|
if (src.slice(pos.value, pos.value + 3) === "ur:") {
|
|
178
|
-
//
|
|
179
|
-
|
|
173
|
+
// Parse as UR and convert to CBOR
|
|
174
|
+
const remaining = src.slice(pos.value);
|
|
175
|
+
const parseResult = parseDcborItemPartial(remaining);
|
|
176
|
+
if (!parseResult.ok) {
|
|
177
|
+
return err(unknown());
|
|
178
|
+
}
|
|
179
|
+
const [cborValue, consumed] = parseResult.value;
|
|
180
|
+
return ok([createCborPattern(cborValue), pos.value + consumed]);
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
// Default: parse as CBOR diagnostic notation
|
|
183
184
|
const remaining = src.slice(pos.value);
|
|
184
|
-
const
|
|
185
|
-
if (!
|
|
185
|
+
const parseResult = parseDcborItemPartial(remaining);
|
|
186
|
+
if (!parseResult.ok) {
|
|
186
187
|
return err(unknown());
|
|
187
188
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const consumed = remaining.length;
|
|
191
|
-
return ok([createCborPattern(cborResult.value), pos.value + consumed]);
|
|
189
|
+
const [cborValue, consumed] = parseResult.value;
|
|
190
|
+
return ok([createCborPattern(cborValue), pos.value + consumed]);
|
|
192
191
|
}
|
|
193
192
|
|
|
194
193
|
/**
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bcts/envelope-pattern - DCBor Pattern Integration
|
|
3
|
+
*
|
|
4
|
+
* This module provides integration between dcbor-pattern and
|
|
5
|
+
* bc-envelope-pattern, allowing dcbor patterns to be used as envelope patterns
|
|
6
|
+
* through conversion.
|
|
7
|
+
*
|
|
8
|
+
* This is a 1:1 TypeScript port of bc-envelope-pattern-rust dcbor_integration.rs
|
|
9
|
+
*
|
|
10
|
+
* @module envelope-pattern/pattern/dcbor-integration
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
type Pattern as DCBORPattern,
|
|
15
|
+
type ValuePattern as DCBORValuePattern,
|
|
16
|
+
type StructurePattern as DCBORStructurePattern,
|
|
17
|
+
type MetaPattern as DCBORMetaPattern,
|
|
18
|
+
} from "@bcts/dcbor-pattern";
|
|
19
|
+
|
|
20
|
+
import type { Pattern } from "./index";
|
|
21
|
+
import type { Result } from "../error";
|
|
22
|
+
import { ok } from "../error";
|
|
23
|
+
|
|
24
|
+
// Import leaf pattern constructors
|
|
25
|
+
import {
|
|
26
|
+
BoolPattern,
|
|
27
|
+
NumberPattern,
|
|
28
|
+
TextPattern,
|
|
29
|
+
ByteStringPattern,
|
|
30
|
+
DatePattern,
|
|
31
|
+
KnownValuePattern,
|
|
32
|
+
NullPattern,
|
|
33
|
+
ArrayPattern,
|
|
34
|
+
MapPattern,
|
|
35
|
+
TaggedPattern,
|
|
36
|
+
CBORPattern,
|
|
37
|
+
leafBool,
|
|
38
|
+
leafNull,
|
|
39
|
+
leafNumber,
|
|
40
|
+
leafText,
|
|
41
|
+
leafByteString,
|
|
42
|
+
leafDate,
|
|
43
|
+
leafKnownValue,
|
|
44
|
+
leafArray,
|
|
45
|
+
leafMap,
|
|
46
|
+
leafTag,
|
|
47
|
+
leafCbor,
|
|
48
|
+
} from "./leaf";
|
|
49
|
+
|
|
50
|
+
// Import meta pattern constructors
|
|
51
|
+
import {
|
|
52
|
+
AnyPattern,
|
|
53
|
+
AndPattern,
|
|
54
|
+
OrPattern,
|
|
55
|
+
NotPattern,
|
|
56
|
+
metaAny,
|
|
57
|
+
metaAnd,
|
|
58
|
+
metaOr,
|
|
59
|
+
metaNot,
|
|
60
|
+
} from "./meta";
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Convert a dcbor-pattern Pattern to a bc-envelope-pattern Pattern.
|
|
64
|
+
*
|
|
65
|
+
* This function serves as the bridge between the two pattern systems,
|
|
66
|
+
* allowing dcbor-pattern expressions to be used in envelope pattern contexts.
|
|
67
|
+
*
|
|
68
|
+
* @param dcborPattern - The dcbor-pattern Pattern to convert
|
|
69
|
+
* @returns The converted envelope pattern, or an error if conversion fails
|
|
70
|
+
*/
|
|
71
|
+
export function convertDcborPatternToEnvelopePattern(dcborPattern: DCBORPattern): Result<Pattern> {
|
|
72
|
+
switch (dcborPattern.kind) {
|
|
73
|
+
case "Value":
|
|
74
|
+
return convertValuePatternToEnvelopePattern(dcborPattern.pattern);
|
|
75
|
+
case "Structure":
|
|
76
|
+
return convertStructurePatternToEnvelopePattern(dcborPattern.pattern);
|
|
77
|
+
case "Meta":
|
|
78
|
+
return convertMetaPatternToEnvelopePattern(dcborPattern.pattern, dcborPattern);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Convert a dcbor-pattern ValuePattern to an envelope leaf pattern.
|
|
84
|
+
*/
|
|
85
|
+
function convertValuePatternToEnvelopePattern(valuePattern: DCBORValuePattern): Result<Pattern> {
|
|
86
|
+
switch (valuePattern.type) {
|
|
87
|
+
case "Bool": {
|
|
88
|
+
const boolPattern = BoolPattern.fromDcborPattern(valuePattern.pattern);
|
|
89
|
+
return ok({ type: "Leaf", pattern: leafBool(boolPattern) });
|
|
90
|
+
}
|
|
91
|
+
case "Number": {
|
|
92
|
+
const numberPattern = NumberPattern.fromDcborPattern(valuePattern.pattern);
|
|
93
|
+
return ok({ type: "Leaf", pattern: leafNumber(numberPattern) });
|
|
94
|
+
}
|
|
95
|
+
case "Text": {
|
|
96
|
+
const textPattern = TextPattern.fromDcborPattern(valuePattern.pattern);
|
|
97
|
+
return ok({ type: "Leaf", pattern: leafText(textPattern) });
|
|
98
|
+
}
|
|
99
|
+
case "ByteString": {
|
|
100
|
+
const byteStringPattern = ByteStringPattern.fromDcborPattern(valuePattern.pattern);
|
|
101
|
+
return ok({ type: "Leaf", pattern: leafByteString(byteStringPattern) });
|
|
102
|
+
}
|
|
103
|
+
case "Date": {
|
|
104
|
+
const datePattern = DatePattern.fromDcborPattern(valuePattern.pattern);
|
|
105
|
+
return ok({ type: "Leaf", pattern: leafDate(datePattern) });
|
|
106
|
+
}
|
|
107
|
+
case "KnownValue": {
|
|
108
|
+
const knownValuePattern = KnownValuePattern.fromDcborPattern(valuePattern.pattern);
|
|
109
|
+
return ok({ type: "Leaf", pattern: leafKnownValue(knownValuePattern) });
|
|
110
|
+
}
|
|
111
|
+
case "Null": {
|
|
112
|
+
return ok({ type: "Leaf", pattern: leafNull(NullPattern.new()) });
|
|
113
|
+
}
|
|
114
|
+
case "Digest": {
|
|
115
|
+
// Digest patterns don't have a direct envelope equivalent yet
|
|
116
|
+
// For now, wrap as a generic CBOR pattern
|
|
117
|
+
const cborPattern = CBORPattern.fromDcborPattern({
|
|
118
|
+
kind: "Value",
|
|
119
|
+
pattern: valuePattern,
|
|
120
|
+
});
|
|
121
|
+
return ok({ type: "Leaf", pattern: leafCbor(cborPattern) });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Convert a dcbor-pattern StructurePattern to an envelope pattern.
|
|
128
|
+
*/
|
|
129
|
+
function convertStructurePatternToEnvelopePattern(
|
|
130
|
+
structurePattern: DCBORStructurePattern,
|
|
131
|
+
): Result<Pattern> {
|
|
132
|
+
switch (structurePattern.type) {
|
|
133
|
+
case "Array": {
|
|
134
|
+
// Wrap the full dcbor pattern for array matching
|
|
135
|
+
const arrayPattern = ArrayPattern.fromDcborPattern({
|
|
136
|
+
kind: "Structure",
|
|
137
|
+
pattern: structurePattern,
|
|
138
|
+
});
|
|
139
|
+
return ok({ type: "Leaf", pattern: leafArray(arrayPattern) });
|
|
140
|
+
}
|
|
141
|
+
case "Map": {
|
|
142
|
+
// MapPattern only supports interval-based matching currently
|
|
143
|
+
// Use any() for general map patterns from dcbor
|
|
144
|
+
const mapPattern = MapPattern.any();
|
|
145
|
+
return ok({ type: "Leaf", pattern: leafMap(mapPattern) });
|
|
146
|
+
}
|
|
147
|
+
case "Tagged": {
|
|
148
|
+
const taggedPattern = TaggedPattern.fromDcborPattern(structurePattern.pattern);
|
|
149
|
+
return ok({ type: "Leaf", pattern: leafTag(taggedPattern) });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Convert a dcbor-pattern MetaPattern to an envelope meta pattern.
|
|
156
|
+
*/
|
|
157
|
+
function convertMetaPatternToEnvelopePattern(
|
|
158
|
+
metaPattern: DCBORMetaPattern,
|
|
159
|
+
originalPattern: DCBORPattern,
|
|
160
|
+
): Result<Pattern> {
|
|
161
|
+
switch (metaPattern.type) {
|
|
162
|
+
case "Any": {
|
|
163
|
+
// The dcbor "any" pattern corresponds to our "any" meta pattern
|
|
164
|
+
return ok({ type: "Meta", pattern: metaAny(AnyPattern.new()) });
|
|
165
|
+
}
|
|
166
|
+
case "And": {
|
|
167
|
+
// Convert AND pattern by recursively converting each sub-pattern
|
|
168
|
+
// dcbor-pattern structure: { type: "And", pattern: AndPattern }
|
|
169
|
+
// where AndPattern is { variant: "And", patterns: Pattern[] }
|
|
170
|
+
const convertedPatterns: Pattern[] = [];
|
|
171
|
+
for (const pattern of metaPattern.pattern.patterns) {
|
|
172
|
+
const result = convertDcborPatternToEnvelopePattern(pattern);
|
|
173
|
+
if (!result.ok) return result;
|
|
174
|
+
convertedPatterns.push(result.value);
|
|
175
|
+
}
|
|
176
|
+
return ok({ type: "Meta", pattern: metaAnd(AndPattern.new(convertedPatterns)) });
|
|
177
|
+
}
|
|
178
|
+
case "Or": {
|
|
179
|
+
// Convert OR pattern by recursively converting each sub-pattern
|
|
180
|
+
// dcbor-pattern structure: { type: "Or", pattern: OrPattern }
|
|
181
|
+
// where OrPattern is { variant: "Or", patterns: Pattern[] }
|
|
182
|
+
const convertedPatterns: Pattern[] = [];
|
|
183
|
+
for (const pattern of metaPattern.pattern.patterns) {
|
|
184
|
+
const result = convertDcborPatternToEnvelopePattern(pattern);
|
|
185
|
+
if (!result.ok) return result;
|
|
186
|
+
convertedPatterns.push(result.value);
|
|
187
|
+
}
|
|
188
|
+
return ok({ type: "Meta", pattern: metaOr(OrPattern.new(convertedPatterns)) });
|
|
189
|
+
}
|
|
190
|
+
case "Not": {
|
|
191
|
+
// Convert NOT pattern by recursively converting the inner pattern
|
|
192
|
+
// dcbor-pattern structure: { type: "Not", pattern: NotPattern }
|
|
193
|
+
// where NotPattern is { variant: "Not", pattern: Pattern }
|
|
194
|
+
const innerResult = convertDcborPatternToEnvelopePattern(metaPattern.pattern.pattern);
|
|
195
|
+
if (!innerResult.ok) return innerResult;
|
|
196
|
+
return ok({ type: "Meta", pattern: metaNot(NotPattern.new(innerResult.value)) });
|
|
197
|
+
}
|
|
198
|
+
case "Capture":
|
|
199
|
+
case "Repeat":
|
|
200
|
+
case "Search":
|
|
201
|
+
case "Sequence": {
|
|
202
|
+
// These patterns don't have direct envelope equivalents yet
|
|
203
|
+
// For now, wrap as a generic CBOR pattern
|
|
204
|
+
const cborPattern = CBORPattern.fromDcborPattern(originalPattern);
|
|
205
|
+
return ok({ type: "Leaf", pattern: leafCbor(cborPattern) });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
package/src/pattern/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ export * from "./structure";
|
|
|
26
26
|
export * from "./meta";
|
|
27
27
|
export * from "./matcher";
|
|
28
28
|
export * from "./vm";
|
|
29
|
+
export * from "./dcbor-integration";
|
|
29
30
|
|
|
30
31
|
// Import leaf patterns
|
|
31
32
|
import {
|
|
@@ -717,3 +718,7 @@ registerAllFactories();
|
|
|
717
718
|
// Register VM pattern functions to resolve circular dependencies
|
|
718
719
|
import { registerVMPatternFunctions } from "./vm";
|
|
719
720
|
registerVMPatternFunctions(patternPathsWithCaptures, patternMatches, patternPaths);
|
|
721
|
+
|
|
722
|
+
// Register pattern match function for meta patterns
|
|
723
|
+
import { registerPatternMatchFn } from "./matcher";
|
|
724
|
+
registerPatternMatchFn(patternMatches);
|
package/src/pattern/matcher.ts
CHANGED
|
@@ -86,3 +86,34 @@ export function compileAsAtomic(
|
|
|
86
86
|
literals.push(pat);
|
|
87
87
|
code.push({ type: "MatchPredicate", literalIndex: idx });
|
|
88
88
|
}
|
|
89
|
+
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// Pattern Match Registry
|
|
92
|
+
// ============================================================================
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Registry for pattern matching function to break circular dependencies.
|
|
96
|
+
* This allows meta patterns to match child patterns without importing from index.ts.
|
|
97
|
+
*/
|
|
98
|
+
let patternMatchFn: ((pattern: Pattern, haystack: Envelope) => boolean) | undefined;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Registers the pattern match function.
|
|
102
|
+
* Called from index.ts after all patterns are defined.
|
|
103
|
+
*/
|
|
104
|
+
export function registerPatternMatchFn(
|
|
105
|
+
fn: (pattern: Pattern, haystack: Envelope) => boolean,
|
|
106
|
+
): void {
|
|
107
|
+
patternMatchFn = fn;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Match a pattern against an envelope using the registered match function.
|
|
112
|
+
* Used by meta patterns to match child patterns.
|
|
113
|
+
*/
|
|
114
|
+
export function matchPattern(pattern: Pattern, haystack: Envelope): boolean {
|
|
115
|
+
if (patternMatchFn === undefined) {
|
|
116
|
+
throw new Error("Pattern match function not registered");
|
|
117
|
+
}
|
|
118
|
+
return patternMatchFn(pattern, haystack);
|
|
119
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { Envelope } from "@bcts/envelope";
|
|
10
10
|
import type { Path } from "../../format";
|
|
11
|
-
import type
|
|
11
|
+
import { type Matcher, matchPattern } from "../matcher";
|
|
12
12
|
import type { Instr } from "../vm";
|
|
13
13
|
import type { Pattern } from "../index";
|
|
14
14
|
|
|
@@ -46,10 +46,7 @@ export class AndPattern implements Matcher {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
49
|
-
const allMatch = this.#patterns.every((pattern) =>
|
|
50
|
-
const matcher = pattern as unknown as Matcher;
|
|
51
|
-
return matcher.matches(haystack);
|
|
52
|
-
});
|
|
49
|
+
const allMatch = this.#patterns.every((pattern) => matchPattern(pattern, haystack));
|
|
53
50
|
|
|
54
51
|
const paths = allMatch ? [[haystack]] : [];
|
|
55
52
|
return [paths, new Map<string, Path[]>()];
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { Envelope } from "@bcts/envelope";
|
|
10
10
|
import type { Path } from "../../format";
|
|
11
|
-
import type
|
|
11
|
+
import { type Matcher, matchPattern } from "../matcher";
|
|
12
12
|
import type { Instr } from "../vm";
|
|
13
13
|
import type { Pattern } from "../index";
|
|
14
14
|
|
|
@@ -47,8 +47,7 @@ export class NotPattern implements Matcher {
|
|
|
47
47
|
|
|
48
48
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
49
49
|
// If the inner pattern doesn't match, then we return the current envelope as a match
|
|
50
|
-
const
|
|
51
|
-
const paths = !matcher.matches(haystack) ? [[haystack]] : [];
|
|
50
|
+
const paths = !matchPattern(this.#pattern, haystack) ? [[haystack]] : [];
|
|
52
51
|
return [paths, new Map<string, Path[]>()];
|
|
53
52
|
}
|
|
54
53
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { Envelope } from "@bcts/envelope";
|
|
10
10
|
import type { Path } from "../../format";
|
|
11
|
-
import type
|
|
11
|
+
import { type Matcher, matchPattern } from "../matcher";
|
|
12
12
|
import type { Instr } from "../vm";
|
|
13
13
|
import type { Pattern } from "../index";
|
|
14
14
|
|
|
@@ -46,10 +46,7 @@ export class OrPattern implements Matcher {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
49
|
-
const anyMatch = this.#patterns.some((pattern) =>
|
|
50
|
-
const matcher = pattern as unknown as Matcher;
|
|
51
|
-
return matcher.matches(haystack);
|
|
52
|
-
});
|
|
49
|
+
const anyMatch = this.#patterns.some((pattern) => matchPattern(pattern, haystack));
|
|
53
50
|
|
|
54
51
|
const paths = anyMatch ? [[haystack]] : [];
|
|
55
52
|
return [paths, new Map<string, Path[]>()];
|