@ztimson/utils 0.26.1 → 0.26.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -199,13 +199,34 @@ ${opts.message || this.desc}`;
199
199
  if (type == "function") return target.toString() == values.toString();
200
200
  return target == values;
201
201
  }
202
- function isEqual(a, b) {
203
- const ta = typeof a, tb = typeof b;
204
- if (ta != "object" || a == null || (tb != "object" || b == null))
205
- return ta == "function" && tb == "function" ? a.toString() == b.toString() : a === b;
206
- const keys = Object.keys(a);
207
- if (keys.length != Object.keys(b).length) return false;
208
- return Object.keys(a).every((key) => isEqual(a[key], b[key]));
202
+ function isEqual(a, b, seen = /* @__PURE__ */ new WeakMap()) {
203
+ if (a === b) return true;
204
+ if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
205
+ if (a instanceof RegExp && b instanceof RegExp) return a.source === b.source && a.flags === b.flags;
206
+ if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
207
+ if (Number.isNaN(a) && Number.isNaN(b)) return true;
208
+ if (typeof a === "function" && typeof b === "function") return a.toString() === b.toString();
209
+ return false;
210
+ }
211
+ if (seen.has(a)) return seen.get(a) === b;
212
+ seen.set(a, b);
213
+ const isArrayA = Array.isArray(a);
214
+ const isArrayB = Array.isArray(b);
215
+ if (isArrayA && isArrayB) {
216
+ if (a.length !== b.length) return false;
217
+ for (let i = 0; i < a.length; i++) {
218
+ if (!isEqual(a[i], b[i], seen)) return false;
219
+ }
220
+ return true;
221
+ }
222
+ if (isArrayA !== isArrayB) return false;
223
+ const keysA = Object.keys(a);
224
+ const keysB = Object.keys(b);
225
+ if (keysA.length !== keysB.length) return false;
226
+ for (const key of keysA) {
227
+ if (!Object.prototype.hasOwnProperty.call(b, key) || !isEqual(a[key], b[key], seen)) return false;
228
+ }
229
+ return true;
209
230
  }
210
231
  function mixin(target, constructors) {
211
232
  constructors.forEach((c) => {
@@ -1723,7 +1744,7 @@ ${opts.message || this.desc}`;
1723
1744
  }
1724
1745
  class PathError extends Error {
1725
1746
  }
1726
- class PathEvent {
1747
+ const _PathEvent = class _PathEvent {
1727
1748
  constructor(e) {
1728
1749
  /** First directory in path */
1729
1750
  __publicField(this, "module");
@@ -1735,7 +1756,14 @@ ${opts.message || this.desc}`;
1735
1756
  __publicField(this, "name");
1736
1757
  /** List of methods */
1737
1758
  __publicField(this, "methods");
1738
- if (typeof e == "object") return Object.assign(this, e);
1759
+ if (typeof e == "object") {
1760
+ Object.assign(this, e);
1761
+ return;
1762
+ }
1763
+ if (_PathEvent.pathEventCache.has(e)) {
1764
+ Object.assign(this, _PathEvent.pathEventCache.get(e));
1765
+ return;
1766
+ }
1739
1767
  let [p, scope, method] = e.replaceAll(/\/{2,}/g, "/").split(":");
1740
1768
  if (!method) method = scope || "*";
1741
1769
  if (p == "*" || !p && method == "*") {
@@ -1748,13 +1776,14 @@ ${opts.message || this.desc}`;
1748
1776
  this.fullPath = `${this.module}${this.module && this.path ? "/" : ""}${this.path}`;
1749
1777
  this.name = temp.pop() || "";
1750
1778
  this.methods = new ASet(method.split(""));
1779
+ _PathEvent.pathEventCache.set(e, this);
1751
1780
  }
1752
1781
  /** All/Wildcard specified */
1753
1782
  get all() {
1754
1783
  return this.methods.has("*");
1755
1784
  }
1756
1785
  set all(v) {
1757
- v ? new ASet(["*"]) : this.methods.delete("*");
1786
+ v ? this.methods = new ASet(["*"]) : this.methods.delete("*");
1758
1787
  }
1759
1788
  /** None specified */
1760
1789
  get none() {
@@ -1791,6 +1820,10 @@ ${opts.message || this.desc}`;
1791
1820
  set delete(v) {
1792
1821
  v ? this.methods.delete("n").delete("*").add("d") : this.methods.delete("d");
1793
1822
  }
1823
+ /** Clear the cache of all PathEvents */
1824
+ static clearCache() {
1825
+ _PathEvent.pathEventCache.clear();
1826
+ }
1794
1827
  /**
1795
1828
  * Combine multiple events into one parsed object. Longest path takes precedent, but all subsequent methods are
1796
1829
  * combined until a "none" is reached
@@ -1800,7 +1833,7 @@ ${opts.message || this.desc}`;
1800
1833
  */
1801
1834
  static combine(...paths) {
1802
1835
  let hitNone = false;
1803
- const combined = paths.map((p) => new PathEvent(p)).toSorted((p1, p2) => {
1836
+ const combined = paths.map((p) => p instanceof _PathEvent ? p : new _PathEvent(p)).toSorted((p1, p2) => {
1804
1837
  const l1 = p1.fullPath.length, l2 = p2.fullPath.length;
1805
1838
  return l1 < l2 ? 1 : l1 > l2 ? -1 : 0;
1806
1839
  }).reduce((acc, p) => {
@@ -1808,10 +1841,9 @@ ${opts.message || this.desc}`;
1808
1841
  if (p.none) hitNone = true;
1809
1842
  if (!acc) return p;
1810
1843
  if (hitNone) return acc;
1811
- acc.methods = [...acc.methods, ...p.methods];
1844
+ acc.methods = new ASet([...acc.methods, ...p.methods]);
1812
1845
  return acc;
1813
1846
  }, null);
1814
- combined.methods = new ASet(combined.methods);
1815
1847
  return combined;
1816
1848
  }
1817
1849
  /**
@@ -1822,11 +1854,12 @@ ${opts.message || this.desc}`;
1822
1854
  * @return {boolean} Whether there is any overlap
1823
1855
  */
1824
1856
  static filter(target, ...filter) {
1825
- const parsedTarget = makeArray(target).map((pe) => new PathEvent(pe));
1826
- const parsedFilter = makeArray(filter).map((pe) => new PathEvent(pe));
1857
+ const parsedTarget = makeArray(target).map((pe) => pe instanceof _PathEvent ? pe : new _PathEvent(pe));
1858
+ const parsedFilter = makeArray(filter).map((pe) => pe instanceof _PathEvent ? pe : new _PathEvent(pe));
1827
1859
  return parsedTarget.filter((t) => !!parsedFilter.find((r) => {
1828
1860
  const wildcard = r.fullPath == "*" || t.fullPath == "*";
1829
- const p1 = r.fullPath.slice(0, r.fullPath.indexOf("*")), p2 = t.fullPath.slice(0, t.fullPath.indexOf("*"));
1861
+ const p1 = r.fullPath.includes("*") ? r.fullPath.slice(0, r.fullPath.indexOf("*")) : r.fullPath;
1862
+ const p2 = t.fullPath.includes("*") ? t.fullPath.slice(0, t.fullPath.indexOf("*")) : t.fullPath;
1830
1863
  const scope = p1.startsWith(p2) || p2.startsWith(p1);
1831
1864
  const methods = r.all || t.all || r.methods.intersection(t.methods).length;
1832
1865
  return (wildcard || scope) && methods;
@@ -1840,11 +1873,12 @@ ${opts.message || this.desc}`;
1840
1873
  * @return {boolean} Whether there is any overlap
1841
1874
  */
1842
1875
  static has(target, ...has) {
1843
- const parsedTarget = makeArray(target).map((pe) => new PathEvent(pe));
1844
- const parsedRequired = makeArray(has).map((pe) => new PathEvent(pe));
1876
+ const parsedTarget = makeArray(target).map((pe) => pe instanceof _PathEvent ? pe : new _PathEvent(pe));
1877
+ const parsedRequired = makeArray(has).map((pe) => pe instanceof _PathEvent ? pe : new _PathEvent(pe));
1845
1878
  return !!parsedRequired.find((r) => !!parsedTarget.find((t) => {
1846
1879
  const wildcard = r.fullPath == "*" || t.fullPath == "*";
1847
- const p1 = r.fullPath.slice(0, r.fullPath.indexOf("*")), p2 = t.fullPath.slice(0, t.fullPath.indexOf("*"));
1880
+ const p1 = r.fullPath.includes("*") ? r.fullPath.slice(0, r.fullPath.indexOf("*")) : r.fullPath;
1881
+ const p2 = t.fullPath.includes("*") ? t.fullPath.slice(0, t.fullPath.indexOf("*")) : t.fullPath;
1848
1882
  const scope = p1.startsWith(p2);
1849
1883
  const methods = r.all || t.all || r.methods.intersection(t.methods).length;
1850
1884
  return (wildcard || scope) && methods;
@@ -1858,7 +1892,7 @@ ${opts.message || this.desc}`;
1858
1892
  * @return {boolean} Whether there is any overlap
1859
1893
  */
1860
1894
  static hasAll(target, ...has) {
1861
- return has.filter((h) => PathEvent.has(target, h)).length == has.length;
1895
+ return has.filter((h) => _PathEvent.has(target, h)).length == has.length;
1862
1896
  }
1863
1897
  /**
1864
1898
  * Same as `has` but raises an error if there is no overlap
@@ -1867,7 +1901,7 @@ ${opts.message || this.desc}`;
1867
1901
  * @param has Target must have at least one of these path
1868
1902
  */
1869
1903
  static hasFatal(target, ...has) {
1870
- if (!PathEvent.has(target, ...has)) throw new PathError(`Requires one of: ${makeArray(has).join(", ")}`);
1904
+ if (!_PathEvent.has(target, ...has)) throw new PathError(`Requires one of: ${makeArray(has).join(", ")}`);
1871
1905
  }
1872
1906
  /**
1873
1907
  * Same as `hasAll` but raises an error if the target is missing any paths
@@ -1876,7 +1910,7 @@ ${opts.message || this.desc}`;
1876
1910
  * @param has Target must have all these paths
1877
1911
  */
1878
1912
  static hasAllFatal(target, ...has) {
1879
- if (!PathEvent.hasAll(target, ...has)) throw new PathError(`Requires all: ${makeArray(has).join(", ")}`);
1913
+ if (!_PathEvent.hasAll(target, ...has)) throw new PathError(`Requires all: ${makeArray(has).join(", ")}`);
1880
1914
  }
1881
1915
  /**
1882
1916
  * Create event string from its components
@@ -1898,7 +1932,7 @@ ${opts.message || this.desc}`;
1898
1932
  * @return {boolean} Whether there is any overlap
1899
1933
  */
1900
1934
  has(...has) {
1901
- return PathEvent.has(this, ...has);
1935
+ return _PathEvent.has(this, ...has);
1902
1936
  }
1903
1937
  /**
1904
1938
  * Squash 2 sets of paths & return true if the target has all paths
@@ -1907,7 +1941,7 @@ ${opts.message || this.desc}`;
1907
1941
  * @return {boolean} Whether there is any overlap
1908
1942
  */
1909
1943
  hasAll(...has) {
1910
- return PathEvent.hasAll(this, ...has);
1944
+ return _PathEvent.hasAll(this, ...has);
1911
1945
  }
1912
1946
  /**
1913
1947
  * Same as `has` but raises an error if there is no overlap
@@ -1915,7 +1949,7 @@ ${opts.message || this.desc}`;
1915
1949
  * @param has Target must have at least one of these path
1916
1950
  */
1917
1951
  hasFatal(...has) {
1918
- return PathEvent.hasFatal(this, ...has);
1952
+ return _PathEvent.hasFatal(this, ...has);
1919
1953
  }
1920
1954
  /**
1921
1955
  * Same as `hasAll` but raises an error if the target is missing any paths
@@ -1923,7 +1957,7 @@ ${opts.message || this.desc}`;
1923
1957
  * @param has Target must have all these paths
1924
1958
  */
1925
1959
  hasAllFatal(...has) {
1926
- return PathEvent.hasAllFatal(this, ...has);
1960
+ return _PathEvent.hasAllFatal(this, ...has);
1927
1961
  }
1928
1962
  /**
1929
1963
  * Filter a set of paths based on this event
@@ -1932,7 +1966,7 @@ ${opts.message || this.desc}`;
1932
1966
  * @return {boolean} Whether there is any overlap
1933
1967
  */
1934
1968
  filter(target) {
1935
- return PathEvent.filter(target, this);
1969
+ return _PathEvent.filter(target, this);
1936
1970
  }
1937
1971
  /**
1938
1972
  * Create event string from its components
@@ -1940,16 +1974,19 @@ ${opts.message || this.desc}`;
1940
1974
  * @return {string} String representation of Event
1941
1975
  */
1942
1976
  toString() {
1943
- return PathEvent.toString(this.fullPath, this.methods);
1977
+ return _PathEvent.toString(this.fullPath, this.methods);
1944
1978
  }
1945
- }
1979
+ };
1980
+ /** Internal cache for PathEvent instances to avoid redundant parsing */
1981
+ __publicField(_PathEvent, "pathEventCache", /* @__PURE__ */ new Map());
1982
+ let PathEvent = _PathEvent;
1946
1983
  class PathEventEmitter {
1947
1984
  constructor(prefix = "") {
1948
1985
  __publicField(this, "listeners", []);
1949
1986
  this.prefix = prefix;
1950
1987
  }
1951
1988
  emit(event, ...args) {
1952
- const parsed = PE`${this.prefix}/${event}`;
1989
+ const parsed = event instanceof PathEvent ? event : new PathEvent(`${this.prefix}/${event}`);
1953
1990
  this.listeners.filter((l) => PathEvent.has(l[0], parsed)).forEach(async (l) => l[1](parsed, ...args));
1954
1991
  }
1955
1992
  off(listener) {
@@ -1957,7 +1994,7 @@ ${opts.message || this.desc}`;
1957
1994
  }
1958
1995
  on(event, listener) {
1959
1996
  makeArray(event).forEach((e) => this.listeners.push([
1960
- new PathEvent(`${this.prefix}/${e}`),
1997
+ e instanceof PathEvent ? e : new PathEvent(`${this.prefix}/${e}`),
1961
1998
  listener
1962
1999
  ]));
1963
2000
  return () => this.off(listener);