@hyperjump/json-pointer 1.1.0 → 1.1.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/LICENSE +1 -1
- package/lib/index.d.ts +35 -48
- package/lib/index.js +189 -30
- package/package.json +6 -8
- package/.github/FUNDING.yml +0 -1
package/LICENSE
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -1,53 +1,40 @@
|
|
|
1
|
-
export const nil: "";
|
|
2
|
-
export const pointerSegments: (pointer: string) => Generator<string>;
|
|
3
|
-
export const append: (
|
|
4
|
-
(segment: string, pointer: string) => string
|
|
5
|
-
) & (
|
|
6
|
-
(segment: string) => (pointer: string) => string
|
|
7
|
-
);
|
|
8
|
-
export const get: (
|
|
9
|
-
(pointer: string, subject: Pointable) => unknown
|
|
10
|
-
) & (
|
|
11
|
-
(pointer: string) => Getter
|
|
12
|
-
);
|
|
13
|
-
export const set: (
|
|
14
|
-
<A extends Pointable>(pointer: string, subject: A, value: unknown) => A
|
|
15
|
-
) & (
|
|
16
|
-
(pointer: string) => Setter
|
|
17
|
-
);
|
|
18
|
-
export const assign: (
|
|
19
|
-
<A extends Pointable>(pointer: string, subject: A, value: unknown) => void
|
|
20
|
-
) & (
|
|
21
|
-
(pointer: string) => Assigner
|
|
22
|
-
);
|
|
23
|
-
export const unset: (
|
|
24
|
-
<A extends Pointable>(pointer: string, subject: A) => A
|
|
25
|
-
) & (
|
|
26
|
-
(pointer: string) => Unsetter
|
|
27
|
-
);
|
|
28
|
-
export const remove: (
|
|
29
|
-
(pointer: string, subject: Pointable) => void
|
|
30
|
-
) & (
|
|
31
|
-
(pointer: string) => Remover
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
export type Getter = (subject: Pointable) => unknown;
|
|
35
|
-
export type Setter = (
|
|
36
|
-
<A extends Pointable>(subject: A, value: unknown) => A
|
|
37
|
-
) & (
|
|
38
|
-
<A extends Pointable>(subject: A) => (value: unknown) => A
|
|
39
|
-
);
|
|
40
|
-
export type Assigner = (
|
|
41
|
-
<A extends Pointable>(subject: A, value: unknown) => void
|
|
42
|
-
) & (
|
|
43
|
-
<A extends Pointable>(subject: A) => (value: unknown) => void
|
|
44
|
-
);
|
|
45
|
-
export type Unsetter = <A extends Pointable>(subject: A) => A;
|
|
46
|
-
export type Remover = (subject: Pointable) => void;
|
|
47
|
-
|
|
48
1
|
export type Json = string | number | boolean | null | JsonObject | Json[];
|
|
49
2
|
export type JsonObject = {
|
|
50
3
|
[property: string]: Json;
|
|
51
4
|
};
|
|
52
5
|
|
|
53
|
-
export
|
|
6
|
+
export const nil: "";
|
|
7
|
+
|
|
8
|
+
export const pointerSegments: (pointer: string) => Generator<string>;
|
|
9
|
+
|
|
10
|
+
export const append: (segment: string, pointer: string) => string;
|
|
11
|
+
|
|
12
|
+
export const get: {
|
|
13
|
+
(pointer: string, subject: Json): Json | undefined;
|
|
14
|
+
(pointer: string): Getter;
|
|
15
|
+
};
|
|
16
|
+
export type Getter = (subject: Json) => Json | undefined;
|
|
17
|
+
|
|
18
|
+
export const set: {
|
|
19
|
+
(pointer: string, subject: Json, value: Json): Json;
|
|
20
|
+
(pointer: string): Setter;
|
|
21
|
+
};
|
|
22
|
+
export type Setter = (subject: Json, value: Json) => Json;
|
|
23
|
+
|
|
24
|
+
export const assign: {
|
|
25
|
+
(pointer: string, subject: Json, value: Json): void;
|
|
26
|
+
(pointer: string): Assigner;
|
|
27
|
+
};
|
|
28
|
+
export type Assigner = (subject: Json, value: Json) => void;
|
|
29
|
+
|
|
30
|
+
export const unset: {
|
|
31
|
+
(pointer: string, subject: Json): Json | undefined;
|
|
32
|
+
(pointer: string): Unsetter;
|
|
33
|
+
};
|
|
34
|
+
export type Unsetter = (subject: Json) => Json | undefined;
|
|
35
|
+
|
|
36
|
+
export const remove: {
|
|
37
|
+
(pointer: string, subject: Json): void;
|
|
38
|
+
(pointer: string): Remover;
|
|
39
|
+
};
|
|
40
|
+
export type Remover = (subject: Json) => void;
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
/** @import * as API from "./index.d.ts" */
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/** @type API.nil */
|
|
1
5
|
export const nil = "";
|
|
2
6
|
|
|
7
|
+
/** @type API.pointerSegments */
|
|
3
8
|
export const pointerSegments = function* (pointer) {
|
|
4
|
-
if (pointer.length > 0 && pointer
|
|
9
|
+
if (pointer.length > 0 && !pointer.startsWith("/")) {
|
|
10
|
+
throw Error("Invalid JSON Pointer");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (/~(?![01])/.test(pointer)) {
|
|
5
14
|
throw Error("Invalid JSON Pointer");
|
|
6
15
|
}
|
|
7
16
|
|
|
@@ -18,6 +27,22 @@ export const pointerSegments = function* (pointer) {
|
|
|
18
27
|
}
|
|
19
28
|
};
|
|
20
29
|
|
|
30
|
+
/**
|
|
31
|
+
* @overload
|
|
32
|
+
* @param {string} pointer
|
|
33
|
+
* @return {API.Getter}
|
|
34
|
+
*
|
|
35
|
+
* @overload
|
|
36
|
+
* @param {string} pointer
|
|
37
|
+
* @param {API.Json} subject
|
|
38
|
+
* @return {API.Json | undefined}
|
|
39
|
+
*
|
|
40
|
+
* @param {string} pointer
|
|
41
|
+
* @param {API.Json} [subject]
|
|
42
|
+
* @return {API.Json | undefined | API.Getter}
|
|
43
|
+
*
|
|
44
|
+
* @type API.get
|
|
45
|
+
*/
|
|
21
46
|
export const get = (pointer, subject = undefined) => {
|
|
22
47
|
if (subject === undefined) {
|
|
23
48
|
const segments = [...pointerSegments(pointer)];
|
|
@@ -27,7 +52,9 @@ export const get = (pointer, subject = undefined) => {
|
|
|
27
52
|
}
|
|
28
53
|
};
|
|
29
54
|
|
|
55
|
+
/** @type (segments: Iterable<string>, subject: API.Json | undefined) => API.Json | undefined */
|
|
30
56
|
const _get = (segments, subject) => {
|
|
57
|
+
/** @type string */
|
|
31
58
|
let cursor = nil;
|
|
32
59
|
for (const segment of segments) {
|
|
33
60
|
subject = applySegment(subject, segment, cursor);
|
|
@@ -37,15 +64,33 @@ const _get = (segments, subject) => {
|
|
|
37
64
|
return subject;
|
|
38
65
|
};
|
|
39
66
|
|
|
67
|
+
/**
|
|
68
|
+
* @overload
|
|
69
|
+
* @param {string} pointer
|
|
70
|
+
* @return {API.Setter}
|
|
71
|
+
*
|
|
72
|
+
* @overload
|
|
73
|
+
* @param {string} pointer
|
|
74
|
+
* @param {API.Json} subject
|
|
75
|
+
* @param {API.Json} value
|
|
76
|
+
* @return {API.Json}
|
|
77
|
+
*
|
|
78
|
+
* @param {string} pointer
|
|
79
|
+
* @param {API.Json} [subject]
|
|
80
|
+
* @param {API.Json} [value]
|
|
81
|
+
* @return {API.Json | API.Setter}
|
|
82
|
+
*
|
|
83
|
+
* @type API.set
|
|
84
|
+
*/
|
|
40
85
|
export const set = (pointer, subject = undefined, value = undefined) => {
|
|
41
86
|
if (subject === undefined) {
|
|
42
|
-
|
|
43
|
-
return (subject, value) => _set(segments.values(), subject, value);
|
|
87
|
+
return (subject, value) => _set(pointerSegments(pointer), subject, value);
|
|
44
88
|
} else {
|
|
45
|
-
return _set(pointerSegments(pointer), subject, value);
|
|
89
|
+
return _set(pointerSegments(pointer), subject, /** @type API.Json */ (value));
|
|
46
90
|
}
|
|
47
91
|
};
|
|
48
92
|
|
|
93
|
+
/** @type (segments: Generator<string>, subject: API.Json | undefined, value: API.Json, cursor?: string) => API.Json */
|
|
49
94
|
const _set = (segments, subject, value, cursor = nil) => {
|
|
50
95
|
const segment = segments.next();
|
|
51
96
|
if (segment.done) {
|
|
@@ -61,45 +106,96 @@ const _set = (segments, subject, value, cursor = nil) => {
|
|
|
61
106
|
}
|
|
62
107
|
cursor = append(segment.value, cursor);
|
|
63
108
|
|
|
109
|
+
// currentSubject could also be an array, but this appeases the type system
|
|
110
|
+
const currentSubject = /** @type API.JsonObject */ (subject);
|
|
64
111
|
const computedSegment = computeSegment(subject, segment.value);
|
|
65
|
-
|
|
66
|
-
return
|
|
112
|
+
currentSubject[computedSegment] = _set(segments, currentSubject[computedSegment], value, cursor);
|
|
113
|
+
return currentSubject;
|
|
67
114
|
};
|
|
68
115
|
|
|
116
|
+
/**
|
|
117
|
+
* @overload
|
|
118
|
+
* @param {string} pointer
|
|
119
|
+
* @returns {API.Assigner}
|
|
120
|
+
*
|
|
121
|
+
* @overload
|
|
122
|
+
* @param {string} pointer
|
|
123
|
+
* @param {API.Json} subject
|
|
124
|
+
* @param {API.Json} value
|
|
125
|
+
* @returns {void}
|
|
126
|
+
*
|
|
127
|
+
* @param {string} pointer
|
|
128
|
+
* @param {API.Json} [subject]
|
|
129
|
+
* @param {API.Json} [value]
|
|
130
|
+
* @returns {void | API.Assigner}
|
|
131
|
+
*
|
|
132
|
+
* @type API.assign
|
|
133
|
+
*/
|
|
69
134
|
export const assign = (pointer, subject = undefined, value = undefined) => {
|
|
70
135
|
if (subject === undefined) {
|
|
71
|
-
|
|
72
|
-
return (subject, value) => _assign(segments.values(), subject, value);
|
|
136
|
+
return (subject, value) => _assign(pointerSegments(pointer), subject, value);
|
|
73
137
|
} else {
|
|
74
|
-
return _assign(pointerSegments(pointer), subject, value);
|
|
138
|
+
return _assign(pointerSegments(pointer), subject, /** @type API.Json */ (value));
|
|
75
139
|
}
|
|
76
140
|
};
|
|
77
141
|
|
|
142
|
+
/** @type (segments: Generator<string>, subject: API.Json, value: API.Json, cursor?: string) => void */
|
|
78
143
|
const _assign = (segments, subject, value, cursor = nil) => {
|
|
144
|
+
/** @type string | undefined */
|
|
79
145
|
let lastSegment;
|
|
146
|
+
|
|
147
|
+
/** @type API.Json | undefined */
|
|
148
|
+
let currentSubject = subject;
|
|
149
|
+
|
|
150
|
+
/** @type API.Json | undefined */
|
|
80
151
|
let lastSubject;
|
|
152
|
+
|
|
81
153
|
for (let segment of segments) {
|
|
82
|
-
segment = computeSegment(
|
|
154
|
+
segment = computeSegment(currentSubject, segment);
|
|
83
155
|
lastSegment = segment;
|
|
84
|
-
lastSubject =
|
|
85
|
-
|
|
156
|
+
lastSubject = currentSubject;
|
|
157
|
+
currentSubject = applySegment(currentSubject, segment, cursor);
|
|
86
158
|
cursor = append(segment, cursor);
|
|
87
159
|
}
|
|
88
160
|
|
|
89
|
-
if (
|
|
90
|
-
|
|
161
|
+
if (lastSegment === undefined) {
|
|
162
|
+
return;
|
|
91
163
|
}
|
|
164
|
+
|
|
165
|
+
// lastSubject could also be an array, but this appeases the type system
|
|
166
|
+
/** @type API.JsonObject */ (lastSubject)[lastSegment] = value;
|
|
92
167
|
};
|
|
93
168
|
|
|
169
|
+
/**
|
|
170
|
+
* @overload
|
|
171
|
+
* @param {string} pointer
|
|
172
|
+
* @returns {API.Unsetter}
|
|
173
|
+
*
|
|
174
|
+
* @overload
|
|
175
|
+
* @param {string} pointer
|
|
176
|
+
* @param {API.Json} subject
|
|
177
|
+
* @returns {API.Json | undefined}
|
|
178
|
+
*
|
|
179
|
+
* @param {string} pointer
|
|
180
|
+
* @param {API.Json} [subject]
|
|
181
|
+
* @returns {API.Json | undefined | API.Unsetter}
|
|
182
|
+
*
|
|
183
|
+
* @type API.unset
|
|
184
|
+
*/
|
|
94
185
|
export const unset = (pointer, subject = undefined) => {
|
|
95
186
|
if (subject === undefined) {
|
|
96
|
-
|
|
97
|
-
return (subject) => _unset(segments.values(), subject);
|
|
187
|
+
return (subject) => _unset(pointerSegments(pointer), subject);
|
|
98
188
|
} else {
|
|
99
189
|
return _unset(pointerSegments(pointer), subject);
|
|
100
190
|
}
|
|
101
191
|
};
|
|
102
192
|
|
|
193
|
+
/**
|
|
194
|
+
* @param {Generator<string>} segments
|
|
195
|
+
* @param {API.Json | undefined} [subject]
|
|
196
|
+
* @param {string} [cursor]
|
|
197
|
+
* @returns {API.JsonObject | API.Json[] | undefined}
|
|
198
|
+
*/
|
|
103
199
|
const _unset = (segments, subject, cursor = nil) => {
|
|
104
200
|
const segment = segments.next();
|
|
105
201
|
if (segment.done) {
|
|
@@ -115,45 +211,104 @@ const _unset = (segments, subject, cursor = nil) => {
|
|
|
115
211
|
}
|
|
116
212
|
cursor = append(segment.value, cursor);
|
|
117
213
|
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
214
|
+
// currentSubject could also be an array, but this appeases the type system
|
|
215
|
+
const currentSubject = /** @type API.JsonObject */ (subject);
|
|
216
|
+
const computedSegment = computeSegment(currentSubject, segment.value);
|
|
217
|
+
const unsetSubject = _unset(segments, currentSubject[computedSegment], cursor);
|
|
218
|
+
if (computedSegment in currentSubject) {
|
|
219
|
+
if (unsetSubject === undefined) {
|
|
220
|
+
delete currentSubject[computedSegment];
|
|
221
|
+
} else {
|
|
222
|
+
currentSubject[computedSegment] = unsetSubject;
|
|
223
|
+
}
|
|
122
224
|
}
|
|
123
|
-
return
|
|
225
|
+
return currentSubject;
|
|
124
226
|
};
|
|
125
227
|
|
|
228
|
+
/**
|
|
229
|
+
* @overload
|
|
230
|
+
* @param {string} pointer
|
|
231
|
+
* @returns {API.Remover}
|
|
232
|
+
*
|
|
233
|
+
* @overload
|
|
234
|
+
* @param {string} pointer
|
|
235
|
+
* @param {API.Json} subject
|
|
236
|
+
* @returns {void}
|
|
237
|
+
*
|
|
238
|
+
* @param {string} pointer
|
|
239
|
+
* @param {API.Json} [subject]
|
|
240
|
+
* @returns {void | API.Remover}
|
|
241
|
+
*
|
|
242
|
+
* @type API.remove
|
|
243
|
+
*/
|
|
126
244
|
export const remove = (pointer, subject = undefined) => {
|
|
127
245
|
if (subject === undefined) {
|
|
128
|
-
|
|
129
|
-
return (subject) => _remove(segments.values(), subject);
|
|
246
|
+
return (subject) => _remove(pointerSegments(pointer), subject);
|
|
130
247
|
} else {
|
|
131
248
|
return _remove(pointerSegments(pointer), subject);
|
|
132
249
|
}
|
|
133
250
|
};
|
|
134
251
|
|
|
252
|
+
/** @type (segments: Generator<string>, subject: API.Json, cursor?: string) => void */
|
|
135
253
|
const _remove = (segments, subject, cursor = nil) => {
|
|
254
|
+
/** @type string | undefined */
|
|
136
255
|
let lastSegment;
|
|
256
|
+
|
|
257
|
+
/** @type API.Json | undefined */
|
|
258
|
+
let currentSubject = subject;
|
|
259
|
+
|
|
260
|
+
/** @type API.Json | undefined */
|
|
137
261
|
let lastSubject;
|
|
262
|
+
|
|
138
263
|
for (let segment of segments) {
|
|
139
|
-
segment = computeSegment(
|
|
264
|
+
segment = computeSegment(currentSubject, segment);
|
|
140
265
|
lastSegment = segment;
|
|
141
|
-
lastSubject =
|
|
142
|
-
|
|
266
|
+
lastSubject = currentSubject;
|
|
267
|
+
currentSubject = applySegment(currentSubject, segment, cursor);
|
|
143
268
|
cursor = append(segment, cursor);
|
|
144
269
|
}
|
|
145
270
|
|
|
146
|
-
if (
|
|
147
|
-
|
|
271
|
+
if (lastSegment === undefined) {
|
|
272
|
+
return;
|
|
148
273
|
}
|
|
274
|
+
|
|
275
|
+
// lastSubject could also be an array, but this appeases the type system
|
|
276
|
+
delete /** @type API.JsonObject */ (lastSubject)[lastSegment];
|
|
149
277
|
};
|
|
150
278
|
|
|
279
|
+
/** @type API.append */
|
|
151
280
|
export const append = (segment, pointer) => pointer + "/" + escape(segment);
|
|
152
281
|
|
|
282
|
+
/** @type (segment: string) => string */
|
|
153
283
|
const escape = (segment) => segment.toString().replace(/~/g, "~0").replace(/\//g, "~1");
|
|
284
|
+
|
|
285
|
+
/** @type (segment: string) => string */
|
|
154
286
|
const unescape = (segment) => segment.toString().replace(/~1/g, "/").replace(/~0/g, "~");
|
|
155
|
-
const computeSegment = (value, segment) => Array.isArray(value) && segment === "-" ? value.length : segment;
|
|
156
287
|
|
|
288
|
+
/**
|
|
289
|
+
* @overload
|
|
290
|
+
* @param {API.Json[]} value
|
|
291
|
+
* @param {string} segment
|
|
292
|
+
* @returns {number}
|
|
293
|
+
*
|
|
294
|
+
* @overload
|
|
295
|
+
* @param {API.Json | undefined} value
|
|
296
|
+
* @param {string} segment
|
|
297
|
+
* @returns {string}
|
|
298
|
+
*
|
|
299
|
+
* @param {API.Json | undefined} value
|
|
300
|
+
* @param {string} segment
|
|
301
|
+
* @returns {string | number}
|
|
302
|
+
*/
|
|
303
|
+
const computeSegment = (value, segment) => {
|
|
304
|
+
if (Array.isArray(value)) {
|
|
305
|
+
return segment === "-" ? value.length : parseInt(segment, 10);
|
|
306
|
+
} else {
|
|
307
|
+
return segment;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
/** @type (value: API.Json | undefined, segment: string, cursor?: string) => API.Json | undefined */
|
|
157
312
|
const applySegment = (value, segment, cursor = "") => {
|
|
158
313
|
if (value === undefined) {
|
|
159
314
|
throw TypeError(`Value at '${cursor}' is undefined and does not have property '${segment}'`);
|
|
@@ -163,8 +318,12 @@ const applySegment = (value, segment, cursor = "") => {
|
|
|
163
318
|
throw TypeError(`Value at '${cursor}' is a ${typeof value} and does not have property '${segment}'`);
|
|
164
319
|
} else {
|
|
165
320
|
const computedSegment = computeSegment(value, segment);
|
|
166
|
-
|
|
321
|
+
if (Object.hasOwn(value, computedSegment)) {
|
|
322
|
+
// value could also be an array, but this appeases the type system
|
|
323
|
+
return /** @type API.JsonObject */ (value)[computedSegment];
|
|
324
|
+
}
|
|
167
325
|
}
|
|
168
326
|
};
|
|
169
327
|
|
|
328
|
+
/** @type (value: API.Json) => value is string | number | boolean | null */
|
|
170
329
|
const isScalar = (value) => value === null || typeof value !== "object";
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperjump/json-pointer",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "An RFC-6901 JSON Pointer implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"exports": "./lib/index.js",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"clean": "xargs -a .gitignore rm -rf",
|
|
10
9
|
"lint": "eslint lib",
|
|
11
|
-
"test": "vitest --watch=false"
|
|
10
|
+
"test": "vitest --watch=false",
|
|
11
|
+
"type-check": "tsc --noEmit"
|
|
12
12
|
},
|
|
13
13
|
"repository": "github:hyperjump-io/json-pointer",
|
|
14
14
|
"keywords": [
|
|
@@ -22,13 +22,11 @@
|
|
|
22
22
|
"url": "https://github.com/sponsors/jdesrosiers"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@
|
|
26
|
-
"@
|
|
27
|
-
"eslint": "*",
|
|
28
|
-
"eslint-import-resolver-node": "*",
|
|
25
|
+
"@stylistic/eslint-plugin": "*",
|
|
26
|
+
"@types/node": "*",
|
|
29
27
|
"eslint-import-resolver-typescript": "*",
|
|
30
28
|
"eslint-plugin-import": "*",
|
|
31
|
-
"typescript": "*",
|
|
29
|
+
"typescript-eslint": "*",
|
|
32
30
|
"vitest": "*"
|
|
33
31
|
}
|
|
34
32
|
}
|
package/.github/FUNDING.yml
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
github: [jdesrosiers]
|