You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
2.5 KiB
100 lines
2.5 KiB
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') 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
|
|
|