@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
|
@@ -1,1987 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { createMagicProxy, getRaw } from './proxy'
|
|
4
|
-
|
|
5
|
-
describe('createMagicProxy', () => {
|
|
6
|
-
describe('get', () => {
|
|
7
|
-
it('should correctly proxy internal refs', () => {
|
|
8
|
-
const input = {
|
|
9
|
-
a: 'hello',
|
|
10
|
-
b: {
|
|
11
|
-
'$ref': '#/a',
|
|
12
|
-
},
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const result = createMagicProxy(input)
|
|
16
|
-
expect(result.b).toEqual({ $ref: '#/a', '$ref-value': 'hello' })
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
it('should correctly proxy deep nested refs', () => {
|
|
20
|
-
const input = {
|
|
21
|
-
a: {
|
|
22
|
-
b: {
|
|
23
|
-
c: {
|
|
24
|
-
d: {
|
|
25
|
-
prop: 'hello',
|
|
26
|
-
},
|
|
27
|
-
e: {
|
|
28
|
-
'$ref': '#/a/b/c/d',
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const result = createMagicProxy(input) as any
|
|
36
|
-
expect(result.a.b.c.e['$ref-value'].prop).toBe('hello')
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('should correctly proxy multi refs', () => {
|
|
40
|
-
const input = {
|
|
41
|
-
a: {
|
|
42
|
-
b: {
|
|
43
|
-
c: {
|
|
44
|
-
prop: 'hello',
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
e: {
|
|
49
|
-
f: {
|
|
50
|
-
$ref: '#/a/b/c/prop',
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
d: {
|
|
54
|
-
$ref: '#/e/f',
|
|
55
|
-
},
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const result = createMagicProxy(input)
|
|
59
|
-
|
|
60
|
-
expect(result.d).toEqual({
|
|
61
|
-
$ref: '#/e/f',
|
|
62
|
-
'$ref-value': {
|
|
63
|
-
$ref: '#/a/b/c/prop',
|
|
64
|
-
'$ref-value': 'hello',
|
|
65
|
-
},
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('should preserve information about the ref when the ref is resolved', () => {
|
|
70
|
-
const input = {
|
|
71
|
-
a: {
|
|
72
|
-
b: {
|
|
73
|
-
c: {
|
|
74
|
-
d: {
|
|
75
|
-
prop: 'hello',
|
|
76
|
-
},
|
|
77
|
-
e: {
|
|
78
|
-
'$ref': '#/a/b/c/d',
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const result = createMagicProxy(input)
|
|
86
|
-
expect(result.a.b.c.e).toEqual({
|
|
87
|
-
'$ref': '#/a/b/c/d',
|
|
88
|
-
'$ref-value': {
|
|
89
|
-
prop: 'hello',
|
|
90
|
-
},
|
|
91
|
-
})
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
it('should resolve the references inside an array', () => {
|
|
95
|
-
const input = {
|
|
96
|
-
$defs: {
|
|
97
|
-
a: {
|
|
98
|
-
b: {
|
|
99
|
-
prop: 'hello',
|
|
100
|
-
},
|
|
101
|
-
c: {
|
|
102
|
-
someOtherProp: 'world',
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
a: {
|
|
107
|
-
b: [
|
|
108
|
-
{
|
|
109
|
-
$ref: '#/$defs/a/b',
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
$ref: '#/$defs/a/c',
|
|
113
|
-
},
|
|
114
|
-
],
|
|
115
|
-
},
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const result = createMagicProxy(input)
|
|
119
|
-
expect(JSON.stringify(result.a)).toEqual(
|
|
120
|
-
JSON.stringify({
|
|
121
|
-
'b': [
|
|
122
|
-
{ '$ref': '#/$defs/a/b', '$ref-value': { 'prop': 'hello' } },
|
|
123
|
-
{ '$ref': '#/$defs/a/c', '$ref-value': { 'someOtherProp': 'world' } },
|
|
124
|
-
],
|
|
125
|
-
}),
|
|
126
|
-
)
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
it('should return undefined if the ref is an external ref', () => {
|
|
130
|
-
const input = {
|
|
131
|
-
a: 'hello',
|
|
132
|
-
b: {
|
|
133
|
-
$ref: 'https://example.com/document.json/#',
|
|
134
|
-
},
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const result = createMagicProxy(input)
|
|
138
|
-
expect(result).toEqual({
|
|
139
|
-
a: 'hello',
|
|
140
|
-
b: {
|
|
141
|
-
$ref: 'https://example.com/document.json/#',
|
|
142
|
-
'$ref-value': undefined,
|
|
143
|
-
},
|
|
144
|
-
})
|
|
145
|
-
})
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
describe('set', () => {
|
|
149
|
-
it('sets properties on the target object', () => {
|
|
150
|
-
const input: any = {
|
|
151
|
-
a: 'hello',
|
|
152
|
-
b: {
|
|
153
|
-
$ref: '#/a',
|
|
154
|
-
},
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const result = createMagicProxy(input)
|
|
158
|
-
result.c = 'world'
|
|
159
|
-
|
|
160
|
-
expect(result.c).toBe('world')
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
it('sets properties on nested objects', () => {
|
|
164
|
-
const input: any = {
|
|
165
|
-
a: {
|
|
166
|
-
b: {
|
|
167
|
-
c: 'hello',
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const result = createMagicProxy(input)
|
|
173
|
-
result.a.b.d = 'world'
|
|
174
|
-
|
|
175
|
-
expect(result.a.b.d).toBe('world')
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
it('sets properties on objects with refs', () => {
|
|
179
|
-
const input: any = {
|
|
180
|
-
a: {
|
|
181
|
-
b: {
|
|
182
|
-
c: 'hello',
|
|
183
|
-
},
|
|
184
|
-
},
|
|
185
|
-
d: {
|
|
186
|
-
$ref: '#/a/b',
|
|
187
|
-
},
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const result = createMagicProxy(input)
|
|
191
|
-
result.d.e = 'world'
|
|
192
|
-
|
|
193
|
-
expect(result.d.e).toBe('world')
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
it('sets properties on arrays', () => {
|
|
197
|
-
const input = {
|
|
198
|
-
items: [{ name: 'item1' }, { name: 'item2' }],
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const result = createMagicProxy(input)
|
|
202
|
-
result.items[2] = { name: 'item3' }
|
|
203
|
-
|
|
204
|
-
expect(result.items[2].name).toBe('item3')
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
it('sets properties on array elements with refs', () => {
|
|
208
|
-
const input: any = {
|
|
209
|
-
$defs: {
|
|
210
|
-
item: { name: 'default' },
|
|
211
|
-
},
|
|
212
|
-
items: [{ $ref: '#/$defs/item' }],
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const result = createMagicProxy(input)
|
|
216
|
-
result.items[0].id = 123
|
|
217
|
-
|
|
218
|
-
expect(input.items[0].id).toBe(123)
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
it('overwrites existing properties', () => {
|
|
222
|
-
const input = {
|
|
223
|
-
a: 'hello',
|
|
224
|
-
b: {
|
|
225
|
-
c: 'world',
|
|
226
|
-
},
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const result = createMagicProxy(input)
|
|
230
|
-
result.a = 'updated'
|
|
231
|
-
result.b.c = 'updated'
|
|
232
|
-
|
|
233
|
-
expect(result.a).toBe('updated')
|
|
234
|
-
expect(result.b.c).toBe('updated')
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
it('sets properties on the root object', () => {
|
|
238
|
-
const input: any = {
|
|
239
|
-
a: 'hello',
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const result = createMagicProxy(input)
|
|
243
|
-
result.rootProperty = 'root value'
|
|
244
|
-
|
|
245
|
-
expect(result.rootProperty).toBe('root value')
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
it('sets properties that are accessed via ref-value', () => {
|
|
249
|
-
const input: any = {
|
|
250
|
-
a: {
|
|
251
|
-
b: {
|
|
252
|
-
c: 'hello',
|
|
253
|
-
},
|
|
254
|
-
},
|
|
255
|
-
d: {
|
|
256
|
-
$ref: '#/a/b',
|
|
257
|
-
},
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const result = createMagicProxy(input)
|
|
261
|
-
const refValue = result.d['$ref-value']
|
|
262
|
-
refValue.newProp = 'new value'
|
|
263
|
-
|
|
264
|
-
expect(refValue.newProp).toBe('new value')
|
|
265
|
-
expect(input.a.b.newProp).toBe('new value')
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
it('sets properties on deeply nested refs', () => {
|
|
269
|
-
const input: any = {
|
|
270
|
-
a: {
|
|
271
|
-
b: {
|
|
272
|
-
c: {
|
|
273
|
-
d: {
|
|
274
|
-
e: 'hello',
|
|
275
|
-
},
|
|
276
|
-
},
|
|
277
|
-
},
|
|
278
|
-
},
|
|
279
|
-
f: {
|
|
280
|
-
$ref: '#/a/b/c/d',
|
|
281
|
-
},
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const result = createMagicProxy(input)
|
|
285
|
-
result.f['$ref-value'].g = 'world'
|
|
286
|
-
|
|
287
|
-
expect(result.f['$ref-value'].g).toBe('world')
|
|
288
|
-
expect(input.a.b.c.d.g).toBe('world')
|
|
289
|
-
})
|
|
290
|
-
|
|
291
|
-
it('correctly writes on the referenced value', () => {
|
|
292
|
-
const input = {
|
|
293
|
-
a: {
|
|
294
|
-
b: {
|
|
295
|
-
hello: 'hi',
|
|
296
|
-
},
|
|
297
|
-
},
|
|
298
|
-
c: {
|
|
299
|
-
$ref: '#/a/b',
|
|
300
|
-
},
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
const proxied = createMagicProxy(input)
|
|
304
|
-
|
|
305
|
-
proxied.c['$ref-value'].hello = 'new value'
|
|
306
|
-
|
|
307
|
-
expect(input).toEqual({
|
|
308
|
-
a: {
|
|
309
|
-
b: {
|
|
310
|
-
hello: 'new value',
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
c: {
|
|
314
|
-
$ref: '#/a/b',
|
|
315
|
-
},
|
|
316
|
-
})
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
it('sets properties on the referenced value #1', () => {
|
|
320
|
-
const input = {
|
|
321
|
-
a: {
|
|
322
|
-
$ref: '#/b',
|
|
323
|
-
},
|
|
324
|
-
b: {
|
|
325
|
-
hello: 'world',
|
|
326
|
-
},
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const proxied = createMagicProxy(input)
|
|
330
|
-
|
|
331
|
-
proxied.a['$ref-value'] = 'new value'
|
|
332
|
-
|
|
333
|
-
expect(proxied).toEqual({
|
|
334
|
-
a: {
|
|
335
|
-
$ref: '#/b',
|
|
336
|
-
'$ref-value': 'new value',
|
|
337
|
-
},
|
|
338
|
-
b: 'new value',
|
|
339
|
-
})
|
|
340
|
-
})
|
|
341
|
-
|
|
342
|
-
it('sets properties on the referenced value #2', () => {
|
|
343
|
-
const input = {
|
|
344
|
-
a: {
|
|
345
|
-
$ref: '#/b/c',
|
|
346
|
-
},
|
|
347
|
-
b: {
|
|
348
|
-
c: {
|
|
349
|
-
hello: 'world',
|
|
350
|
-
},
|
|
351
|
-
},
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
const proxied = createMagicProxy(input)
|
|
355
|
-
|
|
356
|
-
proxied.a['$ref-value'] = {
|
|
357
|
-
message: 'this is the new value',
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
expect(proxied).toEqual({
|
|
361
|
-
a: {
|
|
362
|
-
$ref: '#/b/c',
|
|
363
|
-
'$ref-value': {
|
|
364
|
-
'message': 'this is the new value',
|
|
365
|
-
},
|
|
366
|
-
},
|
|
367
|
-
'b': {
|
|
368
|
-
'c': {
|
|
369
|
-
'message': 'this is the new value',
|
|
370
|
-
},
|
|
371
|
-
},
|
|
372
|
-
})
|
|
373
|
-
})
|
|
374
|
-
|
|
375
|
-
it('throws an error when trying set rewrite a referenced value which is the root of the document', () => {
|
|
376
|
-
const input = {
|
|
377
|
-
a: {
|
|
378
|
-
$ref: '#',
|
|
379
|
-
},
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
const proxied = createMagicProxy(input)
|
|
383
|
-
|
|
384
|
-
expect(() => {
|
|
385
|
-
proxied.a['$ref-value'] = 'new value'
|
|
386
|
-
}).toThrowError("'set' on proxy: trap returned falsish for property '$ref-value'")
|
|
387
|
-
})
|
|
388
|
-
|
|
389
|
-
it('does not throw when trying to update an invalid ref where the parent node does not exists', () => {
|
|
390
|
-
const input = {
|
|
391
|
-
a: {
|
|
392
|
-
$ref: '#/non-existent/some-path',
|
|
393
|
-
},
|
|
394
|
-
b: {
|
|
395
|
-
c: {
|
|
396
|
-
hello: 'world',
|
|
397
|
-
},
|
|
398
|
-
},
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const proxied = createMagicProxy(input)
|
|
402
|
-
|
|
403
|
-
expect(() => {
|
|
404
|
-
proxied.a['$ref-value'] = 'new value'
|
|
405
|
-
}).not.toThrowError("'set' on proxy: trap returned falsish for property '$ref-value'")
|
|
406
|
-
|
|
407
|
-
expect(proxied.a['$ref-value']).toBe('new value')
|
|
408
|
-
|
|
409
|
-
expect(input).toEqual({
|
|
410
|
-
'a': {
|
|
411
|
-
'$ref': '#/non-existent/some-path',
|
|
412
|
-
},
|
|
413
|
-
'b': {
|
|
414
|
-
'c': {
|
|
415
|
-
'hello': 'world',
|
|
416
|
-
},
|
|
417
|
-
},
|
|
418
|
-
'non-existent': {
|
|
419
|
-
'some-path': 'new value',
|
|
420
|
-
},
|
|
421
|
-
})
|
|
422
|
-
})
|
|
423
|
-
})
|
|
424
|
-
|
|
425
|
-
describe('has', () => {
|
|
426
|
-
it('returns true for $ref-value when $ref exists', () => {
|
|
427
|
-
const input = {
|
|
428
|
-
a: 'hello',
|
|
429
|
-
b: {
|
|
430
|
-
$ref: '#/a',
|
|
431
|
-
},
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const result = createMagicProxy(input)
|
|
435
|
-
expect('$ref-value' in result.b).toBe(true)
|
|
436
|
-
})
|
|
437
|
-
|
|
438
|
-
it('returns false for $ref-value when $ref does not exist', () => {
|
|
439
|
-
const input = {
|
|
440
|
-
a: 'hello',
|
|
441
|
-
b: {
|
|
442
|
-
c: 'world',
|
|
443
|
-
},
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const result = createMagicProxy(input)
|
|
447
|
-
expect('$ref-value' in result.b).toBe(false)
|
|
448
|
-
})
|
|
449
|
-
|
|
450
|
-
it('returns true for existing properties', () => {
|
|
451
|
-
const input = {
|
|
452
|
-
a: 'hello',
|
|
453
|
-
b: {
|
|
454
|
-
c: 'world',
|
|
455
|
-
},
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
const result = createMagicProxy(input)
|
|
459
|
-
expect('a' in result).toBe(true)
|
|
460
|
-
expect('b' in result).toBe(true)
|
|
461
|
-
expect('c' in result.b).toBe(true)
|
|
462
|
-
})
|
|
463
|
-
|
|
464
|
-
it('returns false for non-existent properties', () => {
|
|
465
|
-
const input = {
|
|
466
|
-
a: 'hello',
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const result = createMagicProxy(input)
|
|
470
|
-
expect('nonExistent' in result).toBe(false)
|
|
471
|
-
expect('$ref-value' in result).toBe(false)
|
|
472
|
-
})
|
|
473
|
-
|
|
474
|
-
it('handles nested objects with refs', () => {
|
|
475
|
-
const input = {
|
|
476
|
-
a: {
|
|
477
|
-
b: {
|
|
478
|
-
c: 'hello',
|
|
479
|
-
},
|
|
480
|
-
},
|
|
481
|
-
d: {
|
|
482
|
-
$ref: '#/a/b',
|
|
483
|
-
},
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
const result = createMagicProxy(input)
|
|
487
|
-
expect('$ref-value' in result.d).toBe(true)
|
|
488
|
-
expect('c' in result.a.b).toBe(true)
|
|
489
|
-
})
|
|
490
|
-
|
|
491
|
-
it('handles arrays with refs', () => {
|
|
492
|
-
const input = {
|
|
493
|
-
items: [{ name: 'item1' }, { $ref: '#/items/0' }],
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
const result = createMagicProxy(input)
|
|
497
|
-
expect('$ref-value' in result.items[1]).toBe(true)
|
|
498
|
-
expect('name' in result.items[0]).toBe(true)
|
|
499
|
-
})
|
|
500
|
-
|
|
501
|
-
it('handles deeply nested refs', () => {
|
|
502
|
-
const input = {
|
|
503
|
-
a: {
|
|
504
|
-
b: {
|
|
505
|
-
c: {
|
|
506
|
-
d: {
|
|
507
|
-
e: 'hello',
|
|
508
|
-
},
|
|
509
|
-
},
|
|
510
|
-
},
|
|
511
|
-
},
|
|
512
|
-
f: {
|
|
513
|
-
$ref: '#/a/b/c/d',
|
|
514
|
-
},
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
const result = createMagicProxy(input)
|
|
518
|
-
expect('$ref-value' in result.f).toBe(true)
|
|
519
|
-
})
|
|
520
|
-
|
|
521
|
-
it('handles objects with both $ref and other properties', () => {
|
|
522
|
-
const input = {
|
|
523
|
-
a: {
|
|
524
|
-
b: {
|
|
525
|
-
c: 'hello',
|
|
526
|
-
},
|
|
527
|
-
},
|
|
528
|
-
d: {
|
|
529
|
-
$ref: '#/a/b',
|
|
530
|
-
extraProp: 'extra',
|
|
531
|
-
},
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
const result = createMagicProxy(input)
|
|
535
|
-
expect('$ref-value' in result.d).toBe(true)
|
|
536
|
-
expect('extraProp' in result.d).toBe(true)
|
|
537
|
-
expect('$ref' in result.d).toBe(true)
|
|
538
|
-
})
|
|
539
|
-
|
|
540
|
-
it('handles external refs', () => {
|
|
541
|
-
const input = {
|
|
542
|
-
a: 'hello',
|
|
543
|
-
b: {
|
|
544
|
-
$ref: 'https://example.com/document.json/#',
|
|
545
|
-
},
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
const result = createMagicProxy(input)
|
|
549
|
-
expect('$ref-value' in result.b).toBe(true)
|
|
550
|
-
})
|
|
551
|
-
|
|
552
|
-
it('handles empty objects', () => {
|
|
553
|
-
const input = {}
|
|
554
|
-
|
|
555
|
-
const result = createMagicProxy(input)
|
|
556
|
-
expect('$ref-value' in result).toBe(false)
|
|
557
|
-
expect('anyProperty' in result).toBe(false)
|
|
558
|
-
})
|
|
559
|
-
|
|
560
|
-
it('handles null and undefined values', () => {
|
|
561
|
-
const input = {
|
|
562
|
-
a: null,
|
|
563
|
-
b: undefined,
|
|
564
|
-
c: {
|
|
565
|
-
$ref: '#/a',
|
|
566
|
-
},
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
const result = createMagicProxy(input)
|
|
570
|
-
expect('$ref-value' in result.c).toBe(true)
|
|
571
|
-
expect('a' in result).toBe(true)
|
|
572
|
-
expect('b' in result).toBe(true)
|
|
573
|
-
})
|
|
574
|
-
})
|
|
575
|
-
|
|
576
|
-
describe('delete', () => {
|
|
577
|
-
it('deletes properties from the target object', () => {
|
|
578
|
-
const input = {
|
|
579
|
-
a: 'hello',
|
|
580
|
-
b: 'world',
|
|
581
|
-
c: 'test',
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
const result = createMagicProxy(input)
|
|
585
|
-
delete result.b
|
|
586
|
-
|
|
587
|
-
expect('b' in result).toBe(false)
|
|
588
|
-
expect(result.a).toBe('hello')
|
|
589
|
-
expect(result.c).toBe('test')
|
|
590
|
-
})
|
|
591
|
-
|
|
592
|
-
it('deletes properties from nested objects', () => {
|
|
593
|
-
const input = {
|
|
594
|
-
a: {
|
|
595
|
-
b: 'hello',
|
|
596
|
-
c: 'world',
|
|
597
|
-
d: 'test',
|
|
598
|
-
},
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
const result = createMagicProxy(input)
|
|
602
|
-
delete result.a.c
|
|
603
|
-
|
|
604
|
-
expect('c' in result.a).toBe(false)
|
|
605
|
-
expect(result.a.b).toBe('hello')
|
|
606
|
-
expect(result.a.d).toBe('test')
|
|
607
|
-
})
|
|
608
|
-
|
|
609
|
-
it('deletes properties from objects with refs', () => {
|
|
610
|
-
const input = {
|
|
611
|
-
a: {
|
|
612
|
-
b: 'hello',
|
|
613
|
-
c: 'world',
|
|
614
|
-
},
|
|
615
|
-
d: {
|
|
616
|
-
$ref: '#/a',
|
|
617
|
-
extraProp: 'extra',
|
|
618
|
-
},
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
const result = createMagicProxy(input)
|
|
622
|
-
delete result.d.extraProp
|
|
623
|
-
|
|
624
|
-
expect('extraProp' in result.d).toBe(false)
|
|
625
|
-
expect('$ref' in result.d).toBe(true)
|
|
626
|
-
expect('$ref-value' in result.d).toBe(true)
|
|
627
|
-
})
|
|
628
|
-
|
|
629
|
-
it('deletes properties from ref-value objects', () => {
|
|
630
|
-
const input = {
|
|
631
|
-
a: {
|
|
632
|
-
b: {
|
|
633
|
-
c: 'hello',
|
|
634
|
-
d: 'world',
|
|
635
|
-
},
|
|
636
|
-
},
|
|
637
|
-
e: {
|
|
638
|
-
$ref: '#/a/b',
|
|
639
|
-
},
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
const result = createMagicProxy(input)
|
|
643
|
-
delete result.e['$ref-value'].d
|
|
644
|
-
|
|
645
|
-
expect('d' in result.e['$ref-value']).toBe(false)
|
|
646
|
-
expect(result.e['$ref-value'].c).toBe('hello')
|
|
647
|
-
expect(input.a.b.d).toBeUndefined()
|
|
648
|
-
})
|
|
649
|
-
|
|
650
|
-
it('deletes array elements', () => {
|
|
651
|
-
const input = {
|
|
652
|
-
items: ['a', 'b', 'c', 'd'],
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
const result = createMagicProxy(input)
|
|
656
|
-
delete result.items[1]
|
|
657
|
-
|
|
658
|
-
expect(result.items[1]).toBeUndefined()
|
|
659
|
-
expect(result.items[0]).toBe('a')
|
|
660
|
-
expect(result.items[2]).toBe('c')
|
|
661
|
-
expect(result.items[3]).toBe('d')
|
|
662
|
-
})
|
|
663
|
-
|
|
664
|
-
it('deletes properties from array elements with refs', () => {
|
|
665
|
-
const input = {
|
|
666
|
-
$defs: {
|
|
667
|
-
item: { name: 'default', id: 123, type: 'test' },
|
|
668
|
-
},
|
|
669
|
-
items: [{ $ref: '#/$defs/item' }],
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
const result = createMagicProxy(input)
|
|
673
|
-
delete result.items[0]['$ref-value'].type
|
|
674
|
-
|
|
675
|
-
expect('type' in result.items[0]['$ref-value']).toBe(false)
|
|
676
|
-
expect(result.items[0]['$ref-value'].name).toBe('default')
|
|
677
|
-
expect(result.items[0]['$ref-value'].id).toBe(123)
|
|
678
|
-
})
|
|
679
|
-
|
|
680
|
-
it('deletes deeply nested properties', () => {
|
|
681
|
-
const input = {
|
|
682
|
-
a: {
|
|
683
|
-
b: {
|
|
684
|
-
c: {
|
|
685
|
-
d: {
|
|
686
|
-
e: 'hello',
|
|
687
|
-
f: 'world',
|
|
688
|
-
},
|
|
689
|
-
},
|
|
690
|
-
},
|
|
691
|
-
},
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
const result = createMagicProxy(input)
|
|
695
|
-
delete result.a.b.c.d.f
|
|
696
|
-
|
|
697
|
-
expect('f' in result.a.b.c.d).toBe(false)
|
|
698
|
-
expect(result.a.b.c.d.e).toBe('hello')
|
|
699
|
-
})
|
|
700
|
-
|
|
701
|
-
it('deletes properties from deeply nested refs', () => {
|
|
702
|
-
const input = {
|
|
703
|
-
a: {
|
|
704
|
-
b: {
|
|
705
|
-
c: {
|
|
706
|
-
d: {
|
|
707
|
-
e: 'hello',
|
|
708
|
-
f: 'world',
|
|
709
|
-
},
|
|
710
|
-
},
|
|
711
|
-
},
|
|
712
|
-
},
|
|
713
|
-
g: {
|
|
714
|
-
$ref: '#/a/b/c/d',
|
|
715
|
-
},
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
const result = createMagicProxy(input)
|
|
719
|
-
delete result.g['$ref-value'].f
|
|
720
|
-
|
|
721
|
-
expect('f' in result.g['$ref-value']).toBe(false)
|
|
722
|
-
expect(result.g['$ref-value'].e).toBe('hello')
|
|
723
|
-
expect(input.a.b.c.d.f).toBeUndefined()
|
|
724
|
-
})
|
|
725
|
-
|
|
726
|
-
it('deletes root level properties', () => {
|
|
727
|
-
const input: any = {
|
|
728
|
-
rootProp: 'root value',
|
|
729
|
-
nestedProp: 'nested value',
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
const result = createMagicProxy(input)
|
|
733
|
-
delete result.rootProp
|
|
734
|
-
|
|
735
|
-
expect('rootProp' in result).toBe(false)
|
|
736
|
-
expect(result.nestedProp).toBe('nested value')
|
|
737
|
-
})
|
|
738
|
-
|
|
739
|
-
it('deletes properties that do not exist', () => {
|
|
740
|
-
const input: any = {
|
|
741
|
-
a: 'hello',
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
const result = createMagicProxy(input)
|
|
745
|
-
const deleteResult = delete result.nonExistent
|
|
746
|
-
|
|
747
|
-
expect(deleteResult).toBe(true)
|
|
748
|
-
expect('nonExistent' in result).toBe(false)
|
|
749
|
-
})
|
|
750
|
-
|
|
751
|
-
it('deletes properties from objects with multiple refs', () => {
|
|
752
|
-
const input = {
|
|
753
|
-
a: {
|
|
754
|
-
b: {
|
|
755
|
-
c: 'hello',
|
|
756
|
-
d: 'world',
|
|
757
|
-
},
|
|
758
|
-
},
|
|
759
|
-
e: {
|
|
760
|
-
$ref: '#/a/b',
|
|
761
|
-
},
|
|
762
|
-
f: {
|
|
763
|
-
$ref: '#/e',
|
|
764
|
-
},
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
const result = createMagicProxy(input)
|
|
768
|
-
delete result.f['$ref-value']['$ref-value'].d
|
|
769
|
-
|
|
770
|
-
expect('d' in result.f['$ref-value']['$ref-value']).toBe(false)
|
|
771
|
-
expect(result.f['$ref-value']['$ref-value'].c).toBe('hello')
|
|
772
|
-
expect(input.a.b.d).toBeUndefined()
|
|
773
|
-
})
|
|
774
|
-
|
|
775
|
-
it('deletes properties from external refs', () => {
|
|
776
|
-
const input = {
|
|
777
|
-
a: 'hello',
|
|
778
|
-
b: {
|
|
779
|
-
$ref: 'https://example.com/document.json/#',
|
|
780
|
-
localProp: 'local',
|
|
781
|
-
},
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
const result = createMagicProxy(input)
|
|
785
|
-
delete result.b.localProp
|
|
786
|
-
|
|
787
|
-
expect('localProp' in result.b).toBe(false)
|
|
788
|
-
expect('$ref' in result.b).toBe(true)
|
|
789
|
-
expect('$ref-value' in result.b).toBe(true)
|
|
790
|
-
})
|
|
791
|
-
|
|
792
|
-
it('deletes properties from empty objects', () => {
|
|
793
|
-
const input: any = {}
|
|
794
|
-
|
|
795
|
-
const result = createMagicProxy(input)
|
|
796
|
-
const deleteResult = delete result.anyProperty
|
|
797
|
-
|
|
798
|
-
expect(deleteResult).toBe(true)
|
|
799
|
-
expect('anyProperty' in result).toBe(false)
|
|
800
|
-
})
|
|
801
|
-
|
|
802
|
-
it('deletes properties from objects with null and undefined values', () => {
|
|
803
|
-
const input = {
|
|
804
|
-
a: null,
|
|
805
|
-
b: undefined,
|
|
806
|
-
c: {
|
|
807
|
-
d: null,
|
|
808
|
-
e: undefined,
|
|
809
|
-
},
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
const result = createMagicProxy(input)
|
|
813
|
-
delete result.a
|
|
814
|
-
delete result.c.d
|
|
815
|
-
|
|
816
|
-
expect('a' in result).toBe(false)
|
|
817
|
-
expect('d' in result.c).toBe(false)
|
|
818
|
-
expect('b' in result).toBe(true)
|
|
819
|
-
expect('e' in result.c).toBe(true)
|
|
820
|
-
})
|
|
821
|
-
|
|
822
|
-
it('deletes properties from arrays with mixed content', () => {
|
|
823
|
-
const input: any = {
|
|
824
|
-
items: [{ name: 'item1', id: 1 }, { $ref: '#/items/0' }, 'string item', { name: 'item2', id: 2 }],
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
const result = createMagicProxy(input)
|
|
828
|
-
delete result.items[0].id
|
|
829
|
-
delete result.items[1]['$ref-value'].name
|
|
830
|
-
|
|
831
|
-
expect('id' in result.items[0]).toBe(false)
|
|
832
|
-
expect('name' in result.items[1]['$ref-value']).toBe(false)
|
|
833
|
-
expect(result.items[0].name).toBe(undefined)
|
|
834
|
-
expect(result.items[2]).toBe('string item')
|
|
835
|
-
})
|
|
836
|
-
|
|
837
|
-
it('deletes properties from objects with both direct and ref properties', () => {
|
|
838
|
-
const input = {
|
|
839
|
-
a: {
|
|
840
|
-
b: {
|
|
841
|
-
c: 'hello',
|
|
842
|
-
d: 'world',
|
|
843
|
-
},
|
|
844
|
-
},
|
|
845
|
-
e: {
|
|
846
|
-
$ref: '#/a/b',
|
|
847
|
-
directProp: 'direct',
|
|
848
|
-
},
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
const result = createMagicProxy(input)
|
|
852
|
-
delete result.e.directProp
|
|
853
|
-
delete result.e['$ref-value'].d
|
|
854
|
-
|
|
855
|
-
expect('directProp' in result.e).toBe(false)
|
|
856
|
-
expect('d' in result.e['$ref-value']).toBe(false)
|
|
857
|
-
expect('$ref' in result.e).toBe(true)
|
|
858
|
-
expect(result.e['$ref-value'].c).toBe('hello')
|
|
859
|
-
})
|
|
860
|
-
})
|
|
861
|
-
|
|
862
|
-
describe('ownKeys', () => {
|
|
863
|
-
it('returns original keys when no $ref exists', () => {
|
|
864
|
-
const input = {
|
|
865
|
-
a: 'hello',
|
|
866
|
-
b: 'world',
|
|
867
|
-
c: 'test',
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
const result = createMagicProxy(input)
|
|
871
|
-
const keys = Object.keys(result)
|
|
872
|
-
|
|
873
|
-
expect(keys).toEqual(['a', 'b', 'c'])
|
|
874
|
-
})
|
|
875
|
-
|
|
876
|
-
it('includes $ref-value when $ref exists', () => {
|
|
877
|
-
const input = {
|
|
878
|
-
a: 'hello',
|
|
879
|
-
b: {
|
|
880
|
-
$ref: '#/a',
|
|
881
|
-
},
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
const result = createMagicProxy(input)
|
|
885
|
-
const keys = Object.keys(result.b)
|
|
886
|
-
|
|
887
|
-
expect(keys).toEqual(['$ref', '$ref-value'])
|
|
888
|
-
})
|
|
889
|
-
|
|
890
|
-
it('does not duplicate $ref-value if it already exists', () => {
|
|
891
|
-
const input = {
|
|
892
|
-
a: 'hello',
|
|
893
|
-
b: {
|
|
894
|
-
$ref: '#/a',
|
|
895
|
-
'$ref-value': 'existing',
|
|
896
|
-
},
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
const result = createMagicProxy(input)
|
|
900
|
-
const keys = Object.keys(result.b)
|
|
901
|
-
|
|
902
|
-
expect(keys).toEqual(['$ref', '$ref-value'])
|
|
903
|
-
})
|
|
904
|
-
|
|
905
|
-
it('handles nested objects with refs', () => {
|
|
906
|
-
const input = {
|
|
907
|
-
a: {
|
|
908
|
-
b: {
|
|
909
|
-
c: 'hello',
|
|
910
|
-
},
|
|
911
|
-
},
|
|
912
|
-
d: {
|
|
913
|
-
$ref: '#/a/b',
|
|
914
|
-
extraProp: 'extra',
|
|
915
|
-
},
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
const result = createMagicProxy(input)
|
|
919
|
-
const keys = Object.keys(result.d)
|
|
920
|
-
|
|
921
|
-
expect(keys).toEqual(['$ref', 'extraProp', '$ref-value'])
|
|
922
|
-
})
|
|
923
|
-
|
|
924
|
-
it('handles arrays with refs', () => {
|
|
925
|
-
const input = {
|
|
926
|
-
items: [{ name: 'item1' }, { $ref: '#/items/0' }, { name: 'item2', id: 2 }],
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
const result = createMagicProxy(input)
|
|
930
|
-
const keys = Object.keys(result.items[1])
|
|
931
|
-
|
|
932
|
-
expect(keys).toEqual(['$ref', '$ref-value'])
|
|
933
|
-
})
|
|
934
|
-
|
|
935
|
-
it('handles deeply nested refs', () => {
|
|
936
|
-
const input = {
|
|
937
|
-
a: {
|
|
938
|
-
b: {
|
|
939
|
-
c: {
|
|
940
|
-
d: {
|
|
941
|
-
e: 'hello',
|
|
942
|
-
},
|
|
943
|
-
},
|
|
944
|
-
},
|
|
945
|
-
},
|
|
946
|
-
f: {
|
|
947
|
-
$ref: '#/a/b/c/d',
|
|
948
|
-
},
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
const result = createMagicProxy(input)
|
|
952
|
-
const keys = Object.keys(result.f)
|
|
953
|
-
|
|
954
|
-
expect(keys).toEqual(['$ref', '$ref-value'])
|
|
955
|
-
})
|
|
956
|
-
|
|
957
|
-
it('handles objects with multiple refs', () => {
|
|
958
|
-
const input = {
|
|
959
|
-
a: {
|
|
960
|
-
b: {
|
|
961
|
-
c: 'hello',
|
|
962
|
-
},
|
|
963
|
-
},
|
|
964
|
-
d: {
|
|
965
|
-
$ref: '#/a/b',
|
|
966
|
-
},
|
|
967
|
-
e: {
|
|
968
|
-
$ref: '#/d',
|
|
969
|
-
},
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
const result = createMagicProxy(input)
|
|
973
|
-
const dKeys = Object.keys(result.d)
|
|
974
|
-
const eKeys = Object.keys(result.e)
|
|
975
|
-
|
|
976
|
-
expect(dKeys).toEqual(['$ref', '$ref-value'])
|
|
977
|
-
expect(eKeys).toEqual(['$ref', '$ref-value'])
|
|
978
|
-
})
|
|
979
|
-
|
|
980
|
-
it('handles external refs', () => {
|
|
981
|
-
const input = {
|
|
982
|
-
a: 'hello',
|
|
983
|
-
b: {
|
|
984
|
-
$ref: 'https://example.com/document.json/#',
|
|
985
|
-
},
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
const result = createMagicProxy(input)
|
|
989
|
-
const keys = Object.keys(result.b)
|
|
990
|
-
|
|
991
|
-
expect(keys).toEqual(['$ref', '$ref-value'])
|
|
992
|
-
})
|
|
993
|
-
|
|
994
|
-
it('handles empty objects', () => {
|
|
995
|
-
const input = {}
|
|
996
|
-
|
|
997
|
-
const result = createMagicProxy(input)
|
|
998
|
-
const keys = Object.keys(result)
|
|
999
|
-
|
|
1000
|
-
expect(keys).toEqual([])
|
|
1001
|
-
})
|
|
1002
|
-
|
|
1003
|
-
it('handles objects with only $ref', () => {
|
|
1004
|
-
const input = {
|
|
1005
|
-
a: {
|
|
1006
|
-
$ref: '#/b',
|
|
1007
|
-
},
|
|
1008
|
-
b: 'hello',
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
const result = createMagicProxy(input)
|
|
1012
|
-
const keys = Object.keys(result.a)
|
|
1013
|
-
|
|
1014
|
-
expect(keys).toEqual(['$ref', '$ref-value'])
|
|
1015
|
-
})
|
|
1016
|
-
|
|
1017
|
-
it('handles objects with null and undefined values', () => {
|
|
1018
|
-
const input = {
|
|
1019
|
-
a: null,
|
|
1020
|
-
b: undefined,
|
|
1021
|
-
c: {
|
|
1022
|
-
$ref: '#/a',
|
|
1023
|
-
},
|
|
1024
|
-
d: {
|
|
1025
|
-
$ref: '#/b',
|
|
1026
|
-
},
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
const result = createMagicProxy(input)
|
|
1030
|
-
const cKeys = Object.keys(result.c)
|
|
1031
|
-
const dKeys = Object.keys(result.d)
|
|
1032
|
-
|
|
1033
|
-
expect(cKeys).toEqual(['$ref', '$ref-value'])
|
|
1034
|
-
expect(dKeys).toEqual(['$ref', '$ref-value'])
|
|
1035
|
-
})
|
|
1036
|
-
|
|
1037
|
-
it('handles arrays with mixed content', () => {
|
|
1038
|
-
const input = {
|
|
1039
|
-
items: [{ name: 'item1' }, { $ref: '#/items/0' }, 'string item', { name: 'item2', id: 2 }],
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
const result = createMagicProxy(input)
|
|
1043
|
-
const item0Keys = Object.keys(result.items[0])
|
|
1044
|
-
const item1Keys = Object.keys(result.items[1])
|
|
1045
|
-
|
|
1046
|
-
expect(item0Keys).toEqual(['name'])
|
|
1047
|
-
expect(item1Keys).toEqual(['$ref', '$ref-value'])
|
|
1048
|
-
})
|
|
1049
|
-
|
|
1050
|
-
it('handles objects with both direct and ref properties', () => {
|
|
1051
|
-
const input = {
|
|
1052
|
-
a: {
|
|
1053
|
-
b: {
|
|
1054
|
-
c: 'hello',
|
|
1055
|
-
},
|
|
1056
|
-
},
|
|
1057
|
-
d: {
|
|
1058
|
-
$ref: '#/a/b',
|
|
1059
|
-
directProp: 'direct',
|
|
1060
|
-
anotherProp: 'another',
|
|
1061
|
-
},
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
const result = createMagicProxy(input)
|
|
1065
|
-
const keys = Object.keys(result.d)
|
|
1066
|
-
|
|
1067
|
-
expect(keys).toEqual(['$ref', 'directProp', 'anotherProp', '$ref-value'])
|
|
1068
|
-
})
|
|
1069
|
-
|
|
1070
|
-
it('handles objects with symbol keys', () => {
|
|
1071
|
-
const symbolKey = Symbol('test')
|
|
1072
|
-
const input = {
|
|
1073
|
-
[symbolKey]: 'symbol value',
|
|
1074
|
-
a: 'hello',
|
|
1075
|
-
b: {
|
|
1076
|
-
$ref: '#/a',
|
|
1077
|
-
},
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
const result = createMagicProxy(input)
|
|
1081
|
-
const keys = Object.keys(result)
|
|
1082
|
-
const ownKeys = Object.getOwnPropertySymbols(result)
|
|
1083
|
-
|
|
1084
|
-
expect(keys).toEqual(['a', 'b'])
|
|
1085
|
-
expect(ownKeys).toEqual([symbolKey])
|
|
1086
|
-
})
|
|
1087
|
-
|
|
1088
|
-
it('handles objects with non-enumerable properties', () => {
|
|
1089
|
-
const input = {
|
|
1090
|
-
a: 'hello',
|
|
1091
|
-
b: {
|
|
1092
|
-
$ref: '#/a',
|
|
1093
|
-
},
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
Object.defineProperty(input.b, 'nonEnumerable', {
|
|
1097
|
-
value: 'test',
|
|
1098
|
-
enumerable: false,
|
|
1099
|
-
})
|
|
1100
|
-
|
|
1101
|
-
const result = createMagicProxy(input)
|
|
1102
|
-
const keys = Object.keys(result.b)
|
|
1103
|
-
const ownKeys = Reflect.ownKeys(result.b)
|
|
1104
|
-
|
|
1105
|
-
expect(keys).toEqual(['$ref', '$ref-value'])
|
|
1106
|
-
expect(ownKeys).toContain('nonEnumerable')
|
|
1107
|
-
expect(ownKeys).toContain('$ref')
|
|
1108
|
-
expect(ownKeys).toContain('$ref-value')
|
|
1109
|
-
})
|
|
1110
|
-
|
|
1111
|
-
it('handles objects with getter properties', () => {
|
|
1112
|
-
const input = {
|
|
1113
|
-
a: 'hello',
|
|
1114
|
-
b: {
|
|
1115
|
-
$ref: '#/a',
|
|
1116
|
-
},
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
Object.defineProperty(input.b, 'getterProp', {
|
|
1120
|
-
get() {
|
|
1121
|
-
return 'getter value'
|
|
1122
|
-
},
|
|
1123
|
-
enumerable: true,
|
|
1124
|
-
})
|
|
1125
|
-
|
|
1126
|
-
const result = createMagicProxy(input)
|
|
1127
|
-
const keys = Object.keys(result.b)
|
|
1128
|
-
|
|
1129
|
-
expect(keys).toEqual(['$ref', 'getterProp', '$ref-value'])
|
|
1130
|
-
})
|
|
1131
|
-
})
|
|
1132
|
-
|
|
1133
|
-
describe('getRaw', () => {
|
|
1134
|
-
it('should get the raw version of the document', () => {
|
|
1135
|
-
const input = {
|
|
1136
|
-
a: 'hello',
|
|
1137
|
-
b: {
|
|
1138
|
-
$ref: '#/a',
|
|
1139
|
-
},
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
const proxied = createMagicProxy(input)
|
|
1143
|
-
|
|
1144
|
-
expect(proxied).toEqual({
|
|
1145
|
-
a: 'hello',
|
|
1146
|
-
b: {
|
|
1147
|
-
$ref: '#/a',
|
|
1148
|
-
'$ref-value': 'hello',
|
|
1149
|
-
},
|
|
1150
|
-
})
|
|
1151
|
-
|
|
1152
|
-
expect(getRaw(proxied)).toEqual(input)
|
|
1153
|
-
})
|
|
1154
|
-
})
|
|
1155
|
-
|
|
1156
|
-
describe('show underscore properties when specified', () => {
|
|
1157
|
-
it('should not hide properties starting with __scalar_ from direct access', () => {
|
|
1158
|
-
const input = {
|
|
1159
|
-
public: 'visible',
|
|
1160
|
-
__scalar_private: 'hidden',
|
|
1161
|
-
__scalar_internal: 'also hidden',
|
|
1162
|
-
normal_underscore: 'visible with underscore in middle',
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
const result = createMagicProxy(input, { showInternal: true })
|
|
1166
|
-
|
|
1167
|
-
expect(result.public).toBe('visible')
|
|
1168
|
-
expect(result.__scalar_private).toBe('hidden')
|
|
1169
|
-
expect(result.__scalar_internal).toBe('also hidden')
|
|
1170
|
-
expect(result.normal_underscore).toBe('visible with underscore in middle')
|
|
1171
|
-
})
|
|
1172
|
-
|
|
1173
|
-
it('should not hide __scalar_ properties from "in" operator', () => {
|
|
1174
|
-
const input = {
|
|
1175
|
-
public: 'visible',
|
|
1176
|
-
__scalar_private: 'hidden',
|
|
1177
|
-
__scalar_internal: 'also hidden',
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
const result = createMagicProxy(input, { showInternal: true })
|
|
1181
|
-
|
|
1182
|
-
expect('public' in result).toBe(true)
|
|
1183
|
-
expect('__scalar_private' in result).toBe(true)
|
|
1184
|
-
expect('__scalar_internal' in result).toBe(true)
|
|
1185
|
-
})
|
|
1186
|
-
|
|
1187
|
-
it('should not exclude __scalar_ properties from Object.keys enumeration', () => {
|
|
1188
|
-
const input = {
|
|
1189
|
-
public: 'visible',
|
|
1190
|
-
__scalar_private: 'hidden',
|
|
1191
|
-
__scalar_internal: 'also hidden',
|
|
1192
|
-
another: 'visible',
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
const result = createMagicProxy(input, { showInternal: true })
|
|
1196
|
-
const keys = Object.keys(result)
|
|
1197
|
-
|
|
1198
|
-
expect(keys).toContain('public')
|
|
1199
|
-
expect(keys).toContain('another')
|
|
1200
|
-
expect(keys).toContain('__scalar_private')
|
|
1201
|
-
expect(keys).toContain('__scalar_internal')
|
|
1202
|
-
})
|
|
1203
|
-
|
|
1204
|
-
it('should not hide __scalar_ properties from getOwnPropertyDescriptor', () => {
|
|
1205
|
-
const input = {
|
|
1206
|
-
public: 'visible',
|
|
1207
|
-
__scalar_private: 'hidden',
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
const result = createMagicProxy(input, { showInternal: true })
|
|
1211
|
-
|
|
1212
|
-
expect(Object.getOwnPropertyDescriptor(result, 'public')).toBeDefined()
|
|
1213
|
-
expect(Object.getOwnPropertyDescriptor(result, '__scalar_private')).toBeDefined()
|
|
1214
|
-
})
|
|
1215
|
-
|
|
1216
|
-
it('should not hide __scalar_ properties in nested objects', () => {
|
|
1217
|
-
const input = {
|
|
1218
|
-
nested: {
|
|
1219
|
-
public: 'visible',
|
|
1220
|
-
__scalar_private: 'hidden',
|
|
1221
|
-
deeper: {
|
|
1222
|
-
__scalar_alsoHidden: 'secret',
|
|
1223
|
-
visible: 'shown',
|
|
1224
|
-
},
|
|
1225
|
-
},
|
|
1226
|
-
__scalar_topLevel: 'hidden',
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
const result = createMagicProxy(input, { showInternal: true })
|
|
1230
|
-
|
|
1231
|
-
expect(result.__scalar_topLevel).toBe('hidden')
|
|
1232
|
-
expect(result.nested.public).toBe('visible')
|
|
1233
|
-
expect(result.nested.__scalar_private).toBe('hidden')
|
|
1234
|
-
expect(result.nested.deeper.__scalar_alsoHidden).toBe('secret')
|
|
1235
|
-
expect(result.nested.deeper.visible).toBe('shown')
|
|
1236
|
-
})
|
|
1237
|
-
|
|
1238
|
-
it('should show __scalar_ properties with arrays containing objects with __scalar_ properties', () => {
|
|
1239
|
-
const input = {
|
|
1240
|
-
items: [
|
|
1241
|
-
{ public: 'item1', __scalar_private: 'hidden1' },
|
|
1242
|
-
{ public: 'item2', __scalar_private: 'hidden2' },
|
|
1243
|
-
],
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
const result = createMagicProxy(input, { showInternal: true })
|
|
1247
|
-
|
|
1248
|
-
expect(result.items[0].public).toBe('item1')
|
|
1249
|
-
expect(result.items[0].__scalar_private).toBe('hidden1')
|
|
1250
|
-
expect(result.items[1].public).toBe('item2')
|
|
1251
|
-
expect(result.items[1].__scalar_private).toBe('hidden2')
|
|
1252
|
-
})
|
|
1253
|
-
|
|
1254
|
-
it('should show __scalar_ ref properties', () => {
|
|
1255
|
-
const input = {
|
|
1256
|
-
definitions: {
|
|
1257
|
-
example: {
|
|
1258
|
-
value: 'hello',
|
|
1259
|
-
__scalar_internal: 'hidden',
|
|
1260
|
-
},
|
|
1261
|
-
},
|
|
1262
|
-
__scalar_hiddenRef: { $ref: '#/definitions/example' },
|
|
1263
|
-
publicRef: { $ref: '#/definitions/example' },
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
const result = createMagicProxy(input, { showInternal: true })
|
|
1267
|
-
|
|
1268
|
-
// __scalar_ property should be hidden
|
|
1269
|
-
expect(result.__scalar_hiddenRef).toEqual({
|
|
1270
|
-
'$ref': '#/definitions/example',
|
|
1271
|
-
'$ref-value': {
|
|
1272
|
-
'__scalar_internal': 'hidden',
|
|
1273
|
-
'value': 'hello',
|
|
1274
|
-
},
|
|
1275
|
-
})
|
|
1276
|
-
|
|
1277
|
-
// Public ref should work normally
|
|
1278
|
-
expect(result.publicRef['$ref-value'].value).toBe('hello')
|
|
1279
|
-
|
|
1280
|
-
// __scalar_ properties in referenced objects should be hidden
|
|
1281
|
-
expect(result.publicRef['$ref-value'].__scalar_internal).toBe('hidden')
|
|
1282
|
-
})
|
|
1283
|
-
})
|
|
1284
|
-
|
|
1285
|
-
describe('$id and $anchor reference resolution', () => {
|
|
1286
|
-
it('resolves references to schemas with $id property', () => {
|
|
1287
|
-
const input = {
|
|
1288
|
-
$id: 'https://example.com/schema',
|
|
1289
|
-
definitions: {
|
|
1290
|
-
user: {
|
|
1291
|
-
$id: 'https://example.com/user',
|
|
1292
|
-
type: 'object',
|
|
1293
|
-
properties: {
|
|
1294
|
-
name: { type: 'string' },
|
|
1295
|
-
age: { type: 'number' },
|
|
1296
|
-
},
|
|
1297
|
-
},
|
|
1298
|
-
},
|
|
1299
|
-
userRef: {
|
|
1300
|
-
$ref: 'https://example.com/user',
|
|
1301
|
-
},
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
const result = createMagicProxy(input)
|
|
1305
|
-
|
|
1306
|
-
expect(result.userRef['$ref-value']).toEqual({
|
|
1307
|
-
$id: 'https://example.com/user',
|
|
1308
|
-
type: 'object',
|
|
1309
|
-
properties: {
|
|
1310
|
-
name: { type: 'string' },
|
|
1311
|
-
age: { type: 'number' },
|
|
1312
|
-
},
|
|
1313
|
-
})
|
|
1314
|
-
})
|
|
1315
|
-
|
|
1316
|
-
it('resolves references to schemas with $anchor property', () => {
|
|
1317
|
-
const input = {
|
|
1318
|
-
$id: 'https://example.com/schema',
|
|
1319
|
-
definitions: {
|
|
1320
|
-
user: {
|
|
1321
|
-
$anchor: 'user-schema',
|
|
1322
|
-
type: 'object',
|
|
1323
|
-
properties: {
|
|
1324
|
-
name: { type: 'string' },
|
|
1325
|
-
email: { type: 'string' },
|
|
1326
|
-
},
|
|
1327
|
-
},
|
|
1328
|
-
},
|
|
1329
|
-
userRef: {
|
|
1330
|
-
$ref: 'https://example.com/schema#user-schema',
|
|
1331
|
-
},
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
const result = createMagicProxy(input)
|
|
1335
|
-
|
|
1336
|
-
expect(result.userRef['$ref-value']).toEqual({
|
|
1337
|
-
$anchor: 'user-schema',
|
|
1338
|
-
type: 'object',
|
|
1339
|
-
properties: {
|
|
1340
|
-
name: { type: 'string' },
|
|
1341
|
-
email: { type: 'string' },
|
|
1342
|
-
},
|
|
1343
|
-
})
|
|
1344
|
-
})
|
|
1345
|
-
|
|
1346
|
-
it('resolves references to schemas with both $id and $anchor properties', () => {
|
|
1347
|
-
const input = {
|
|
1348
|
-
$id: 'https://example.com/root',
|
|
1349
|
-
definitions: {
|
|
1350
|
-
user: {
|
|
1351
|
-
$id: 'https://example.com/user',
|
|
1352
|
-
$anchor: 'user-schema',
|
|
1353
|
-
type: 'object',
|
|
1354
|
-
properties: {
|
|
1355
|
-
id: { type: 'string' },
|
|
1356
|
-
profile: { type: 'object' },
|
|
1357
|
-
},
|
|
1358
|
-
},
|
|
1359
|
-
},
|
|
1360
|
-
userByIdRef: {
|
|
1361
|
-
$ref: 'https://example.com/user',
|
|
1362
|
-
},
|
|
1363
|
-
userByAnchorRef: {
|
|
1364
|
-
$ref: 'https://example.com/user#user-schema',
|
|
1365
|
-
},
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
const result = createMagicProxy(input)
|
|
1369
|
-
|
|
1370
|
-
const expectedUser = {
|
|
1371
|
-
$id: 'https://example.com/user',
|
|
1372
|
-
$anchor: 'user-schema',
|
|
1373
|
-
type: 'object',
|
|
1374
|
-
properties: {
|
|
1375
|
-
id: { type: 'string' },
|
|
1376
|
-
profile: { type: 'object' },
|
|
1377
|
-
},
|
|
1378
|
-
}
|
|
1379
|
-
|
|
1380
|
-
expect(result.userByIdRef['$ref-value']).toEqual(expectedUser)
|
|
1381
|
-
expect(result.userByAnchorRef['$ref-value']).toEqual(expectedUser)
|
|
1382
|
-
})
|
|
1383
|
-
|
|
1384
|
-
it('resolves nested references with $id and $anchor', () => {
|
|
1385
|
-
const input = {
|
|
1386
|
-
$id: 'https://example.com/api',
|
|
1387
|
-
components: {
|
|
1388
|
-
schemas: {
|
|
1389
|
-
user: {
|
|
1390
|
-
$id: 'https://example.com/user',
|
|
1391
|
-
$anchor: 'user-schema',
|
|
1392
|
-
type: 'object',
|
|
1393
|
-
properties: {
|
|
1394
|
-
profile: {
|
|
1395
|
-
$anchor: 'profile-schema',
|
|
1396
|
-
type: 'object',
|
|
1397
|
-
properties: {
|
|
1398
|
-
name: { type: 'string' },
|
|
1399
|
-
},
|
|
1400
|
-
},
|
|
1401
|
-
},
|
|
1402
|
-
},
|
|
1403
|
-
},
|
|
1404
|
-
},
|
|
1405
|
-
userRef: {
|
|
1406
|
-
$ref: 'https://example.com/user',
|
|
1407
|
-
},
|
|
1408
|
-
profileRef: {
|
|
1409
|
-
$ref: 'https://example.com/user#profile-schema',
|
|
1410
|
-
},
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
const result = createMagicProxy(input)
|
|
1414
|
-
|
|
1415
|
-
expect(result.userRef['$ref-value']).toEqual({
|
|
1416
|
-
$id: 'https://example.com/user',
|
|
1417
|
-
$anchor: 'user-schema',
|
|
1418
|
-
type: 'object',
|
|
1419
|
-
properties: {
|
|
1420
|
-
profile: {
|
|
1421
|
-
$anchor: 'profile-schema',
|
|
1422
|
-
type: 'object',
|
|
1423
|
-
properties: {
|
|
1424
|
-
name: { type: 'string' },
|
|
1425
|
-
},
|
|
1426
|
-
},
|
|
1427
|
-
},
|
|
1428
|
-
})
|
|
1429
|
-
|
|
1430
|
-
expect(result.profileRef['$ref-value']).toEqual({
|
|
1431
|
-
$anchor: 'profile-schema',
|
|
1432
|
-
type: 'object',
|
|
1433
|
-
properties: {
|
|
1434
|
-
name: { type: 'string' },
|
|
1435
|
-
},
|
|
1436
|
-
})
|
|
1437
|
-
})
|
|
1438
|
-
|
|
1439
|
-
it('resolves references with path fragments after $id', () => {
|
|
1440
|
-
const input = {
|
|
1441
|
-
$id: 'https://example.com/schema',
|
|
1442
|
-
definitions: {
|
|
1443
|
-
user: {
|
|
1444
|
-
$id: 'https://example.com/user',
|
|
1445
|
-
type: 'object',
|
|
1446
|
-
properties: {
|
|
1447
|
-
name: { type: 'string' },
|
|
1448
|
-
address: {
|
|
1449
|
-
type: 'object',
|
|
1450
|
-
properties: {
|
|
1451
|
-
street: { type: 'string' },
|
|
1452
|
-
},
|
|
1453
|
-
},
|
|
1454
|
-
},
|
|
1455
|
-
},
|
|
1456
|
-
},
|
|
1457
|
-
addressRef: {
|
|
1458
|
-
$ref: 'https://example.com/user#/properties/address',
|
|
1459
|
-
},
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
const result = createMagicProxy(input)
|
|
1463
|
-
|
|
1464
|
-
expect(result.addressRef['$ref-value']).toEqual({
|
|
1465
|
-
type: 'object',
|
|
1466
|
-
properties: {
|
|
1467
|
-
street: { type: 'string' },
|
|
1468
|
-
},
|
|
1469
|
-
})
|
|
1470
|
-
})
|
|
1471
|
-
|
|
1472
|
-
it('handles multiple schemas with different $id values', () => {
|
|
1473
|
-
const input = {
|
|
1474
|
-
$id: 'https://example.com/root',
|
|
1475
|
-
schemas: {
|
|
1476
|
-
user: {
|
|
1477
|
-
$id: 'https://example.com/user',
|
|
1478
|
-
type: 'object',
|
|
1479
|
-
properties: {
|
|
1480
|
-
name: { type: 'string' },
|
|
1481
|
-
},
|
|
1482
|
-
},
|
|
1483
|
-
product: {
|
|
1484
|
-
$id: 'https://example.com/product',
|
|
1485
|
-
type: 'object',
|
|
1486
|
-
properties: {
|
|
1487
|
-
title: { type: 'string' },
|
|
1488
|
-
},
|
|
1489
|
-
},
|
|
1490
|
-
},
|
|
1491
|
-
userRef: {
|
|
1492
|
-
$ref: 'https://example.com/user',
|
|
1493
|
-
},
|
|
1494
|
-
productRef: {
|
|
1495
|
-
$ref: 'https://example.com/product',
|
|
1496
|
-
},
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
const result = createMagicProxy(input)
|
|
1500
|
-
|
|
1501
|
-
expect(result.userRef['$ref-value']).toEqual({
|
|
1502
|
-
$id: 'https://example.com/user',
|
|
1503
|
-
type: 'object',
|
|
1504
|
-
properties: {
|
|
1505
|
-
name: { type: 'string' },
|
|
1506
|
-
},
|
|
1507
|
-
})
|
|
1508
|
-
|
|
1509
|
-
expect(result.productRef['$ref-value']).toEqual({
|
|
1510
|
-
$id: 'https://example.com/product',
|
|
1511
|
-
type: 'object',
|
|
1512
|
-
properties: {
|
|
1513
|
-
title: { type: 'string' },
|
|
1514
|
-
},
|
|
1515
|
-
})
|
|
1516
|
-
})
|
|
1517
|
-
|
|
1518
|
-
it('handles multiple schemas with different $anchor values', () => {
|
|
1519
|
-
const input = {
|
|
1520
|
-
$id: 'https://example.com/schema',
|
|
1521
|
-
definitions: {
|
|
1522
|
-
user: {
|
|
1523
|
-
$anchor: 'user',
|
|
1524
|
-
type: 'object',
|
|
1525
|
-
properties: {
|
|
1526
|
-
name: { type: 'string' },
|
|
1527
|
-
},
|
|
1528
|
-
},
|
|
1529
|
-
admin: {
|
|
1530
|
-
$anchor: 'admin',
|
|
1531
|
-
type: 'object',
|
|
1532
|
-
properties: {
|
|
1533
|
-
permissions: { type: 'array' },
|
|
1534
|
-
},
|
|
1535
|
-
},
|
|
1536
|
-
},
|
|
1537
|
-
userRef: {
|
|
1538
|
-
$ref: 'https://example.com/schema#user',
|
|
1539
|
-
},
|
|
1540
|
-
adminRef: {
|
|
1541
|
-
$ref: 'https://example.com/schema#admin',
|
|
1542
|
-
},
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
const result = createMagicProxy(input)
|
|
1546
|
-
|
|
1547
|
-
expect(result.userRef['$ref-value']).toEqual({
|
|
1548
|
-
$anchor: 'user',
|
|
1549
|
-
type: 'object',
|
|
1550
|
-
properties: {
|
|
1551
|
-
name: { type: 'string' },
|
|
1552
|
-
},
|
|
1553
|
-
})
|
|
1554
|
-
|
|
1555
|
-
expect(result.adminRef['$ref-value']).toEqual({
|
|
1556
|
-
$anchor: 'admin',
|
|
1557
|
-
type: 'object',
|
|
1558
|
-
properties: {
|
|
1559
|
-
permissions: { type: 'array' },
|
|
1560
|
-
},
|
|
1561
|
-
})
|
|
1562
|
-
})
|
|
1563
|
-
|
|
1564
|
-
it('handles external references to $id schemas', () => {
|
|
1565
|
-
const input = {
|
|
1566
|
-
$id: 'https://example.com/schema',
|
|
1567
|
-
definitions: {
|
|
1568
|
-
external: {
|
|
1569
|
-
$id: 'https://external.com/schema',
|
|
1570
|
-
type: 'object',
|
|
1571
|
-
properties: {
|
|
1572
|
-
externalProp: { type: 'string' },
|
|
1573
|
-
},
|
|
1574
|
-
},
|
|
1575
|
-
},
|
|
1576
|
-
externalRef: {
|
|
1577
|
-
$ref: 'https://external.com/schema',
|
|
1578
|
-
},
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
const result = createMagicProxy(input)
|
|
1582
|
-
|
|
1583
|
-
expect(result.externalRef['$ref-value']).toEqual({
|
|
1584
|
-
$id: 'https://external.com/schema',
|
|
1585
|
-
type: 'object',
|
|
1586
|
-
properties: {
|
|
1587
|
-
externalProp: { type: 'string' },
|
|
1588
|
-
},
|
|
1589
|
-
})
|
|
1590
|
-
})
|
|
1591
|
-
|
|
1592
|
-
it('handles references in arrays with $id and $anchor', () => {
|
|
1593
|
-
const input = {
|
|
1594
|
-
$id: 'https://example.com/schema',
|
|
1595
|
-
definitions: {
|
|
1596
|
-
item: {
|
|
1597
|
-
$anchor: 'item-schema',
|
|
1598
|
-
type: 'object',
|
|
1599
|
-
properties: {
|
|
1600
|
-
id: { type: 'string' },
|
|
1601
|
-
},
|
|
1602
|
-
},
|
|
1603
|
-
},
|
|
1604
|
-
items: [{ $ref: 'https://example.com/schema#item-schema' }, { $ref: 'https://example.com/schema#item-schema' }],
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
const result = createMagicProxy(input)
|
|
1608
|
-
|
|
1609
|
-
expect(result.items[0]['$ref-value']).toEqual({
|
|
1610
|
-
$anchor: 'item-schema',
|
|
1611
|
-
type: 'object',
|
|
1612
|
-
properties: {
|
|
1613
|
-
id: { type: 'string' },
|
|
1614
|
-
},
|
|
1615
|
-
})
|
|
1616
|
-
|
|
1617
|
-
expect(result.items[1]['$ref-value']).toEqual({
|
|
1618
|
-
$anchor: 'item-schema',
|
|
1619
|
-
type: 'object',
|
|
1620
|
-
properties: {
|
|
1621
|
-
id: { type: 'string' },
|
|
1622
|
-
},
|
|
1623
|
-
})
|
|
1624
|
-
})
|
|
1625
|
-
|
|
1626
|
-
it('preserves $ref information when resolving $id references', () => {
|
|
1627
|
-
const input = {
|
|
1628
|
-
$id: 'https://example.com/schema',
|
|
1629
|
-
definitions: {
|
|
1630
|
-
user: {
|
|
1631
|
-
$id: 'https://example.com/user',
|
|
1632
|
-
type: 'object',
|
|
1633
|
-
properties: {
|
|
1634
|
-
name: { type: 'string' },
|
|
1635
|
-
},
|
|
1636
|
-
},
|
|
1637
|
-
},
|
|
1638
|
-
userRef: {
|
|
1639
|
-
$ref: 'https://example.com/user',
|
|
1640
|
-
},
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
|
-
const result = createMagicProxy(input)
|
|
1644
|
-
|
|
1645
|
-
expect(result.userRef).toEqual({
|
|
1646
|
-
$ref: 'https://example.com/user',
|
|
1647
|
-
'$ref-value': {
|
|
1648
|
-
$id: 'https://example.com/user',
|
|
1649
|
-
type: 'object',
|
|
1650
|
-
properties: {
|
|
1651
|
-
name: { type: 'string' },
|
|
1652
|
-
},
|
|
1653
|
-
},
|
|
1654
|
-
})
|
|
1655
|
-
})
|
|
1656
|
-
|
|
1657
|
-
it('preserves $ref information when resolving $anchor references', () => {
|
|
1658
|
-
const input = {
|
|
1659
|
-
$id: 'https://example.com/schema',
|
|
1660
|
-
definitions: {
|
|
1661
|
-
user: {
|
|
1662
|
-
$anchor: 'user-schema',
|
|
1663
|
-
type: 'object',
|
|
1664
|
-
properties: {
|
|
1665
|
-
email: { type: 'string' },
|
|
1666
|
-
},
|
|
1667
|
-
},
|
|
1668
|
-
},
|
|
1669
|
-
userRef: {
|
|
1670
|
-
$ref: 'https://example.com/schema#user-schema',
|
|
1671
|
-
},
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
const result = createMagicProxy(input)
|
|
1675
|
-
|
|
1676
|
-
expect(result.userRef).toEqual({
|
|
1677
|
-
$ref: 'https://example.com/schema#user-schema',
|
|
1678
|
-
'$ref-value': {
|
|
1679
|
-
$anchor: 'user-schema',
|
|
1680
|
-
type: 'object',
|
|
1681
|
-
properties: {
|
|
1682
|
-
email: { type: 'string' },
|
|
1683
|
-
},
|
|
1684
|
-
},
|
|
1685
|
-
})
|
|
1686
|
-
})
|
|
1687
|
-
|
|
1688
|
-
it('handles deeply nested $id and $anchor references', () => {
|
|
1689
|
-
const input = {
|
|
1690
|
-
$id: 'https://example.com/root',
|
|
1691
|
-
api: {
|
|
1692
|
-
$id: 'https://example.com/api',
|
|
1693
|
-
v1: {
|
|
1694
|
-
schemas: {
|
|
1695
|
-
user: {
|
|
1696
|
-
$id: 'https://example.com/user',
|
|
1697
|
-
$anchor: 'user-schema',
|
|
1698
|
-
type: 'object',
|
|
1699
|
-
properties: {
|
|
1700
|
-
profile: {
|
|
1701
|
-
$anchor: 'profile-schema',
|
|
1702
|
-
type: 'object',
|
|
1703
|
-
properties: {
|
|
1704
|
-
name: { type: 'string' },
|
|
1705
|
-
},
|
|
1706
|
-
},
|
|
1707
|
-
},
|
|
1708
|
-
},
|
|
1709
|
-
},
|
|
1710
|
-
},
|
|
1711
|
-
},
|
|
1712
|
-
userRef: {
|
|
1713
|
-
$ref: 'https://example.com/user',
|
|
1714
|
-
},
|
|
1715
|
-
profileRef: {
|
|
1716
|
-
$ref: 'https://example.com/user#profile-schema',
|
|
1717
|
-
},
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
|
-
const result = createMagicProxy(input)
|
|
1721
|
-
|
|
1722
|
-
expect(result.userRef['$ref-value']).toEqual({
|
|
1723
|
-
$id: 'https://example.com/user',
|
|
1724
|
-
$anchor: 'user-schema',
|
|
1725
|
-
type: 'object',
|
|
1726
|
-
properties: {
|
|
1727
|
-
profile: {
|
|
1728
|
-
$anchor: 'profile-schema',
|
|
1729
|
-
type: 'object',
|
|
1730
|
-
properties: {
|
|
1731
|
-
name: { type: 'string' },
|
|
1732
|
-
},
|
|
1733
|
-
},
|
|
1734
|
-
},
|
|
1735
|
-
})
|
|
1736
|
-
|
|
1737
|
-
expect(result.profileRef['$ref-value']).toEqual({
|
|
1738
|
-
$anchor: 'profile-schema',
|
|
1739
|
-
type: 'object',
|
|
1740
|
-
properties: {
|
|
1741
|
-
name: { type: 'string' },
|
|
1742
|
-
},
|
|
1743
|
-
})
|
|
1744
|
-
})
|
|
1745
|
-
})
|
|
1746
|
-
|
|
1747
|
-
describe('setting on $id and $anchor properties', () => {
|
|
1748
|
-
it('should allow writing on an $id property', () => {
|
|
1749
|
-
const input = {
|
|
1750
|
-
$id: 'https://example.com/schema',
|
|
1751
|
-
definitions: {
|
|
1752
|
-
user: {
|
|
1753
|
-
$id: 'https://example.com/user',
|
|
1754
|
-
type: 'object',
|
|
1755
|
-
properties: {
|
|
1756
|
-
name: { type: 'string' },
|
|
1757
|
-
},
|
|
1758
|
-
},
|
|
1759
|
-
},
|
|
1760
|
-
a: {
|
|
1761
|
-
$ref: 'https://example.com/user',
|
|
1762
|
-
},
|
|
1763
|
-
}
|
|
1764
|
-
|
|
1765
|
-
const proxy = createMagicProxy(input)
|
|
1766
|
-
|
|
1767
|
-
proxy.a['$ref-value'] = {
|
|
1768
|
-
message: 'I rewrote the user schema',
|
|
1769
|
-
}
|
|
1770
|
-
|
|
1771
|
-
expect(proxy.definitions.user).toEqual({
|
|
1772
|
-
'message': 'I rewrote the user schema',
|
|
1773
|
-
})
|
|
1774
|
-
})
|
|
1775
|
-
|
|
1776
|
-
it('should allow writing on an $anchor property', () => {
|
|
1777
|
-
const input = {
|
|
1778
|
-
$id: 'https://example.com/schema',
|
|
1779
|
-
definitions: {
|
|
1780
|
-
user: {
|
|
1781
|
-
$id: 'https://example.com/user',
|
|
1782
|
-
$anchor: 'user-schema',
|
|
1783
|
-
type: 'object',
|
|
1784
|
-
properties: {
|
|
1785
|
-
name: { type: 'string' },
|
|
1786
|
-
},
|
|
1787
|
-
},
|
|
1788
|
-
},
|
|
1789
|
-
a: {
|
|
1790
|
-
$ref: 'https://example.com/user#user-schema',
|
|
1791
|
-
},
|
|
1792
|
-
}
|
|
1793
|
-
|
|
1794
|
-
const proxy = createMagicProxy(input)
|
|
1795
|
-
|
|
1796
|
-
proxy.a['$ref-value'] = {
|
|
1797
|
-
message: 'I rewrote the user schema',
|
|
1798
|
-
}
|
|
1799
|
-
|
|
1800
|
-
expect(proxy.definitions.user).toEqual({
|
|
1801
|
-
'message': 'I rewrote the user schema',
|
|
1802
|
-
})
|
|
1803
|
-
})
|
|
1804
|
-
|
|
1805
|
-
it('should allow writing on a top level $anchor property', () => {
|
|
1806
|
-
const input = {
|
|
1807
|
-
definitions: {
|
|
1808
|
-
user: {
|
|
1809
|
-
$anchor: 'user-schema',
|
|
1810
|
-
type: 'object',
|
|
1811
|
-
properties: {
|
|
1812
|
-
name: { type: 'string' },
|
|
1813
|
-
},
|
|
1814
|
-
},
|
|
1815
|
-
},
|
|
1816
|
-
a: {
|
|
1817
|
-
$ref: '#user-schema',
|
|
1818
|
-
},
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
|
-
const proxy = createMagicProxy(input)
|
|
1822
|
-
|
|
1823
|
-
proxy.a['$ref-value'] = {
|
|
1824
|
-
message: 'I rewrote the user schema',
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
|
-
expect(proxy.definitions.user).toEqual({
|
|
1828
|
-
'message': 'I rewrote the user schema',
|
|
1829
|
-
})
|
|
1830
|
-
})
|
|
1831
|
-
})
|
|
1832
|
-
|
|
1833
|
-
describe('hide __scalar_ properties', () => {
|
|
1834
|
-
it('should hide properties starting with __scalar_ from direct access', () => {
|
|
1835
|
-
const input = {
|
|
1836
|
-
public: 'visible',
|
|
1837
|
-
__scalar_private: 'hidden',
|
|
1838
|
-
__scalar_internal: 'also hidden',
|
|
1839
|
-
normal_underscore: 'visible with underscore in middle',
|
|
1840
|
-
_id: 'legitimate user property', // This should NOT be hidden
|
|
1841
|
-
_type: 'another legitimate property', // This should NOT be hidden
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
const result = createMagicProxy(input)
|
|
1845
|
-
|
|
1846
|
-
expect(result.public).toBe('visible')
|
|
1847
|
-
expect(result.__scalar_private).toBe(undefined)
|
|
1848
|
-
expect(result.__scalar_internal).toBe(undefined)
|
|
1849
|
-
expect(result.normal_underscore).toBe('visible with underscore in middle')
|
|
1850
|
-
expect(result._id).toBe('legitimate user property') // Should be visible
|
|
1851
|
-
expect(result._type).toBe('another legitimate property') // Should be visible
|
|
1852
|
-
})
|
|
1853
|
-
|
|
1854
|
-
it('should hide __scalar_ properties from "in" operator', () => {
|
|
1855
|
-
const input = {
|
|
1856
|
-
public: 'visible',
|
|
1857
|
-
__scalar_private: 'hidden',
|
|
1858
|
-
__scalar_internal: 'also hidden',
|
|
1859
|
-
}
|
|
1860
|
-
|
|
1861
|
-
const result = createMagicProxy(input)
|
|
1862
|
-
|
|
1863
|
-
expect('public' in result).toBe(true)
|
|
1864
|
-
expect('__scalar_private' in result).toBe(false)
|
|
1865
|
-
expect('__scalar_internal' in result).toBe(false)
|
|
1866
|
-
})
|
|
1867
|
-
|
|
1868
|
-
it('should exclude __scalar_ properties from Object.keys enumeration', () => {
|
|
1869
|
-
const input = {
|
|
1870
|
-
public: 'visible',
|
|
1871
|
-
__scalar_private: 'hidden',
|
|
1872
|
-
__scalar_internal: 'also hidden',
|
|
1873
|
-
another: 'visible',
|
|
1874
|
-
}
|
|
1875
|
-
|
|
1876
|
-
const result = createMagicProxy(input)
|
|
1877
|
-
const keys = Object.keys(result)
|
|
1878
|
-
|
|
1879
|
-
expect(keys).toContain('public')
|
|
1880
|
-
expect(keys).toContain('another')
|
|
1881
|
-
expect(keys).not.toContain('__scalar_private')
|
|
1882
|
-
expect(keys).not.toContain('__scalar_internal')
|
|
1883
|
-
})
|
|
1884
|
-
|
|
1885
|
-
it('should hide __scalar_ properties from getOwnPropertyDescriptor', () => {
|
|
1886
|
-
const input = {
|
|
1887
|
-
public: 'visible',
|
|
1888
|
-
__scalar_private: 'hidden',
|
|
1889
|
-
}
|
|
1890
|
-
|
|
1891
|
-
const result = createMagicProxy(input)
|
|
1892
|
-
|
|
1893
|
-
expect(Object.getOwnPropertyDescriptor(result, 'public')).toBeDefined()
|
|
1894
|
-
expect(Object.getOwnPropertyDescriptor(result, '__scalar_private')).toBe(undefined)
|
|
1895
|
-
})
|
|
1896
|
-
|
|
1897
|
-
it('should hide __scalar_ properties in nested objects', () => {
|
|
1898
|
-
const input = {
|
|
1899
|
-
nested: {
|
|
1900
|
-
public: 'visible',
|
|
1901
|
-
__scalar_private: 'hidden',
|
|
1902
|
-
deeper: {
|
|
1903
|
-
__scalar_alsoHidden: 'secret',
|
|
1904
|
-
visible: 'shown',
|
|
1905
|
-
},
|
|
1906
|
-
},
|
|
1907
|
-
__scalar_topLevel: 'hidden',
|
|
1908
|
-
}
|
|
1909
|
-
|
|
1910
|
-
const result = createMagicProxy(input)
|
|
1911
|
-
|
|
1912
|
-
expect(result.__scalar_topLevel).toBe(undefined)
|
|
1913
|
-
expect(result.nested.public).toBe('visible')
|
|
1914
|
-
expect(result.nested.__scalar_private).toBe(undefined)
|
|
1915
|
-
expect(result.nested.deeper.__scalar_alsoHidden).toBe(undefined)
|
|
1916
|
-
expect(result.nested.deeper.visible).toBe('shown')
|
|
1917
|
-
})
|
|
1918
|
-
|
|
1919
|
-
it('should work with arrays containing objects with __scalar_ properties', () => {
|
|
1920
|
-
const input = {
|
|
1921
|
-
items: [
|
|
1922
|
-
{ public: 'item1', __scalar_private: 'hidden1' },
|
|
1923
|
-
{ public: 'item2', __scalar_private: 'hidden2' },
|
|
1924
|
-
],
|
|
1925
|
-
}
|
|
1926
|
-
|
|
1927
|
-
const result = createMagicProxy(input)
|
|
1928
|
-
|
|
1929
|
-
expect(result.items[0].public).toBe('item1')
|
|
1930
|
-
expect(result.items[0].__scalar_private).toBe(undefined)
|
|
1931
|
-
expect(result.items[1].public).toBe('item2')
|
|
1932
|
-
expect(result.items[1].__scalar_private).toBe(undefined)
|
|
1933
|
-
})
|
|
1934
|
-
|
|
1935
|
-
it('should still allow refs to work with __scalar_ hiding', () => {
|
|
1936
|
-
const input = {
|
|
1937
|
-
definitions: {
|
|
1938
|
-
example: {
|
|
1939
|
-
value: 'hello',
|
|
1940
|
-
__scalar_internal: 'hidden',
|
|
1941
|
-
},
|
|
1942
|
-
},
|
|
1943
|
-
__scalar_hiddenRef: { $ref: '#/definitions/example' },
|
|
1944
|
-
publicRef: { $ref: '#/definitions/example' },
|
|
1945
|
-
}
|
|
1946
|
-
|
|
1947
|
-
const result = createMagicProxy(input)
|
|
1948
|
-
|
|
1949
|
-
// __scalar_ property should be hidden
|
|
1950
|
-
expect(result.__scalar_hiddenRef).toBe(undefined)
|
|
1951
|
-
|
|
1952
|
-
// Public ref should work normally
|
|
1953
|
-
expect(result.publicRef['$ref-value'].value).toBe('hello')
|
|
1954
|
-
|
|
1955
|
-
// __scalar_ properties in referenced objects should be hidden
|
|
1956
|
-
expect(result.publicRef['$ref-value'].__scalar_internal).toBe(undefined)
|
|
1957
|
-
})
|
|
1958
|
-
|
|
1959
|
-
it('preserves regular underscore properties', () => {
|
|
1960
|
-
const input = {
|
|
1961
|
-
_id: 'user123',
|
|
1962
|
-
user_name: 'john',
|
|
1963
|
-
__version: '1.0',
|
|
1964
|
-
normal_property: 'visible',
|
|
1965
|
-
}
|
|
1966
|
-
|
|
1967
|
-
const result = createMagicProxy(input)
|
|
1968
|
-
|
|
1969
|
-
// Regular underscore properties should be visible
|
|
1970
|
-
expect(result._id).toBe('user123')
|
|
1971
|
-
expect(result.user_name).toBe('john')
|
|
1972
|
-
expect(result.__version).toBe('1.0')
|
|
1973
|
-
expect(result.normal_property).toBe('visible')
|
|
1974
|
-
|
|
1975
|
-
// Should be included in enumeration and "in" checks
|
|
1976
|
-
expect('_id' in result).toBe(true)
|
|
1977
|
-
expect('user_name' in result).toBe(true)
|
|
1978
|
-
expect('__version' in result).toBe(true)
|
|
1979
|
-
|
|
1980
|
-
const keys = Object.keys(result)
|
|
1981
|
-
expect(keys).toContain('_id')
|
|
1982
|
-
expect(keys).toContain('user_name')
|
|
1983
|
-
expect(keys).toContain('__version')
|
|
1984
|
-
expect(keys).toContain('normal_property')
|
|
1985
|
-
})
|
|
1986
|
-
})
|
|
1987
|
-
})
|