cow-value-model.js 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  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 == null ? undefined : 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 == null ? undefined : 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. if (typeof value === "undefined") return;
  33. const modifier = cowValueModel(resultKeys[index]);
  34. const oldResult = result;
  35. result = modifier(oldResult, value);
  36. if (result !== oldResult) {
  37. diff = modifier(diff, value);
  38. }
  39. });
  40. return {result, diff};
  41. };