jsonpointer.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. var hasExcape = /~/
  2. var escapeMatcher = /~[01]/g
  3. function escapeReplacer (m) {
  4. switch (m) {
  5. case '~1': return '/'
  6. case '~0': return '~'
  7. }
  8. throw new Error('Invalid tilde escape: ' + m)
  9. }
  10. function untilde (str) {
  11. if (!hasExcape.test(str)) return str
  12. return str.replace(escapeMatcher, escapeReplacer)
  13. }
  14. function setter (obj, pointer, value) {
  15. var part
  16. var hasNextPart
  17. for (var p = 1, len = pointer.length; p < len;) {
  18. if (pointer[p] === 'constructor' || pointer[p] === 'prototype' || pointer[p] === '__proto__') return obj
  19. part = untilde(pointer[p++])
  20. hasNextPart = len > p
  21. if (typeof obj[part] === 'undefined') {
  22. // support setting of /-
  23. if (Array.isArray(obj) && part === '-') {
  24. part = obj.length
  25. }
  26. // support nested objects/array when setting values
  27. if (hasNextPart) {
  28. if ((pointer[p] !== '' && pointer[p] < Infinity) || pointer[p] === '-') obj[part] = []
  29. else obj[part] = {}
  30. }
  31. }
  32. if (!hasNextPart) break
  33. obj = obj[part]
  34. }
  35. var oldValue = obj[part]
  36. if (value === undefined) delete obj[part]
  37. else obj[part] = value
  38. return oldValue
  39. }
  40. function compilePointer (pointer) {
  41. if (typeof pointer === 'string') {
  42. pointer = pointer.split('/')
  43. if (pointer[0] === '') return pointer
  44. throw new Error('Invalid JSON pointer.')
  45. } else if (Array.isArray(pointer)) {
  46. for (const part of pointer) {
  47. if (typeof part !== 'string' && typeof part !== 'number') {
  48. throw new Error('Invalid JSON pointer. Must be of type string or number.')
  49. }
  50. }
  51. return pointer
  52. }
  53. throw new Error('Invalid JSON pointer.')
  54. }
  55. function get (obj, pointer) {
  56. if (typeof obj !== 'object') throw new Error('Invalid input object.')
  57. pointer = compilePointer(pointer)
  58. var len = pointer.length
  59. if (len === 1) return obj
  60. for (var p = 1; p < len;) {
  61. obj = obj[untilde(pointer[p++])]
  62. if (len === p) return obj
  63. if (typeof obj !== 'object' || obj === null) return undefined
  64. }
  65. }
  66. function set (obj, pointer, value) {
  67. if (typeof obj !== 'object') throw new Error('Invalid input object.')
  68. pointer = compilePointer(pointer)
  69. if (pointer.length === 0) throw new Error('Invalid JSON pointer for set.')
  70. return setter(obj, pointer, value)
  71. }
  72. function compile (pointer) {
  73. var compiled = compilePointer(pointer)
  74. return {
  75. get: function (object) {
  76. return get(object, compiled)
  77. },
  78. set: function (object, value) {
  79. return set(object, compiled, value)
  80. }
  81. }
  82. }
  83. exports.get = get
  84. exports.set = set
  85. exports.compile = compile