@dxos/effect 0.8.4-main.5ad4a44 → 0.8.4-main.66e292d

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/effect",
3
- "version": "0.8.4-main.5ad4a44",
3
+ "version": "0.8.4-main.66e292d",
4
4
  "description": "Effect utils.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -27,10 +27,10 @@
27
27
  "@effect/opentelemetry": "^0.58.0",
28
28
  "@opentelemetry/api": "^1.9.0",
29
29
  "jsonpath-plus": "10.2.0",
30
- "@dxos/context": "0.8.4-main.5ad4a44",
31
- "@dxos/invariant": "0.8.4-main.5ad4a44",
32
- "@dxos/util": "0.8.4-main.5ad4a44",
33
- "@dxos/node-std": "0.8.4-main.5ad4a44"
30
+ "@dxos/context": "0.8.4-main.66e292d",
31
+ "@dxos/invariant": "0.8.4-main.66e292d",
32
+ "@dxos/node-std": "0.8.4-main.66e292d",
33
+ "@dxos/util": "0.8.4-main.66e292d"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@opentelemetry/api-logs": "^0.203.0",
@@ -40,7 +40,7 @@
40
40
  "@opentelemetry/sdk-trace-node": "^2.1.0",
41
41
  "@opentelemetry/semantic-conventions": "^1.37.0",
42
42
  "effect": "3.18.3",
43
- "@dxos/log": "0.8.4-main.5ad4a44"
43
+ "@dxos/log": "0.8.4-main.66e292d"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "effect": "^3.13.3"
package/src/ast.test.ts CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  isSimpleType,
22
22
  visit,
23
23
  } from './ast';
24
- import { type JsonPath, type JsonProp } from './jsonPath';
24
+ import { type JsonPath, type JsonProp } from './json-path';
25
25
 
26
26
  const ZipCode = Schema.String.pipe(
27
27
  Schema.pattern(/^\d{5}$/, {
package/src/ast.ts CHANGED
@@ -10,7 +10,7 @@ import * as SchemaAST from 'effect/SchemaAST';
10
10
  import { invariant } from '@dxos/invariant';
11
11
  import { isNonNullable } from '@dxos/util';
12
12
 
13
- import { type JsonPath, type JsonProp } from './jsonPath';
13
+ import { type JsonPath, type JsonProp } from './json-path';
14
14
 
15
15
  //
16
16
  // Refs
@@ -214,6 +214,12 @@ export const findNode = (node: SchemaAST.AST, test: (node: SchemaAST.AST) => boo
214
214
  return child;
215
215
  }
216
216
  }
217
+ for (const prop of getIndexSignatures(node)) {
218
+ const child = findNode(prop.type, test);
219
+ if (child) {
220
+ return child;
221
+ }
222
+ }
217
223
  }
218
224
 
219
225
  // Tuple.
@@ -444,6 +450,7 @@ export const mapAst = (
444
450
  ),
445
451
  ),
446
452
  ast.indexSignatures,
453
+ ast.annotations,
447
454
  );
448
455
  }
449
456
  case 'Union': {
@@ -480,3 +487,19 @@ export const isArrayType = (node: SchemaAST.AST): boolean => {
480
487
  node.types.length === 2)
481
488
  );
482
489
  };
490
+
491
+ const getIndexSignatures = (ast: SchemaAST.AST): Array<SchemaAST.IndexSignature> => {
492
+ const annotation = SchemaAST.getSurrogateAnnotation(ast);
493
+ if (Option.isSome(annotation)) {
494
+ return getIndexSignatures(annotation.value);
495
+ }
496
+ switch (ast._tag) {
497
+ case 'TypeLiteral':
498
+ return ast.indexSignatures.slice();
499
+ case 'Suspend':
500
+ return getIndexSignatures(ast.f());
501
+ case 'Refinement':
502
+ return getIndexSignatures(ast.from);
503
+ }
504
+ return [];
505
+ };
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  export * from './ast';
6
- export * from './jsonPath';
6
+ export * from './json-path';
7
7
  export * from './url';
8
8
  export * from './context';
9
9
  export * from './errors';
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { describe, expect, test } from 'vitest';
6
6
 
7
- import { type JsonPath, createJsonPath, getField, isJsonPath, splitJsonPath } from './jsonPath';
7
+ import { type JsonPath, createJsonPath, getField, getValue, isJsonPath, setValue, splitJsonPath } from './json-path';
8
8
 
9
9
  describe('createJsonPath', () => {
10
10
  test('supported path subset', () => {
@@ -99,3 +99,42 @@ describe('createJsonPath', () => {
99
99
  expect(getField({ a: 'foo' }, 'a' as JsonPath)).toBe('foo');
100
100
  });
101
101
  });
102
+
103
+ describe('Types', () => {
104
+ test('checks sanity', async ({ expect }) => {
105
+ const obj = {};
106
+ expect(obj).to.exist;
107
+ });
108
+ });
109
+
110
+ describe('get/set deep', () => {
111
+ test('get/set operations', ({ expect }) => {
112
+ const obj = {
113
+ name: 'test',
114
+ items: ['a', 'b', 'c'],
115
+ nested: {
116
+ prop: 'value',
117
+ arr: [1, 2, 3],
118
+ },
119
+ };
120
+
121
+ // Basic property access.
122
+ expect(getValue(obj, 'name' as JsonPath)).toBe('test');
123
+
124
+ // Array index access.
125
+ expect(getValue(obj, 'items[1]' as JsonPath)).toBe('b');
126
+
127
+ // Nested property access.
128
+ expect(getValue(obj, 'nested.prop' as JsonPath)).toBe('value');
129
+
130
+ // Nested array access.
131
+ expect(getValue(obj, 'nested.arr[2]' as JsonPath)).toBe(3);
132
+
133
+ // Setting values.
134
+ const updated1 = setValue(obj, 'items[1]' as JsonPath, 'x');
135
+ expect(updated1.items[1]).toBe('x');
136
+
137
+ const updated2 = setValue(obj, 'nested.arr[0]' as JsonPath, 99);
138
+ expect(updated2.nested.arr[0]).toBe(99);
139
+ });
140
+ });
@@ -7,16 +7,21 @@ import * as Schema from 'effect/Schema';
7
7
  import { JSONPath } from 'jsonpath-plus';
8
8
 
9
9
  import { invariant } from '@dxos/invariant';
10
+ import { getDeep, setDeep } from '@dxos/util';
10
11
 
11
12
  export type JsonProp = string & { __JsonPath: true; __JsonProp: true };
12
13
  export type JsonPath = string & { __JsonPath: true };
13
14
 
15
+ // TODO(burdon): Start with "$."?
16
+
14
17
  const PATH_REGEX = /^($|[a-zA-Z_$][\w$]*(?:\.[a-zA-Z_$][\w$]*|\[\d+\](?:\.)?)*$)/;
18
+
15
19
  const PROP_REGEX = /^\w+$/;
16
20
 
17
21
  /**
18
22
  * https://www.ietf.org/archive/id/draft-goessner-dispatch-jsonpath-00.html
19
23
  */
24
+ // TODO(burdon): Keys could be arbitrary strings.
20
25
  export const JsonPath = Schema.String.pipe(Schema.pattern(PATH_REGEX)).annotations({
21
26
  title: 'JSON path',
22
27
  description: 'JSON path to a property',
@@ -95,7 +100,29 @@ export const splitJsonPath = (path: JsonPath): string[] => {
95
100
  /**
96
101
  * Applies a JsonPath to an object.
97
102
  */
103
+ // TODO(burdon): Reconcile with getValue.
98
104
  export const getField = (object: any, path: JsonPath): any => {
99
105
  // By default, JSONPath returns an array of results.
100
106
  return JSONPath({ path, json: object })[0];
101
107
  };
108
+
109
+ /**
110
+ * Get value from object using JsonPath.
111
+ */
112
+ export const getValue = <T extends object>(obj: T, path: JsonPath): any => {
113
+ return getDeep(
114
+ obj,
115
+ splitJsonPath(path).map((p) => p.replace(/[[\]]/g, '')),
116
+ );
117
+ };
118
+
119
+ /**
120
+ * Set value on object using JsonPath.
121
+ */
122
+ export const setValue = <T extends object>(obj: T, path: JsonPath, value: any): T => {
123
+ return setDeep(
124
+ obj,
125
+ splitJsonPath(path).map((p) => p.replace(/[[\]]/g, '')),
126
+ value,
127
+ );
128
+ };
package/src/otel.test.ts CHANGED
@@ -76,6 +76,7 @@ const makeOtelLogProcessor = (logger: Logger): LogProcessor => {
76
76
  });
77
77
  };
78
78
  };
79
+
79
80
  log.addProcessor(makeOtelLogProcessor(logger));
80
81
 
81
82
  beforeAll(() => {
@@ -5,13 +5,13 @@
5
5
  import { it } from '@effect/vitest';
6
6
  import * as Effect from 'effect/Effect';
7
7
 
8
- import { accuireReleaseResource } from './resource';
8
+ import { acquireReleaseResource } from './resource';
9
9
 
10
10
  it.effect(
11
11
  'acquire-release',
12
12
  Effect.fn(function* ({ expect }) {
13
13
  const events: string[] = [];
14
- const makeResource = accuireReleaseResource(() => ({
14
+ const makeResource = acquireReleaseResource(() => ({
15
15
  open: () => {
16
16
  events.push('open');
17
17
  },
package/src/resource.ts CHANGED
@@ -3,11 +3,16 @@
3
3
  //
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
+ import type * as Scope from 'effect/Scope';
6
7
 
7
8
  import type { Lifecycle } from '@dxos/context';
8
9
 
9
- // TODO(dmaretskyi): Extract to effect-utils.
10
- export const accuireReleaseResource = <T extends Lifecycle>(getResource: () => T) =>
10
+ /**
11
+ * Acquires a resource and releases it when the scope is closed.
12
+ */
13
+ export const acquireReleaseResource = <T extends Lifecycle>(
14
+ getResource: () => T,
15
+ ): Effect.Effect<T, never, Scope.Scope> =>
11
16
  Effect.acquireRelease(
12
17
  Effect.gen(function* () {
13
18
  const resource = getResource();
@@ -22,11 +22,17 @@ describe('sanity tests', () => {
22
22
  const result = await Effect.runPromise(
23
23
  Function.pipe(
24
24
  Effect.promise(() => Promise.resolve(100)),
25
- Effect.tap((value) => log('tap', { value })),
25
+ Effect.tap((value) => {
26
+ log('tap', { value });
27
+ }),
26
28
  Effect.map((value: number) => String(value)),
27
- Effect.tap((value) => log('tap', { value })),
29
+ Effect.tap((value) => {
30
+ log('tap', { value });
31
+ }),
28
32
  Effect.map((value: string) => value.length),
29
- Effect.tap((value) => log('tap', { value })),
33
+ Effect.tap((value) => {
34
+ log('tap', { value });
35
+ }),
30
36
  ),
31
37
  );
32
38
  expect(result).to.eq(3);
@@ -36,11 +42,17 @@ describe('sanity tests', () => {
36
42
  const result = await Effect.runPromise(
37
43
  Function.pipe(
38
44
  Effect.succeed(100),
39
- Effect.tap((value) => log('tap', { value })),
45
+ Effect.tap((value) => {
46
+ log('tap', { value });
47
+ }),
40
48
  Effect.flatMap((value) => Effect.promise(() => Promise.resolve(String(value)))),
41
- Effect.tap((value) => log('tap', { value })),
49
+ Effect.tap((value) => {
50
+ log('tap', { value });
51
+ }),
42
52
  Effect.map((value) => value.length),
43
- Effect.tap((value) => log('tap', { value })),
53
+ Effect.tap((value) => {
54
+ log('tap', { value });
55
+ }),
44
56
  ),
45
57
  );
46
58
  expect(result).to.eq(3);
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsonPath.d.ts","sourceRoot":"","sources":["../../../src/jsonPath.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAKxC,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,UAAU,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,IAAI,CAAA;CAAE,CAAC;AACvE,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,UAAU,EAAE,IAAI,CAAA;CAAE,CAAC;AAKrD;;GAEG;AACH,eAAO,MAAM,QAAQ,EAGR,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACrC,eAAO,MAAM,QAAQ,EAIT,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEpC,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,QAEpD,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAG,QAa1D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GAAI,YAAY,MAAM,KAAG,QAK7D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,QAAQ,KAAG,MAAM,EAUpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,GAAG,EAAE,MAAM,QAAQ,KAAG,GAGtD,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=jsonPath.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsonPath.test.d.ts","sourceRoot":"","sources":["../../../src/jsonPath.test.ts"],"names":[],"mappings":""}