@dxos/effect 0.7.5-labs.e27f9b9 → 0.7.5-main.2567c87
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/lib/browser/index.mjs +15 -66
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +16 -69
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +15 -66
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/ast.d.ts +13 -2
- package/dist/types/src/ast.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/ast.test.ts +24 -1
- package/src/ast.ts +17 -13
- package/src/index.ts +0 -1
- package/dist/types/src/jsonPath.d.ts +0 -45
- package/dist/types/src/jsonPath.d.ts.map +0 -1
- package/dist/types/src/jsonPath.test.d.ts +0 -2
- package/dist/types/src/jsonPath.test.d.ts.map +0 -1
- package/src/jsonPath.test.ts +0 -96
- package/src/jsonPath.ts +0 -85
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/effect",
|
|
3
|
-
"version": "0.7.5-
|
|
3
|
+
"version": "0.7.5-main.2567c87",
|
|
4
4
|
"description": "Effect utils.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -22,18 +22,18 @@
|
|
|
22
22
|
"src"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@dxos/invariant": "0.7.5-
|
|
26
|
-
"@dxos/
|
|
27
|
-
"@dxos/
|
|
25
|
+
"@dxos/invariant": "0.7.5-main.2567c87",
|
|
26
|
+
"@dxos/util": "0.7.5-main.2567c87",
|
|
27
|
+
"@dxos/node-std": "0.7.5-main.2567c87"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@effect/schema": "^0.75.5",
|
|
31
|
-
"effect": "^3.12.
|
|
32
|
-
"@dxos/log": "0.7.5-
|
|
31
|
+
"effect": "^3.12.1",
|
|
32
|
+
"@dxos/log": "0.7.5-main.2567c87"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@effect/schema": "^0.75.5",
|
|
36
|
-
"effect": "^3.
|
|
36
|
+
"effect": "^3.9.2"
|
|
37
37
|
},
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public"
|
package/src/ast.test.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { AST, Schema as S } from '@effect/schema';
|
|
6
|
+
import { isNone, isSome } from 'effect/Option';
|
|
6
7
|
import { describe, test } from 'vitest';
|
|
7
8
|
|
|
8
9
|
import { invariant } from '@dxos/invariant';
|
|
@@ -18,8 +19,9 @@ import {
|
|
|
18
19
|
isOption,
|
|
19
20
|
isSimpleType,
|
|
20
21
|
visit,
|
|
22
|
+
JsonPath,
|
|
23
|
+
type JsonProp,
|
|
21
24
|
} from './ast';
|
|
22
|
-
import { type JsonPath, type JsonProp } from './jsonPath';
|
|
23
25
|
|
|
24
26
|
const ZipCode = S.String.pipe(
|
|
25
27
|
S.pattern(/^\d{5}$/, {
|
|
@@ -181,4 +183,25 @@ describe('AST', () => {
|
|
|
181
183
|
);
|
|
182
184
|
}
|
|
183
185
|
});
|
|
186
|
+
|
|
187
|
+
// TODO(ZaymonFC): Update this when we settle on the right indexing syntax for arrays.
|
|
188
|
+
test('json path validation', ({ expect }) => {
|
|
189
|
+
const validatePath = S.validateOption(JsonPath);
|
|
190
|
+
|
|
191
|
+
// Valid paths.
|
|
192
|
+
expect(isSome(validatePath('foo'))).toBe(true);
|
|
193
|
+
expect(isSome(validatePath('foo.bar'))).toBe(true);
|
|
194
|
+
expect(isSome(validatePath('foo.bar.baz'))).toBe(true);
|
|
195
|
+
expect(isSome(validatePath('foo[1].bar'))).toBe(true);
|
|
196
|
+
expect(isSome(validatePath('_foo.$bar'))).toBe(true);
|
|
197
|
+
|
|
198
|
+
// Invalid paths.
|
|
199
|
+
expect(isNone(validatePath(''))).toBe(true);
|
|
200
|
+
expect(isNone(validatePath('.'))).toBe(true);
|
|
201
|
+
expect(isNone(validatePath('foo.'))).toBe(true);
|
|
202
|
+
expect(isNone(validatePath('foo..bar'))).toBe(true);
|
|
203
|
+
expect(isNone(validatePath('foo.#bar'))).toBe(true);
|
|
204
|
+
expect(isNone(validatePath('[1].bar'))).toBe(true);
|
|
205
|
+
expect(isNone(validatePath('test.[1].bar[1]'))).toBe(true);
|
|
206
|
+
});
|
|
184
207
|
});
|
package/src/ast.ts
CHANGED
|
@@ -8,8 +8,6 @@ import { Option, pipe } from 'effect';
|
|
|
8
8
|
import { invariant } from '@dxos/invariant';
|
|
9
9
|
import { nonNullable } from '@dxos/util';
|
|
10
10
|
|
|
11
|
-
import { type JsonPath, type JsonProp } from './jsonPath';
|
|
12
|
-
|
|
13
11
|
//
|
|
14
12
|
// Refs
|
|
15
13
|
// https://effect.website/docs/schema/introduction
|
|
@@ -78,6 +76,18 @@ export namespace SimpleType {
|
|
|
78
76
|
// Branded types
|
|
79
77
|
//
|
|
80
78
|
|
|
79
|
+
export type JsonProp = string & { __JsonPath: true; __JsonProp: true };
|
|
80
|
+
export type JsonPath = string & { __JsonPath: true };
|
|
81
|
+
|
|
82
|
+
const PATH_REGEX = /^[a-zA-Z_$][\w$]*(?:\.[a-zA-Z_$][\w$]*|\[\d+\])*$/;
|
|
83
|
+
const PROP_REGEX = /\w+/;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* https://www.ietf.org/archive/id/draft-goessner-dispatch-jsonpath-00.html
|
|
87
|
+
*/
|
|
88
|
+
export const JsonPath = S.NonEmptyString.pipe(S.pattern(PATH_REGEX)) as any as S.Schema<JsonPath>;
|
|
89
|
+
export const JsonProp = S.NonEmptyString.pipe(S.pattern(PROP_REGEX)) as any as S.Schema<JsonProp>;
|
|
90
|
+
|
|
81
91
|
export enum VisitResult {
|
|
82
92
|
CONTINUE = 0,
|
|
83
93
|
/**
|
|
@@ -403,19 +413,13 @@ export const getDiscriminatedType = (node: AST.AST, value: Record<string, any> =
|
|
|
403
413
|
* The user is responsible for recursively calling {@link mapAst} on the AST.
|
|
404
414
|
* NOTE: Will evaluate suspended ASTs.
|
|
405
415
|
*/
|
|
406
|
-
export const mapAst = (ast: AST.AST, f: (ast: AST.AST
|
|
416
|
+
export const mapAst = (ast: AST.AST, f: (ast: AST.AST) => AST.AST): AST.AST => {
|
|
407
417
|
switch (ast._tag) {
|
|
408
418
|
case 'TypeLiteral':
|
|
409
419
|
return new AST.TypeLiteral(
|
|
410
420
|
ast.propertySignatures.map(
|
|
411
421
|
(prop) =>
|
|
412
|
-
new AST.PropertySignature(
|
|
413
|
-
prop.name,
|
|
414
|
-
f(prop.type, prop.name),
|
|
415
|
-
prop.isOptional,
|
|
416
|
-
prop.isReadonly,
|
|
417
|
-
prop.annotations,
|
|
418
|
-
),
|
|
422
|
+
new AST.PropertySignature(prop.name, f(prop.type), prop.isOptional, prop.isReadonly, prop.annotations),
|
|
419
423
|
),
|
|
420
424
|
ast.indexSignatures,
|
|
421
425
|
);
|
|
@@ -423,13 +427,13 @@ export const mapAst = (ast: AST.AST, f: (ast: AST.AST, key: keyof any | undefine
|
|
|
423
427
|
return AST.Union.make(ast.types.map(f), ast.annotations);
|
|
424
428
|
case 'TupleType':
|
|
425
429
|
return new AST.TupleType(
|
|
426
|
-
ast.elements.map((t
|
|
427
|
-
ast.rest.map((t) => new AST.Type(f(t.type
|
|
430
|
+
ast.elements.map((t) => new AST.OptionalType(f(t.type), t.isOptional, t.annotations)),
|
|
431
|
+
ast.rest.map((t) => new AST.Type(f(t.type), t.annotations)),
|
|
428
432
|
ast.isReadonly,
|
|
429
433
|
ast.annotations,
|
|
430
434
|
);
|
|
431
435
|
case 'Suspend': {
|
|
432
|
-
const newAst = f(ast.f()
|
|
436
|
+
const newAst = f(ast.f());
|
|
433
437
|
return new AST.Suspend(() => newAst, ast.annotations);
|
|
434
438
|
}
|
|
435
439
|
default:
|
package/src/index.ts
CHANGED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Schema as S } from '@effect/schema';
|
|
2
|
-
export type JsonProp = string & {
|
|
3
|
-
__JsonPath: true;
|
|
4
|
-
__JsonProp: true;
|
|
5
|
-
};
|
|
6
|
-
export type JsonPath = string & {
|
|
7
|
-
__JsonPath: true;
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* https://www.ietf.org/archive/id/draft-goessner-dispatch-jsonpath-00.html
|
|
11
|
-
*/
|
|
12
|
-
export declare const JsonPath: S.Schema<JsonPath>;
|
|
13
|
-
export declare const JsonProp: S.Schema<JsonProp>;
|
|
14
|
-
export declare const isJsonPath: (value: unknown) => value is JsonPath;
|
|
15
|
-
/**
|
|
16
|
-
* Creates a JsonPath from an array of path segments.
|
|
17
|
-
*
|
|
18
|
-
* Currently supports:
|
|
19
|
-
* - Simple property access (e.g., 'foo.bar')
|
|
20
|
-
* - Array indexing with non-negative integers (e.g., 'foo[0]')
|
|
21
|
-
* - Identifiers starting with letters, underscore, or $ (e.g., '$foo', '_bar')
|
|
22
|
-
* - Dot notation for nested properties (e.g., 'foo.bar.baz')
|
|
23
|
-
*
|
|
24
|
-
* Does not support (yet?).
|
|
25
|
-
* - Recursive descent (..)
|
|
26
|
-
* - Wildcards (*)
|
|
27
|
-
* - Array slicing
|
|
28
|
-
* - Filters
|
|
29
|
-
* - Negative indices
|
|
30
|
-
*
|
|
31
|
-
* @param path Array of string or number segments
|
|
32
|
-
* @returns Valid JsonPath or undefined if invalid
|
|
33
|
-
*/
|
|
34
|
-
export declare const createJsonPath: (path: (string | number)[]) => JsonPath;
|
|
35
|
-
/**
|
|
36
|
-
* Converts Effect validation path format (e.g. "addresses.[0].zip")
|
|
37
|
-
* to JsonPath format (e.g. "addresses[0].zip")
|
|
38
|
-
*/
|
|
39
|
-
export declare const fromEffectValidationPath: (effectPath: string) => JsonPath;
|
|
40
|
-
/**
|
|
41
|
-
* Splits a JsonPath into its constituent parts.
|
|
42
|
-
* Handles property access and array indexing.
|
|
43
|
-
*/
|
|
44
|
-
export declare const splitJsonPath: (path: JsonPath) => string[];
|
|
45
|
-
//# sourceMappingURL=jsonPath.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jsonPath.d.ts","sourceRoot":"","sources":["../../../src/jsonPath.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,gBAAgB,CAAC;AAK7C,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,EAAkD,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC1F,eAAO,MAAM,QAAQ,EAA0D,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAElG,eAAO,MAAM,UAAU,UAAW,OAAO,KAAG,KAAK,IAAI,QAEpD,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,cAAc,SAAU,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAG,QAa1D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,eAAgB,MAAM,KAAG,QAK7D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,SAAU,QAAQ,KAAG,MAAM,EAUpD,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jsonPath.test.d.ts","sourceRoot":"","sources":["../../../src/jsonPath.test.ts"],"names":[],"mappings":""}
|
package/src/jsonPath.test.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { describe, expect, test } from 'vitest';
|
|
6
|
-
|
|
7
|
-
import { createJsonPath, isJsonPath, type JsonPath, splitJsonPath } from './jsonPath';
|
|
8
|
-
|
|
9
|
-
describe('createJsonPath', () => {
|
|
10
|
-
test('supported path subset', () => {
|
|
11
|
-
// Simple property access.
|
|
12
|
-
expect(createJsonPath(['foo'])).toBe('foo');
|
|
13
|
-
expect(createJsonPath(['foo', 'bar'])).toBe('foo.bar');
|
|
14
|
-
expect(createJsonPath(['names', 1, 'bar'])).toBe('names[1].bar');
|
|
15
|
-
expect(createJsonPath(['names', 1])).toBe('names[1]');
|
|
16
|
-
expect(createJsonPath(['names', 1, 'names'])).toBe('names[1].names');
|
|
17
|
-
|
|
18
|
-
// Array indexing.
|
|
19
|
-
expect(createJsonPath(['foo', 0, 'bar'])).toBe('foo[0].bar');
|
|
20
|
-
expect(createJsonPath(['items', 1])).toBe('items[1]');
|
|
21
|
-
|
|
22
|
-
// $ is valid in identifiers.
|
|
23
|
-
expect(createJsonPath(['$foo', '$bar'])).toBe('$foo.$bar');
|
|
24
|
-
expect(createJsonPath([])).toBe('');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test('invalid paths', () => {
|
|
28
|
-
expect(() => createJsonPath(['123foo'])).toThrow(); // Can't start with number.
|
|
29
|
-
expect(() => createJsonPath(['foo', -1, 'bar'])).toThrow(); // No negative indices.
|
|
30
|
-
expect(() => createJsonPath(['foo', 1.5, 'bar'])).toThrow(); // No float indices.
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('path splitting', () => {
|
|
34
|
-
const cases = [
|
|
35
|
-
['foo.bar[0].baz', ['foo', 'bar', '0', 'baz']],
|
|
36
|
-
['users[1].name', ['users', '1', 'name']],
|
|
37
|
-
['data[0][1]', ['data', '0', '1']],
|
|
38
|
-
['simple.path', ['simple', 'path']],
|
|
39
|
-
['root', ['root']],
|
|
40
|
-
] as const;
|
|
41
|
-
|
|
42
|
-
cases.forEach(([input, expected]) => {
|
|
43
|
-
expect(splitJsonPath(input as JsonPath)).toEqual(expected);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test('path splitting - extended cases', () => {
|
|
48
|
-
const cases = [
|
|
49
|
-
// Multiple consecutive array indices.
|
|
50
|
-
['matrix[0][1][2]', ['matrix', '0', '1', '2']],
|
|
51
|
-
// Properties with underscores and $.
|
|
52
|
-
['$_foo.bar_baz', ['$_foo', 'bar_baz']],
|
|
53
|
-
// Deep nesting.
|
|
54
|
-
['very.deep.nested[0].property.path[5]', ['very', 'deep', 'nested', '0', 'property', 'path', '5']],
|
|
55
|
-
// Single character properties.
|
|
56
|
-
['a[0].b.c', ['a', '0', 'b', 'c']],
|
|
57
|
-
// Properties containing numbers.
|
|
58
|
-
['prop123.item456[7]', ['prop123', 'item456', '7']],
|
|
59
|
-
] as const;
|
|
60
|
-
|
|
61
|
-
cases.forEach(([input, expected]) => {
|
|
62
|
-
expect(splitJsonPath(input as JsonPath)).toEqual(expected);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('invalid path formats', () => {
|
|
67
|
-
// These should return empty array or handle gracefully.
|
|
68
|
-
const invalidPaths = ['', '.', '[', ']', 'foo[].bar', 'foo[a].bar', 'foo[-1].bar'] as const;
|
|
69
|
-
|
|
70
|
-
invalidPaths.forEach((path) => {
|
|
71
|
-
expect(splitJsonPath(path as JsonPath)).toEqual([]);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test('isJsonPath validation', () => {
|
|
76
|
-
// Valid paths.
|
|
77
|
-
expect(isJsonPath('')).toBe(true);
|
|
78
|
-
expect(isJsonPath('foo')).toBe(true);
|
|
79
|
-
expect(isJsonPath('foo.bar')).toBe(true);
|
|
80
|
-
expect(isJsonPath('foo[0].bar')).toBe(true);
|
|
81
|
-
expect(isJsonPath('items[1]')).toBe(true);
|
|
82
|
-
expect(isJsonPath('$foo.$bar')).toBe(true);
|
|
83
|
-
expect(isJsonPath('matrix[0][1][2]')).toBe(true);
|
|
84
|
-
expect(isJsonPath('deep.nested[0].path')).toBe(true);
|
|
85
|
-
|
|
86
|
-
// Invalid paths.
|
|
87
|
-
expect(isJsonPath('items[0]name')).toBe(false); // Missing dot
|
|
88
|
-
expect(isJsonPath('123foo')).toBe(false); // Starts with number
|
|
89
|
-
expect(isJsonPath('foo[].bar')).toBe(false); // Empty brackets
|
|
90
|
-
expect(isJsonPath('foo[-1]')).toBe(false); // Negative index
|
|
91
|
-
expect(isJsonPath('foo[a]')).toBe(false); // Non-numeric index
|
|
92
|
-
expect(isJsonPath('.foo')).toBe(false); // Starts with dot
|
|
93
|
-
expect(isJsonPath('foo.')).toBe(false); // Ends with dot
|
|
94
|
-
expect(isJsonPath('[0]foo')).toBe(false); // Starts with bracket
|
|
95
|
-
});
|
|
96
|
-
});
|
package/src/jsonPath.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { Schema as S } from '@effect/schema';
|
|
6
|
-
import { isSome } from 'effect/Option';
|
|
7
|
-
|
|
8
|
-
import { invariant } from '@dxos/invariant';
|
|
9
|
-
|
|
10
|
-
export type JsonProp = string & { __JsonPath: true; __JsonProp: true };
|
|
11
|
-
export type JsonPath = string & { __JsonPath: true };
|
|
12
|
-
|
|
13
|
-
const PATH_REGEX = /^($|[a-zA-Z_$][\w$]*(?:\.[a-zA-Z_$][\w$]*|\[\d+\](?:\.)?)*$)/;
|
|
14
|
-
const PROP_REGEX = /\w+/;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* https://www.ietf.org/archive/id/draft-goessner-dispatch-jsonpath-00.html
|
|
18
|
-
*/
|
|
19
|
-
export const JsonPath = S.String.pipe(S.pattern(PATH_REGEX)) as any as S.Schema<JsonPath>;
|
|
20
|
-
export const JsonProp = S.NonEmptyString.pipe(S.pattern(PROP_REGEX)) as any as S.Schema<JsonProp>;
|
|
21
|
-
|
|
22
|
-
export const isJsonPath = (value: unknown): value is JsonPath => {
|
|
23
|
-
return isSome(S.validateOption(JsonPath)(value));
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Creates a JsonPath from an array of path segments.
|
|
28
|
-
*
|
|
29
|
-
* Currently supports:
|
|
30
|
-
* - Simple property access (e.g., 'foo.bar')
|
|
31
|
-
* - Array indexing with non-negative integers (e.g., 'foo[0]')
|
|
32
|
-
* - Identifiers starting with letters, underscore, or $ (e.g., '$foo', '_bar')
|
|
33
|
-
* - Dot notation for nested properties (e.g., 'foo.bar.baz')
|
|
34
|
-
*
|
|
35
|
-
* Does not support (yet?).
|
|
36
|
-
* - Recursive descent (..)
|
|
37
|
-
* - Wildcards (*)
|
|
38
|
-
* - Array slicing
|
|
39
|
-
* - Filters
|
|
40
|
-
* - Negative indices
|
|
41
|
-
*
|
|
42
|
-
* @param path Array of string or number segments
|
|
43
|
-
* @returns Valid JsonPath or undefined if invalid
|
|
44
|
-
*/
|
|
45
|
-
export const createJsonPath = (path: (string | number)[]): JsonPath => {
|
|
46
|
-
const candidatePath = path
|
|
47
|
-
.map((p, i) => {
|
|
48
|
-
if (typeof p === 'number') {
|
|
49
|
-
return `[${p}]`;
|
|
50
|
-
} else {
|
|
51
|
-
return i === 0 ? p : `.${p}`;
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
.join('');
|
|
55
|
-
|
|
56
|
-
invariant(isJsonPath(candidatePath), `Invalid JsonPath: ${candidatePath}`);
|
|
57
|
-
return candidatePath;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Converts Effect validation path format (e.g. "addresses.[0].zip")
|
|
62
|
-
* to JsonPath format (e.g. "addresses[0].zip")
|
|
63
|
-
*/
|
|
64
|
-
export const fromEffectValidationPath = (effectPath: string): JsonPath => {
|
|
65
|
-
// Handle array notation: convert "prop.[0]" to "prop[0]"
|
|
66
|
-
const jsonPath = effectPath.replace(/\.\[(\d+)\]/g, '[$1]');
|
|
67
|
-
invariant(isJsonPath(jsonPath), `Invalid JsonPath: ${jsonPath}`);
|
|
68
|
-
return jsonPath;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Splits a JsonPath into its constituent parts.
|
|
73
|
-
* Handles property access and array indexing.
|
|
74
|
-
*/
|
|
75
|
-
export const splitJsonPath = (path: JsonPath): string[] => {
|
|
76
|
-
if (!isJsonPath(path)) {
|
|
77
|
-
return [];
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
path
|
|
82
|
-
.match(/[a-zA-Z_$][\w$]*|\[\d+\]/g)
|
|
83
|
-
?.map((part) => (part.startsWith('[') ? part.replace(/[[\]]/g, '') : part)) ?? []
|
|
84
|
-
);
|
|
85
|
-
};
|