@hyperjump/json-pointer 1.1.0 → 1.1.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2018 Jason Desrosiers
3
+ Copyright (c) 2018 Hyperjump Software, LLC
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
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 type Pointable = JsonObject | Json[];
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,12 @@
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[0] !== "/") {
9
+ if (pointer.length > 0 && !pointer.startsWith("/")) {
5
10
  throw Error("Invalid JSON Pointer");
6
11
  }
7
12
 
@@ -18,6 +23,22 @@ export const pointerSegments = function* (pointer) {
18
23
  }
19
24
  };
20
25
 
26
+ /**
27
+ * @overload
28
+ * @param {string} pointer
29
+ * @return {API.Getter}
30
+ *
31
+ * @overload
32
+ * @param {string} pointer
33
+ * @param {API.Json} subject
34
+ * @return {API.Json | undefined}
35
+ *
36
+ * @param {string} pointer
37
+ * @param {API.Json} [subject]
38
+ * @return {API.Json | undefined | API.Getter}
39
+ *
40
+ * @type API.get
41
+ */
21
42
  export const get = (pointer, subject = undefined) => {
22
43
  if (subject === undefined) {
23
44
  const segments = [...pointerSegments(pointer)];
@@ -27,7 +48,9 @@ export const get = (pointer, subject = undefined) => {
27
48
  }
28
49
  };
29
50
 
51
+ /** @type (segments: Iterable<string>, subject: API.Json | undefined) => API.Json | undefined */
30
52
  const _get = (segments, subject) => {
53
+ /** @type string */
31
54
  let cursor = nil;
32
55
  for (const segment of segments) {
33
56
  subject = applySegment(subject, segment, cursor);
@@ -37,15 +60,33 @@ const _get = (segments, subject) => {
37
60
  return subject;
38
61
  };
39
62
 
63
+ /**
64
+ * @overload
65
+ * @param {string} pointer
66
+ * @return {API.Setter}
67
+ *
68
+ * @overload
69
+ * @param {string} pointer
70
+ * @param {API.Json} subject
71
+ * @param {API.Json} value
72
+ * @return {API.Json}
73
+ *
74
+ * @param {string} pointer
75
+ * @param {API.Json} [subject]
76
+ * @param {API.Json} [value]
77
+ * @return {API.Json | API.Setter}
78
+ *
79
+ * @type API.set
80
+ */
40
81
  export const set = (pointer, subject = undefined, value = undefined) => {
41
82
  if (subject === undefined) {
42
- const segments = [...pointerSegments(pointer)];
43
- return (subject, value) => _set(segments.values(), subject, value);
83
+ return (subject, value) => _set(pointerSegments(pointer), subject, value);
44
84
  } else {
45
- return _set(pointerSegments(pointer), subject, value);
85
+ return _set(pointerSegments(pointer), subject, /** @type API.Json */ (value));
46
86
  }
47
87
  };
48
88
 
89
+ /** @type (segments: Generator<string>, subject: API.Json | undefined, value: API.Json, cursor?: string) => API.Json */
49
90
  const _set = (segments, subject, value, cursor = nil) => {
50
91
  const segment = segments.next();
51
92
  if (segment.done) {
@@ -61,45 +102,96 @@ const _set = (segments, subject, value, cursor = nil) => {
61
102
  }
62
103
  cursor = append(segment.value, cursor);
63
104
 
105
+ // currentSubject could also be an array, but this appeases the type system
106
+ const currentSubject = /** @type API.JsonObject */ (subject);
64
107
  const computedSegment = computeSegment(subject, segment.value);
65
- subject[computedSegment] = _set(segments, subject[computedSegment], value, cursor);
66
- return subject;
108
+ currentSubject[computedSegment] = _set(segments, currentSubject[computedSegment], value, cursor);
109
+ return currentSubject;
67
110
  };
68
111
 
112
+ /**
113
+ * @overload
114
+ * @param {string} pointer
115
+ * @returns {API.Assigner}
116
+ *
117
+ * @overload
118
+ * @param {string} pointer
119
+ * @param {API.Json} subject
120
+ * @param {API.Json} value
121
+ * @returns {void}
122
+ *
123
+ * @param {string} pointer
124
+ * @param {API.Json} [subject]
125
+ * @param {API.Json} [value]
126
+ * @returns {void | API.Assigner}
127
+ *
128
+ * @type API.assign
129
+ */
69
130
  export const assign = (pointer, subject = undefined, value = undefined) => {
70
131
  if (subject === undefined) {
71
- const segments = [...pointerSegments(pointer)];
72
- return (subject, value) => _assign(segments.values(), subject, value);
132
+ return (subject, value) => _assign(pointerSegments(pointer), subject, value);
73
133
  } else {
74
- return _assign(pointerSegments(pointer), subject, value);
134
+ return _assign(pointerSegments(pointer), subject, /** @type API.Json */ (value));
75
135
  }
76
136
  };
77
137
 
138
+ /** @type (segments: Generator<string>, subject: API.Json, value: API.Json, cursor?: string) => void */
78
139
  const _assign = (segments, subject, value, cursor = nil) => {
140
+ /** @type string | undefined */
79
141
  let lastSegment;
142
+
143
+ /** @type API.Json | undefined */
144
+ let currentSubject = subject;
145
+
146
+ /** @type API.Json | undefined */
80
147
  let lastSubject;
148
+
81
149
  for (let segment of segments) {
82
- segment = computeSegment(subject, segment);
150
+ segment = computeSegment(currentSubject, segment);
83
151
  lastSegment = segment;
84
- lastSubject = subject;
85
- subject = applySegment(subject, segment, cursor);
152
+ lastSubject = currentSubject;
153
+ currentSubject = applySegment(currentSubject, segment, cursor);
86
154
  cursor = append(segment, cursor);
87
155
  }
88
156
 
89
- if (lastSubject !== undefined) {
90
- lastSubject[lastSegment] = value;
157
+ if (lastSegment === undefined) {
158
+ return;
91
159
  }
160
+
161
+ // lastSubject could also be an array, but this appeases the type system
162
+ /** @type API.JsonObject */ (lastSubject)[lastSegment] = value;
92
163
  };
93
164
 
165
+ /**
166
+ * @overload
167
+ * @param {string} pointer
168
+ * @returns {API.Unsetter}
169
+ *
170
+ * @overload
171
+ * @param {string} pointer
172
+ * @param {API.Json} subject
173
+ * @returns {API.Json | undefined}
174
+ *
175
+ * @param {string} pointer
176
+ * @param {API.Json} [subject]
177
+ * @returns {API.Json | undefined | API.Unsetter}
178
+ *
179
+ * @type API.unset
180
+ */
94
181
  export const unset = (pointer, subject = undefined) => {
95
182
  if (subject === undefined) {
96
- const segments = [...pointerSegments(pointer)];
97
- return (subject) => _unset(segments.values(), subject);
183
+ return (subject) => _unset(pointerSegments(pointer), subject);
98
184
  } else {
99
185
  return _unset(pointerSegments(pointer), subject);
100
186
  }
101
187
  };
102
188
 
189
+ /**
190
+ * @param {Generator<string>} segments
191
+ * @param {API.Json | undefined} [subject]
192
+ * @param {string} [cursor]
193
+ * @returns {API.JsonObject | API.Json[] | undefined}
194
+ */
103
195
  const _unset = (segments, subject, cursor = nil) => {
104
196
  const segment = segments.next();
105
197
  if (segment.done) {
@@ -115,45 +207,104 @@ const _unset = (segments, subject, cursor = nil) => {
115
207
  }
116
208
  cursor = append(segment.value, cursor);
117
209
 
118
- const computedSegment = computeSegment(subject, segment.value);
119
- const unsetSubject = _unset(segments, subject[computedSegment], cursor);
120
- if (computedSegment in subject) {
121
- subject[computedSegment] = unsetSubject;
210
+ // currentSubject could also be an array, but this appeases the type system
211
+ const currentSubject = /** @type API.JsonObject */ (subject);
212
+ const computedSegment = computeSegment(currentSubject, segment.value);
213
+ const unsetSubject = _unset(segments, currentSubject[computedSegment], cursor);
214
+ if (computedSegment in currentSubject) {
215
+ if (unsetSubject === undefined) {
216
+ delete currentSubject[computedSegment];
217
+ } else {
218
+ currentSubject[computedSegment] = unsetSubject;
219
+ }
122
220
  }
123
- return subject;
221
+ return currentSubject;
124
222
  };
125
223
 
224
+ /**
225
+ * @overload
226
+ * @param {string} pointer
227
+ * @returns {API.Remover}
228
+ *
229
+ * @overload
230
+ * @param {string} pointer
231
+ * @param {API.Json} subject
232
+ * @returns {void}
233
+ *
234
+ * @param {string} pointer
235
+ * @param {API.Json} [subject]
236
+ * @returns {void | API.Remover}
237
+ *
238
+ * @type API.remove
239
+ */
126
240
  export const remove = (pointer, subject = undefined) => {
127
241
  if (subject === undefined) {
128
- const segments = [...pointerSegments(pointer)];
129
- return (subject) => _remove(segments.values(), subject);
242
+ return (subject) => _remove(pointerSegments(pointer), subject);
130
243
  } else {
131
244
  return _remove(pointerSegments(pointer), subject);
132
245
  }
133
246
  };
134
247
 
248
+ /** @type (segments: Generator<string>, subject: API.Json, cursor?: string) => void */
135
249
  const _remove = (segments, subject, cursor = nil) => {
250
+ /** @type string | undefined */
136
251
  let lastSegment;
252
+
253
+ /** @type API.Json | undefined */
254
+ let currentSubject = subject;
255
+
256
+ /** @type API.Json | undefined */
137
257
  let lastSubject;
258
+
138
259
  for (let segment of segments) {
139
- segment = computeSegment(subject, segment);
260
+ segment = computeSegment(currentSubject, segment);
140
261
  lastSegment = segment;
141
- lastSubject = subject;
142
- subject = applySegment(subject, segment, cursor);
262
+ lastSubject = currentSubject;
263
+ currentSubject = applySegment(currentSubject, segment, cursor);
143
264
  cursor = append(segment, cursor);
144
265
  }
145
266
 
146
- if (lastSubject !== undefined) {
147
- delete lastSubject[lastSegment];
267
+ if (lastSegment === undefined) {
268
+ return;
148
269
  }
270
+
271
+ // lastSubject could also be an array, but this appeases the type system
272
+ delete /** @type API.JsonObject */ (lastSubject)[lastSegment];
149
273
  };
150
274
 
275
+ /** @type API.append */
151
276
  export const append = (segment, pointer) => pointer + "/" + escape(segment);
152
277
 
278
+ /** @type (segment: string) => string */
153
279
  const escape = (segment) => segment.toString().replace(/~/g, "~0").replace(/\//g, "~1");
280
+
281
+ /** @type (segment: string) => string */
154
282
  const unescape = (segment) => segment.toString().replace(/~1/g, "/").replace(/~0/g, "~");
155
- const computeSegment = (value, segment) => Array.isArray(value) && segment === "-" ? value.length : segment;
156
283
 
284
+ /**
285
+ * @overload
286
+ * @param {API.Json[]} value
287
+ * @param {string} segment
288
+ * @returns {number}
289
+ *
290
+ * @overload
291
+ * @param {API.Json | undefined} value
292
+ * @param {string} segment
293
+ * @returns {string}
294
+ *
295
+ * @param {API.Json | undefined} value
296
+ * @param {string} segment
297
+ * @returns {string | number}
298
+ */
299
+ const computeSegment = (value, segment) => {
300
+ if (Array.isArray(value)) {
301
+ return segment === "-" ? value.length : parseInt(segment, 10);
302
+ } else {
303
+ return segment;
304
+ }
305
+ };
306
+
307
+ /** @type (value: API.Json | undefined, segment: string, cursor?: string) => API.Json | undefined */
157
308
  const applySegment = (value, segment, cursor = "") => {
158
309
  if (value === undefined) {
159
310
  throw TypeError(`Value at '${cursor}' is undefined and does not have property '${segment}'`);
@@ -163,8 +314,12 @@ const applySegment = (value, segment, cursor = "") => {
163
314
  throw TypeError(`Value at '${cursor}' is a ${typeof value} and does not have property '${segment}'`);
164
315
  } else {
165
316
  const computedSegment = computeSegment(value, segment);
166
- return value[computedSegment];
317
+ if (Object.hasOwn(value, computedSegment)) {
318
+ // value could also be an array, but this appeases the type system
319
+ return /** @type API.JsonObject */ (value)[computedSegment];
320
+ }
167
321
  }
168
322
  };
169
323
 
324
+ /** @type (value: API.Json) => value is string | number | boolean | null */
170
325
  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.0",
3
+ "version": "1.1.1",
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
- "@typescript-eslint/eslint-plugin": "*",
26
- "@typescript-eslint/parser": "*",
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
  }
@@ -1 +0,0 @@
1
- github: [jdesrosiers]