timm.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.clone = clone;
  6. exports.addLast = addLast;
  7. exports.addFirst = addFirst;
  8. exports.removeLast = removeLast;
  9. exports.removeFirst = removeFirst;
  10. exports.insert = insert;
  11. exports.removeAt = removeAt;
  12. exports.replaceAt = replaceAt;
  13. exports.getIn = getIn;
  14. exports.set = set;
  15. exports.setIn = setIn;
  16. exports.update = update;
  17. exports.updateIn = updateIn;
  18. exports.merge = merge;
  19. exports.mergeDeep = mergeDeep;
  20. exports.mergeIn = mergeIn;
  21. exports.omit = omit;
  22. exports.addDefaults = addDefaults;
  23. exports.default = void 0;
  24. /* eslint-disable @typescript-eslint/ban-types */
  25. /*!
  26. * Timm
  27. *
  28. * Immutability helpers with fast reads and acceptable writes.
  29. *
  30. * @copyright Guillermo Grau Panea 2016
  31. * @license MIT
  32. */
  33. const INVALID_ARGS = 'INVALID_ARGS';
  34. const IS_DEV = process.env.NODE_ENV !== 'production';
  35. // ===============================================
  36. // ### Helpers
  37. // ===============================================
  38. function throwStr(msg) {
  39. throw new Error(msg);
  40. }
  41. function getKeysAndSymbols(obj) {
  42. const keys = Object.keys(obj);
  43. if (Object.getOwnPropertySymbols) {
  44. // @ts-ignore
  45. return keys.concat(Object.getOwnPropertySymbols(obj));
  46. }
  47. return keys;
  48. }
  49. const hasOwnProperty = {}.hasOwnProperty;
  50. function clone(obj0) {
  51. // As array
  52. if (Array.isArray(obj0)) return obj0.slice(); // As object
  53. const obj = obj0;
  54. const keys = getKeysAndSymbols(obj);
  55. const out = {};
  56. for (let i = 0; i < keys.length; i++) {
  57. const key = keys[i];
  58. out[key] = obj[key];
  59. } // @ts-ignore (see type tests)
  60. return out;
  61. } // Custom guard
  62. function isObject(o) {
  63. return o != null && typeof o === 'object';
  64. } // _deepFreeze = (obj) ->
  65. // Object.freeze obj
  66. // for key in Object.getOwnPropertyNames obj
  67. // val = obj[key]
  68. // if isObject(val) and not Object.isFrozen val
  69. // _deepFreeze val
  70. // obj
  71. // ===============================================
  72. // -- ### Arrays
  73. // ===============================================
  74. // -- #### addLast()
  75. // -- Returns a new array with an appended item or items.
  76. // --
  77. // -- Usage: `addLast(array, val)`
  78. // --
  79. // -- ```js
  80. // -- arr = ['a', 'b']
  81. // -- arr2 = addLast(arr, 'c')
  82. // -- // ['a', 'b', 'c']
  83. // -- arr2 === arr
  84. // -- // false
  85. // -- arr3 = addLast(arr, ['c', 'd'])
  86. // -- // ['a', 'b', 'c', 'd']
  87. // -- ```
  88. // `array.concat(val)` also handles the scalar case,
  89. // but is apparently very slow
  90. function addLast(array, val) {
  91. if (Array.isArray(val)) return array.concat(val);
  92. return array.concat([val]);
  93. } // -- #### addFirst()
  94. // -- Returns a new array with a prepended item or items.
  95. // --
  96. // -- Usage: `addFirst(array, val)`
  97. // --
  98. // -- ```js
  99. // -- arr = ['a', 'b']
  100. // -- arr2 = addFirst(arr, 'c')
  101. // -- // ['c', 'a', 'b']
  102. // -- arr2 === arr
  103. // -- // false
  104. // -- arr3 = addFirst(arr, ['c', 'd'])
  105. // -- // ['c', 'd', 'a', 'b']
  106. // -- ```
  107. function addFirst(array, val) {
  108. if (Array.isArray(val)) return val.concat(array);
  109. return [val].concat(array);
  110. } // -- #### removeLast()
  111. // -- Returns a new array removing the last item.
  112. // --
  113. // -- Usage: `removeLast(array)`
  114. // --
  115. // -- ```js
  116. // -- arr = ['a', 'b']
  117. // -- arr2 = removeLast(arr)
  118. // -- // ['a']
  119. // -- arr2 === arr
  120. // -- // false
  121. // --
  122. // -- // The same array is returned if there are no changes:
  123. // -- arr3 = []
  124. // -- removeLast(arr3) === arr3
  125. // -- // true
  126. // -- ```
  127. function removeLast(array) {
  128. if (!array.length) return array;
  129. return array.slice(0, array.length - 1);
  130. } // -- #### removeFirst()
  131. // -- Returns a new array removing the first item.
  132. // --
  133. // -- Usage: `removeFirst(array)`
  134. // --
  135. // -- ```js
  136. // -- arr = ['a', 'b']
  137. // -- arr2 = removeFirst(arr)
  138. // -- // ['b']
  139. // -- arr2 === arr
  140. // -- // false
  141. // --
  142. // -- // The same array is returned if there are no changes:
  143. // -- arr3 = []
  144. // -- removeFirst(arr3) === arr3
  145. // -- // true
  146. // -- ```
  147. function removeFirst(array) {
  148. if (!array.length) return array;
  149. return array.slice(1);
  150. } // -- #### insert()
  151. // -- Returns a new array obtained by inserting an item or items
  152. // -- at a specified index.
  153. // --
  154. // -- Usage: `insert(array, idx, val)`
  155. // --
  156. // -- ```js
  157. // -- arr = ['a', 'b', 'c']
  158. // -- arr2 = insert(arr, 1, 'd')
  159. // -- // ['a', 'd', 'b', 'c']
  160. // -- arr2 === arr
  161. // -- // false
  162. // -- insert(arr, 1, ['d', 'e'])
  163. // -- // ['a', 'd', 'e', 'b', 'c']
  164. // -- ```
  165. function insert(array, idx, val) {
  166. return array.slice(0, idx).concat(Array.isArray(val) ? val : [val]).concat(array.slice(idx));
  167. } // -- #### removeAt()
  168. // -- Returns a new array obtained by removing an item at
  169. // -- a specified index.
  170. // --
  171. // -- Usage: `removeAt(array, idx)`
  172. // --
  173. // -- ```js
  174. // -- arr = ['a', 'b', 'c']
  175. // -- arr2 = removeAt(arr, 1)
  176. // -- // ['a', 'c']
  177. // -- arr2 === arr
  178. // -- // false
  179. // --
  180. // -- // The same array is returned if there are no changes:
  181. // -- removeAt(arr, 4) === arr
  182. // -- // true
  183. // -- ```
  184. function removeAt(array, idx) {
  185. if (idx >= array.length || idx < 0) return array;
  186. return array.slice(0, idx).concat(array.slice(idx + 1));
  187. } // -- #### replaceAt()
  188. // -- Returns a new array obtained by replacing an item at
  189. // -- a specified index. If the provided item is the same as
  190. // -- (*referentially equal to*) the previous item at that position,
  191. // -- the original array is returned.
  192. // --
  193. // -- Usage: `replaceAt(array, idx, newItem)`
  194. // --
  195. // -- ```js
  196. // -- arr = ['a', 'b', 'c']
  197. // -- arr2 = replaceAt(arr, 1, 'd')
  198. // -- // ['a', 'd', 'c']
  199. // -- arr2 === arr
  200. // -- // false
  201. // --
  202. // -- // The same object is returned if there are no changes:
  203. // -- replaceAt(arr, 1, 'b') === arr
  204. // -- // true
  205. // -- ```
  206. function replaceAt(array, idx, newItem) {
  207. if (array[idx] === newItem) return array;
  208. const len = array.length;
  209. const result = Array(len);
  210. for (let i = 0; i < len; i++) {
  211. result[i] = array[i];
  212. }
  213. result[idx] = newItem;
  214. return result;
  215. } // ===============================================
  216. // -- ### Collections (objects and arrays)
  217. // ===============================================
  218. // -- #### getIn()
  219. // -- Returns a value from an object at a given path. Works with
  220. // -- nested arrays and objects. If the path does not exist, it returns
  221. // -- `undefined`.
  222. // --
  223. // -- Usage: `getIn(obj, path)`
  224. // --
  225. // -- ```js
  226. // -- obj = { a: 1, b: 2, d: { d1: 3, d2: 4 }, e: ['a', 'b', 'c'] }
  227. // -- getIn(obj, ['d', 'd1'])
  228. // -- // 3
  229. // -- getIn(obj, ['e', 1])
  230. // -- // 'b'
  231. // -- ```
  232. function getIn(obj, path) {
  233. if (!Array.isArray(path)) {
  234. throwStr(IS_DEV ? 'A path array should be provided when calling getIn()' : INVALID_ARGS);
  235. }
  236. if (obj == null) return undefined;
  237. let ptr = obj;
  238. for (let i = 0; i < path.length; i++) {
  239. const key = path[i];
  240. ptr = ptr != null ? ptr[key] : undefined;
  241. if (ptr === undefined) return ptr;
  242. }
  243. return ptr;
  244. } // -- #### set()
  245. // -- Returns a new object with a modified attribute.
  246. // -- If the provided value is the same as (*referentially equal to*)
  247. // -- the previous value, the original object is returned.
  248. // --
  249. // -- Usage: `set(obj, key, val)`
  250. // --
  251. // -- ```js
  252. // -- obj = { a: 1, b: 2, c: 3 }
  253. // -- obj2 = set(obj, 'b', 5)
  254. // -- // { a: 1, b: 5, c: 3 }
  255. // -- obj2 === obj
  256. // -- // false
  257. // --
  258. // -- // The same object is returned if there are no changes:
  259. // -- set(obj, 'b', 2) === obj
  260. // -- // true
  261. // -- ```
  262. // When called with an undefined/null `obj`, `set()` returns either
  263. // a single-element array, or a single-key object
  264. // Implementation
  265. function set(obj0, key, val) {
  266. let obj = obj0;
  267. if (obj == null) obj = typeof key === 'number' ? [] : {};
  268. if (obj[key] === val) return obj;
  269. const obj2 = clone(obj);
  270. obj2[key] = val;
  271. return obj2;
  272. } // -- #### setIn()
  273. // -- Returns a new object with a modified **nested** attribute.
  274. // --
  275. // -- Notes:
  276. // --
  277. // -- * If the provided value is the same as (*referentially equal to*)
  278. // -- the previous value, the original object is returned.
  279. // -- * If the path does not exist, it will be created before setting
  280. // -- the new value.
  281. // --
  282. // -- Usage: `setIn(obj, path, val)`
  283. // --
  284. // -- ```js
  285. // -- obj = { a: 1, b: 2, d: { d1: 3, d2: 4 }, e: { e1: 'foo', e2: 'bar' } }
  286. // -- obj2 = setIn(obj, ['d', 'd1'], 4)
  287. // -- // { a: 1, b: 2, d: { d1: 4, d2: 4 }, e: { e1: 'foo', e2: 'bar' } }
  288. // -- obj2 === obj
  289. // -- // false
  290. // -- obj2.d === obj.d
  291. // -- // false
  292. // -- obj2.e === obj.e
  293. // -- // true
  294. // --
  295. // -- // The same object is returned if there are no changes:
  296. // -- obj3 = setIn(obj, ['d', 'd1'], 3)
  297. // -- // { a: 1, b: 2, d: { d1: 3, d2: 4 }, e: { e1: 'foo', e2: 'bar' } }
  298. // -- obj3 === obj
  299. // -- // true
  300. // -- obj3.d === obj.d
  301. // -- // true
  302. // -- obj3.e === obj.e
  303. // -- // true
  304. // --
  305. // -- // ... unknown paths create intermediate keys. Numeric segments are treated as array indices:
  306. // -- setIn({ a: 3 }, ['unknown', 0, 'path'], 4)
  307. // -- // { a: 3, unknown: [{ path: 4 }] }
  308. // -- ```
  309. function setIn(obj, path, val) {
  310. if (!path.length) return val;
  311. return doSetIn(obj, path, val, 0);
  312. }
  313. function doSetIn(obj, path, val, idx) {
  314. let newValue;
  315. const key = path[idx];
  316. if (idx === path.length - 1) {
  317. newValue = val;
  318. } else {
  319. const nestedObj = isObject(obj) && isObject(obj[key]) ? obj[key] : typeof path[idx + 1] === 'number' ? [] : {};
  320. newValue = doSetIn(nestedObj, path, val, idx + 1);
  321. }
  322. return set(obj, key, newValue);
  323. } // -- #### update()
  324. // -- Returns a new object with a modified attribute,
  325. // -- calculated via a user-provided callback based on the current value.
  326. // -- If the calculated value is the same as (*referentially equal to*)
  327. // -- the previous value, the original object is returned.
  328. // --
  329. // -- Usage: `update(obj, key, fnUpdate)`
  330. // --
  331. // -- ```js
  332. // -- obj = { a: 1, b: 2, c: 3 }
  333. // -- obj2 = update(obj, 'b', (val) => val + 1)
  334. // -- // { a: 1, b: 3, c: 3 }
  335. // -- obj2 === obj
  336. // -- // false
  337. // --
  338. // -- // The same object is returned if there are no changes:
  339. // -- update(obj, 'b', (val) => val) === obj
  340. // -- // true
  341. // -- ```
  342. function update(obj, key, fnUpdate) {
  343. const prevVal = obj == null ? undefined : obj[key];
  344. const nextVal = fnUpdate(prevVal);
  345. return set(obj, key, nextVal);
  346. } // -- #### updateIn()
  347. // -- Returns a new object with a modified **nested** attribute,
  348. // -- calculated via a user-provided callback based on the current value.
  349. // -- If the calculated value is the same as (*referentially equal to*)
  350. // -- the previous value, the original object is returned.
  351. // --
  352. // -- Usage: `updateIn<T: ArrayOrObject>(obj: T, path: Array<Key>,
  353. // -- fnUpdate: (prevValue: any) => any): T`
  354. // --
  355. // -- ```js
  356. // -- obj = { a: 1, d: { d1: 3, d2: 4 } }
  357. // -- obj2 = updateIn(obj, ['d', 'd1'], (val) => val + 1)
  358. // -- // { a: 1, d: { d1: 4, d2: 4 } }
  359. // -- obj2 === obj
  360. // -- // false
  361. // --
  362. // -- // The same object is returned if there are no changes:
  363. // -- obj3 = updateIn(obj, ['d', 'd1'], (val) => val)
  364. // -- // { a: 1, d: { d1: 3, d2: 4 } }
  365. // -- obj3 === obj
  366. // -- // true
  367. // -- ```
  368. function updateIn(obj, path, fnUpdate) {
  369. const prevVal = getIn(obj, path);
  370. const nextVal = fnUpdate(prevVal);
  371. return setIn(obj, path, nextVal);
  372. } // -- #### merge()
  373. // -- Returns a new object built as follows: the overlapping keys from the
  374. // -- second one overwrite the corresponding entries from the first one.
  375. // -- Similar to `Object.assign()`, but immutable.
  376. // --
  377. // -- Usage:
  378. // --
  379. // -- * `merge(obj1, obj2)`
  380. // -- * `merge(obj1, ...objects)`
  381. // --
  382. // -- The unmodified `obj1` is returned if `obj2` does not *provide something
  383. // -- new to* `obj1`, i.e. if either of the following
  384. // -- conditions are true:
  385. // --
  386. // -- * `obj2` is `null` or `undefined`
  387. // -- * `obj2` is an object, but it is empty
  388. // -- * All attributes of `obj2` are `undefined`
  389. // -- * All attributes of `obj2` are referentially equal to the
  390. // -- corresponding attributes of `obj1`
  391. // --
  392. // -- Note that `undefined` attributes in `obj2` do not modify the
  393. // -- corresponding attributes in `obj1`.
  394. // --
  395. // -- ```js
  396. // -- obj1 = { a: 1, b: 2, c: 3 }
  397. // -- obj2 = { c: 4, d: 5 }
  398. // -- obj3 = merge(obj1, obj2)
  399. // -- // { a: 1, b: 2, c: 4, d: 5 }
  400. // -- obj3 === obj1
  401. // -- // false
  402. // --
  403. // -- // The same object is returned if there are no changes:
  404. // -- merge(obj1, { c: 3 }) === obj1
  405. // -- // true
  406. // -- ```
  407. // Signatures:
  408. // - 1 arg
  409. // Implementation
  410. function merge(a, b, c, d, e, f, ...rest) {
  411. return rest.length ? doMerge.call(null, false, false, a, b, c, d, e, f, ...rest) : doMerge(false, false, a, b, c, d, e, f);
  412. } // -- #### mergeDeep()
  413. // -- Returns a new object built as follows: the overlapping keys from the
  414. // -- second one overwrite the corresponding entries from the first one.
  415. // -- If both the first and second entries are objects they are merged recursively.
  416. // -- Similar to `Object.assign()`, but immutable, and deeply merging.
  417. // --
  418. // -- Usage:
  419. // --
  420. // -- * `mergeDeep(obj1, obj2)`
  421. // -- * `mergeDeep(obj1, ...objects)`
  422. // --
  423. // -- The unmodified `obj1` is returned if `obj2` does not *provide something
  424. // -- new to* `obj1`, i.e. if either of the following
  425. // -- conditions are true:
  426. // --
  427. // -- * `obj2` is `null` or `undefined`
  428. // -- * `obj2` is an object, but it is empty
  429. // -- * All attributes of `obj2` are `undefined`
  430. // -- * All attributes of `obj2` are referentially equal to the
  431. // -- corresponding attributes of `obj1`
  432. // --
  433. // -- Note that `undefined` attributes in `obj2` do not modify the
  434. // -- corresponding attributes in `obj1`.
  435. // --
  436. // -- ```js
  437. // -- obj1 = { a: 1, b: 2, c: { a: 1 } }
  438. // -- obj2 = { b: 3, c: { b: 2 } }
  439. // -- obj3 = mergeDeep(obj1, obj2)
  440. // -- // { a: 1, b: 3, c: { a: 1, b: 2 } }
  441. // -- obj3 === obj1
  442. // -- // false
  443. // --
  444. // -- // The same object is returned if there are no changes:
  445. // -- mergeDeep(obj1, { c: { a: 1 } }) === obj1
  446. // -- // true
  447. // -- ```
  448. function mergeDeep(a, b, c, d, e, f, ...rest) {
  449. return rest.length ? doMerge.call(null, false, true, a, b, c, d, e, f, ...rest) : doMerge(false, true, a, b, c, d, e, f);
  450. } // -- #### mergeIn()
  451. // -- Similar to `merge()`, but merging the value at a given nested path.
  452. // --
  453. // -- Usage examples:
  454. // --
  455. // -- * `mergeIn(obj1, path, obj2)`
  456. // -- * `mergeIn(obj1, path, ...objects)`
  457. // --
  458. // -- ```js
  459. // -- obj1 = { a: 1, d: { b: { d1: 3, d2: 4 } } }
  460. // -- obj2 = { d3: 5 }
  461. // -- obj3 = mergeIn(obj1, ['d', 'b'], obj2)
  462. // -- // { a: 1, d: { b: { d1: 3, d2: 4, d3: 5 } } }
  463. // -- obj3 === obj1
  464. // -- // false
  465. // --
  466. // -- // The same object is returned if there are no changes:
  467. // -- mergeIn(obj1, ['d', 'b'], { d2: 4 }) === obj1
  468. // -- // true
  469. // -- ```
  470. function mergeIn(a, path, b, c, d, e, f, ...rest) {
  471. let prevVal = getIn(a, path);
  472. if (prevVal == null) prevVal = {};
  473. let nextVal;
  474. if (rest.length) {
  475. nextVal = doMerge.call(null, false, false, prevVal, b, c, d, e, f, ...rest);
  476. } else {
  477. nextVal = doMerge(false, false, prevVal, b, c, d, e, f);
  478. }
  479. return setIn(a, path, nextVal);
  480. } // -- #### omit()
  481. // -- Returns an object excluding one or several attributes.
  482. // --
  483. // -- Usage: `omit(obj, attrs)`
  484. //
  485. // -- ```js
  486. // -- obj = { a: 1, b: 2, c: 3, d: 4 }
  487. // -- omit(obj, 'a')
  488. // -- // { b: 2, c: 3, d: 4 }
  489. // -- omit(obj, ['b', 'c'])
  490. // -- // { a: 1, d: 4 }
  491. // --
  492. // -- // The same object is returned if there are no changes:
  493. // -- omit(obj, 'z') === obj1
  494. // -- // true
  495. // -- ```
  496. function omit(obj, attrs) {
  497. const omitList = Array.isArray(attrs) ? attrs : [attrs];
  498. let fDoSomething = false;
  499. for (let i = 0; i < omitList.length; i++) {
  500. if (hasOwnProperty.call(obj, omitList[i])) {
  501. fDoSomething = true;
  502. break;
  503. }
  504. }
  505. if (!fDoSomething) return obj;
  506. const out = {};
  507. const keys = getKeysAndSymbols(obj);
  508. for (let i = 0; i < keys.length; i++) {
  509. const key = keys[i];
  510. if (omitList.indexOf(key) >= 0) continue;
  511. out[key] = obj[key];
  512. }
  513. return out;
  514. } // -- #### addDefaults()
  515. // -- Returns a new object built as follows: `undefined` keys in the first one
  516. // -- are filled in with the corresponding values from the second one
  517. // -- (even if they are `null`).
  518. // --
  519. // -- Usage:
  520. // --
  521. // -- * `addDefaults(obj, defaults)`
  522. // -- * `addDefaults(obj, ...defaultObjects)`
  523. // --
  524. // -- ```js
  525. // -- obj1 = { a: 1, b: 2, c: 3 }
  526. // -- obj2 = { c: 4, d: 5, e: null }
  527. // -- obj3 = addDefaults(obj1, obj2)
  528. // -- // { a: 1, b: 2, c: 3, d: 5, e: null }
  529. // -- obj3 === obj1
  530. // -- // false
  531. // --
  532. // -- // The same object is returned if there are no changes:
  533. // -- addDefaults(obj1, { c: 4 }) === obj1
  534. // -- // true
  535. // -- ```
  536. // Signatures:
  537. // - 2 args
  538. // Implementation and catch-all
  539. function addDefaults(a, b, c, d, e, f, ...rest) {
  540. return rest.length ? doMerge.call(null, true, false, a, b, c, d, e, f, ...rest) : doMerge(true, false, a, b, c, d, e, f);
  541. }
  542. function doMerge(fAddDefaults, fDeep, first, ...rest) {
  543. let out = first;
  544. if (!(out != null)) {
  545. throwStr(IS_DEV ? 'At least one object should be provided to merge()' : INVALID_ARGS);
  546. }
  547. let fChanged = false;
  548. for (let idx = 0; idx < rest.length; idx++) {
  549. const obj = rest[idx];
  550. if (obj == null) continue;
  551. const keys = getKeysAndSymbols(obj);
  552. if (!keys.length) continue;
  553. for (let j = 0; j <= keys.length; j++) {
  554. const key = keys[j];
  555. if (fAddDefaults && out[key] !== undefined) continue;
  556. let nextVal = obj[key];
  557. if (fDeep && isObject(out[key]) && isObject(nextVal)) {
  558. nextVal = doMerge(fAddDefaults, fDeep, out[key], nextVal);
  559. }
  560. if (nextVal === undefined || nextVal === out[key]) continue;
  561. if (!fChanged) {
  562. fChanged = true;
  563. out = clone(out);
  564. }
  565. out[key] = nextVal;
  566. }
  567. }
  568. return out;
  569. } // ===============================================
  570. // ### Public API
  571. // ===============================================
  572. const timm = {
  573. clone,
  574. addLast,
  575. addFirst,
  576. removeLast,
  577. removeFirst,
  578. insert,
  579. removeAt,
  580. replaceAt,
  581. getIn,
  582. set,
  583. setIn,
  584. update,
  585. updateIn,
  586. merge,
  587. mergeDeep,
  588. mergeIn,
  589. omit,
  590. addDefaults
  591. };
  592. var _default = timm;
  593. exports.default = _default;