cow-value-model.js 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. function copyWith (obj, key, value) {
  2. const result = typeof key === 'number' ? [...obj] : {...obj};
  3. result[key] = value;
  4. return result;
  5. }
  6. export const cowValueModel = (...keyDescriptions) => {
  7. const keys = [];
  8. function fillKeys (keyDescriptions) {
  9. keyDescriptions.forEach(each => {
  10. if (typeof each === 'number') keys.push(each);
  11. else if (Array.isArray(each)) fillKeys(each);
  12. else keys.push(...each.toString().split('.'));
  13. });
  14. }
  15. fillKeys(keyDescriptions);
  16. function setField (x = {}, index, val) {
  17. if (index >= keys.length) return val;
  18. const key = keys[index],
  19. value = x[key],
  20. modified = setField(value, index + 1, val);
  21. return value === modified ? x : copyWith(x, key, modified);
  22. }
  23. const GET_SENTINEL = {};
  24. return (obj, val = GET_SENTINEL) =>
  25. val === GET_SENTINEL ?
  26. keys.reduce((x = {}, key) => x[key], obj) :
  27. setField(obj, 0, val);
  28. };
  29. export const cowWorkshop = (keys, fn = x => x) => (obj, {result = obj, resultKeys = keys, diff} = {}) => {
  30. keys.forEach((key, index) => {
  31. const value = fn(cowValueModel(key)(obj));
  32. const modifier = cowValueModel(resultKeys[index]);
  33. const oldDst = result;
  34. result = modifier(oldDst, value);
  35. if (result !== oldDst) {
  36. diff = modifier(diff, value);
  37. }
  38. });
  39. return {result, diff};
  40. };