index.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. "use strict";
  2. var __create = Object.create;
  3. var __defProp = Object.defineProperty;
  4. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  5. var __getOwnPropNames = Object.getOwnPropertyNames;
  6. var __getProtoOf = Object.getPrototypeOf;
  7. var __hasOwnProp = Object.prototype.hasOwnProperty;
  8. var __export = (target, all) => {
  9. for (var name in all)
  10. __defProp(target, name, { get: all[name], enumerable: true });
  11. };
  12. var __copyProps = (to, from, except, desc) => {
  13. if (from && typeof from === "object" || typeof from === "function") {
  14. for (let key of __getOwnPropNames(from))
  15. if (!__hasOwnProp.call(to, key) && key !== except)
  16. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  17. }
  18. return to;
  19. };
  20. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  21. // If the importer is in node compatibility mode or this is not an ESM
  22. // file that has been converted to a CommonJS file using a Babel-
  23. // compatible transform (i.e. "__esModule" has not been set), then set
  24. // "default" to the CommonJS "module.exports" for node compatibility.
  25. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  26. mod
  27. ));
  28. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  29. // src/index.ts
  30. var src_exports = {};
  31. __export(src_exports, {
  32. default: () => treeChanges
  33. });
  34. module.exports = __toCommonJS(src_exports);
  35. var import_deep_equal2 = __toESM(require("@gilbarbara/deep-equal"));
  36. var import_is_lite2 = __toESM(require("is-lite"));
  37. // src/helpers.ts
  38. var import_deep_equal = __toESM(require("@gilbarbara/deep-equal"));
  39. var import_is_lite = __toESM(require("is-lite"));
  40. function canHaveLength(...arguments_) {
  41. return arguments_.every((d) => import_is_lite.default.string(d) || import_is_lite.default.array(d) || import_is_lite.default.plainObject(d));
  42. }
  43. function checkEquality(left, right, value) {
  44. if (!isSameType(left, right)) {
  45. return false;
  46. }
  47. if ([left, right].every(import_is_lite.default.array)) {
  48. return !left.some(hasValue(value)) && right.some(hasValue(value));
  49. }
  50. if ([left, right].every(import_is_lite.default.plainObject)) {
  51. return !Object.entries(left).some(hasEntry(value)) && Object.entries(right).some(hasEntry(value));
  52. }
  53. return right === value;
  54. }
  55. function compareNumbers(previousData, data, options) {
  56. const { actual, key, previous, type } = options;
  57. const left = nested(previousData, key);
  58. const right = nested(data, key);
  59. let changed = [left, right].every(import_is_lite.default.number) && (type === "increased" ? left < right : left > right);
  60. if (!import_is_lite.default.undefined(actual)) {
  61. changed = changed && right === actual;
  62. }
  63. if (!import_is_lite.default.undefined(previous)) {
  64. changed = changed && left === previous;
  65. }
  66. return changed;
  67. }
  68. function compareValues(previousData, data, options) {
  69. const { key, type, value } = options;
  70. const left = nested(previousData, key);
  71. const right = nested(data, key);
  72. const primary = type === "added" ? left : right;
  73. const secondary = type === "added" ? right : left;
  74. if (!import_is_lite.default.nullOrUndefined(value)) {
  75. if (import_is_lite.default.defined(primary)) {
  76. if (import_is_lite.default.array(primary) || import_is_lite.default.plainObject(primary)) {
  77. return checkEquality(primary, secondary, value);
  78. }
  79. } else {
  80. return (0, import_deep_equal.default)(secondary, value);
  81. }
  82. return false;
  83. }
  84. if ([left, right].every(import_is_lite.default.array)) {
  85. return !secondary.every(isEqualPredicate(primary));
  86. }
  87. if ([left, right].every(import_is_lite.default.plainObject)) {
  88. return hasExtraKeys(Object.keys(primary), Object.keys(secondary));
  89. }
  90. return ![left, right].every((d) => import_is_lite.default.primitive(d) && import_is_lite.default.defined(d)) && (type === "added" ? !import_is_lite.default.defined(left) && import_is_lite.default.defined(right) : import_is_lite.default.defined(left) && !import_is_lite.default.defined(right));
  91. }
  92. function getIterables(previousData, data, { key } = {}) {
  93. let left = nested(previousData, key);
  94. let right = nested(data, key);
  95. if (!isSameType(left, right)) {
  96. throw new TypeError("Inputs have different types");
  97. }
  98. if (!canHaveLength(left, right)) {
  99. throw new TypeError("Inputs don't have length");
  100. }
  101. if ([left, right].every(import_is_lite.default.plainObject)) {
  102. left = Object.keys(left);
  103. right = Object.keys(right);
  104. }
  105. return [left, right];
  106. }
  107. function hasEntry(input) {
  108. return ([key, value]) => {
  109. if (import_is_lite.default.array(input)) {
  110. return (0, import_deep_equal.default)(input, value) || input.some((d) => (0, import_deep_equal.default)(d, value) || import_is_lite.default.array(value) && isEqualPredicate(value)(d));
  111. }
  112. if (import_is_lite.default.plainObject(input) && input[key]) {
  113. return !!input[key] && (0, import_deep_equal.default)(input[key], value);
  114. }
  115. return (0, import_deep_equal.default)(input, value);
  116. };
  117. }
  118. function hasExtraKeys(left, right) {
  119. return right.some((d) => !left.includes(d));
  120. }
  121. function hasValue(input) {
  122. return (value) => {
  123. if (import_is_lite.default.array(input)) {
  124. return input.some((d) => (0, import_deep_equal.default)(d, value) || import_is_lite.default.array(value) && isEqualPredicate(value)(d));
  125. }
  126. return (0, import_deep_equal.default)(input, value);
  127. };
  128. }
  129. function includesOrEqualsTo(previousValue, value) {
  130. return import_is_lite.default.array(previousValue) ? previousValue.some((d) => (0, import_deep_equal.default)(d, value)) : (0, import_deep_equal.default)(previousValue, value);
  131. }
  132. function isEqualPredicate(data) {
  133. return (value) => data.some((d) => (0, import_deep_equal.default)(d, value));
  134. }
  135. function isSameType(...arguments_) {
  136. return arguments_.every(import_is_lite.default.array) || arguments_.every(import_is_lite.default.number) || arguments_.every(import_is_lite.default.plainObject) || arguments_.every(import_is_lite.default.string);
  137. }
  138. function nested(data, property) {
  139. if (import_is_lite.default.plainObject(data) || import_is_lite.default.array(data)) {
  140. if (import_is_lite.default.string(property)) {
  141. const props = property.split(".");
  142. return props.reduce((acc, d) => acc && acc[d], data);
  143. }
  144. if (import_is_lite.default.number(property)) {
  145. return data[property];
  146. }
  147. return data;
  148. }
  149. return data;
  150. }
  151. // src/index.ts
  152. function treeChanges(previousData, data) {
  153. if ([previousData, data].some(import_is_lite2.default.nullOrUndefined)) {
  154. throw new Error("Missing required parameters");
  155. }
  156. if (![previousData, data].every((d) => import_is_lite2.default.plainObject(d) || import_is_lite2.default.array(d))) {
  157. throw new Error("Expected plain objects or array");
  158. }
  159. const added = (key, value) => {
  160. try {
  161. return compareValues(previousData, data, { key, type: "added", value });
  162. } catch {
  163. return false;
  164. }
  165. };
  166. const changed = (key, actual, previous) => {
  167. try {
  168. const left = nested(previousData, key);
  169. const right = nested(data, key);
  170. const hasActual = import_is_lite2.default.defined(actual);
  171. const hasPrevious = import_is_lite2.default.defined(previous);
  172. if (hasActual || hasPrevious) {
  173. const leftComparator = hasPrevious ? includesOrEqualsTo(previous, left) : !includesOrEqualsTo(actual, left);
  174. const rightComparator = includesOrEqualsTo(actual, right);
  175. return leftComparator && rightComparator;
  176. }
  177. if ([left, right].every(import_is_lite2.default.array) || [left, right].every(import_is_lite2.default.plainObject)) {
  178. return !(0, import_deep_equal2.default)(left, right);
  179. }
  180. return left !== right;
  181. } catch {
  182. return false;
  183. }
  184. };
  185. const changedFrom = (key, previous, actual) => {
  186. if (!import_is_lite2.default.defined(key)) {
  187. return false;
  188. }
  189. try {
  190. const left = nested(previousData, key);
  191. const right = nested(data, key);
  192. const hasActual = import_is_lite2.default.defined(actual);
  193. return includesOrEqualsTo(previous, left) && (hasActual ? includesOrEqualsTo(actual, right) : !hasActual);
  194. } catch {
  195. return false;
  196. }
  197. };
  198. const decreased = (key, actual, previous) => {
  199. if (!import_is_lite2.default.defined(key)) {
  200. return false;
  201. }
  202. try {
  203. return compareNumbers(previousData, data, { key, actual, previous, type: "decreased" });
  204. } catch {
  205. return false;
  206. }
  207. };
  208. const emptied = (key) => {
  209. try {
  210. const [left, right] = getIterables(previousData, data, { key });
  211. return !!left.length && !right.length;
  212. } catch {
  213. return false;
  214. }
  215. };
  216. const filled = (key) => {
  217. try {
  218. const [left, right] = getIterables(previousData, data, { key });
  219. return !left.length && !!right.length;
  220. } catch {
  221. return false;
  222. }
  223. };
  224. const increased = (key, actual, previous) => {
  225. if (!import_is_lite2.default.defined(key)) {
  226. return false;
  227. }
  228. try {
  229. return compareNumbers(previousData, data, { key, actual, previous, type: "increased" });
  230. } catch {
  231. return false;
  232. }
  233. };
  234. const removed = (key, value) => {
  235. try {
  236. return compareValues(previousData, data, { key, type: "removed", value });
  237. } catch {
  238. return false;
  239. }
  240. };
  241. return { added, changed, changedFrom, decreased, emptied, filled, increased, removed };
  242. }
  243. //# sourceMappingURL=index.js.map
  244. // fix-cjs-exports
  245. if (module.exports.default) {
  246. Object.assign(module.exports.default, module.exports);
  247. module.exports = module.exports.default;
  248. delete module.exports.default;
  249. }