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.

123 lines
2.2 KiB

4 years ago
  1. 'use strict';
  2. const isObj = require('is-obj');
  3. function getPathSegments(path) {
  4. const pathArr = path.split('.');
  5. const parts = [];
  6. for (let i = 0; i < pathArr.length; i++) {
  7. let p = pathArr[i];
  8. while (p[p.length - 1] === '\\' && pathArr[i + 1] !== undefined) {
  9. p = p.slice(0, -1) + '.';
  10. p += pathArr[++i];
  11. }
  12. parts.push(p);
  13. }
  14. return parts;
  15. }
  16. module.exports = {
  17. get(obj, path, value) {
  18. if (!isObj(obj) || typeof path !== 'string') {
  19. return value === undefined ? obj : value;
  20. }
  21. const pathArr = getPathSegments(path);
  22. for (let i = 0; i < pathArr.length; i++) {
  23. if (!Object.prototype.propertyIsEnumerable.call(obj, pathArr[i])) {
  24. return value;
  25. }
  26. obj = obj[pathArr[i]];
  27. if (obj === undefined || obj === null) {
  28. // `obj` is either `undefined` or `null` so we want to stop the loop, and
  29. // if this is not the last bit of the path, and
  30. // if it did't return `undefined`
  31. // it would return `null` if `obj` is `null`
  32. // but we want `get({foo: null}, 'foo.bar')` to equal `undefined`, or the supplied value, not `null`
  33. if (i !== pathArr.length - 1) {
  34. return value;
  35. }
  36. break;
  37. }
  38. }
  39. return obj;
  40. },
  41. set(obj, path, value) {
  42. if (!isObj(obj) || typeof path !== 'string') {
  43. return obj;
  44. }
  45. const root = obj;
  46. const pathArr = getPathSegments(path);
  47. for (let i = 0; i < pathArr.length; i++) {
  48. const p = pathArr[i];
  49. if (!isObj(obj[p])) {
  50. obj[p] = {};
  51. }
  52. if (i === pathArr.length - 1) {
  53. obj[p] = value;
  54. }
  55. obj = obj[p];
  56. }
  57. return root;
  58. },
  59. delete(obj, path) {
  60. if (!isObj(obj) || typeof path !== 'string') {
  61. return;
  62. }
  63. const pathArr = getPathSegments(path);
  64. for (let i = 0; i < pathArr.length; i++) {
  65. const p = pathArr[i];
  66. if (i === pathArr.length - 1) {
  67. delete obj[p];
  68. return;
  69. }
  70. obj = obj[p];
  71. if (!isObj(obj)) {
  72. return;
  73. }
  74. }
  75. },
  76. has(obj, path) {
  77. if (!isObj(obj) || typeof path !== 'string') {
  78. return false;
  79. }
  80. const pathArr = getPathSegments(path);
  81. for (let i = 0; i < pathArr.length; i++) {
  82. if (isObj(obj)) {
  83. if (!(pathArr[i] in obj)) {
  84. return false;
  85. }
  86. obj = obj[pathArr[i]];
  87. } else {
  88. return false;
  89. }
  90. }
  91. return true;
  92. }
  93. };