@milaboratories/pl-tree 1.5.0 → 1.5.2

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.0",
3
+ "version": "1.5.2",
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,10 @@
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/ts-helpers": "^1.1.4",
25
- "@milaboratories/pl-errors": "^1.0.1",
26
- "@milaboratories/pl-client": "^2.7.12"
26
+ "@milaboratories/computable": "^2.4.2",
27
+ "@milaboratories/ts-helpers": "^1.1.5",
28
+ "@milaboratories/pl-client": "^2.7.14",
29
+ "@milaboratories/pl-errors": "^1.0.3"
27
30
  },
28
31
  "devDependencies": {
29
32
  "typescript": "~5.5.4",
@@ -32,11 +35,12 @@
32
35
  "jest": "^29.7.0",
33
36
  "@jest/globals": "^29.7.0",
34
37
  "ts-jest": "^29.2.6",
35
- "@milaboratories/platforma-build-configs": "1.0.2"
38
+ "@milaboratories/platforma-build-configs": "1.0.3"
36
39
  },
37
40
  "scripts": {
38
41
  "type-check": "tsc --noEmit --composite false",
39
42
  "build": "vite build",
43
+ "lint": "eslint .",
40
44
  "test": "jest --runInBand",
41
45
  "do-pack": "rm -f *.tgz && pnpm pack && mv *.tgz package.tgz"
42
46
  }
package/src/accessors.ts CHANGED
@@ -1,28 +1,30 @@
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';
28
30
 
@@ -38,25 +40,25 @@ export type TreeAccessorInstanceData = {
38
40
 
39
41
  export function isPlTreeEntry(obj: unknown): obj is PlTreeEntry {
40
42
  return (
41
- typeof obj === 'object' &&
42
- obj !== null &&
43
- (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntry'
43
+ typeof obj === 'object'
44
+ && obj !== null
45
+ && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntry'
44
46
  );
45
47
  }
46
48
 
47
49
  export function isPlTreeEntryAccessor(obj: unknown): obj is PlTreeEntryAccessor {
48
50
  return (
49
- typeof obj === 'object' &&
50
- obj !== null &&
51
- (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntryAccessor'
51
+ typeof obj === 'object'
52
+ && obj !== null
53
+ && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeEntryAccessor'
52
54
  );
53
55
  }
54
56
 
55
57
  export function isPlTreeNodeAccessor(obj: unknown): obj is PlTreeNodeAccessor {
56
58
  return (
57
- typeof obj === 'object' &&
58
- obj !== null &&
59
- (obj as any)['__pl_tree_type_marker__'] === 'PlTreeNodeAccessor'
59
+ typeof obj === 'object'
60
+ && obj !== null
61
+ && (obj as any)['__pl_tree_type_marker__'] === 'PlTreeNodeAccessor'
60
62
  );
61
63
  }
62
64
 
@@ -66,13 +68,13 @@ export class PlTreeEntry implements AccessorProvider<PlTreeEntryAccessor> {
66
68
 
67
69
  constructor(
68
70
  private readonly accessorData: TreeAccessorData,
69
- public readonly rid: ResourceId
71
+ public readonly rid: ResourceId,
70
72
  ) {}
71
73
 
72
74
  public createAccessor(ctx: ComputableCtx, guard: UsageGuard): PlTreeEntryAccessor {
73
75
  return new PlTreeEntryAccessor(this.accessorData, this.accessorData.treeProvider(), this.rid, {
74
76
  ctx,
75
- guard
77
+ guard,
76
78
  });
77
79
  }
78
80
 
@@ -90,13 +92,13 @@ function getResourceFromTree(
90
92
  tree: PlTreeState,
91
93
  instanceData: TreeAccessorInstanceData,
92
94
  rid: ResourceId,
93
- ops: ResourceTraversalOps
95
+ ops: ResourceTraversalOps,
94
96
  ): PlTreeNodeAccessor {
95
97
  const acc = new PlTreeNodeAccessor(
96
98
  accessorData,
97
99
  tree,
98
100
  tree.get(instanceData.ctx.watcher, rid),
99
- instanceData
101
+ instanceData,
100
102
  );
101
103
 
102
104
  if (!ops.ignoreError) {
@@ -106,13 +108,14 @@ function getResourceFromTree(
106
108
  }
107
109
 
108
110
  if (
109
- ops.assertResourceType !== undefined &&
110
- (Array.isArray(ops.assertResourceType)
111
+ ops.assertResourceType !== undefined
112
+ && (Array.isArray(ops.assertResourceType)
111
113
  ? ops.assertResourceType.findIndex((rt) => resourceTypesEqual(rt, acc.resourceType)) === -1
112
114
  : !resourceTypesEqual(ops.assertResourceType, acc.resourceType))
113
115
  )
114
116
  throw new Error(
115
- `wrong resource type ${resourceTypeToString(acc.resourceType)} but expected ${ops.assertResourceType}`
117
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
118
+ `wrong resource type ${resourceTypeToString(acc.resourceType)} but expected ${ops.assertResourceType}`,
116
119
  );
117
120
 
118
121
  return acc;
@@ -125,7 +128,7 @@ export class PlTreeEntryAccessor {
125
128
  private readonly accessorData: TreeAccessorData,
126
129
  private readonly tree: PlTreeState,
127
130
  private readonly rid: ResourceId,
128
- private readonly instanceData: TreeAccessorInstanceData
131
+ private readonly instanceData: TreeAccessorInstanceData,
129
132
  ) {}
130
133
 
131
134
  node(ops: ResourceTraversalOps = {}): PlTreeNodeAccessor {
@@ -171,7 +174,7 @@ export class PlTreeNodeAccessor {
171
174
  private readonly accessorData: TreeAccessorData,
172
175
  private readonly tree: PlTreeState,
173
176
  private readonly resource: PlTreeResource,
174
- private readonly instanceData: TreeAccessorInstanceData
177
+ private readonly instanceData: TreeAccessorInstanceData,
175
178
  ) {}
176
179
 
177
180
  public get id(): ResourceId {
@@ -201,7 +204,7 @@ export class PlTreeNodeAccessor {
201
204
  ...steps: [
202
205
  Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {
203
206
  errorIfFieldNotSet: true;
204
- }
207
+ },
205
208
  ]
206
209
  ): PlTreeNodeAccessor;
207
210
  public traverse(...steps: (FieldTraversalStep | string)[]): PlTreeNodeAccessor | undefined;
@@ -213,7 +216,7 @@ export class PlTreeNodeAccessor {
213
216
  ...steps: [
214
217
  Omit<FieldTraversalStep, 'errorIfFieldNotSet'> & {
215
218
  errorIfFieldNotSet: true;
216
- }
219
+ },
217
220
  ]
218
221
  ): ValueOrError<PlTreeNodeAccessor, string>;
219
222
  public traverseOrError(
@@ -231,6 +234,7 @@ export class PlTreeNodeAccessor {
231
234
  ): PlTreeNodeAccessor | undefined {
232
235
  const result = this.traverseOrErrorWithCommon(commonOptions, ...steps);
233
236
  if (result === undefined) return undefined;
237
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
234
238
  if (!result.ok) throw result.error;
235
239
  return result.value;
236
240
  }
@@ -239,14 +243,15 @@ export class PlTreeNodeAccessor {
239
243
  commonOptions: CommonFieldTraverseOps,
240
244
  ...steps: (FieldTraversalStep | string)[]
241
245
  ): ValueOrError<PlTreeNodeAccessor, string> | undefined {
246
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
242
247
  let current: PlTreeNodeAccessor = this;
243
248
 
244
249
  for (const _step of steps) {
245
- const step: FieldTraversalStep =
246
- typeof _step === 'string'
250
+ const step: FieldTraversalStep
251
+ = typeof _step === 'string'
247
252
  ? {
248
253
  ...commonOptions,
249
- field: _step
254
+ field: _step,
250
255
  }
251
256
  : { ...commonOptions, ..._step };
252
257
 
@@ -392,7 +397,7 @@ export class PlTreeNodeAccessor {
392
397
 
393
398
  public getKeyValueAsJson<T = unknown>(
394
399
  key: string,
395
- unstableIfNotFound: boolean = false
400
+ unstableIfNotFound: boolean = false,
396
401
  ): T | undefined {
397
402
  const result = this.resource.getKeyValueString(this.instanceData.ctx.watcher, key);
398
403
  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
  }