@hyperjump/json-pointer 1.0.1 → 1.1.0
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/README.md +40 -10
- package/lib/index.d.ts +1 -0
- package/lib/index.js +100 -90
- package/package.json +4 -11
package/README.md
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
JSON Pointer
|
|
2
|
-
============
|
|
1
|
+
# JSON Pointer
|
|
3
2
|
|
|
4
3
|
This is an implementation of RFC-6901 JSON Pointer. JSON Pointer is designed for
|
|
5
4
|
referring to data values within a JSON document. It's designed to be URL
|
|
6
5
|
friendly so it can be used as a URL fragment that points to a specific part of
|
|
7
6
|
the JSON document.
|
|
8
7
|
|
|
9
|
-
Installation
|
|
10
|
-
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
11
10
|
Includes support for node.js (ES Modules, TypeScript) and browsers.
|
|
12
11
|
|
|
13
12
|
```bash
|
|
14
13
|
npm install @hyperjump/json-pointer
|
|
15
14
|
```
|
|
16
15
|
|
|
17
|
-
Usage
|
|
18
|
-
-----
|
|
16
|
+
## Usage
|
|
19
17
|
|
|
20
18
|
```javascript
|
|
21
|
-
|
|
19
|
+
import * as JsonPointer from "@hyperjump/json-pointer";
|
|
22
20
|
|
|
23
21
|
const value = {
|
|
24
22
|
"foo": {
|
|
@@ -27,7 +25,7 @@ const value = {
|
|
|
27
25
|
};
|
|
28
26
|
|
|
29
27
|
// Construct pointers
|
|
30
|
-
const fooPointer = JsonPointer.append(JsonPointer.nil
|
|
28
|
+
const fooPointer = JsonPointer.append("foo", JsonPointer.nil); // "/foo"
|
|
31
29
|
const fooBarPointer = JsonPointer.append(fooPointer, "bar"); // "/foo/bar"
|
|
32
30
|
|
|
33
31
|
// Get a value from a pointer
|
|
@@ -55,8 +53,40 @@ const deleteFooBar = JsonPointer.remove(fooBarPointer);
|
|
|
55
53
|
deleteFooBar(value); // { "foo": {} }
|
|
56
54
|
```
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
## API
|
|
57
|
+
|
|
58
|
+
* **nil**: ""
|
|
59
|
+
|
|
60
|
+
The empty pointer.
|
|
61
|
+
* **pointerSegments**: (pointer: string) => Generator\<string>
|
|
62
|
+
|
|
63
|
+
An iterator for the segments of a JSON Pointer that handles escaping.
|
|
64
|
+
* **append**: (segment: string, pointer: string) => string
|
|
65
|
+
|
|
66
|
+
Append a segment to a JSON Pointer.
|
|
67
|
+
* **get**: (pointer: string, subject: any) => any
|
|
68
|
+
|
|
69
|
+
Use a JSON Pointer to get a value. This function can be curried.
|
|
70
|
+
* **set**: (pointer: string, subject: any, value: any) => any
|
|
71
|
+
|
|
72
|
+
Immutably set a value using a JSON Pointer. Returns a new version of
|
|
73
|
+
`subject` with the value set. The original `subject` is not changed, but the
|
|
74
|
+
value isn't entirely cloned. Values that aren't changed will point to
|
|
75
|
+
the same value as the original. This function can be curried.
|
|
76
|
+
* **assign**: (pointer: string, subject: any, value: any) => void
|
|
77
|
+
|
|
78
|
+
Mutate a value using a JSON Pointer. This function can be curried.
|
|
79
|
+
* **unset**: (pointer: string, subject: any) => any
|
|
80
|
+
|
|
81
|
+
Immutably delete a value using a JSON Pointer. Returns a new version of
|
|
82
|
+
`subject` without the value. The original `subject` is not changed, but the
|
|
83
|
+
value isn't entirely cloned. Values that aren't changed will point to the
|
|
84
|
+
same value as the original. This function can be curried.
|
|
85
|
+
* **remove**: (pointer: string, subject: any) => void
|
|
86
|
+
|
|
87
|
+
Delete a value using a JSON Pointer. This function can be curried.
|
|
88
|
+
|
|
89
|
+
## Contributing
|
|
60
90
|
|
|
61
91
|
### Tests
|
|
62
92
|
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import curry from "just-curry-it";
|
|
2
|
-
|
|
3
|
-
|
|
4
1
|
export const nil = "";
|
|
5
2
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const segmentGenerator = (pointer) => {
|
|
3
|
+
export const pointerSegments = function* (pointer) {
|
|
9
4
|
if (pointer.length > 0 && pointer[0] !== "/") {
|
|
10
5
|
throw Error("Invalid JSON Pointer");
|
|
11
6
|
}
|
|
@@ -13,132 +8,147 @@ const segmentGenerator = (pointer) => {
|
|
|
13
8
|
let segmentStart = 1;
|
|
14
9
|
let segmentEnd = 0;
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
if (mode === EXISTS) {
|
|
18
|
-
return segmentEnd < pointer.length;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (segmentEnd >= pointer.length) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
11
|
+
while (segmentEnd < pointer.length) {
|
|
25
12
|
const position = pointer.indexOf("/", segmentStart);
|
|
26
13
|
segmentEnd = position === -1 ? pointer.length : position;
|
|
27
|
-
const segment =
|
|
14
|
+
const segment = pointer.slice(segmentStart, segmentEnd);
|
|
28
15
|
segmentStart = segmentEnd + 1;
|
|
29
16
|
|
|
30
|
-
|
|
31
|
-
}
|
|
17
|
+
yield unescape(segment);
|
|
18
|
+
}
|
|
32
19
|
};
|
|
33
20
|
|
|
34
21
|
export const get = (pointer, subject = undefined) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
22
|
+
if (subject === undefined) {
|
|
23
|
+
const segments = [...pointerSegments(pointer)];
|
|
24
|
+
return (subject) => _get(segments, subject);
|
|
25
|
+
} else {
|
|
26
|
+
return _get(pointerSegments(pointer), subject);
|
|
27
|
+
}
|
|
38
28
|
};
|
|
39
29
|
|
|
40
|
-
const _get = (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return _get(nextSegment, applySegment(subject, segment, cursor), append(segment, cursor));
|
|
30
|
+
const _get = (segments, subject) => {
|
|
31
|
+
let cursor = nil;
|
|
32
|
+
for (const segment of segments) {
|
|
33
|
+
subject = applySegment(subject, segment, cursor);
|
|
34
|
+
cursor = append(segment, cursor);
|
|
46
35
|
}
|
|
36
|
+
|
|
37
|
+
return subject;
|
|
47
38
|
};
|
|
48
39
|
|
|
49
40
|
export const set = (pointer, subject = undefined, value = undefined) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
if (subject === undefined) {
|
|
42
|
+
const segments = [...pointerSegments(pointer)];
|
|
43
|
+
return (subject, value) => _set(segments.values(), subject, value);
|
|
44
|
+
} else {
|
|
45
|
+
return _set(pointerSegments(pointer), subject, value);
|
|
46
|
+
}
|
|
53
47
|
};
|
|
54
48
|
|
|
55
|
-
const _set = (
|
|
56
|
-
const segment =
|
|
57
|
-
if (segment
|
|
49
|
+
const _set = (segments, subject, value, cursor = nil) => {
|
|
50
|
+
const segment = segments.next();
|
|
51
|
+
if (segment.done) {
|
|
58
52
|
return value;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return clonedSubject;
|
|
64
|
-
} else {
|
|
65
|
-
return { ...subject, [segment]: _set(nextSegment, applySegment(subject, segment, cursor), value, append(segment, cursor)) };
|
|
66
|
-
}
|
|
67
|
-
} else if (Array.isArray(subject)) {
|
|
68
|
-
const clonedSubject = [...subject];
|
|
69
|
-
clonedSubject[computeSegment(subject, segment)] = value;
|
|
70
|
-
return clonedSubject;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (Array.isArray(subject)) {
|
|
56
|
+
subject = [...subject];
|
|
71
57
|
} else if (typeof subject === "object" && subject !== null) {
|
|
72
|
-
|
|
58
|
+
subject = { ...subject };
|
|
73
59
|
} else {
|
|
74
|
-
|
|
60
|
+
applySegment(subject, segment.value, cursor);
|
|
75
61
|
}
|
|
62
|
+
cursor = append(segment.value, cursor);
|
|
63
|
+
|
|
64
|
+
const computedSegment = computeSegment(subject, segment.value);
|
|
65
|
+
subject[computedSegment] = _set(segments, subject[computedSegment], value, cursor);
|
|
66
|
+
return subject;
|
|
76
67
|
};
|
|
77
68
|
|
|
78
69
|
export const assign = (pointer, subject = undefined, value = undefined) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
70
|
+
if (subject === undefined) {
|
|
71
|
+
const segments = [...pointerSegments(pointer)];
|
|
72
|
+
return (subject, value) => _assign(segments.values(), subject, value);
|
|
73
|
+
} else {
|
|
74
|
+
return _assign(pointerSegments(pointer), subject, value);
|
|
75
|
+
}
|
|
82
76
|
};
|
|
83
77
|
|
|
84
|
-
const _assign = (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
78
|
+
const _assign = (segments, subject, value, cursor = nil) => {
|
|
79
|
+
let lastSegment;
|
|
80
|
+
let lastSubject;
|
|
81
|
+
for (let segment of segments) {
|
|
82
|
+
segment = computeSegment(subject, segment);
|
|
83
|
+
lastSegment = segment;
|
|
84
|
+
lastSubject = subject;
|
|
85
|
+
subject = applySegment(subject, segment, cursor);
|
|
86
|
+
cursor = append(segment, cursor);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (lastSubject !== undefined) {
|
|
90
|
+
lastSubject[lastSegment] = value;
|
|
92
91
|
}
|
|
93
92
|
};
|
|
94
93
|
|
|
95
94
|
export const unset = (pointer, subject = undefined) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
if (subject === undefined) {
|
|
96
|
+
const segments = [...pointerSegments(pointer)];
|
|
97
|
+
return (subject) => _unset(segments.values(), subject);
|
|
98
|
+
} else {
|
|
99
|
+
return _unset(pointerSegments(pointer), subject);
|
|
100
|
+
}
|
|
99
101
|
};
|
|
100
102
|
|
|
101
|
-
const _unset = (
|
|
102
|
-
const segment =
|
|
103
|
-
if (segment
|
|
103
|
+
const _unset = (segments, subject, cursor = nil) => {
|
|
104
|
+
const segment = segments.next();
|
|
105
|
+
if (segment.done) {
|
|
104
106
|
return;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const clonedSubject = [...subject];
|
|
110
|
-
delete clonedSubject[computeSegment(subject, segment)];
|
|
111
|
-
return clonedSubject;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (Array.isArray(subject)) {
|
|
110
|
+
subject = [...subject];
|
|
112
111
|
} else if (typeof subject === "object" && subject !== null) {
|
|
113
|
-
|
|
114
|
-
const { [segment]: _, ...result } = subject;
|
|
115
|
-
return result;
|
|
112
|
+
subject = { ...subject };
|
|
116
113
|
} else {
|
|
117
|
-
|
|
114
|
+
applySegment(subject, segment.value, cursor);
|
|
118
115
|
}
|
|
116
|
+
cursor = append(segment.value, cursor);
|
|
117
|
+
|
|
118
|
+
const computedSegment = computeSegment(subject, segment.value);
|
|
119
|
+
const unsetSubject = _unset(segments, subject[computedSegment], cursor);
|
|
120
|
+
if (computedSegment in subject) {
|
|
121
|
+
subject[computedSegment] = unsetSubject;
|
|
122
|
+
}
|
|
123
|
+
return subject;
|
|
119
124
|
};
|
|
120
125
|
|
|
121
126
|
export const remove = (pointer, subject = undefined) => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
if (subject === undefined) {
|
|
128
|
+
const segments = [...pointerSegments(pointer)];
|
|
129
|
+
return (subject) => _remove(segments.values(), subject);
|
|
130
|
+
} else {
|
|
131
|
+
return _remove(pointerSegments(pointer), subject);
|
|
132
|
+
}
|
|
125
133
|
};
|
|
126
134
|
|
|
127
|
-
const _remove = (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
135
|
+
const _remove = (segments, subject, cursor = nil) => {
|
|
136
|
+
let lastSegment;
|
|
137
|
+
let lastSubject;
|
|
138
|
+
for (let segment of segments) {
|
|
139
|
+
segment = computeSegment(subject, segment);
|
|
140
|
+
lastSegment = segment;
|
|
141
|
+
lastSubject = subject;
|
|
142
|
+
subject = applySegment(subject, segment, cursor);
|
|
143
|
+
cursor = append(segment, cursor);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (lastSubject !== undefined) {
|
|
147
|
+
delete lastSubject[lastSegment];
|
|
138
148
|
}
|
|
139
149
|
};
|
|
140
150
|
|
|
141
|
-
export const append =
|
|
151
|
+
export const append = (segment, pointer) => pointer + "/" + escape(segment);
|
|
142
152
|
|
|
143
153
|
const escape = (segment) => segment.toString().replace(/~/g, "~0").replace(/\//g, "~1");
|
|
144
154
|
const unescape = (segment) => segment.toString().replace(/~1/g, "/").replace(/~0/g, "~");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperjump/json-pointer",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "An RFC-6901 JSON Pointer implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"clean": "xargs -a .gitignore rm -rf",
|
|
10
10
|
"lint": "eslint lib",
|
|
11
|
-
"test": "
|
|
11
|
+
"test": "vitest --watch=false"
|
|
12
12
|
},
|
|
13
13
|
"repository": "github:hyperjump-io/json-pointer",
|
|
14
14
|
"keywords": [
|
|
@@ -22,20 +22,13 @@
|
|
|
22
22
|
"url": "https://github.com/sponsors/jdesrosiers"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@types/chai": "*",
|
|
26
|
-
"@types/mocha": "*",
|
|
27
25
|
"@typescript-eslint/eslint-plugin": "*",
|
|
28
26
|
"@typescript-eslint/parser": "*",
|
|
29
|
-
"chai": "*",
|
|
30
27
|
"eslint": "*",
|
|
31
28
|
"eslint-import-resolver-node": "*",
|
|
32
29
|
"eslint-import-resolver-typescript": "*",
|
|
33
30
|
"eslint-plugin-import": "*",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"typescript": "*"
|
|
37
|
-
},
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"just-curry-it": "^5.3.0"
|
|
31
|
+
"typescript": "*",
|
|
32
|
+
"vitest": "*"
|
|
40
33
|
}
|
|
41
34
|
}
|