find.js 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. "use strict";
  2. /* tslint:disable no-string-throw */
  3. Object.defineProperty(exports, "__esModule", { value: true });
  4. exports.isObjectReference = exports.isArrayEnd = exports.isArrayReference = exports.find = void 0;
  5. const hasOwnProperty_1 = require("@jsonjoy.com/util/lib/hasOwnProperty");
  6. const { isArray } = Array;
  7. /**
  8. * Finds a target in document specified by JSON Pointer. Also returns the
  9. * object containing the target and key used to reference that object.
  10. *
  11. * Throws Error('NOT_FOUND') if pointer does not result into a value in the middle
  12. * of the path. If the last element of the path does not result into a value, the
  13. * lookup succeeds with `val` set to `undefined`. It can be used to discriminate
  14. * missing values, because `undefined` is not a valid JSON value.
  15. *
  16. * If last element in array is targeted using "-", e.g. "/arr/-", use
  17. * `isArrayEnd` to verify that:
  18. *
  19. * ```js
  20. * const ref = find({arr: [1, 2, 3], ['arr', '-']});
  21. * if (isArrayReference(ref)) {
  22. * if (isArrayEnd(ref)) {
  23. * // ...
  24. * }
  25. * }
  26. * ```
  27. *
  28. * @param skipLast Number of steps to skip at the end. Useful to find reference of
  29. * parent step, without constructing a new `Path` array.
  30. */
  31. const find = (val, path) => {
  32. const pathLength = path.length;
  33. if (!pathLength)
  34. return { val };
  35. let obj;
  36. let key;
  37. for (let i = 0; i < pathLength; i++) {
  38. obj = val;
  39. key = path[i];
  40. if (isArray(obj)) {
  41. const length = obj.length;
  42. if (key === '-')
  43. key = length;
  44. else {
  45. if (typeof key === 'string') {
  46. const key2 = ~~key;
  47. if ('' + key2 !== key)
  48. throw new Error('INVALID_INDEX');
  49. key = key2;
  50. if (key < 0)
  51. throw new Error('INVALID_INDEX');
  52. }
  53. }
  54. val = obj[key];
  55. }
  56. else if (typeof obj === 'object' && !!obj) {
  57. val = (0, hasOwnProperty_1.hasOwnProperty)(obj, key) ? obj[key] : undefined;
  58. }
  59. else
  60. throw new Error('NOT_FOUND');
  61. }
  62. const ref = { val, obj, key };
  63. return ref;
  64. };
  65. exports.find = find;
  66. const isArrayReference = (ref) => isArray(ref.obj) && typeof ref.key === 'number';
  67. exports.isArrayReference = isArrayReference;
  68. const isArrayEnd = (ref) => ref.obj.length === ref.key;
  69. exports.isArrayEnd = isArrayEnd;
  70. const isObjectReference = (ref) => typeof ref.obj === 'object' && typeof ref.key === 'string';
  71. exports.isObjectReference = isObjectReference;