accessDeep.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import { isMap, isArray, isPlainObject, isSet } from './is.js';
  2. import { includes } from './util.js';
  3. const getNthKey = (value, n) => {
  4. if (n > value.size)
  5. throw new Error('index out of bounds');
  6. const keys = value.keys();
  7. while (n > 0) {
  8. keys.next();
  9. n--;
  10. }
  11. return keys.next().value;
  12. };
  13. function validatePath(path) {
  14. if (includes(path, '__proto__')) {
  15. throw new Error('__proto__ is not allowed as a property');
  16. }
  17. if (includes(path, 'prototype')) {
  18. throw new Error('prototype is not allowed as a property');
  19. }
  20. if (includes(path, 'constructor')) {
  21. throw new Error('constructor is not allowed as a property');
  22. }
  23. }
  24. export const getDeep = (object, path) => {
  25. validatePath(path);
  26. for (let i = 0; i < path.length; i++) {
  27. const key = path[i];
  28. if (isSet(object)) {
  29. object = getNthKey(object, +key);
  30. }
  31. else if (isMap(object)) {
  32. const row = +key;
  33. const type = +path[++i] === 0 ? 'key' : 'value';
  34. const keyOfRow = getNthKey(object, row);
  35. switch (type) {
  36. case 'key':
  37. object = keyOfRow;
  38. break;
  39. case 'value':
  40. object = object.get(keyOfRow);
  41. break;
  42. }
  43. }
  44. else {
  45. object = object[key];
  46. }
  47. }
  48. return object;
  49. };
  50. export const setDeep = (object, path, mapper) => {
  51. validatePath(path);
  52. if (path.length === 0) {
  53. return mapper(object);
  54. }
  55. let parent = object;
  56. for (let i = 0; i < path.length - 1; i++) {
  57. const key = path[i];
  58. if (isArray(parent)) {
  59. const index = +key;
  60. parent = parent[index];
  61. }
  62. else if (isPlainObject(parent)) {
  63. parent = parent[key];
  64. }
  65. else if (isSet(parent)) {
  66. const row = +key;
  67. parent = getNthKey(parent, row);
  68. }
  69. else if (isMap(parent)) {
  70. const isEnd = i === path.length - 2;
  71. if (isEnd) {
  72. break;
  73. }
  74. const row = +key;
  75. const type = +path[++i] === 0 ? 'key' : 'value';
  76. const keyOfRow = getNthKey(parent, row);
  77. switch (type) {
  78. case 'key':
  79. parent = keyOfRow;
  80. break;
  81. case 'value':
  82. parent = parent.get(keyOfRow);
  83. break;
  84. }
  85. }
  86. }
  87. const lastKey = path[path.length - 1];
  88. if (isArray(parent)) {
  89. parent[+lastKey] = mapper(parent[+lastKey]);
  90. }
  91. else if (isPlainObject(parent)) {
  92. parent[lastKey] = mapper(parent[lastKey]);
  93. }
  94. if (isSet(parent)) {
  95. const oldValue = getNthKey(parent, +lastKey);
  96. const newValue = mapper(oldValue);
  97. if (oldValue !== newValue) {
  98. parent.delete(oldValue);
  99. parent.add(newValue);
  100. }
  101. }
  102. if (isMap(parent)) {
  103. const row = +path[path.length - 2];
  104. const keyToRow = getNthKey(parent, row);
  105. const type = +lastKey === 0 ? 'key' : 'value';
  106. switch (type) {
  107. case 'key': {
  108. const newKey = mapper(keyToRow);
  109. parent.set(newKey, parent.get(keyToRow));
  110. if (newKey !== keyToRow) {
  111. parent.delete(keyToRow);
  112. }
  113. break;
  114. }
  115. case 'value': {
  116. parent.set(keyToRow, mapper(parent.get(keyToRow)));
  117. break;
  118. }
  119. }
  120. }
  121. return object;
  122. };
  123. //# sourceMappingURL=accessDeep.js.map