--- /dev/null
+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;) {
+ 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)) {
+ 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