@milaboratories/pl-tree 1.5.1 → 1.5.3

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/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "@milaboratories/pl-tree",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "description": "Reactive pl tree state",
5
+ "engines": {
6
+ "node": ">=20.16.0"
7
+ },
5
8
  "types": "./dist/index.d.ts",
6
9
  "main": "./dist/index.js",
7
10
  "module": "./dist/index.mjs",
@@ -20,10 +23,11 @@
20
23
  "denque": "^2.1.0",
21
24
  "utility-types": "^3.11.0",
22
25
  "zod": "~3.23.8",
23
- "@milaboratories/computable": "^2.4.1",
24
- "@milaboratories/pl-client": "^2.7.13",
25
- "@milaboratories/pl-errors": "^1.0.2",
26
- "@milaboratories/ts-helpers": "^1.1.4"
26
+ "@milaboratories/pl-client": "^2.7.14",
27
+ "@milaboratories/computable": "^2.4.3",
28
+ "@milaboratories/pl-error-like": "^1.12.0",
29
+ "@milaboratories/ts-helpers": "^1.1.5",
30
+ "@milaboratories/pl-errors": "^1.0.4"
27
31
  },
28
32
  "devDependencies": {
29
33
  "typescript": "~5.5.4",
@@ -37,6 +41,7 @@
37
41
  "scripts": {
38
42
  "type-check": "tsc --noEmit --composite false",
39
43
  "build": "vite build",
44
+ "lint": "eslint .",
40
45
  "test": "jest --runInBand",
41
46
  "do-pack": "rm -f *.tgz && pnpm pack && mv *.tgz package.tgz"
42
47
  }
package/src/accessors.ts CHANGED
@@ -1,30 +1,38 @@
1
- import { PlTreeResource, PlTreeState } from './state';
2
- import {
1
+ import type { PlTreeResource, PlTreeState } from './state';
2
+ import type {
3
3
  AccessorProvider,
4
4
  ComputableCtx,
5
5
  ComputableHooks,
6
- UsageGuard
6
+ UsageGuard,
7
7
  } from '@milaboratories/computable';
8
- import {
8
+ import type {
9
9
  ResourceId,
10
- resourceIdToString,
11
10
  ResourceType,
11
+ OptionalResourceId } from '@milaboratories/pl-client';
12
+ import {
13
+ resourceIdToString,
12
14
  resourceTypesEqual,
13
15
  resourceTypeToString,
16
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
14
17
  NullResourceId,
15
- OptionalResourceId,
16
- stringifyWithResourceId
17
18
  } from '@milaboratories/pl-client';
18
- import { mapValueAndError, ValueAndError } from './value_and_error';
19
- import {
19
+ import type { ValueAndError } from './value_and_error';
20
+ import { mapValueAndError } from './value_and_error';
21
+ import type {
20
22
  CommonFieldTraverseOps,
21
23
  FieldTraversalStep,
22
24
  GetFieldStep,
23
- ResourceTraversalOps
25
+ ResourceTraversalOps,
24
26
  } from './traversal_ops';
25
- import { ValueOrError } from './value_or_error';
27
+ import type { ValueOrError } from './value_or_error';
26
28
  import { parsePlError } from '@milaboratories/pl-errors';
27
29
  import { notEmpty } from '@milaboratories/ts-helpers';
30
+ /** Error encountered during traversal in field or resource. */
31
+ export class PlError extends Error {
32
+ constructor(message: string) {
33
+ super(message);
34
+ }
35
+ }
28
36
 
29
37
  export type TreeAccessorData = {
30
38
  readonly treeProvider: () => PlTreeState;
@@ -38,25 +46,25 @@ export type TreeAccessorInstanceData = {
38
46
 
39
47
  export function isPlTreeEntry(obj: unknown): obj is PlTreeEntry {
40
48
  return (
41
- typeof obj === 'object' &&
42
- obj !== null &&
43
- (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntry'
49
+ typeof obj === 'object'
50
+ && obj !== null
51
+ && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntry'
44
52
  );
45
53
  }
46
54
 
47
55
  export function isPlTreeEntryAccessor(obj: unknown): obj is PlTreeEntryAccessor {
48
56
  return (
49
- typeof obj === 'object' &&
50
- obj !== null &&
51
- (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntryAccessor'
57
+ typeof obj === 'object'
58
+ && obj !== null
59
+ && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntryAccessor'
52
60
  );
53
61
  }
54
62
 
55
63
  export function isPlTreeNodeAccessor(obj: unknown): obj is PlTreeNodeAccessor {
56
64
  return (
57
- typeof obj === 'object' &&
58
- obj !== null &&
59
- (obj as any)['__pl_tree_type_marker__'] === 'PlTreeNodeAccessor'
65
+ typeof obj === 'object'
66
+ && obj !== null
67
+ && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeNodeAccessor'
60
68
  );
61
69
  }
62
70
 
@@ -66,13 +74,13 @@ export class PlTreeEntry implements AccessorProvider<PlTreeEntryAccessor> {
66
74
 
67
75
  constructor(
68
76
  private readonly accessorData: TreeAccessorData,
69
- public readonly rid: ResourceId
77
+ public readonly rid: ResourceId,
70
78
  ) {}
71
79
 
72
80
  public createAccessor(ctx: ComputableCtx, guard: UsageGuard): PlTreeEntryAccessor {
73
81
  return new PlTreeEntryAccessor(this.accessorData, this.accessorData.treeProvider(), this.rid, {
74
82
  ctx,
75
- guard
83
+ guard,
76
84
  });
77
85
  }
78
86
 
@@ -90,13 +98,13 @@ function getResourceFromTree(
90
98
  tree: PlTreeState,
91
99
  instanceData: TreeAccessorInstanceData,
92
100
  rid: ResourceId,
93
- ops: ResourceTraversalOps
101
+ ops: ResourceTraversalOps,
94
102
  ): PlTreeNodeAccessor {
95
103
  const acc = new PlTreeNodeAccessor(
96
104
  accessorData,
97
105
  tree,
98
106
  tree.get(instanceData.ctx.watcher, rid),
99
- instanceData
107
+ instanceData,
100
108
  );
101
109
 
102
110
  if (!ops.ignoreError) {
@@ -106,13 +114,14 @@ function getResourceFromTree(
106
114
  }
107
115
 
108
116
  if (
109
- ops.assertResourceType !== undefined &&
110
- (Array.isArray(ops.assertResourceType)
117
+ ops.assertResourceType !== undefined
118
+ && (Array.isArray(ops.assertResourceType)
111
119
  ? ops.assertResourceType.findIndex((rt) => resourceTypesEqual(rt, acc.resourceType)) === -1
112
120
  : !resourceTypesEqual(ops.assertResourceType, acc.resourceType))
113
121
  )
114
122
  throw new Error(
115
- `wrong resource type ${resourceTypeToString(acc.resourceType)} but expected ${ops.assertResourceType}`
123
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
124
+ `wrong resource type ${resourceTypeToString(acc.resourceType)} but expected ${ops.assertResourceType}`,
116
125
  );
117
126
 
118
127
  return acc;
@@ -125,7 +134,7 @@ export class PlTreeEntryAccessor {
125
134
  private readonly accessorData: TreeAccessorData,
126
135
  private readonly tree: PlTreeState,
127
136
  private readonly rid: ResourceId,
128
- private readonly instanceData: TreeAccessorInstanceData
137
+ private readonly instanceData: TreeAccessorInstanceData,
129
138
  ) {}
130
139
 
131
140
  node(ops: ResourceTraversalOps = {}): PlTreeNodeAccessor {
@@ -171,7 +180,7 @@ export class PlTreeNodeAccessor {
171
180
  private readonly accessorData: TreeAccessorData,
172
181
  private readonly tree: PlTreeState,
173
182
  private readonly resource: PlTreeResource,
174
- private readonly instanceData: TreeAccessorInstanceData
183
+ private readonly instanceData: TreeAccessorInstanceData,
175
184
  ) {}
176
185
 
177
186
  public get id(): ResourceId {
@@ -201,7 +210,7 @@ export class PlTreeNodeAccessor {
201
210
  ...steps: [
202
211
  Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {
203
212
  errorIfFieldNotSet: true;
204
- }
213
+ },
205
214
  ]
206
215
  ): PlTreeNodeAccessor;
207
216
  public traverse(...steps: (FieldTraversalStep | string)[]): PlTreeNodeAccessor | undefined;
@@ -213,15 +222,15 @@ export class PlTreeNodeAccessor {
213
222
  ...steps: [
214
223
  Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {
215
224
  errorIfFieldNotSet: true;
216
- }
225
+ },
217
226
  ]
218
- ): ValueOrError<PlTreeNodeAccessor, string>;
227
+ ): ValueOrError<PlTreeNodeAccessor, Error>;
219
228
  public traverseOrError(
220
229
  ...steps: (FieldTraversalStep | string)[]
221
- ): ValueOrError<PlTreeNodeAccessor, string> | undefined;
230
+ ): ValueOrError<PlTreeNodeAccessor, Error> | undefined;
222
231
  public traverseOrError(
223
232
  ...steps: (FieldTraversalStep | string)[]
224
- ): ValueOrError<PlTreeNodeAccessor, string> | undefined {
233
+ ): ValueOrError<PlTreeNodeAccessor, Error> | undefined {
225
234
  return this.traverseOrErrorWithCommon({}, ...steps);
226
235
  }
227
236
 
@@ -231,6 +240,7 @@ export class PlTreeNodeAccessor {
231
240
  ): PlTreeNodeAccessor | undefined {
232
241
  const result = this.traverseOrErrorWithCommon(commonOptions, ...steps);
233
242
  if (result === undefined) return undefined;
243
+
234
244
  if (!result.ok) throw result.error;
235
245
  return result.value;
236
246
  }
@@ -238,15 +248,16 @@ export class PlTreeNodeAccessor {
238
248
  public traverseOrErrorWithCommon(
239
249
  commonOptions: CommonFieldTraverseOps,
240
250
  ...steps: (FieldTraversalStep | string)[]
241
- ): ValueOrError<PlTreeNodeAccessor, string> | undefined {
251
+ ): ValueOrError<PlTreeNodeAccessor, Error> | undefined {
252
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
242
253
  let current: PlTreeNodeAccessor = this;
243
254
 
244
255
  for (const _step of steps) {
245
- const step: FieldTraversalStep =
246
- typeof _step === 'string'
256
+ const step: FieldTraversalStep
257
+ = typeof _step === 'string'
247
258
  ? {
248
259
  ...commonOptions,
249
- field: _step
260
+ field: _step,
250
261
  }
251
262
  : { ...commonOptions, ..._step };
252
263
 
@@ -262,17 +273,17 @@ export class PlTreeNodeAccessor {
262
273
  ok: false,
263
274
 
264
275
  // FIXME: in next tickets we'll allow Errors to be thrown.
265
- error: (parsePlError(
276
+ error: parsePlError(
266
277
  notEmpty(next.error.getDataAsString()),
267
278
  current.id, current.resourceType, step.field,
268
- ) as unknown as string),
279
+ ),
269
280
  };
270
281
 
271
282
  if (next.value === undefined) {
272
283
  if (step.errorIfFieldNotSet)
273
284
  return {
274
285
  ok: false,
275
- error: `field have no assigned value ${step.field} of ${resourceIdToString(current.id)}`,
286
+ error: new Error(`field have no assigned value ${step.field} of ${resourceIdToString(current.id)}`),
276
287
  };
277
288
  // existing but unpopulated field is unstable because it must be resolved at some point
278
289
  this.onUnstableLambda('unpopulated_field:' + step.field);
@@ -392,7 +403,7 @@ export class PlTreeNodeAccessor {
392
403
 
393
404
  public getKeyValueAsJson<T = unknown>(
394
405
  key: string,
395
- unstableIfNotFound: boolean = false
406
+ unstableIfNotFound: boolean = false,
396
407
  ): T | undefined {
397
408
  const result = this.resource.getKeyValueString(this.instanceData.ctx.watcher, key);
398
409
  if (result === undefined) {
package/src/dump.ts CHANGED
@@ -1,33 +1,33 @@
1
- import { ExtendedResourceData } from "./state"
1
+ import type { ExtendedResourceData } from './state';
2
2
 
3
3
  export type ResourceStats = {
4
- /** Number of resources of this type */
5
- count: number,
6
- /** Total number of bytes in the field names of all resources of this type */
7
- fieldNameBytes: number,
8
- /** Total number of fields in all resources of this type */
9
- fieldsCount: number,
10
- /** Total number of bytes in the data of all resources of this type */
11
- dataBytes: number,
12
- /** Total number of key-value records in all resources of this type */
13
- kvCount: number,
14
- /** Total number of bytes in the key-value records of all resources of this type */
15
- kvBytes: number,
16
- }
4
+ /** Number of resources of this type */
5
+ count: number;
6
+ /** Total number of bytes in the field names of all resources of this type */
7
+ fieldNameBytes: number;
8
+ /** Total number of fields in all resources of this type */
9
+ fieldsCount: number;
10
+ /** Total number of bytes in the data of all resources of this type */
11
+ dataBytes: number;
12
+ /** Total number of key-value records in all resources of this type */
13
+ kvCount: number;
14
+ /** Total number of bytes in the key-value records of all resources of this type */
15
+ kvBytes: number;
16
+ };
17
17
 
18
18
  /**
19
19
  * A map of resource type statistics, keyed by the resource type name and version.
20
- *
20
+ *
21
21
  * @type {Record<string, ResourceStats>}
22
22
  */
23
23
  export type TreeDumpStats = {
24
- total: ResourceStats,
25
- byResourceType: Record<`${string}/${string}`, ResourceStats>
26
- }
24
+ total: ResourceStats;
25
+ byResourceType: Record<`${string}/${string}`, ResourceStats>;
26
+ };
27
27
 
28
28
  /**
29
29
  * Analyzes a collection of resources and generates statistics grouped by resource type.
30
- *
30
+ *
31
31
  * This function processes an array of ExtendedResourceData and calculates various metrics
32
32
  * for each unique resource type, including:
33
33
  * - Count of resources
@@ -36,9 +36,9 @@ export type TreeDumpStats = {
36
36
  * - Total bytes in resource data
37
37
  * - Total number of key-value records
38
38
  * - Total bytes in key-value records
39
- *
39
+ *
40
40
  * The statistics are organized by resource type using a key in the format "typeName/version".
41
- *
41
+ *
42
42
  * @param dumpStats - Array of ExtendedResourceData objects to analyze
43
43
  * @returns A DumpStats object containing statistics for each resource type
44
44
  * @example
@@ -59,57 +59,57 @@ export type TreeDumpStats = {
59
59
  * ```
60
60
  */
61
61
  export function treeDumpStats(dumpStats: ExtendedResourceData[]): TreeDumpStats {
62
- const stats: TreeDumpStats = {
63
- total: {
64
- count: 0,
65
- fieldNameBytes: 0,
66
- fieldsCount: 0,
67
- dataBytes: 0,
68
- kvCount: 0,
69
- kvBytes: 0
70
- },
71
- byResourceType: {}
72
- };
62
+ const stats: TreeDumpStats = {
63
+ total: {
64
+ count: 0,
65
+ fieldNameBytes: 0,
66
+ fieldsCount: 0,
67
+ dataBytes: 0,
68
+ kvCount: 0,
69
+ kvBytes: 0,
70
+ },
71
+ byResourceType: {},
72
+ };
73
73
 
74
- for (const resource of dumpStats) {
75
- const typeKey = `${resource.type.name}/${resource.type.version}` as const;
76
- if (!stats.byResourceType[typeKey]) {
77
- stats.byResourceType[typeKey] = {
78
- count: 0,
79
- fieldNameBytes: 0,
80
- fieldsCount: 0,
81
- dataBytes: 0,
82
- kvCount: 0,
83
- kvBytes: 0
84
- };
85
- }
74
+ for (const resource of dumpStats) {
75
+ const typeKey = `${resource.type.name}/${resource.type.version}` as const;
76
+ if (!stats.byResourceType[typeKey]) {
77
+ stats.byResourceType[typeKey] = {
78
+ count: 0,
79
+ fieldNameBytes: 0,
80
+ fieldsCount: 0,
81
+ dataBytes: 0,
82
+ kvCount: 0,
83
+ kvBytes: 0,
84
+ };
85
+ }
86
86
 
87
- const typeStats = stats.byResourceType[typeKey];
88
- typeStats.count++;
89
- stats.total.count++;
87
+ const typeStats = stats.byResourceType[typeKey];
88
+ typeStats.count++;
89
+ stats.total.count++;
90
90
 
91
- for (const field of resource.fields) {
92
- typeStats.fieldNameBytes += field.name.length;
93
- typeStats.fieldsCount++;
94
- stats.total.fieldNameBytes += field.name.length;
95
- stats.total.fieldsCount++;
96
- }
91
+ for (const field of resource.fields) {
92
+ typeStats.fieldNameBytes += field.name.length;
93
+ typeStats.fieldsCount++;
94
+ stats.total.fieldNameBytes += field.name.length;
95
+ stats.total.fieldsCount++;
96
+ }
97
97
 
98
- if (resource.data) {
99
- const dataLength = resource.data?.length ?? 0;
100
- typeStats.dataBytes += dataLength;
101
- stats.total.dataBytes += dataLength;
102
- }
98
+ if (resource.data) {
99
+ const dataLength = resource.data?.length ?? 0;
100
+ typeStats.dataBytes += dataLength;
101
+ stats.total.dataBytes += dataLength;
102
+ }
103
+
104
+ typeStats.kvCount += resource.kv.length;
105
+ stats.total.kvCount += resource.kv.length;
103
106
 
104
- typeStats.kvCount += resource.kv.length;
105
- stats.total.kvCount += resource.kv.length;
106
-
107
- for (const kv of resource.kv) {
108
- const kvLength = kv.key.length + kv.value.length;
109
- typeStats.kvBytes += kvLength;
110
- stats.total.kvBytes += kvLength;
111
- }
107
+ for (const kv of resource.kv) {
108
+ const kvLength = kv.key.length + kv.value.length;
109
+ typeStats.kvBytes += kvLength;
110
+ stats.total.kvBytes += kvLength;
112
111
  }
112
+ }
113
113
 
114
- return stats;
115
- }
114
+ return stats;
115
+ }
package/src/snapshot.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { ResourceId, ResourceType } from '@milaboratories/pl-client';
2
- import { Optional, Writable } from 'utility-types';
3
- import { ZodType, z } from 'zod';
4
- import { PlTreeEntry, PlTreeEntryAccessor, PlTreeNodeAccessor } from './accessors';
5
- import { ComputableCtx } from '@milaboratories/computable';
1
+ import type { ResourceId, ResourceType } from '@milaboratories/pl-client';
2
+ import type { Optional, Writable } from 'utility-types';
3
+ import type { ZodType, z } from 'zod';
4
+ import type { PlTreeNodeAccessor } from './accessors';
5
+ import { PlTreeEntry, PlTreeEntryAccessor } from './accessors';
6
+ import type { ComputableCtx } from '@milaboratories/computable';
6
7
  import { notEmpty } from '@milaboratories/ts-helpers';
7
8
 
8
9
  /**
@@ -13,7 +14,7 @@ import { notEmpty } from '@milaboratories/ts-helpers';
13
14
  export type ResourceSnapshot<
14
15
  Data = undefined,
15
16
  Fields extends Record<string, ResourceId | undefined> | undefined = undefined,
16
- KV extends Record<string, unknown> | undefined = undefined
17
+ KV extends Record<string, unknown> | undefined = undefined,
17
18
  > = {
18
19
  readonly id: ResourceId;
19
20
  readonly type: ResourceType;
@@ -33,7 +34,7 @@ type ResourceSnapshotGeneric = ResourceSnapshot<
33
34
  export type ResourceSnapshotSchema<
34
35
  Data extends ZodType | 'raw' | undefined = undefined,
35
36
  Fields extends Record<string, boolean> | undefined = undefined,
36
- KV extends Record<string, ZodType | 'raw'> | undefined = undefined
37
+ KV extends Record<string, ZodType | 'raw'> | undefined = undefined,
37
38
  > = {
38
39
  readonly data: Data;
39
40
  readonly fields: Fields;
@@ -44,9 +45,9 @@ export type ResourceSnapshotSchema<
44
45
  export function rsSchema<
45
46
  const Data extends ZodType | 'raw' | undefined = undefined,
46
47
  const Fields extends Record<string, boolean> | undefined = undefined,
47
- const KV extends Record<string, ZodType | 'raw'> | undefined = undefined
48
+ const KV extends Record<string, ZodType | 'raw'> | undefined = undefined,
48
49
  >(
49
- schema: Optional<ResourceSnapshotSchema<Data, Fields, KV>>
50
+ schema: Optional<ResourceSnapshotSchema<Data, Fields, KV>>,
50
51
  ): ResourceSnapshotSchema<Data, Fields, KV> {
51
52
  return schema as any;
52
53
  }
@@ -114,10 +115,10 @@ export function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneri
114
115
  export function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneric>(
115
116
  res: PlTreeEntry | PlTreeEntryAccessor | PlTreeNodeAccessor,
116
117
  schema: Schema,
117
- ctx?: ComputableCtx
118
+ ctx?: ComputableCtx,
118
119
  ): InferSnapshot<Schema> {
119
- const node =
120
- res instanceof PlTreeEntry
120
+ const node
121
+ = res instanceof PlTreeEntry
121
122
  ? notEmpty(ctx).accessor(res).node()
122
123
  : res instanceof PlTreeEntryAccessor
123
124
  ? res.node()
@@ -138,7 +139,7 @@ export function makeResourceSnapshot<Schema extends ResourceSnapshotSchemaGeneri
138
139
  fields[fieldName] = node.traverse({
139
140
  field: fieldName,
140
141
  errorIfFieldNotSet: required,
141
- stableIfNotFound: !required
142
+ stableIfNotFound: !required,
142
143
  })?.id;
143
144
  result.fields = fields;
144
145
  }
@@ -174,21 +175,21 @@ export type ResourceWithData = {
174
175
  export function treeEntryToResourceWithData(
175
176
  res: PlTreeEntry | ResourceWithData,
176
177
  fields: string[],
177
- ctx: ComputableCtx
178
+ ctx: ComputableCtx,
178
179
  ): ResourceWithData {
179
180
  if (res instanceof PlTreeEntry) {
180
- const node = ctx.accessor(res as PlTreeEntry).node();
181
+ const node = ctx.accessor(res).node();
181
182
  const info = node.resourceInfo;
182
183
 
183
184
  const fValues: [string, ResourceId | undefined][] = fields.map((name) => [
184
185
  name,
185
- node.getField(name)?.value?.id
186
+ node.getField(name)?.value?.id,
186
187
  ]);
187
188
 
188
189
  return {
189
190
  ...info,
190
191
  fields: new Map(fValues),
191
- data: node.getData() ?? new Uint8Array()
192
+ data: node.getData() ?? new Uint8Array(),
192
193
  };
193
194
  }
194
195
 
@@ -206,16 +207,16 @@ export type ResourceWithMetadata = {
206
207
  export function treeEntryToResourceWithMetadata(
207
208
  res: PlTreeEntry | ResourceWithMetadata,
208
209
  mdKeys: string[],
209
- ctx: ComputableCtx
210
+ ctx: ComputableCtx,
210
211
  ): ResourceWithMetadata {
211
212
  if (!(res instanceof PlTreeEntry)) return res;
212
213
 
213
- const node = ctx.accessor(res as PlTreeEntry).node();
214
+ const node = ctx.accessor(res).node();
214
215
  const info = node.resourceInfo;
215
216
  const mdEntries: [string, any][] = mdKeys.map((k) => [k, node.getKeyValue(k)]);
216
217
 
217
218
  return {
218
219
  ...info,
219
- metadata: Object.fromEntries(mdEntries)
220
+ metadata: Object.fromEntries(mdEntries),
220
221
  };
221
222
  }