pointer-props
Version:
JavaScript object manipulation (get/set/del) using JSON Pointer (RFC6901) and JSON Reference paths.
216 lines (208 loc) • 3.9 kB
JavaScript
import { test } from 'uvu'
import * as assert from 'uvu/assert'
import { toTokens, toPointer, get, set, del, resolve } from './index.js'
test('toTokens', () => {
assert.equal(
toTokens('/foo/3/bar'),
[ 'foo', '3', 'bar' ],
'basic pointers',
)
assert.equal(
toTokens('/f~1o~1o/b~0a~0r'),
[ 'f/o/o', 'b~a~r' ],
'escaped characters',
)
assert.equal(
toTokens('/~01'),
[ '~1' ],
'order of un-escaping is correct',
)
assert.equal(
toTokens('#/foo/3/bar'),
[ 'foo', '3', 'bar' ],
'json reference works as well',
)
})
test('toPointer', () => {
assert.equal(
toPointer([ 'foo', 3, 'bar' ]),
'/foo/3/bar',
'basic pointers',
)
assert.equal(
toPointer([ 'f/o/o', 'b~a~r' ]),
'/f~1o~1o/b~0a~0r',
'escaping characters',
)
assert.equal(
toPointer([ '~1' ]),
'/~01',
'order of un-escaping is correct',
)
})
test('get', () => {
assert.equal(
get({ foo: { bar: 'baz' } }, '/foo/bar'),
'baz',
'basic pointer access',
)
assert.equal(
get({ foo: { bar: 'baz' } }, [ 'foo', 'bar' ]),
'baz',
'array access is okay',
)
assert.equal(
get({ 'f/o/o': { 'b~a~r': 'baz' } }, '/f~1o~1o/b~0a~0r'),
'baz',
'encoded characters',
)
assert.equal(
get({ foo: { bar: 'baz' } }, '#/foo/bar'),
'baz',
'json reference works as well',
)
})
test('set', () => {
assert.equal(
set({ foo: { bar: 'baz' } }, '/foo/bar', 'fizz').foo.bar,
'fizz',
'basic pointer access',
)
assert.equal(
set({ foo: { bar: 'baz' } }, [ 'foo', 'bar' ], 'fizz').foo.bar,
'fizz',
'array access is okay',
)
assert.equal(
set({ 'f/o/o': { 'b~a~r': 'baz' } }, '/f~1o~1o/b~0a~0r', 'fizz')['f/o/o']['b~a~r'],
'fizz',
'encoded characters',
)
})
test('del', () => {
assert.equal(
del({ foo: { bar: 'baz' } }, '/foo/bar').foo.bar,
undefined,
'basic pointer access',
)
assert.equal(
del({ foo: { bar: 'baz' } }, [ 'foo', 'bar' ]).foo.bar,
undefined,
'array access is okay',
)
assert.equal(
del({ 'f/o/o': { 'b~a~r': 'baz' } }, '/f~1o~1o/b~0a~0r')['f/o/o']['b~a~r'],
undefined,
'encoded characters',
)
assert.equal(
del({ foo: [ 'a', 'b', 'c' ] }, '/foo/1').foo,
[ 'a', 'c' ],
'array by index does not leave holes',
)
})
test('resolve', () => {
assert.equal(
resolve({
foo: {
$ref: '#/bar',
},
bar: 'baz',
}, '#/foo'),
[ 'bar' ],
'single $ref deep',
)
assert.equal(
resolve({
foo: {
$ref: '#/bar',
},
bar: 'baz',
}, [ 'foo' ]),
[ 'bar' ],
'single $ref deep with array accessor',
)
assert.equal(
resolve({
foo: {
bar: {
$ref: '#/fizz',
},
},
fizz: {
buzz: 'should resolve here',
},
}, '#/foo/bar/buzz'),
[ 'fizz', 'buzz' ],
'deeper $ref chain',
)
assert.equal(
resolve({
'f/o/o': {
$ref: '#/b~0a~0r',
},
'b~a~r': {
'b~a/z': 'buzz',
},
}, '#/f~1o~1o/b~0a~1z'),
[ 'b~a~r', 'b~a/z' ],
'deep access with encoded characters',
)
assert.equal(
resolve({
'f/o/o': {
$ref: '#/b~0a~0r',
},
'b~a~r': {
'b~a/z': 'buzz',
},
}, [ 'f/o/o', 'b~a/z' ]),
[ 'b~a~r', 'b~a/z' ],
'deep access with non-encoded characters is possible with an array',
)
assert.equal(
resolve({
foo: {
$ref: '#/bar',
},
bar: {
$ref: '#/fizz',
},
fizz: {
$ref: '#/buzz',
},
buzz: {
somePropertyName: 3,
},
}, '#/foo'),
[ 'buzz' ],
'long $ref chain',
)
assert.equal(
resolve({}, [ 'foo', 'bar', 'fizz' ]),
null,
'if the path does not exist',
)
assert.throws(
() => resolve({
foo: {
$ref: '#/bar',
},
bar: {
$ref: '#/foo',
},
}, [ 'foo' ]),
err => err.name === 'InfiniteReference',
'it should detect infinite cycles and throw',
)
assert.throws(
() => resolve({
foo: {
$ref: 'https://site.com/#/bar',
},
}, [ 'foo' ]),
err => err.name === 'ExternalReference',
'external pointers are not supported',
)
})
test.run()