20aabcc8bdb6734d58a50fba5c38f9d8cc5022c0a88cd637bc2c3fe9e157f3edd24c9428b18b9e3c90fe4715080d284d2c4539fc8f1d6a46177d74b81d8059 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import cloneDeep = require('lodash.clonedeep');
  2. import isEqual = require('lodash.isequal');
  3. interface AttributeMap {
  4. [key: string]: unknown;
  5. }
  6. namespace AttributeMap {
  7. export function compose(
  8. a: AttributeMap = {},
  9. b: AttributeMap = {},
  10. keepNull = false,
  11. ): AttributeMap | undefined {
  12. if (typeof a !== 'object') {
  13. a = {};
  14. }
  15. if (typeof b !== 'object') {
  16. b = {};
  17. }
  18. let attributes = cloneDeep(b);
  19. if (!keepNull) {
  20. attributes = Object.keys(attributes).reduce<AttributeMap>((copy, key) => {
  21. if (attributes[key] != null) {
  22. copy[key] = attributes[key];
  23. }
  24. return copy;
  25. }, {});
  26. }
  27. for (const key in a) {
  28. if (a[key] !== undefined && b[key] === undefined) {
  29. attributes[key] = a[key];
  30. }
  31. }
  32. return Object.keys(attributes).length > 0 ? attributes : undefined;
  33. }
  34. export function diff(
  35. a: AttributeMap = {},
  36. b: AttributeMap = {},
  37. ): AttributeMap | undefined {
  38. if (typeof a !== 'object') {
  39. a = {};
  40. }
  41. if (typeof b !== 'object') {
  42. b = {};
  43. }
  44. const attributes = Object.keys(a)
  45. .concat(Object.keys(b))
  46. .reduce<AttributeMap>((attrs, key) => {
  47. if (!isEqual(a[key], b[key])) {
  48. attrs[key] = b[key] === undefined ? null : b[key];
  49. }
  50. return attrs;
  51. }, {});
  52. return Object.keys(attributes).length > 0 ? attributes : undefined;
  53. }
  54. export function invert(
  55. attr: AttributeMap = {},
  56. base: AttributeMap = {},
  57. ): AttributeMap {
  58. attr = attr || {};
  59. const baseInverted = Object.keys(base).reduce<AttributeMap>((memo, key) => {
  60. if (base[key] !== attr[key] && attr[key] !== undefined) {
  61. memo[key] = base[key];
  62. }
  63. return memo;
  64. }, {});
  65. return Object.keys(attr).reduce<AttributeMap>((memo, key) => {
  66. if (attr[key] !== base[key] && base[key] === undefined) {
  67. memo[key] = null;
  68. }
  69. return memo;
  70. }, baseInverted);
  71. }
  72. export function transform(
  73. a: AttributeMap | undefined,
  74. b: AttributeMap | undefined,
  75. priority = false,
  76. ): AttributeMap | undefined {
  77. if (typeof a !== 'object') {
  78. return b;
  79. }
  80. if (typeof b !== 'object') {
  81. return undefined;
  82. }
  83. if (!priority) {
  84. return b; // b simply overwrites us without priority
  85. }
  86. const attributes = Object.keys(b).reduce<AttributeMap>((attrs, key) => {
  87. if (a[key] === undefined) {
  88. attrs[key] = b[key]; // null is a valid value
  89. }
  90. return attrs;
  91. }, {});
  92. return Object.keys(attributes).length > 0 ? attributes : undefined;
  93. }
  94. }
  95. export default AttributeMap;