@scalar/json-magic 0.8.2 → 0.8.4
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/CHANGELOG.md +20 -0
- package/dist/bundle/index.d.ts +1 -0
- package/dist/bundle/index.d.ts.map +1 -1
- package/dist/bundle/index.js.map +1 -1
- package/dist/bundle/plugins/browser.js.map +1 -1
- package/dist/bundle/plugins/node.d.ts +1 -1
- package/dist/bundle/plugins/node.js +1 -1
- package/dist/bundle/plugins/node.js.map +1 -1
- package/dist/dereference/index.d.ts.map +1 -1
- package/dist/dereference/index.js.map +2 -2
- package/dist/diff/index.d.ts +1 -1
- package/dist/diff/index.d.ts.map +1 -1
- package/dist/diff/index.js +1 -1
- package/dist/diff/index.js.map +2 -2
- package/dist/helpers/escape-json-pointer.d.ts +1 -1
- package/dist/helpers/escape-json-pointer.js.map +1 -1
- package/dist/magic-proxy/index.d.ts.map +1 -1
- package/dist/magic-proxy/index.js.map +2 -2
- package/dist/magic-proxy/proxy.d.ts +0 -1
- package/dist/magic-proxy/proxy.d.ts.map +1 -1
- package/dist/magic-proxy/proxy.js +1 -2
- package/dist/magic-proxy/proxy.js.map +2 -2
- package/package.json +12 -13
- package/.turbo/turbo-build.log +0 -10
- package/esbuild.ts +0 -15
- package/src/bundle/bundle.test.ts +0 -2917
- package/src/bundle/bundle.ts +0 -916
- package/src/bundle/create-limiter.test.ts +0 -28
- package/src/bundle/create-limiter.ts +0 -52
- package/src/bundle/index.ts +0 -3
- package/src/bundle/plugins/browser.ts +0 -4
- package/src/bundle/plugins/fetch-urls/index.test.ts +0 -141
- package/src/bundle/plugins/fetch-urls/index.ts +0 -105
- package/src/bundle/plugins/node.ts +0 -5
- package/src/bundle/plugins/parse-json/index.test.ts +0 -24
- package/src/bundle/plugins/parse-json/index.ts +0 -32
- package/src/bundle/plugins/parse-yaml/index.test.ts +0 -26
- package/src/bundle/plugins/parse-yaml/index.ts +0 -34
- package/src/bundle/plugins/read-files/index.test.ts +0 -36
- package/src/bundle/plugins/read-files/index.ts +0 -58
- package/src/bundle/value-generator.test.ts +0 -165
- package/src/bundle/value-generator.ts +0 -143
- package/src/dereference/dereference.test.ts +0 -142
- package/src/dereference/dereference.ts +0 -84
- package/src/dereference/index.ts +0 -2
- package/src/diff/apply.test.ts +0 -262
- package/src/diff/apply.ts +0 -83
- package/src/diff/diff.test.ts +0 -328
- package/src/diff/diff.ts +0 -93
- package/src/diff/index.test.ts +0 -150
- package/src/diff/index.ts +0 -5
- package/src/diff/merge.test.ts +0 -1109
- package/src/diff/merge.ts +0 -136
- package/src/diff/trie.test.ts +0 -30
- package/src/diff/trie.ts +0 -113
- package/src/diff/utils.test.ts +0 -169
- package/src/diff/utils.ts +0 -111
- package/src/helpers/convert-to-local-ref.test.ts +0 -211
- package/src/helpers/convert-to-local-ref.ts +0 -43
- package/src/helpers/escape-json-pointer.test.ts +0 -13
- package/src/helpers/escape-json-pointer.ts +0 -8
- package/src/helpers/get-schemas.test.ts +0 -356
- package/src/helpers/get-schemas.ts +0 -80
- package/src/helpers/get-segments-from-path.test.ts +0 -17
- package/src/helpers/get-segments-from-path.ts +0 -17
- package/src/helpers/get-value-by-path.test.ts +0 -338
- package/src/helpers/get-value-by-path.ts +0 -44
- package/src/helpers/is-json-object.ts +0 -31
- package/src/helpers/is-object.test.ts +0 -27
- package/src/helpers/is-object.ts +0 -4
- package/src/helpers/is-yaml.ts +0 -18
- package/src/helpers/json-path-utils.test.ts +0 -57
- package/src/helpers/json-path-utils.ts +0 -50
- package/src/helpers/normalize.test.ts +0 -92
- package/src/helpers/normalize.ts +0 -35
- package/src/helpers/unescape-json-pointer.test.ts +0 -23
- package/src/helpers/unescape-json-pointer.ts +0 -9
- package/src/magic-proxy/index.ts +0 -2
- package/src/magic-proxy/proxy.test.ts +0 -1987
- package/src/magic-proxy/proxy.ts +0 -323
- package/src/types.ts +0 -1
- package/tsconfig.build.json +0 -12
- package/tsconfig.json +0 -16
- package/vite.config.ts +0 -8
package/src/diff/apply.test.ts
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
import { apply, InvalidChangesDetectedError } from '@/diff/apply'
|
|
2
|
-
import { describe, expect, test } from 'vitest'
|
|
3
|
-
|
|
4
|
-
const deepClone = <T extends object>(obj: T) => JSON.parse(JSON.stringify(obj)) as T
|
|
5
|
-
|
|
6
|
-
describe('apply', () => {
|
|
7
|
-
describe('should apply `add` operations', () => {
|
|
8
|
-
test('should apply `add` operation correctly', () => {
|
|
9
|
-
const doc = {
|
|
10
|
-
name: 'John',
|
|
11
|
-
age: 25,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const docCopy = deepClone(doc)
|
|
15
|
-
const location = { city: 'New York', street: '5th Avenue' }
|
|
16
|
-
|
|
17
|
-
expect(apply(doc, [{ path: ['location'], changes: location, type: 'add' }])).toEqual({
|
|
18
|
-
...docCopy,
|
|
19
|
-
location,
|
|
20
|
-
})
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test('should apply `add` operation on deeply nested objects correctly', () => {
|
|
24
|
-
const doc = {
|
|
25
|
-
name: 'John',
|
|
26
|
-
age: 25,
|
|
27
|
-
location: {
|
|
28
|
-
city: 'New York',
|
|
29
|
-
street: '5th Avenue',
|
|
30
|
-
},
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const docCopy = deepClone(doc)
|
|
34
|
-
const coordinates = { lat: 40.7128, long: 74.006 }
|
|
35
|
-
|
|
36
|
-
expect(
|
|
37
|
-
apply(doc, [
|
|
38
|
-
{
|
|
39
|
-
path: ['location', 'coordinates'],
|
|
40
|
-
changes: coordinates,
|
|
41
|
-
type: 'add',
|
|
42
|
-
},
|
|
43
|
-
]),
|
|
44
|
-
).toEqual({
|
|
45
|
-
...docCopy,
|
|
46
|
-
location: {
|
|
47
|
-
...docCopy.location,
|
|
48
|
-
coordinates,
|
|
49
|
-
},
|
|
50
|
-
})
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
describe('should apply `update` operation', () => {
|
|
55
|
-
test('should apply `update` operation correctly', () => {
|
|
56
|
-
const doc = {
|
|
57
|
-
name: 'John',
|
|
58
|
-
age: 25,
|
|
59
|
-
location: {
|
|
60
|
-
city: 'New York',
|
|
61
|
-
street: '5th Avenue',
|
|
62
|
-
},
|
|
63
|
-
}
|
|
64
|
-
const docCopy = deepClone(doc)
|
|
65
|
-
const updatedAge = 26
|
|
66
|
-
|
|
67
|
-
expect(apply(doc, [{ path: ['age'], changes: updatedAge, type: 'update' }])).toEqual({
|
|
68
|
-
...docCopy,
|
|
69
|
-
age: updatedAge,
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
test('should apply `update` operation correctly on nested objects', () => {
|
|
74
|
-
const doc = {
|
|
75
|
-
name: 'John',
|
|
76
|
-
age: 25,
|
|
77
|
-
location: {
|
|
78
|
-
city: 'New York',
|
|
79
|
-
street: '5th Avenue',
|
|
80
|
-
},
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const docCopy = deepClone(doc)
|
|
84
|
-
const updatedCity = 'Boston'
|
|
85
|
-
|
|
86
|
-
expect(apply(doc, [{ path: ['location', 'city'], changes: updatedCity, type: 'update' }])).toEqual({
|
|
87
|
-
...docCopy,
|
|
88
|
-
location: { ...docCopy.location, city: updatedCity },
|
|
89
|
-
})
|
|
90
|
-
})
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
describe('should apply `delete` operation', () => {
|
|
94
|
-
test('should apply `delete` operation correctly', () => {
|
|
95
|
-
const doc2 = {
|
|
96
|
-
name: 'John',
|
|
97
|
-
age: 25,
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const doc1 = {
|
|
101
|
-
...doc2,
|
|
102
|
-
location: {
|
|
103
|
-
city: 'New York',
|
|
104
|
-
street: '5th Avenue',
|
|
105
|
-
},
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
expect(apply(doc1, [{ path: ['location'], changes: doc1.location, type: 'delete' }])).toEqual(doc2)
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
test('should apply `delete` operation correctly on nested objects', () => {
|
|
112
|
-
const doc2 = {
|
|
113
|
-
name: 'John',
|
|
114
|
-
age: 25,
|
|
115
|
-
location: {
|
|
116
|
-
city: 'New York',
|
|
117
|
-
},
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const doc1 = {
|
|
121
|
-
...doc2,
|
|
122
|
-
location: {
|
|
123
|
-
...doc2.location,
|
|
124
|
-
street: '5th Avenue',
|
|
125
|
-
},
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
expect(
|
|
129
|
-
apply(doc1, [
|
|
130
|
-
{
|
|
131
|
-
path: ['location', 'street'],
|
|
132
|
-
changes: doc1.location.street,
|
|
133
|
-
type: 'delete',
|
|
134
|
-
},
|
|
135
|
-
]),
|
|
136
|
-
).toEqual(doc2)
|
|
137
|
-
})
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
describe('should throw on incorrect diff', () => {
|
|
141
|
-
test('wrong nested key', () => {
|
|
142
|
-
const doc = {
|
|
143
|
-
name: 'John',
|
|
144
|
-
age: 25,
|
|
145
|
-
location: {
|
|
146
|
-
city: 'New York',
|
|
147
|
-
street: '5th Avenue',
|
|
148
|
-
},
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
expect(() =>
|
|
152
|
-
apply(doc, [
|
|
153
|
-
{
|
|
154
|
-
path: ['location', 'city', 'something'],
|
|
155
|
-
changes: { test: 1 },
|
|
156
|
-
type: 'add',
|
|
157
|
-
},
|
|
158
|
-
]),
|
|
159
|
-
).toThrow(InvalidChangesDetectedError)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
test('wrong non existing path', () => {
|
|
163
|
-
const doc = {
|
|
164
|
-
name: 'John',
|
|
165
|
-
age: 25,
|
|
166
|
-
location: {
|
|
167
|
-
city: 'New York',
|
|
168
|
-
street: '5th Avenue',
|
|
169
|
-
},
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
expect(() =>
|
|
173
|
-
apply(doc, [
|
|
174
|
-
{
|
|
175
|
-
path: ['location', 'coordinates', 'lang'],
|
|
176
|
-
changes: 41.25,
|
|
177
|
-
type: 'add',
|
|
178
|
-
},
|
|
179
|
-
]),
|
|
180
|
-
).toThrow(InvalidChangesDetectedError)
|
|
181
|
-
})
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
describe('should correctly handle arrays', () => {
|
|
185
|
-
test('should correctly apply `add` changes on an array', () => {
|
|
186
|
-
const doc = {
|
|
187
|
-
name: 'John',
|
|
188
|
-
age: 25,
|
|
189
|
-
location: {
|
|
190
|
-
city: 'New York',
|
|
191
|
-
street: '5th Avenue',
|
|
192
|
-
},
|
|
193
|
-
hobbies: ['swimming'],
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const docCopy = deepClone(doc)
|
|
197
|
-
const newHobby = 'coding'
|
|
198
|
-
|
|
199
|
-
expect(
|
|
200
|
-
apply(doc, [
|
|
201
|
-
{
|
|
202
|
-
path: ['hobbies', '1'],
|
|
203
|
-
changes: newHobby,
|
|
204
|
-
type: 'add',
|
|
205
|
-
},
|
|
206
|
-
]),
|
|
207
|
-
).toEqual({ ...docCopy, hobbies: [...docCopy.hobbies, newHobby] })
|
|
208
|
-
})
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
test('should correctly apply `update` changes on an array', () => {
|
|
212
|
-
const doc = {
|
|
213
|
-
name: 'John',
|
|
214
|
-
age: 25,
|
|
215
|
-
location: {
|
|
216
|
-
city: 'New York',
|
|
217
|
-
street: '5th Avenue',
|
|
218
|
-
},
|
|
219
|
-
hobbies: ['swimming', 'fish', 'coding'],
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const docCopy = deepClone(doc)
|
|
223
|
-
const updatedHobby = 'running'
|
|
224
|
-
docCopy.hobbies[1] = updatedHobby
|
|
225
|
-
|
|
226
|
-
expect(
|
|
227
|
-
apply(doc, [
|
|
228
|
-
{
|
|
229
|
-
path: ['hobbies', '1'],
|
|
230
|
-
changes: updatedHobby,
|
|
231
|
-
type: 'update',
|
|
232
|
-
},
|
|
233
|
-
]),
|
|
234
|
-
).toEqual(docCopy)
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
test('should correctly apply `delete` changes on an array', () => {
|
|
238
|
-
const doc = {
|
|
239
|
-
name: 'John',
|
|
240
|
-
age: 25,
|
|
241
|
-
location: {
|
|
242
|
-
city: 'New York',
|
|
243
|
-
street: '5th Avenue',
|
|
244
|
-
},
|
|
245
|
-
hobbies: ['swimming', 'fish', 'coding'],
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const docCopy = deepClone(doc)
|
|
249
|
-
// Perform the delete operation
|
|
250
|
-
docCopy.hobbies.splice(1, 1)
|
|
251
|
-
|
|
252
|
-
expect(
|
|
253
|
-
apply(doc, [
|
|
254
|
-
{
|
|
255
|
-
path: ['hobbies', '1'],
|
|
256
|
-
changes: doc.hobbies[1],
|
|
257
|
-
type: 'delete',
|
|
258
|
-
},
|
|
259
|
-
]),
|
|
260
|
-
).toEqual(docCopy)
|
|
261
|
-
})
|
|
262
|
-
})
|
package/src/diff/apply.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import type { Difference } from '@/diff/diff'
|
|
2
|
-
|
|
3
|
-
export class InvalidChangesDetectedError extends Error {
|
|
4
|
-
constructor(message: string) {
|
|
5
|
-
super(message)
|
|
6
|
-
this.name = 'InvalidChangesDetectedError'
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Applies a set of differences to a document object.
|
|
12
|
-
* The function traverses the document structure following the paths specified in the differences
|
|
13
|
-
* and applies the corresponding changes (add, update, or delete) at each location.
|
|
14
|
-
*
|
|
15
|
-
* @param document - The original document to apply changes to
|
|
16
|
-
* @param diff - Array of differences to apply, each containing a path and change type
|
|
17
|
-
* @returns The modified document with all changes applied
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* const original = {
|
|
21
|
-
* paths: {
|
|
22
|
-
* '/users': {
|
|
23
|
-
* get: { responses: { '200': { description: 'OK' } } }
|
|
24
|
-
* }
|
|
25
|
-
* }
|
|
26
|
-
* }
|
|
27
|
-
*
|
|
28
|
-
* const changes = [
|
|
29
|
-
* {
|
|
30
|
-
* path: ['paths', '/users', 'get', 'responses', '200', 'content'],
|
|
31
|
-
* type: 'add',
|
|
32
|
-
* changes: { 'application/json': { schema: { type: 'object' } } }
|
|
33
|
-
* }
|
|
34
|
-
* ]
|
|
35
|
-
*
|
|
36
|
-
* const updated = apply(original, changes)
|
|
37
|
-
* // Result: original document with content added to the 200 response
|
|
38
|
-
*/
|
|
39
|
-
export const apply = <T extends Record<string, unknown>>(
|
|
40
|
-
document: Record<string, unknown>,
|
|
41
|
-
diff: Difference<T>[],
|
|
42
|
-
): T => {
|
|
43
|
-
// Traverse the object and apply the change
|
|
44
|
-
const applyChange = (current: any, path: string[], d: Difference<T>, depth = 0) => {
|
|
45
|
-
if (path[depth] === undefined) {
|
|
46
|
-
throw new InvalidChangesDetectedError(
|
|
47
|
-
`Process aborted. Path ${path.join('.')} at depth ${depth} is undefined, check diff object`,
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// We reach where we want to be, now we can apply changes
|
|
52
|
-
if (depth >= path.length - 1) {
|
|
53
|
-
if (d.type === 'add' || d.type === 'update') {
|
|
54
|
-
current[path[depth]] = d.changes
|
|
55
|
-
} else {
|
|
56
|
-
// For arrays we don't use delete operator since it will leave blank spots and not actually remove the element
|
|
57
|
-
if (Array.isArray(current)) {
|
|
58
|
-
current.splice(Number.parseInt(path[depth]), 1)
|
|
59
|
-
} else {
|
|
60
|
-
delete current[path[depth]]
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Throw an error
|
|
67
|
-
// This scenario should not happen
|
|
68
|
-
// 1- if we are adding a new entry, the diff should only give us the higher level diff
|
|
69
|
-
// 2- if we are updating/deleting an entry, the path to that entry should exists
|
|
70
|
-
if (current[path[depth]] === undefined || typeof current[path[depth]] !== 'object') {
|
|
71
|
-
throw new InvalidChangesDetectedError('Process aborted, check diff object')
|
|
72
|
-
}
|
|
73
|
-
applyChange(current[path[depth]], path, d, depth + 1)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
for (const d of diff) {
|
|
77
|
-
applyChange(document, d.path, d)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// It is safe to cast here because this function mutates the input document
|
|
81
|
-
// to match the target type T as described by the diff changeset.
|
|
82
|
-
return document as T
|
|
83
|
-
}
|
package/src/diff/diff.test.ts
DELETED
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
import { diff } from '@/diff'
|
|
2
|
-
import { describe, expect, test } from 'vitest'
|
|
3
|
-
|
|
4
|
-
describe('diff', () => {
|
|
5
|
-
describe('Should correctly detect `add` type diff', () => {
|
|
6
|
-
test('should correctly get added properties between two json objects', () => {
|
|
7
|
-
const doc1 = {
|
|
8
|
-
name: 'John',
|
|
9
|
-
age: 25,
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const doc2 = {
|
|
13
|
-
...doc1,
|
|
14
|
-
address: {
|
|
15
|
-
city: 'New York',
|
|
16
|
-
street: '5th Avenue',
|
|
17
|
-
},
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
expect(diff(doc1, doc2)).toEqual([{ path: ['address'], changes: doc2.address, type: 'add' }])
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test('should correctly get added properties in nested objects between two json objects', () => {
|
|
24
|
-
const doc1 = {
|
|
25
|
-
name: 'John',
|
|
26
|
-
age: 25,
|
|
27
|
-
address: {
|
|
28
|
-
city: 'New York',
|
|
29
|
-
street: '5th Avenue',
|
|
30
|
-
},
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const doc2 = {
|
|
34
|
-
...doc1,
|
|
35
|
-
address: {
|
|
36
|
-
...doc1.address,
|
|
37
|
-
coordinates: {
|
|
38
|
-
lat: 40.7128,
|
|
39
|
-
long: 74.006,
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
expect(diff(doc1, doc2)).toEqual([
|
|
45
|
-
{
|
|
46
|
-
path: ['address', 'coordinates'],
|
|
47
|
-
changes: doc2.address.coordinates,
|
|
48
|
-
type: 'add',
|
|
49
|
-
},
|
|
50
|
-
])
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
test('should correctly get added properties in deeply nested objects between two json objects', () => {
|
|
54
|
-
const doc1 = {
|
|
55
|
-
name: 'John',
|
|
56
|
-
age: 25,
|
|
57
|
-
address: {
|
|
58
|
-
city: 'New York',
|
|
59
|
-
street: '5th Avenue',
|
|
60
|
-
coordinates: {
|
|
61
|
-
lat: 40.7128,
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const doc2 = {
|
|
67
|
-
...doc1,
|
|
68
|
-
address: {
|
|
69
|
-
...doc1.address,
|
|
70
|
-
coordinates: {
|
|
71
|
-
...doc1.address.coordinates,
|
|
72
|
-
long: 74.006,
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
expect(diff(doc1, doc2)).toEqual([
|
|
78
|
-
{
|
|
79
|
-
path: ['address', 'coordinates', 'long'],
|
|
80
|
-
changes: doc2.address.coordinates.long,
|
|
81
|
-
type: 'add',
|
|
82
|
-
},
|
|
83
|
-
])
|
|
84
|
-
})
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
describe('Should correctly detect `update` type diff', () => {
|
|
88
|
-
test('should correctly get updates on primitives between two objects', () => {
|
|
89
|
-
const doc1 = {
|
|
90
|
-
name: 'John',
|
|
91
|
-
age: 25,
|
|
92
|
-
address: {
|
|
93
|
-
city: 'New York',
|
|
94
|
-
street: '5th Avenue',
|
|
95
|
-
},
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const doc2: typeof doc1 = {
|
|
99
|
-
...doc1,
|
|
100
|
-
age: 26,
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
expect(diff(doc1, doc2)).toEqual([{ path: ['age'], changes: doc2.age, type: 'update' }])
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
test('should correctly get updates on nested objects between two objects', () => {
|
|
107
|
-
const doc1 = {
|
|
108
|
-
name: 'John',
|
|
109
|
-
age: 25,
|
|
110
|
-
address: {
|
|
111
|
-
city: 'New York',
|
|
112
|
-
street: '5th Avenue',
|
|
113
|
-
},
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const doc2: typeof doc1 = {
|
|
117
|
-
...doc1,
|
|
118
|
-
address: {
|
|
119
|
-
...doc1.address,
|
|
120
|
-
city: 'Los Angeles',
|
|
121
|
-
},
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
expect(diff(doc1, doc2)).toEqual([
|
|
125
|
-
{
|
|
126
|
-
path: ['address', 'city'],
|
|
127
|
-
changes: doc2.address.city,
|
|
128
|
-
type: 'update',
|
|
129
|
-
},
|
|
130
|
-
])
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
test('should correctly get updates when the type is different', () => {
|
|
134
|
-
const doc1 = {
|
|
135
|
-
name: 'John',
|
|
136
|
-
age: 25,
|
|
137
|
-
address: {
|
|
138
|
-
city: 'New York',
|
|
139
|
-
street: '5th Avenue',
|
|
140
|
-
},
|
|
141
|
-
isStudent: 1,
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const doc2 = {
|
|
145
|
-
...doc1,
|
|
146
|
-
isStudent: true,
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
expect(diff(doc1, doc2)).toEqual([{ path: ['isStudent'], changes: doc2.isStudent, type: 'update' }])
|
|
150
|
-
})
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
describe('Should correctly detect `delete` type diff', () => {
|
|
154
|
-
test('should correctly get removed properties between two objects', () => {
|
|
155
|
-
const doc2 = {
|
|
156
|
-
name: 'John',
|
|
157
|
-
age: 25,
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const doc1 = {
|
|
161
|
-
...doc2,
|
|
162
|
-
address: {
|
|
163
|
-
city: 'New York',
|
|
164
|
-
street: '5th Avenue',
|
|
165
|
-
},
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
expect(diff(doc1, doc2)).toEqual([{ path: ['address'], changes: doc1.address, type: 'delete' }])
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
test('should correctly get removed properties on deeply nested objects', () => {
|
|
172
|
-
const doc2 = {
|
|
173
|
-
name: 'John',
|
|
174
|
-
age: 25,
|
|
175
|
-
address: {
|
|
176
|
-
city: 'New York',
|
|
177
|
-
street: '5th Avenue',
|
|
178
|
-
},
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const doc1 = {
|
|
182
|
-
...doc2,
|
|
183
|
-
address: {
|
|
184
|
-
...doc2.address,
|
|
185
|
-
coordinates: {
|
|
186
|
-
lat: 40.7128,
|
|
187
|
-
long: 74.006,
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
expect(diff(doc1, doc2)).toEqual([
|
|
193
|
-
{
|
|
194
|
-
path: ['address', 'coordinates'],
|
|
195
|
-
changes: doc1.address.coordinates,
|
|
196
|
-
type: 'delete',
|
|
197
|
-
},
|
|
198
|
-
])
|
|
199
|
-
})
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
describe('Should correctly detect changes on arrays', () => {
|
|
203
|
-
test('detect adding elements on arrays of primitives', () => {
|
|
204
|
-
const doc1 = {
|
|
205
|
-
name: 'John',
|
|
206
|
-
age: 25,
|
|
207
|
-
hobbies: ['reading', 'running'],
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const doc2 = {
|
|
211
|
-
...doc1,
|
|
212
|
-
hobbies: ['reading', 'running', 'swimming'],
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
expect(diff(doc1, doc2)).toEqual([{ path: ['hobbies', '2'], changes: doc2.hobbies[2], type: 'add' }])
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
test('detect adding elements on arrays of objects', () => {
|
|
219
|
-
const doc1 = {
|
|
220
|
-
name: 'John',
|
|
221
|
-
age: 25,
|
|
222
|
-
hobbies: [
|
|
223
|
-
{ name: 'reading', duration: 2 },
|
|
224
|
-
{ name: 'running', duration: 1 },
|
|
225
|
-
],
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const doc2 = {
|
|
229
|
-
...doc1,
|
|
230
|
-
hobbies: [...doc1.hobbies, { name: 'swimming', duration: 3 }],
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
expect(diff(doc1, doc2)).toEqual([{ path: ['hobbies', '2'], changes: doc2.hobbies[2], type: 'add' }])
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
test('detects updates on objects on array of objects', () => {
|
|
237
|
-
const doc1 = {
|
|
238
|
-
name: 'John',
|
|
239
|
-
age: 25,
|
|
240
|
-
hobbies: [
|
|
241
|
-
{ name: 'reading', duration: 2 },
|
|
242
|
-
{ name: 'running', duration: 1 },
|
|
243
|
-
],
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const doc2 = {
|
|
247
|
-
...doc1,
|
|
248
|
-
hobbies: [doc1.hobbies[0], { name: 'swimming', duration: 3 }],
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
expect(diff(doc1, doc2)).toEqual([
|
|
252
|
-
{
|
|
253
|
-
path: ['hobbies', '1', 'name'],
|
|
254
|
-
changes: doc2.hobbies[1]?.name,
|
|
255
|
-
type: 'update',
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
path: ['hobbies', '1', 'duration'],
|
|
259
|
-
changes: doc2.hobbies[1]?.duration,
|
|
260
|
-
type: 'update',
|
|
261
|
-
},
|
|
262
|
-
])
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
test('detects delete operations on array of objects', () => {
|
|
266
|
-
const doc1 = {
|
|
267
|
-
name: 'John',
|
|
268
|
-
age: 25,
|
|
269
|
-
hobbies: [
|
|
270
|
-
{ name: 'reading', duration: 2 },
|
|
271
|
-
{ name: 'running', duration: 1 },
|
|
272
|
-
],
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const doc2 = {
|
|
276
|
-
...doc1,
|
|
277
|
-
hobbies: [doc1.hobbies[0]],
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
expect(diff(doc1, doc2)).toEqual([{ path: ['hobbies', '1'], changes: doc1.hobbies[1], type: 'delete' }])
|
|
281
|
-
})
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
test('Should correctly detect multiple changes', () => {
|
|
285
|
-
const doc1 = {
|
|
286
|
-
name: 'John',
|
|
287
|
-
age: 25,
|
|
288
|
-
address: {
|
|
289
|
-
city: 'New York',
|
|
290
|
-
street: '5th Avenue',
|
|
291
|
-
},
|
|
292
|
-
hobbies: [
|
|
293
|
-
{ name: 'reading', duration: 2 },
|
|
294
|
-
{ name: 'running', duration: 1 },
|
|
295
|
-
],
|
|
296
|
-
isStudent: true,
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const doc2 = {
|
|
300
|
-
...(doc1 as Partial<typeof doc1>), // Partial is needed to remove the key student key from doc2
|
|
301
|
-
age: 26,
|
|
302
|
-
address: {
|
|
303
|
-
...doc1.address,
|
|
304
|
-
city: 'Los Angeles',
|
|
305
|
-
},
|
|
306
|
-
hobbies: [doc1.hobbies[0], { name: 'swimming', duration: 3 }, { name: 'running', duration: 2 }],
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
delete doc2.isStudent
|
|
310
|
-
|
|
311
|
-
expect(diff(doc1, doc2)).toEqual([
|
|
312
|
-
{ path: ['age'], changes: doc2.age, type: 'update' },
|
|
313
|
-
{ path: ['address', 'city'], changes: doc2.address.city, type: 'update' },
|
|
314
|
-
{
|
|
315
|
-
path: ['hobbies', '1', 'name'],
|
|
316
|
-
changes: doc2.hobbies[1]?.name,
|
|
317
|
-
type: 'update',
|
|
318
|
-
},
|
|
319
|
-
{
|
|
320
|
-
path: ['hobbies', '1', 'duration'],
|
|
321
|
-
changes: doc2.hobbies[1]?.duration,
|
|
322
|
-
type: 'update',
|
|
323
|
-
},
|
|
324
|
-
{ path: ['hobbies', '2'], changes: doc2.hobbies[2], type: 'add' },
|
|
325
|
-
{ path: ['isStudent'], changes: doc1.isStudent, type: 'delete' },
|
|
326
|
-
])
|
|
327
|
-
})
|
|
328
|
-
})
|