@scalar/json-magic 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +22 -0
- package/dist/bundle/bundle.d.ts +1 -0
- package/dist/bundle/bundle.d.ts.map +1 -1
- package/dist/bundle/bundle.js +3 -3
- package/dist/bundle/bundle.js.map +2 -2
- package/dist/bundle/plugins/fetch-urls/index.d.ts.map +1 -1
- package/dist/bundle/plugins/fetch-urls/index.js +8 -1
- package/dist/bundle/plugins/fetch-urls/index.js.map +2 -2
- package/dist/bundle/plugins/parse-json/index.d.ts.map +1 -1
- package/dist/bundle/plugins/parse-json/index.js +7 -6
- package/dist/bundle/plugins/parse-json/index.js.map +2 -2
- package/dist/bundle/plugins/parse-yaml/index.d.ts.map +1 -1
- package/dist/bundle/plugins/parse-yaml/index.js +7 -6
- package/dist/bundle/plugins/parse-yaml/index.js.map +2 -2
- package/dist/bundle/plugins/read-files/index.d.ts.map +1 -1
- package/dist/bundle/plugins/read-files/index.js +2 -1
- package/dist/bundle/plugins/read-files/index.js.map +2 -2
- package/dist/diff/diff.d.ts.map +1 -1
- package/dist/diff/diff.js.map +2 -2
- package/dist/diff/utils.d.ts.map +1 -1
- package/dist/diff/utils.js.map +2 -2
- package/dist/magic-proxy/proxy.d.ts +7 -6
- package/dist/magic-proxy/proxy.d.ts.map +1 -1
- package/dist/magic-proxy/proxy.js +21 -11
- package/dist/magic-proxy/proxy.js.map +2 -2
- package/package.json +4 -4
- package/src/bundle/bundle.test.ts +278 -259
- package/src/bundle/bundle.ts +4 -4
- package/src/bundle/plugins/fetch-urls/index.test.ts +21 -24
- package/src/bundle/plugins/fetch-urls/index.ts +10 -0
- package/src/bundle/plugins/parse-json/index.test.ts +3 -1
- package/src/bundle/plugins/parse-json/index.ts +7 -6
- package/src/bundle/plugins/parse-yaml/index.test.ts +3 -1
- package/src/bundle/plugins/parse-yaml/index.ts +7 -6
- package/src/bundle/plugins/read-files/index.test.ts +4 -3
- package/src/bundle/plugins/read-files/index.ts +1 -0
- package/src/bundle/value-generator.test.ts +7 -8
- package/src/dereference/dereference.test.ts +6 -6
- package/src/diff/diff.ts +0 -1
- package/src/diff/utils.test.ts +2 -2
- package/src/diff/utils.ts +0 -2
- package/src/helpers/escape-json-pointer.test.ts +1 -1
- package/src/helpers/unescape-json-pointer.test.ts +1 -1
- package/src/magic-proxy/proxy.test.ts +108 -76
- package/src/magic-proxy/proxy.ts +34 -20
|
@@ -1154,41 +1154,41 @@ describe('createMagicProxy', () => {
|
|
|
1154
1154
|
})
|
|
1155
1155
|
|
|
1156
1156
|
describe('show underscore properties when specified', () => {
|
|
1157
|
-
it('should not hide properties starting with
|
|
1157
|
+
it('should not hide properties starting with __scalar_ from direct access', () => {
|
|
1158
1158
|
const input = {
|
|
1159
1159
|
public: 'visible',
|
|
1160
|
-
|
|
1161
|
-
|
|
1160
|
+
__scalar_private: 'hidden',
|
|
1161
|
+
__scalar_internal: 'also hidden',
|
|
1162
1162
|
normal_underscore: 'visible with underscore in middle',
|
|
1163
1163
|
}
|
|
1164
1164
|
|
|
1165
1165
|
const result = createMagicProxy(input, { showInternal: true })
|
|
1166
1166
|
|
|
1167
1167
|
expect(result.public).toBe('visible')
|
|
1168
|
-
expect(result.
|
|
1169
|
-
expect(result.
|
|
1168
|
+
expect(result.__scalar_private).toBe('hidden')
|
|
1169
|
+
expect(result.__scalar_internal).toBe('also hidden')
|
|
1170
1170
|
expect(result.normal_underscore).toBe('visible with underscore in middle')
|
|
1171
1171
|
})
|
|
1172
1172
|
|
|
1173
|
-
it('should not hide
|
|
1173
|
+
it('should not hide __scalar_ properties from "in" operator', () => {
|
|
1174
1174
|
const input = {
|
|
1175
1175
|
public: 'visible',
|
|
1176
|
-
|
|
1177
|
-
|
|
1176
|
+
__scalar_private: 'hidden',
|
|
1177
|
+
__scalar_internal: 'also hidden',
|
|
1178
1178
|
}
|
|
1179
1179
|
|
|
1180
1180
|
const result = createMagicProxy(input, { showInternal: true })
|
|
1181
1181
|
|
|
1182
1182
|
expect('public' in result).toBe(true)
|
|
1183
|
-
expect('
|
|
1184
|
-
expect('
|
|
1183
|
+
expect('__scalar_private' in result).toBe(true)
|
|
1184
|
+
expect('__scalar_internal' in result).toBe(true)
|
|
1185
1185
|
})
|
|
1186
1186
|
|
|
1187
|
-
it('should not exclude
|
|
1187
|
+
it('should not exclude __scalar_ properties from Object.keys enumeration', () => {
|
|
1188
1188
|
const input = {
|
|
1189
1189
|
public: 'visible',
|
|
1190
|
-
|
|
1191
|
-
|
|
1190
|
+
__scalar_private: 'hidden',
|
|
1191
|
+
__scalar_internal: 'also hidden',
|
|
1192
1192
|
another: 'visible',
|
|
1193
1193
|
}
|
|
1194
1194
|
|
|
@@ -1197,79 +1197,79 @@ describe('createMagicProxy', () => {
|
|
|
1197
1197
|
|
|
1198
1198
|
expect(keys).toContain('public')
|
|
1199
1199
|
expect(keys).toContain('another')
|
|
1200
|
-
expect(keys).toContain('
|
|
1201
|
-
expect(keys).toContain('
|
|
1200
|
+
expect(keys).toContain('__scalar_private')
|
|
1201
|
+
expect(keys).toContain('__scalar_internal')
|
|
1202
1202
|
})
|
|
1203
1203
|
|
|
1204
|
-
it('should not hide
|
|
1204
|
+
it('should not hide __scalar_ properties from getOwnPropertyDescriptor', () => {
|
|
1205
1205
|
const input = {
|
|
1206
1206
|
public: 'visible',
|
|
1207
|
-
|
|
1207
|
+
__scalar_private: 'hidden',
|
|
1208
1208
|
}
|
|
1209
1209
|
|
|
1210
1210
|
const result = createMagicProxy(input, { showInternal: true })
|
|
1211
1211
|
|
|
1212
1212
|
expect(Object.getOwnPropertyDescriptor(result, 'public')).toBeDefined()
|
|
1213
|
-
expect(Object.getOwnPropertyDescriptor(result, '
|
|
1213
|
+
expect(Object.getOwnPropertyDescriptor(result, '__scalar_private')).toBeDefined()
|
|
1214
1214
|
})
|
|
1215
1215
|
|
|
1216
|
-
it('should not hide
|
|
1216
|
+
it('should not hide __scalar_ properties in nested objects', () => {
|
|
1217
1217
|
const input = {
|
|
1218
1218
|
nested: {
|
|
1219
1219
|
public: 'visible',
|
|
1220
|
-
|
|
1220
|
+
__scalar_private: 'hidden',
|
|
1221
1221
|
deeper: {
|
|
1222
|
-
|
|
1222
|
+
__scalar_alsoHidden: 'secret',
|
|
1223
1223
|
visible: 'shown',
|
|
1224
1224
|
},
|
|
1225
1225
|
},
|
|
1226
|
-
|
|
1226
|
+
__scalar_topLevel: 'hidden',
|
|
1227
1227
|
}
|
|
1228
1228
|
|
|
1229
1229
|
const result = createMagicProxy(input, { showInternal: true })
|
|
1230
1230
|
|
|
1231
|
-
expect(result.
|
|
1231
|
+
expect(result.__scalar_topLevel).toBe('hidden')
|
|
1232
1232
|
expect(result.nested.public).toBe('visible')
|
|
1233
|
-
expect(result.nested.
|
|
1234
|
-
expect(result.nested.deeper.
|
|
1233
|
+
expect(result.nested.__scalar_private).toBe('hidden')
|
|
1234
|
+
expect(result.nested.deeper.__scalar_alsoHidden).toBe('secret')
|
|
1235
1235
|
expect(result.nested.deeper.visible).toBe('shown')
|
|
1236
1236
|
})
|
|
1237
1237
|
|
|
1238
|
-
it('should show
|
|
1238
|
+
it('should show __scalar_ properties with arrays containing objects with __scalar_ properties', () => {
|
|
1239
1239
|
const input = {
|
|
1240
1240
|
items: [
|
|
1241
|
-
{ public: 'item1',
|
|
1242
|
-
{ public: 'item2',
|
|
1241
|
+
{ public: 'item1', __scalar_private: 'hidden1' },
|
|
1242
|
+
{ public: 'item2', __scalar_private: 'hidden2' },
|
|
1243
1243
|
],
|
|
1244
1244
|
}
|
|
1245
1245
|
|
|
1246
1246
|
const result = createMagicProxy(input, { showInternal: true })
|
|
1247
1247
|
|
|
1248
1248
|
expect(result.items[0].public).toBe('item1')
|
|
1249
|
-
expect(result.items[0].
|
|
1249
|
+
expect(result.items[0].__scalar_private).toBe('hidden1')
|
|
1250
1250
|
expect(result.items[1].public).toBe('item2')
|
|
1251
|
-
expect(result.items[1].
|
|
1251
|
+
expect(result.items[1].__scalar_private).toBe('hidden2')
|
|
1252
1252
|
})
|
|
1253
1253
|
|
|
1254
|
-
it('should show
|
|
1254
|
+
it('should show __scalar_ ref properties', () => {
|
|
1255
1255
|
const input = {
|
|
1256
1256
|
definitions: {
|
|
1257
1257
|
example: {
|
|
1258
1258
|
value: 'hello',
|
|
1259
|
-
|
|
1259
|
+
__scalar_internal: 'hidden',
|
|
1260
1260
|
},
|
|
1261
1261
|
},
|
|
1262
|
-
|
|
1262
|
+
__scalar_hiddenRef: { $ref: '#/definitions/example' },
|
|
1263
1263
|
publicRef: { $ref: '#/definitions/example' },
|
|
1264
1264
|
}
|
|
1265
1265
|
|
|
1266
1266
|
const result = createMagicProxy(input, { showInternal: true })
|
|
1267
1267
|
|
|
1268
|
-
//
|
|
1269
|
-
expect(result.
|
|
1268
|
+
// __scalar_ property should be hidden
|
|
1269
|
+
expect(result.__scalar_hiddenRef).toEqual({
|
|
1270
1270
|
'$ref': '#/definitions/example',
|
|
1271
1271
|
'$ref-value': {
|
|
1272
|
-
'
|
|
1272
|
+
'__scalar_internal': 'hidden',
|
|
1273
1273
|
'value': 'hello',
|
|
1274
1274
|
},
|
|
1275
1275
|
})
|
|
@@ -1277,8 +1277,8 @@ describe('createMagicProxy', () => {
|
|
|
1277
1277
|
// Public ref should work normally
|
|
1278
1278
|
expect(result.publicRef['$ref-value'].value).toBe('hello')
|
|
1279
1279
|
|
|
1280
|
-
//
|
|
1281
|
-
expect(result.publicRef['$ref-value'].
|
|
1280
|
+
// __scalar_ properties in referenced objects should be hidden
|
|
1281
|
+
expect(result.publicRef['$ref-value'].__scalar_internal).toBe('hidden')
|
|
1282
1282
|
})
|
|
1283
1283
|
})
|
|
1284
1284
|
|
|
@@ -1830,42 +1830,46 @@ describe('createMagicProxy', () => {
|
|
|
1830
1830
|
})
|
|
1831
1831
|
})
|
|
1832
1832
|
|
|
1833
|
-
describe('hide
|
|
1834
|
-
it('should hide properties starting with
|
|
1833
|
+
describe('hide __scalar_ properties', () => {
|
|
1834
|
+
it('should hide properties starting with __scalar_ from direct access', () => {
|
|
1835
1835
|
const input = {
|
|
1836
1836
|
public: 'visible',
|
|
1837
|
-
|
|
1838
|
-
|
|
1837
|
+
__scalar_private: 'hidden',
|
|
1838
|
+
__scalar_internal: 'also hidden',
|
|
1839
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
|
|
1840
1842
|
}
|
|
1841
1843
|
|
|
1842
1844
|
const result = createMagicProxy(input)
|
|
1843
1845
|
|
|
1844
1846
|
expect(result.public).toBe('visible')
|
|
1845
|
-
expect(result.
|
|
1846
|
-
expect(result.
|
|
1847
|
+
expect(result.__scalar_private).toBe(undefined)
|
|
1848
|
+
expect(result.__scalar_internal).toBe(undefined)
|
|
1847
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
|
|
1848
1852
|
})
|
|
1849
1853
|
|
|
1850
|
-
it('should hide
|
|
1854
|
+
it('should hide __scalar_ properties from "in" operator', () => {
|
|
1851
1855
|
const input = {
|
|
1852
1856
|
public: 'visible',
|
|
1853
|
-
|
|
1854
|
-
|
|
1857
|
+
__scalar_private: 'hidden',
|
|
1858
|
+
__scalar_internal: 'also hidden',
|
|
1855
1859
|
}
|
|
1856
1860
|
|
|
1857
1861
|
const result = createMagicProxy(input)
|
|
1858
1862
|
|
|
1859
1863
|
expect('public' in result).toBe(true)
|
|
1860
|
-
expect('
|
|
1861
|
-
expect('
|
|
1864
|
+
expect('__scalar_private' in result).toBe(false)
|
|
1865
|
+
expect('__scalar_internal' in result).toBe(false)
|
|
1862
1866
|
})
|
|
1863
1867
|
|
|
1864
|
-
it('should exclude
|
|
1868
|
+
it('should exclude __scalar_ properties from Object.keys enumeration', () => {
|
|
1865
1869
|
const input = {
|
|
1866
1870
|
public: 'visible',
|
|
1867
|
-
|
|
1868
|
-
|
|
1871
|
+
__scalar_private: 'hidden',
|
|
1872
|
+
__scalar_internal: 'also hidden',
|
|
1869
1873
|
another: 'visible',
|
|
1870
1874
|
}
|
|
1871
1875
|
|
|
@@ -1874,82 +1878,110 @@ describe('createMagicProxy', () => {
|
|
|
1874
1878
|
|
|
1875
1879
|
expect(keys).toContain('public')
|
|
1876
1880
|
expect(keys).toContain('another')
|
|
1877
|
-
expect(keys).not.toContain('
|
|
1878
|
-
expect(keys).not.toContain('
|
|
1881
|
+
expect(keys).not.toContain('__scalar_private')
|
|
1882
|
+
expect(keys).not.toContain('__scalar_internal')
|
|
1879
1883
|
})
|
|
1880
1884
|
|
|
1881
|
-
it('should hide
|
|
1885
|
+
it('should hide __scalar_ properties from getOwnPropertyDescriptor', () => {
|
|
1882
1886
|
const input = {
|
|
1883
1887
|
public: 'visible',
|
|
1884
|
-
|
|
1888
|
+
__scalar_private: 'hidden',
|
|
1885
1889
|
}
|
|
1886
1890
|
|
|
1887
1891
|
const result = createMagicProxy(input)
|
|
1888
1892
|
|
|
1889
1893
|
expect(Object.getOwnPropertyDescriptor(result, 'public')).toBeDefined()
|
|
1890
|
-
expect(Object.getOwnPropertyDescriptor(result, '
|
|
1894
|
+
expect(Object.getOwnPropertyDescriptor(result, '__scalar_private')).toBe(undefined)
|
|
1891
1895
|
})
|
|
1892
1896
|
|
|
1893
|
-
it('should hide
|
|
1897
|
+
it('should hide __scalar_ properties in nested objects', () => {
|
|
1894
1898
|
const input = {
|
|
1895
1899
|
nested: {
|
|
1896
1900
|
public: 'visible',
|
|
1897
|
-
|
|
1901
|
+
__scalar_private: 'hidden',
|
|
1898
1902
|
deeper: {
|
|
1899
|
-
|
|
1903
|
+
__scalar_alsoHidden: 'secret',
|
|
1900
1904
|
visible: 'shown',
|
|
1901
1905
|
},
|
|
1902
1906
|
},
|
|
1903
|
-
|
|
1907
|
+
__scalar_topLevel: 'hidden',
|
|
1904
1908
|
}
|
|
1905
1909
|
|
|
1906
1910
|
const result = createMagicProxy(input)
|
|
1907
1911
|
|
|
1908
|
-
expect(result.
|
|
1912
|
+
expect(result.__scalar_topLevel).toBe(undefined)
|
|
1909
1913
|
expect(result.nested.public).toBe('visible')
|
|
1910
|
-
expect(result.nested.
|
|
1911
|
-
expect(result.nested.deeper.
|
|
1914
|
+
expect(result.nested.__scalar_private).toBe(undefined)
|
|
1915
|
+
expect(result.nested.deeper.__scalar_alsoHidden).toBe(undefined)
|
|
1912
1916
|
expect(result.nested.deeper.visible).toBe('shown')
|
|
1913
1917
|
})
|
|
1914
1918
|
|
|
1915
|
-
it('should work with arrays containing objects with
|
|
1919
|
+
it('should work with arrays containing objects with __scalar_ properties', () => {
|
|
1916
1920
|
const input = {
|
|
1917
1921
|
items: [
|
|
1918
|
-
{ public: 'item1',
|
|
1919
|
-
{ public: 'item2',
|
|
1922
|
+
{ public: 'item1', __scalar_private: 'hidden1' },
|
|
1923
|
+
{ public: 'item2', __scalar_private: 'hidden2' },
|
|
1920
1924
|
],
|
|
1921
1925
|
}
|
|
1922
1926
|
|
|
1923
1927
|
const result = createMagicProxy(input)
|
|
1924
1928
|
|
|
1925
1929
|
expect(result.items[0].public).toBe('item1')
|
|
1926
|
-
expect(result.items[0].
|
|
1930
|
+
expect(result.items[0].__scalar_private).toBe(undefined)
|
|
1927
1931
|
expect(result.items[1].public).toBe('item2')
|
|
1928
|
-
expect(result.items[1].
|
|
1932
|
+
expect(result.items[1].__scalar_private).toBe(undefined)
|
|
1929
1933
|
})
|
|
1930
1934
|
|
|
1931
|
-
it('should still allow refs to work with
|
|
1935
|
+
it('should still allow refs to work with __scalar_ hiding', () => {
|
|
1932
1936
|
const input = {
|
|
1933
1937
|
definitions: {
|
|
1934
1938
|
example: {
|
|
1935
1939
|
value: 'hello',
|
|
1936
|
-
|
|
1940
|
+
__scalar_internal: 'hidden',
|
|
1937
1941
|
},
|
|
1938
1942
|
},
|
|
1939
|
-
|
|
1943
|
+
__scalar_hiddenRef: { $ref: '#/definitions/example' },
|
|
1940
1944
|
publicRef: { $ref: '#/definitions/example' },
|
|
1941
1945
|
}
|
|
1942
1946
|
|
|
1943
1947
|
const result = createMagicProxy(input)
|
|
1944
1948
|
|
|
1945
|
-
//
|
|
1946
|
-
expect(result.
|
|
1949
|
+
// __scalar_ property should be hidden
|
|
1950
|
+
expect(result.__scalar_hiddenRef).toBe(undefined)
|
|
1947
1951
|
|
|
1948
1952
|
// Public ref should work normally
|
|
1949
1953
|
expect(result.publicRef['$ref-value'].value).toBe('hello')
|
|
1950
1954
|
|
|
1951
|
-
//
|
|
1952
|
-
expect(result.publicRef['$ref-value'].
|
|
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')
|
|
1953
1985
|
})
|
|
1954
1986
|
})
|
|
1955
1987
|
})
|
package/src/magic-proxy/proxy.ts
CHANGED
|
@@ -18,7 +18,7 @@ const REF_KEY = '$ref'
|
|
|
18
18
|
* Features:
|
|
19
19
|
* - If an object contains a `$ref` property, accessing the special `$ref-value` property will resolve and return the referenced value from the root object.
|
|
20
20
|
* - All nested objects and arrays are recursively wrapped in proxies, so reference resolution works at any depth.
|
|
21
|
-
* - Properties starting with
|
|
21
|
+
* - Properties starting with `__scalar_` are considered internal and are hidden by default: they return undefined on access, are excluded from enumeration, and `'in'` checks return false. This can be overridden with the `showInternal` option.
|
|
22
22
|
* - Setting, deleting, and enumerating properties works as expected, including for proxied references.
|
|
23
23
|
* - Ensures referential stability by caching proxies for the same target object.
|
|
24
24
|
*
|
|
@@ -33,17 +33,17 @@ const REF_KEY = '$ref'
|
|
|
33
33
|
* foo: { bar: 123 }
|
|
34
34
|
* },
|
|
35
35
|
* refObj: { $ref: '#/definitions/foo' },
|
|
36
|
-
*
|
|
36
|
+
* __scalar_internal: 'hidden property'
|
|
37
37
|
* }
|
|
38
38
|
* const proxy = createMagicProxy(input)
|
|
39
39
|
*
|
|
40
40
|
* // Accessing proxy.refObj['$ref-value'] will resolve to { bar: 123 }
|
|
41
41
|
* console.log(proxy.refObj['$ref-value']) // { bar: 123 }
|
|
42
42
|
*
|
|
43
|
-
* // Properties starting with
|
|
44
|
-
* console.log(proxy.
|
|
45
|
-
* console.log('
|
|
46
|
-
* console.log(Object.keys(proxy)) // ['definitions', 'refObj'] (no '
|
|
43
|
+
* // Properties starting with __scalar_ are hidden
|
|
44
|
+
* console.log(proxy.__scalar_internal) // undefined
|
|
45
|
+
* console.log('__scalar_internal' in proxy) // false
|
|
46
|
+
* console.log(Object.keys(proxy)) // ['definitions', 'refObj'] (no '__scalar_internal')
|
|
47
47
|
*
|
|
48
48
|
* // Setting and deleting properties works as expected
|
|
49
49
|
* proxy.refObj.extra = 'hello'
|
|
@@ -99,7 +99,7 @@ export const createMagicProxy = <T extends Record<keyof T & symbol, unknown>, S
|
|
|
99
99
|
* Proxy "get" trap for magic proxy.
|
|
100
100
|
* - If accessing the special isMagicProxy symbol, return true to identify proxy.
|
|
101
101
|
* - If accessing the magicProxyTarget symbol, return the original target object.
|
|
102
|
-
* - Hide properties starting with
|
|
102
|
+
* - Hide properties starting with __scalar_ by returning undefined.
|
|
103
103
|
* - If accessing "$ref-value" and the object has a local $ref, resolve and return the referenced value as a new magic proxy.
|
|
104
104
|
* - For all other properties, recursively wrap the returned value in a magic proxy (if applicable).
|
|
105
105
|
*/
|
|
@@ -114,9 +114,9 @@ export const createMagicProxy = <T extends Record<keyof T & symbol, unknown>, S
|
|
|
114
114
|
return target
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
// Hide properties starting with
|
|
117
|
+
// Hide properties starting with __scalar_ - these are considered internal/private properties
|
|
118
118
|
// and should not be accessible through the magic proxy interface
|
|
119
|
-
if (typeof prop === 'string' && prop.startsWith('
|
|
119
|
+
if (typeof prop === 'string' && prop.startsWith('__scalar_') && !options?.showInternal) {
|
|
120
120
|
return undefined
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -140,6 +140,10 @@ export const createMagicProxy = <T extends Record<keyof T & symbol, unknown>, S
|
|
|
140
140
|
|
|
141
141
|
// Resolve the reference and create a new magic proxy
|
|
142
142
|
const resolvedValue = getValueByPath(args.root, parseJsonPointer(`#/${path}`))
|
|
143
|
+
// Return early if the value is already a magic proxy
|
|
144
|
+
if (isMagicProxyObject(resolvedValue.value)) {
|
|
145
|
+
return resolvedValue.value
|
|
146
|
+
}
|
|
143
147
|
const proxiedValue = createMagicProxy(resolvedValue.value, options, {
|
|
144
148
|
...args,
|
|
145
149
|
currentContext: resolvedValue.context,
|
|
@@ -152,6 +156,12 @@ export const createMagicProxy = <T extends Record<keyof T & symbol, unknown>, S
|
|
|
152
156
|
|
|
153
157
|
// For all other properties, recursively wrap the value in a magic proxy
|
|
154
158
|
const value = Reflect.get(target, prop, receiver)
|
|
159
|
+
|
|
160
|
+
// Return early if the value is already a magic proxy
|
|
161
|
+
if (isMagicProxyObject(value)) {
|
|
162
|
+
return value
|
|
163
|
+
}
|
|
164
|
+
|
|
155
165
|
return createMagicProxy(value as T, options, { ...args, currentContext: id ?? args.currentContext })
|
|
156
166
|
},
|
|
157
167
|
/**
|
|
@@ -159,13 +169,13 @@ export const createMagicProxy = <T extends Record<keyof T & symbol, unknown>, S
|
|
|
159
169
|
* Allows setting properties on the proxied object.
|
|
160
170
|
* This will update the underlying target object.
|
|
161
171
|
*
|
|
162
|
-
* Note: it will not update if the property starts with
|
|
172
|
+
* Note: it will not update if the property starts with __scalar_
|
|
163
173
|
* Those will be considered private properties by the proxy
|
|
164
174
|
*/
|
|
165
175
|
set(target, prop, newValue, receiver) {
|
|
166
176
|
const ref = Reflect.get(target, REF_KEY, receiver)
|
|
167
177
|
|
|
168
|
-
if (typeof prop === 'string' && prop.startsWith('
|
|
178
|
+
if (typeof prop === 'string' && prop.startsWith('__scalar_') && !options?.showInternal) {
|
|
169
179
|
return true
|
|
170
180
|
}
|
|
171
181
|
|
|
@@ -215,12 +225,12 @@ export const createMagicProxy = <T extends Record<keyof T & symbol, unknown>, S
|
|
|
215
225
|
* - Pretend that "$ref-value" exists if "$ref" exists on the target.
|
|
216
226
|
* This allows expressions like `"$ref-value" in obj` to return true for objects with a $ref,
|
|
217
227
|
* even though "$ref-value" is a virtual property provided by the proxy.
|
|
218
|
-
* - Hide properties starting with
|
|
228
|
+
* - Hide properties starting with __scalar_ by returning false.
|
|
219
229
|
* - For all other properties, defer to the default Reflect.has behavior.
|
|
220
230
|
*/
|
|
221
231
|
has(target, prop) {
|
|
222
|
-
// Hide properties starting with
|
|
223
|
-
if (typeof prop === 'string' && prop.startsWith('
|
|
232
|
+
// Hide properties starting with __scalar_
|
|
233
|
+
if (typeof prop === 'string' && prop.startsWith('__scalar_') && !options?.showInternal) {
|
|
224
234
|
return false
|
|
225
235
|
}
|
|
226
236
|
|
|
@@ -236,14 +246,14 @@ export const createMagicProxy = <T extends Record<keyof T & symbol, unknown>, S
|
|
|
236
246
|
* - If the object has a "$ref" property, ensures that "$ref-value" is also included in the keys,
|
|
237
247
|
* even though "$ref-value" is a virtual property provided by the proxy.
|
|
238
248
|
* This allows Object.keys, Reflect.ownKeys, etc. to include "$ref-value" for objects with $ref.
|
|
239
|
-
* - Filters out properties starting with
|
|
249
|
+
* - Filters out properties starting with __scalar_.
|
|
240
250
|
*/
|
|
241
251
|
ownKeys(target) {
|
|
242
252
|
const keys = Reflect.ownKeys(target)
|
|
243
253
|
|
|
244
|
-
// Filter out properties starting with
|
|
254
|
+
// Filter out properties starting with __scalar_
|
|
245
255
|
const filteredKeys = keys.filter(
|
|
246
|
-
(key) => typeof key !== 'string' || !(key.startsWith('
|
|
256
|
+
(key) => typeof key !== 'string' || !(key.startsWith('__scalar_') && !options?.showInternal),
|
|
247
257
|
)
|
|
248
258
|
|
|
249
259
|
if (REF_KEY in target && !filteredKeys.includes(REF_VALUE)) {
|
|
@@ -255,13 +265,13 @@ export const createMagicProxy = <T extends Record<keyof T & symbol, unknown>, S
|
|
|
255
265
|
/**
|
|
256
266
|
* Proxy "getOwnPropertyDescriptor" trap for magic proxy.
|
|
257
267
|
* - For the virtual "$ref-value" property, returns a descriptor that makes it appear as a regular property.
|
|
258
|
-
* - Hide properties starting with
|
|
268
|
+
* - Hide properties starting with __scalar_ by returning undefined.
|
|
259
269
|
* - For all other properties, delegates to the default Reflect.getOwnPropertyDescriptor behavior.
|
|
260
270
|
* - This ensures that Object.getOwnPropertyDescriptor and similar methods work correctly with the virtual property.
|
|
261
271
|
*/
|
|
262
272
|
getOwnPropertyDescriptor(target, prop) {
|
|
263
|
-
// Hide properties starting with
|
|
264
|
-
if (typeof prop === 'string' && prop.startsWith('
|
|
273
|
+
// Hide properties starting with __scalar_
|
|
274
|
+
if (typeof prop === 'string' && prop.startsWith('__scalar_') && !options?.showInternal) {
|
|
265
275
|
return undefined
|
|
266
276
|
}
|
|
267
277
|
|
|
@@ -286,6 +296,10 @@ export const createMagicProxy = <T extends Record<keyof T & symbol, unknown>, S
|
|
|
286
296
|
return proxied
|
|
287
297
|
}
|
|
288
298
|
|
|
299
|
+
export const isMagicProxyObject = (obj: unknown): boolean => {
|
|
300
|
+
return typeof obj === 'object' && obj !== null && (obj as { [isMagicProxy]: boolean })[isMagicProxy] === true
|
|
301
|
+
}
|
|
302
|
+
|
|
289
303
|
/**
|
|
290
304
|
* Gets the raw (non-proxied) version of an object created by createMagicProxy.
|
|
291
305
|
* This is useful when you need to access the original object without the magic proxy wrapper.
|