101 lines
2.5 KiB
JavaScript
101 lines
2.5 KiB
JavaScript
|
var hasExcape = /~/
|
||
|
var escapeMatcher = /~[01]/g
|
||
|
function escapeReplacer (m) {
|
||
|
switch (m) {
|
||
|
case '~1': return '/'
|
||
|
case '~0': return '~'
|
||
|
}
|
||
|
throw new Error('Invalid tilde escape: ' + m)
|
||
|
}
|
||
|
|
||
|
function untilde (str) {
|
||
|
if (!hasExcape.test(str)) return str
|
||
|
return str.replace(escapeMatcher, escapeReplacer)
|
||
|
}
|
||
|
|
||
|
function setter (obj, pointer, value) {
|
||
|
var part
|
||
|
var hasNextPart
|
||
|
|
||
|
for (var p = 1, len = pointer.length; p < len;) {
|
||
|
if (pointer[p] === 'constructor' || pointer[p] === 'prototype' || pointer[p] === '__proto__') return obj
|
||
|
|
||
|
part = untilde(pointer[p++])
|
||
|
hasNextPart = len > p
|
||
|
|
||
|
if (typeof obj[part] === 'undefined') {
|
||
|
// support setting of /-
|
||
|
if (Array.isArray(obj) && part === '-') {
|
||
|
part = obj.length
|
||
|
}
|
||
|
|
||
|
// support nested objects/array when setting values
|
||
|
if (hasNextPart) {
|
||
|
if ((pointer[p] !== '' && pointer[p] < Infinity) || pointer[p] === '-') obj[part] = []
|
||
|
else obj[part] = {}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!hasNextPart) break
|
||
|
obj = obj[part]
|
||
|
}
|
||
|
|
||
|
var oldValue = obj[part]
|
||
|
if (value === undefined) delete obj[part]
|
||
|
else obj[part] = value
|
||
|
return oldValue
|
||
|
}
|
||
|
|
||
|
function compilePointer (pointer) {
|
||
|
if (typeof pointer === 'string') {
|
||
|
pointer = pointer.split('/')
|
||
|
if (pointer[0] === '') return pointer
|
||
|
throw new Error('Invalid JSON pointer.')
|
||
|
} else if (Array.isArray(pointer)) {
|
||
|
for (const part of pointer) {
|
||
|
if (typeof part !== 'string' && typeof part !== 'number') {
|
||
|
throw new Error('Invalid JSON pointer. Must be of type string or number.')
|
||
|
}
|
||
|
}
|
||
|
return pointer
|
||
|
}
|
||
|
|
||
|
throw new Error('Invalid JSON pointer.')
|
||
|
}
|
||
|
|
||
|
function get (obj, pointer) {
|
||
|
if (typeof obj !== 'object') throw new Error('Invalid input object.')
|
||
|
pointer = compilePointer(pointer)
|
||
|
var len = pointer.length
|
||
|
if (len === 1) return obj
|
||
|
|
||
|
for (var p = 1; p < len;) {
|
||
|
obj = obj[untilde(pointer[p++])]
|
||
|
if (len === p) return obj
|
||
|
if (typeof obj !== 'object' || obj === null) return undefined
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function set (obj, pointer, value) {
|
||
|
if (typeof obj !== 'object') throw new Error('Invalid input object.')
|
||
|
pointer = compilePointer(pointer)
|
||
|
if (pointer.length === 0) throw new Error('Invalid JSON pointer for set.')
|
||
|
return setter(obj, pointer, value)
|
||
|
}
|
||
|
|
||
|
function compile (pointer) {
|
||
|
var compiled = compilePointer(pointer)
|
||
|
return {
|
||
|
get: function (object) {
|
||
|
return get(object, compiled)
|
||
|
},
|
||
|
set: function (object, value) {
|
||
|
return set(object, compiled, value)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exports.get = get
|
||
|
exports.set = set
|
||
|
exports.compile = compile
|