@bcts/dcbor 1.0.0-alpha.11 → 1.0.0-alpha.13
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/dist/index.cjs +40 -178
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +268 -317
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +268 -317
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +40 -178
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +40 -174
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -3
- package/src/cbor.ts +3 -3
- package/src/diag.ts +17 -2
- package/src/index.ts +2 -6
- package/src/tags-store.ts +35 -54
- package/src/tags.ts +7 -6
- package/src/walk.ts +8 -179
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bcts/dcbor",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Blockchain Commons Deterministic CBOR (dCBOR) for TypeScript",
|
|
6
6
|
"license": "BSD-2-Clause-Patent",
|
|
@@ -47,8 +47,6 @@
|
|
|
47
47
|
"dev": "tsdown --watch",
|
|
48
48
|
"test": "vitest run",
|
|
49
49
|
"test:watch": "vitest",
|
|
50
|
-
"test:cli": "vitest run tests/cli.test.ts",
|
|
51
|
-
"test:examples": "npm run build && node scripts/test-examples.js",
|
|
52
50
|
"lint": "eslint 'src/**/*.ts' 'tests/**/*.ts'",
|
|
53
51
|
"lint:fix": "eslint 'src/**/*.ts' 'tests/**/*.ts' --fix",
|
|
54
52
|
"typecheck": "tsc --noEmit",
|
package/src/cbor.ts
CHANGED
|
@@ -250,7 +250,7 @@ export interface CborMethods {
|
|
|
250
250
|
* @param initialState - Initial state for the visitor
|
|
251
251
|
* @param visitor - Visitor function called for each element
|
|
252
252
|
*/
|
|
253
|
-
walk<State>(initialState: State, visitor: Visitor<State>):
|
|
253
|
+
walk<State>(initialState: State, visitor: Visitor<State>): void;
|
|
254
254
|
/**
|
|
255
255
|
* Validate that value has one of the expected tags.
|
|
256
256
|
* @param expectedTags - Array of expected tag values
|
|
@@ -774,8 +774,8 @@ export const attachMethods = <T extends Omit<Cbor, keyof CborMethods>>(obj: T):
|
|
|
774
774
|
},
|
|
775
775
|
|
|
776
776
|
// Advanced operations
|
|
777
|
-
walk<State>(this: Cbor, initialState: State, visitor: Visitor<State>):
|
|
778
|
-
|
|
777
|
+
walk<State>(this: Cbor, initialState: State, visitor: Visitor<State>): void {
|
|
778
|
+
walk(this, initialState, visitor);
|
|
779
779
|
},
|
|
780
780
|
validateTag(this: Cbor, expectedTags: Tag[]): Tag {
|
|
781
781
|
if (this.type !== MajorType.Tagged) {
|
package/src/diag.ts
CHANGED
|
@@ -376,14 +376,29 @@ function formatMap(map: CborMap, opts: DiagFormatOpts): string {
|
|
|
376
376
|
|
|
377
377
|
/**
|
|
378
378
|
* Format tagged value.
|
|
379
|
+
*
|
|
380
|
+
* Matches Rust's diag_item() for Tagged case.
|
|
379
381
|
*/
|
|
380
382
|
function formatTagged(tag: number | bigint, content: Cbor, opts: DiagFormatOpts): string {
|
|
381
|
-
// Check for summarizer first
|
|
383
|
+
// Check for summarizer first (matches Rust's summarization logic)
|
|
382
384
|
if (opts.summarize === true) {
|
|
383
385
|
const store = resolveTagsStore(opts.tags);
|
|
384
386
|
const summarizer = store?.summarizer(tag);
|
|
385
387
|
if (summarizer !== undefined) {
|
|
386
|
-
|
|
388
|
+
// Call summarizer and handle Result type (matching Rust's match on Result)
|
|
389
|
+
const result = summarizer(content, opts.flat ?? false);
|
|
390
|
+
if (result.ok) {
|
|
391
|
+
return result.value;
|
|
392
|
+
} else {
|
|
393
|
+
// Match Rust's error format: "<error: {}>"
|
|
394
|
+
const errorMsg =
|
|
395
|
+
result.error.type === "Custom"
|
|
396
|
+
? result.error.message
|
|
397
|
+
: result.error.type === "WrongTag"
|
|
398
|
+
? `expected CBOR tag ${result.error.expected.value}, but got ${result.error.actual.value}`
|
|
399
|
+
: result.error.type;
|
|
400
|
+
return `<error: ${errorMsg}>`;
|
|
401
|
+
}
|
|
387
402
|
}
|
|
388
403
|
}
|
|
389
404
|
|
package/src/index.ts
CHANGED
|
@@ -52,6 +52,7 @@ export {
|
|
|
52
52
|
TagsStore,
|
|
53
53
|
type TagsStoreTrait,
|
|
54
54
|
type CborSummarizer,
|
|
55
|
+
type SummarizerResult,
|
|
55
56
|
getGlobalTagsStore,
|
|
56
57
|
} from "./tags-store";
|
|
57
58
|
export * from "./tags";
|
|
@@ -72,15 +73,10 @@ export {
|
|
|
72
73
|
type EdgeTypeVariant,
|
|
73
74
|
type WalkElement,
|
|
74
75
|
type Visitor,
|
|
76
|
+
walk,
|
|
75
77
|
asSingle,
|
|
76
78
|
asKeyValue,
|
|
77
79
|
edgeLabel,
|
|
78
|
-
// Helper functions
|
|
79
|
-
countElements,
|
|
80
|
-
collectAtLevel,
|
|
81
|
-
findFirst,
|
|
82
|
-
collectAllText,
|
|
83
|
-
maxDepth,
|
|
84
80
|
} from "./walk";
|
|
85
81
|
|
|
86
82
|
// Codable interfaces
|
package/src/tags-store.ts
CHANGED
|
@@ -9,17 +9,26 @@
|
|
|
9
9
|
|
|
10
10
|
import type { Cbor, CborNumber } from "./cbor";
|
|
11
11
|
import type { Tag } from "./tag";
|
|
12
|
+
import type { Error as CborErrorType } from "./error";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Result type for summarizer functions, matching Rust's Result<String, Error>.
|
|
16
|
+
*/
|
|
17
|
+
export type SummarizerResult =
|
|
18
|
+
| { readonly ok: true; readonly value: string }
|
|
19
|
+
| { readonly ok: false; readonly error: CborErrorType };
|
|
12
20
|
|
|
13
21
|
/**
|
|
14
22
|
* Function type for custom CBOR value summarizers.
|
|
15
23
|
*
|
|
16
24
|
* Summarizers provide custom string representations for tagged values.
|
|
25
|
+
* Returns a Result type matching Rust's `Result<String, Error>`.
|
|
17
26
|
*
|
|
18
27
|
* @param cbor - The CBOR value to summarize
|
|
19
28
|
* @param flat - If true, produce single-line output
|
|
20
|
-
* @returns
|
|
29
|
+
* @returns Result with summary string on success, or error on failure
|
|
21
30
|
*/
|
|
22
|
-
export type CborSummarizer = (cbor: Cbor, flat: boolean) =>
|
|
31
|
+
export type CborSummarizer = (cbor: Cbor, flat: boolean) => SummarizerResult;
|
|
23
32
|
|
|
24
33
|
/**
|
|
25
34
|
* Interface for tag store operations.
|
|
@@ -92,7 +101,13 @@ export class TagsStore implements TagsStoreTrait {
|
|
|
92
101
|
/**
|
|
93
102
|
* Insert a tag into the registry.
|
|
94
103
|
*
|
|
95
|
-
*
|
|
104
|
+
* Matches Rust's TagsStore::insert() behavior:
|
|
105
|
+
* - Throws if the tag name is undefined or empty
|
|
106
|
+
* - Throws if a tag with the same value exists with a different name
|
|
107
|
+
* - Allows re-registering the same tag value with the same name
|
|
108
|
+
*
|
|
109
|
+
* @param tag - The tag to register (must have a non-empty name)
|
|
110
|
+
* @throws Error if tag has no name, empty name, or conflicts with existing registration
|
|
96
111
|
*
|
|
97
112
|
* @example
|
|
98
113
|
* ```typescript
|
|
@@ -101,11 +116,25 @@ export class TagsStore implements TagsStoreTrait {
|
|
|
101
116
|
* ```
|
|
102
117
|
*/
|
|
103
118
|
insert(tag: Tag): void {
|
|
119
|
+
const name = tag.name;
|
|
120
|
+
|
|
121
|
+
// Rust: let name = tag.name().unwrap(); assert!(!name.is_empty());
|
|
122
|
+
if (name === undefined || name === "") {
|
|
123
|
+
throw new Error(`Tag ${tag.value} must have a non-empty name`);
|
|
124
|
+
}
|
|
125
|
+
|
|
104
126
|
const key = this.#valueKey(tag.value);
|
|
105
|
-
this.#tagsByValue.
|
|
106
|
-
|
|
107
|
-
|
|
127
|
+
const existing = this.#tagsByValue.get(key);
|
|
128
|
+
|
|
129
|
+
// Rust: if old_name != name { panic!(...) }
|
|
130
|
+
if (existing?.name !== undefined && existing.name !== name) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`Attempt to register tag: ${tag.value} '${existing.name}' with different name: '${name}'`,
|
|
133
|
+
);
|
|
108
134
|
}
|
|
135
|
+
|
|
136
|
+
this.#tagsByValue.set(key, tag);
|
|
137
|
+
this.#tagsByName.set(name, tag);
|
|
109
138
|
}
|
|
110
139
|
|
|
111
140
|
/**
|
|
@@ -148,27 +177,6 @@ export class TagsStore implements TagsStoreTrait {
|
|
|
148
177
|
this.#summarizers.set(key, summarizer);
|
|
149
178
|
}
|
|
150
179
|
|
|
151
|
-
/**
|
|
152
|
-
* Remove a tag from the registry.
|
|
153
|
-
*
|
|
154
|
-
* @param tagValue - The numeric tag value to remove
|
|
155
|
-
* @returns true if a tag was removed, false otherwise
|
|
156
|
-
*/
|
|
157
|
-
remove(tagValue: CborNumber): boolean {
|
|
158
|
-
const key = this.#valueKey(tagValue);
|
|
159
|
-
const tag = this.#tagsByValue.get(key);
|
|
160
|
-
if (tag === undefined) {
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
this.#tagsByValue.delete(key);
|
|
165
|
-
if (tag.name !== undefined) {
|
|
166
|
-
this.#tagsByName.delete(tag.name);
|
|
167
|
-
}
|
|
168
|
-
this.#summarizers.delete(key);
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
180
|
assignedNameForTag(tag: Tag): string | undefined {
|
|
173
181
|
const key = this.#valueKey(tag.value);
|
|
174
182
|
const stored = this.#tagsByValue.get(key);
|
|
@@ -198,33 +206,6 @@ export class TagsStore implements TagsStoreTrait {
|
|
|
198
206
|
return this.#summarizers.get(key);
|
|
199
207
|
}
|
|
200
208
|
|
|
201
|
-
/**
|
|
202
|
-
* Get all registered tags.
|
|
203
|
-
*
|
|
204
|
-
* @returns Array of all registered tags
|
|
205
|
-
*/
|
|
206
|
-
getAllTags(): Tag[] {
|
|
207
|
-
return Array.from(this.#tagsByValue.values());
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Clear all registered tags and summarizers.
|
|
212
|
-
*/
|
|
213
|
-
clear(): void {
|
|
214
|
-
this.#tagsByValue.clear();
|
|
215
|
-
this.#tagsByName.clear();
|
|
216
|
-
this.#summarizers.clear();
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Get the number of registered tags.
|
|
221
|
-
*
|
|
222
|
-
* @returns Number of tags in the registry
|
|
223
|
-
*/
|
|
224
|
-
get size(): number {
|
|
225
|
-
return this.#tagsByValue.size;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
209
|
/**
|
|
229
210
|
* Create a string key for a numeric tag value.
|
|
230
211
|
* Handles both number and bigint types.
|
package/src/tags.ts
CHANGED
|
@@ -148,11 +148,10 @@ export const TAG_SELF_DESCRIBE_CBOR = 55799;
|
|
|
148
148
|
// Matches Rust's register_tags() functionality
|
|
149
149
|
// ============================================================================
|
|
150
150
|
|
|
151
|
-
import type { TagsStore } from "./tags-store";
|
|
151
|
+
import type { TagsStore, SummarizerResult } from "./tags-store";
|
|
152
152
|
import { getGlobalTagsStore } from "./tags-store";
|
|
153
153
|
import { CborDate } from "./date";
|
|
154
154
|
import type { Cbor } from "./cbor";
|
|
155
|
-
import { diagnostic } from "./diag";
|
|
156
155
|
|
|
157
156
|
// Tag constants matching Rust
|
|
158
157
|
export const TAG_DATE = 1;
|
|
@@ -169,11 +168,13 @@ export const registerTagsIn = (tagsStore: TagsStore): void => {
|
|
|
169
168
|
tagsStore.insertAll(tags);
|
|
170
169
|
|
|
171
170
|
// Set summarizer for date tag
|
|
172
|
-
tagsStore.setSummarizer(TAG_DATE, (untaggedCbor: Cbor, _flat: boolean):
|
|
171
|
+
tagsStore.setSummarizer(TAG_DATE, (untaggedCbor: Cbor, _flat: boolean): SummarizerResult => {
|
|
173
172
|
try {
|
|
174
|
-
return CborDate.fromUntaggedCbor(untaggedCbor).toString();
|
|
175
|
-
} catch {
|
|
176
|
-
return
|
|
173
|
+
return { ok: true, value: CborDate.fromUntaggedCbor(untaggedCbor).toString() };
|
|
174
|
+
} catch (e) {
|
|
175
|
+
// On error, return error result matching Rust's Result::Err
|
|
176
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
177
|
+
return { ok: false, error: { type: "Custom", message } };
|
|
177
178
|
}
|
|
178
179
|
});
|
|
179
180
|
};
|
package/src/walk.ts
CHANGED
|
@@ -158,21 +158,20 @@ export type Visitor<State> = (
|
|
|
158
158
|
* @param cbor - The CBOR value to traverse
|
|
159
159
|
* @param initialState - Initial state value
|
|
160
160
|
* @param visitor - Function to call for each element
|
|
161
|
-
* @returns Final state after traversal
|
|
162
161
|
*
|
|
163
162
|
* @example
|
|
164
163
|
* ```typescript
|
|
165
|
-
* // Count all text strings in a structure
|
|
166
|
-
*
|
|
164
|
+
* // Count all text strings in a structure using RefCell-like pattern
|
|
165
|
+
* const count = { value: 0 };
|
|
167
166
|
*
|
|
168
167
|
* const structure = cbor({ name: 'Alice', tags: ['urgent', 'draft'] });
|
|
169
|
-
*
|
|
168
|
+
* walk(structure, null, (element, level, edge, state) => {
|
|
170
169
|
* if (element.type === 'single' && element.cbor.type === MajorType.Text) {
|
|
171
|
-
*
|
|
170
|
+
* count.value++;
|
|
172
171
|
* }
|
|
173
172
|
* return [state, false];
|
|
174
173
|
* });
|
|
175
|
-
* console.log(
|
|
174
|
+
* console.log(count.value); // 3 (name, urgent, draft)
|
|
176
175
|
* ```
|
|
177
176
|
*
|
|
178
177
|
* @example
|
|
@@ -181,7 +180,7 @@ export type Visitor<State> = (
|
|
|
181
180
|
* const structure = cbor([1, 2, 3, 'found', 5, 6]);
|
|
182
181
|
* let found = false;
|
|
183
182
|
*
|
|
184
|
-
* walk(structure, null, (element, level, edge) => {
|
|
183
|
+
* walk(structure, null, (element, level, edge, state) => {
|
|
185
184
|
* if (element.type === 'single' &&
|
|
186
185
|
* element.cbor.type === MajorType.Text &&
|
|
187
186
|
* element.cbor.value === 'found') {
|
|
@@ -192,8 +191,8 @@ export type Visitor<State> = (
|
|
|
192
191
|
* });
|
|
193
192
|
* ```
|
|
194
193
|
*/
|
|
195
|
-
export const walk = <State>(cbor: Cbor, initialState: State, visitor: Visitor<State>):
|
|
196
|
-
|
|
194
|
+
export const walk = <State>(cbor: Cbor, initialState: State, visitor: Visitor<State>): void => {
|
|
195
|
+
walkInternal(cbor, 0, { type: EdgeType.None }, initialState, visitor);
|
|
197
196
|
};
|
|
198
197
|
|
|
199
198
|
/**
|
|
@@ -344,173 +343,3 @@ function walkTagged<State>(
|
|
|
344
343
|
): State {
|
|
345
344
|
return walkInternal(cbor.value, level + 1, { type: EdgeType.TaggedContent }, state, visitor);
|
|
346
345
|
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Helper: Count all elements in a CBOR tree.
|
|
350
|
-
*
|
|
351
|
-
* @param cbor - The CBOR value to count
|
|
352
|
-
* @returns Total number of elements visited
|
|
353
|
-
*
|
|
354
|
-
* @example
|
|
355
|
-
* ```typescript
|
|
356
|
-
* const structure = cbor([1, 2, [3, 4]]);
|
|
357
|
-
* const count = countElements(structure);
|
|
358
|
-
* console.log(count); // 6 (array, 1, 2, inner array, 3, 4)
|
|
359
|
-
* ```
|
|
360
|
-
*/
|
|
361
|
-
export const countElements = (cbor: Cbor): number => {
|
|
362
|
-
interface CountState {
|
|
363
|
-
count: number;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
const result = walk<CountState>(cbor, { count: 0 }, (_element, _level, _edge, state) => {
|
|
367
|
-
return [{ count: state.count + 1 }, false];
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
return result.count;
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Helper: Collect all elements at a specific depth level.
|
|
375
|
-
*
|
|
376
|
-
* @param cbor - The CBOR value to traverse
|
|
377
|
-
* @param targetLevel - The depth level to collect (0 = root)
|
|
378
|
-
* @returns Array of CBOR values at the target level
|
|
379
|
-
*
|
|
380
|
-
* @example
|
|
381
|
-
* ```typescript
|
|
382
|
-
* const structure = cbor([[1, 2], [3, 4]]);
|
|
383
|
-
* const level1 = collectAtLevel(structure, 1);
|
|
384
|
-
* // Returns: [[1, 2], [3, 4]]
|
|
385
|
-
* const level2 = collectAtLevel(structure, 2);
|
|
386
|
-
* // Returns: [1, 2, 3, 4]
|
|
387
|
-
* ```
|
|
388
|
-
*/
|
|
389
|
-
export const collectAtLevel = (cbor: Cbor, targetLevel: number): Cbor[] => {
|
|
390
|
-
interface CollectState {
|
|
391
|
-
items: Cbor[];
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
const result = walk<CollectState>(cbor, { items: [] }, (element, level, _edge, state) => {
|
|
395
|
-
if (level === targetLevel && element.type === "single") {
|
|
396
|
-
return [{ items: [...state.items, element.cbor] }, false];
|
|
397
|
-
}
|
|
398
|
-
return [state, false];
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
return result.items;
|
|
402
|
-
};
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Helper: Find first element matching a predicate.
|
|
406
|
-
*
|
|
407
|
-
* @template T - Type of extracted value
|
|
408
|
-
* @param cbor - The CBOR value to search
|
|
409
|
-
* @param predicate - Function to test each element
|
|
410
|
-
* @returns First matching element, or undefined if not found
|
|
411
|
-
*
|
|
412
|
-
* @example
|
|
413
|
-
* ```typescript
|
|
414
|
-
* const structure = cbor({ users: [
|
|
415
|
-
* { name: 'Alice', age: 30 },
|
|
416
|
-
* { name: 'Bob', age: 25 }
|
|
417
|
-
* ]});
|
|
418
|
-
*
|
|
419
|
-
* const bob = findFirst(structure, (element) => {
|
|
420
|
-
* if (element.type === 'single' &&
|
|
421
|
-
* element.cbor.type === MajorType.Text &&
|
|
422
|
-
* element.cbor.value === 'Bob') {
|
|
423
|
-
* return true;
|
|
424
|
-
* }
|
|
425
|
-
* return false;
|
|
426
|
-
* });
|
|
427
|
-
* ```
|
|
428
|
-
*/
|
|
429
|
-
export const findFirst = (
|
|
430
|
-
cbor: Cbor,
|
|
431
|
-
predicate: (element: WalkElement) => boolean,
|
|
432
|
-
): Cbor | undefined => {
|
|
433
|
-
interface FindState {
|
|
434
|
-
found?: Cbor;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
const result = walk<FindState>(cbor, {}, (element, _level, _edge, state) => {
|
|
438
|
-
if (state.found !== undefined) {
|
|
439
|
-
// Already found, stop descending
|
|
440
|
-
return [state, true];
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
if (predicate(element)) {
|
|
444
|
-
if (element.type === "single") {
|
|
445
|
-
return [{ found: element.cbor }, true]; // Stop after finding
|
|
446
|
-
}
|
|
447
|
-
// Matched but not a single element, stop anyway
|
|
448
|
-
return [state, true];
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
return [state, false];
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
return result.found;
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Helper: Collect all text strings in a CBOR tree.
|
|
459
|
-
*
|
|
460
|
-
* @param cbor - The CBOR value to traverse
|
|
461
|
-
* @returns Array of all text string values found
|
|
462
|
-
*
|
|
463
|
-
* @example
|
|
464
|
-
* ```typescript
|
|
465
|
-
* const doc = cbor({
|
|
466
|
-
* title: 'Document',
|
|
467
|
-
* tags: ['urgent', 'draft'],
|
|
468
|
-
* author: { name: 'Alice' }
|
|
469
|
-
* });
|
|
470
|
-
*
|
|
471
|
-
* const texts = collectAllText(doc);
|
|
472
|
-
* // Returns: ['Document', 'urgent', 'draft', 'Alice']
|
|
473
|
-
* ```
|
|
474
|
-
*/
|
|
475
|
-
export const collectAllText = (cbor: Cbor): string[] => {
|
|
476
|
-
interface TextState {
|
|
477
|
-
texts: string[];
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
const result = walk<TextState>(cbor, { texts: [] }, (element, _level, _edge, state) => {
|
|
481
|
-
if (element.type === "single" && element.cbor.type === MajorType.Text) {
|
|
482
|
-
return [{ texts: [...state.texts, element.cbor.value] }, false];
|
|
483
|
-
}
|
|
484
|
-
return [state, false];
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
return result.texts;
|
|
488
|
-
};
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* Helper: Get the maximum depth of a CBOR tree.
|
|
492
|
-
*
|
|
493
|
-
* @param cbor - The CBOR value to measure
|
|
494
|
-
* @returns Maximum depth (0 for leaf values, 1+ for containers)
|
|
495
|
-
*
|
|
496
|
-
* @example
|
|
497
|
-
* ```typescript
|
|
498
|
-
* const flat = cbor([1, 2, 3]);
|
|
499
|
-
* console.log(maxDepth(flat)); // 1
|
|
500
|
-
*
|
|
501
|
-
* const nested = cbor([[[1]]]);
|
|
502
|
-
* console.log(maxDepth(nested)); // 3
|
|
503
|
-
* ```
|
|
504
|
-
*/
|
|
505
|
-
export const maxDepth = (cbor: Cbor): number => {
|
|
506
|
-
interface DepthState {
|
|
507
|
-
maxDepth: number;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
const result = walk<DepthState>(cbor, { maxDepth: 0 }, (_element, level, _edge, state) => {
|
|
511
|
-
const newMaxDepth = Math.max(state.maxDepth, level);
|
|
512
|
-
return [{ maxDepth: newMaxDepth }, false];
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
return result.maxDepth;
|
|
516
|
-
};
|