@oscarpalmer/atoms 0.168.0 → 0.170.0

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.d.mts CHANGED
@@ -2980,6 +2980,12 @@ declare function isNumber(value: unknown): value is number;
2980
2980
  * @returns `true` if the value is a plain object, otherwise `false`
2981
2981
  */
2982
2982
  declare function isPlainObject(value: unknown): value is PlainObject;
2983
+ /**
2984
+ * - Is the value a primitive value?
2985
+ * @param value Value to check
2986
+ * @returns `true` if the value matches, otherwise `false`
2987
+ */
2988
+ declare function isPrimitive(value: unknown): value is Primitive;
2983
2989
  /**
2984
2990
  * Is the value a typed array?
2985
2991
  * @param value Value to check
@@ -3030,12 +3036,6 @@ declare function isNumerical(value: unknown): value is number | `${number}`;
3030
3036
  * @returns `true` if the value matches, otherwise `false`
3031
3037
  */
3032
3038
  declare function isObject(value: unknown): value is object;
3033
- /**
3034
- * - Is the value a primitive value?
3035
- * @param value Value to check
3036
- * @returns `true` if the value matches, otherwise `false`
3037
- */
3038
- declare function isPrimitive(value: unknown): value is Primitive;
3039
3039
  //#endregion
3040
3040
  //#region src/logger.d.ts
3041
3041
  declare class Logger {
package/dist/index.mjs CHANGED
@@ -215,6 +215,14 @@ function isPlainObject(value) {
215
215
  return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
216
216
  }
217
217
  /**
218
+ * - Is the value a primitive value?
219
+ * @param value Value to check
220
+ * @returns `true` if the value matches, otherwise `false`
221
+ */
222
+ function isPrimitive(value) {
223
+ return value == null || EXPRESSION_PRIMITIVE.test(typeof value);
224
+ }
225
+ /**
218
226
  * Is the value a typed array?
219
227
  * @param value Value to check
220
228
  * @returns `true` if the value is a typed array, otherwise `false`
@@ -235,6 +243,7 @@ function isTypedArray(value) {
235
243
  ]);
236
244
  return TYPED_ARRAYS.has(value?.constructor);
237
245
  }
246
+ const EXPRESSION_PRIMITIVE = /^(bigint|boolean|number|string|symbol)$/;
238
247
  let TYPED_ARRAYS;
239
248
  //#endregion
240
249
  //#region src/internal/random.ts
@@ -1137,24 +1146,25 @@ function getInterval(value) {
1137
1146
  }
1138
1147
  function getTimer(type, callback, time) {
1139
1148
  const interval = getInterval(time);
1140
- function run(now) {
1149
+ function run() {
1150
+ const now = performance.now();
1141
1151
  start ??= now;
1142
1152
  if (interval === 0 || now - start >= interval - OFFSET) {
1143
1153
  start = throttle ? now : void 0;
1144
1154
  callback(...args);
1145
- } else frame = requestAnimationFrame(run);
1155
+ } else id = startTimer(run);
1146
1156
  }
1147
1157
  const throttle = type === TIMER_THROTTLE;
1148
1158
  let args;
1149
- let frame;
1159
+ let id;
1150
1160
  let start;
1151
1161
  const timer = (...parameters) => {
1152
1162
  timer.cancel();
1153
1163
  args = parameters;
1154
- frame = requestAnimationFrame(run);
1164
+ id = startTimer(run);
1155
1165
  };
1156
1166
  timer.cancel = () => {
1157
- cancelAnimationFrame(frame);
1167
+ clearTimer(id);
1158
1168
  };
1159
1169
  return timer;
1160
1170
  }
@@ -1162,6 +1172,8 @@ const OFFSET = 5;
1162
1172
  const TIMER_DEBOUNCE = "debounce";
1163
1173
  const TIMER_THROTTLE = "throttle";
1164
1174
  const TIMER_WAIT = "wait";
1175
+ const clearTimer = typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : clearTimeout;
1176
+ const startTimer = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout;
1165
1177
  //#endregion
1166
1178
  //#region src/internal/function/misc.ts
1167
1179
  /**
@@ -1255,7 +1267,7 @@ var SizedMap = class extends Map {
1255
1267
  * Is the Map full?
1256
1268
  */
1257
1269
  get full() {
1258
- return this.size >= this.#maximumSize;
1270
+ return super.size >= this.#maximumSize;
1259
1271
  }
1260
1272
  get maximum() {
1261
1273
  return this.#maximumSize;
@@ -1274,17 +1286,23 @@ var SizedMap = class extends Map {
1274
1286
  * @inheritdoc
1275
1287
  */
1276
1288
  get(key) {
1277
- const value = super.get(key);
1278
- if (value !== void 0 || this.has(key)) this.set(key, value);
1279
- return value;
1289
+ if (super.has(key)) {
1290
+ const value = super.get(key);
1291
+ this.#setValue(key, value, true);
1292
+ return value;
1293
+ }
1280
1294
  }
1281
1295
  /**
1282
1296
  * @inheritdoc
1283
1297
  */
1284
1298
  set(key, value) {
1285
- if (this.has(key)) this.delete(key);
1286
- else if (this.size >= this.#maximumSize) this.delete(this.keys().next().value);
1287
- return super.set(key, value);
1299
+ return this.#setValue(key, value, super.has(key));
1300
+ }
1301
+ #setValue(key, value, has) {
1302
+ if (has) super.delete(key);
1303
+ else if (super.size >= this.#maximumSize) super.delete(super.keys().next().value);
1304
+ super.set(key, value);
1305
+ return this;
1288
1306
  }
1289
1307
  };
1290
1308
  //#endregion
@@ -1685,15 +1703,8 @@ function equalArray(first, second, options) {
1685
1703
  offset = offset > ARRAY_THRESHOLD ? ARRAY_THRESHOLD : offset;
1686
1704
  for (let index = 0; index < offset; index += 1) if (!(equalValue(first[index], second[index], options) && equalValue(first[length - index - 1], second[length - index - 1], options))) return false;
1687
1705
  }
1688
- const firstChunks = chunk(first.slice(offset, length - offset), ARRAY_THRESHOLD);
1689
- const secondChunks = chunk(second.slice(offset, length - offset), ARRAY_THRESHOLD);
1690
- const chunksLength = firstChunks.length;
1691
- for (let chunkIndex = 0; chunkIndex < chunksLength; chunkIndex += 1) {
1692
- const firstChunk = firstChunks[chunkIndex];
1693
- const secondChunk = secondChunks[chunkIndex];
1694
- const chunkLength = firstChunk.length;
1695
- for (let index = 0; index < chunkLength; index += 1) if (!equalValue(firstChunk[index], secondChunk[index], options)) return false;
1696
- }
1706
+ const end = length - offset;
1707
+ for (let index = offset; index < end; index += 1) if (!equalValue(first[index], second[index], options)) return false;
1697
1708
  return true;
1698
1709
  }
1699
1710
  function equalArrayBuffer(first, second, options) {
@@ -1706,11 +1717,9 @@ function equalMap(first, second, options) {
1706
1717
  const { size } = first;
1707
1718
  if (size !== second.size) return false;
1708
1719
  const firstKeys = [...first.keys()];
1709
- const secondKeys = [...second.keys()];
1710
- if (firstKeys.some((key) => !secondKeys.includes(key))) return false;
1711
1720
  for (let index = 0; index < size; index += 1) {
1712
1721
  const key = firstKeys[index];
1713
- if (!equalValue(first.get(key), second.get(key), options)) return false;
1722
+ if (!second.has(key) || !equalValue(first.get(key), second.get(key), options)) return false;
1714
1723
  }
1715
1724
  return true;
1716
1725
  }
@@ -1721,11 +1730,12 @@ function equalPlainObject(first, second, options) {
1721
1730
  firstKeys = firstKeys.filter((key) => filterKey(key, options));
1722
1731
  secondKeys = secondKeys.filter((key) => filterKey(key, options));
1723
1732
  }
1733
+ const secondSet = secondKeys.length >= MINIMUM_LENGTH_FOR_SET ? new Set(secondKeys) : void 0;
1724
1734
  const { length } = firstKeys;
1725
- if (length !== secondKeys.length || firstKeys.some((key) => !secondKeys.includes(key))) return false;
1735
+ if (length !== secondKeys.length) return false;
1726
1736
  for (let index = 0; index < length; index += 1) {
1727
1737
  const key = firstKeys[index];
1728
- if (!equalValue(first[key], second[key], options)) return false;
1738
+ if (!(secondSet?.has(key) ?? secondKeys.includes(key)) || !equalValue(first[key], second[key], options)) return false;
1729
1739
  }
1730
1740
  return true;
1731
1741
  }
@@ -1744,7 +1754,7 @@ function equalSet(first, second, options) {
1744
1754
  const secondValues = [...second];
1745
1755
  for (let index = 0; index < size; index += 1) {
1746
1756
  const firstValue = firstValues[index];
1747
- if (!secondValues.some((secondValue) => equalValue(firstValue, secondValue, options))) return false;
1757
+ if (isPrimitive(firstValue) ? !second.has(firstValue) : !secondValues.some((secondValue) => equalValue(firstValue, secondValue, options))) return false;
1748
1758
  }
1749
1759
  return true;
1750
1760
  }
@@ -1838,6 +1848,7 @@ const ARRAY_PEEK_PERCENTAGE = 10;
1838
1848
  const ARRAY_THRESHOLD = 100;
1839
1849
  const ERROR_PROPERTIES = ["name", "message"];
1840
1850
  const EXPRESSION_PROPERTIES = ["source", "flags"];
1851
+ const MINIMUM_LENGTH_FOR_SET = 16;
1841
1852
  //#endregion
1842
1853
  //#region src/internal/value/misc.ts
1843
1854
  function findKey(needle, haystack) {
@@ -2242,18 +2253,12 @@ function cloneDataView(value, depth, references) {
2242
2253
  references.set(value, cloned);
2243
2254
  return cloned;
2244
2255
  }
2245
- function cloneMapOrSet(value, depth, references) {
2246
- if (depth >= MAX_CLONE_DEPTH) return value;
2247
- const isMap = value instanceof Map;
2248
- const cloned = isMap ? /* @__PURE__ */ new Map() : /* @__PURE__ */ new Set();
2249
- const entries = [...value.entries()];
2250
- const { length } = entries;
2251
- for (let index = 0; index < length; index += 1) {
2252
- const entry = entries[index];
2253
- if (isMap) cloned.set(cloneValue(entry[0], depth + 1, references), cloneValue(entry[1], depth + 1, references));
2254
- else cloned.add(cloneValue(entry[0], depth + 1, references));
2255
- }
2256
- references.set(value, cloned);
2256
+ function cloneMap(map, depth, references) {
2257
+ if (depth >= MAX_CLONE_DEPTH) return map;
2258
+ const cloned = /* @__PURE__ */ new Map();
2259
+ const entries = map.entries();
2260
+ for (const entry of entries) cloned.set(cloneValue(entry[0], depth + 1, references), cloneValue(entry[1], depth + 1, references));
2261
+ references.set(map, cloned);
2257
2262
  return cloned;
2258
2263
  }
2259
2264
  function cloneNode(node, depth, references) {
@@ -2281,6 +2286,15 @@ function cloneRegularExpression(value, depth, references) {
2281
2286
  references.set(value, cloned);
2282
2287
  return cloned;
2283
2288
  }
2289
+ function cloneSet(set, depth, references) {
2290
+ if (depth >= MAX_CLONE_DEPTH) return set;
2291
+ const cloned = /* @__PURE__ */ new Set();
2292
+ const values = [...set.values()];
2293
+ const { length } = values;
2294
+ for (let index = 0; index < length; index += 1) cloned.add(cloneValue(values[index], depth + 1, references));
2295
+ references.set(set, cloned);
2296
+ return cloned;
2297
+ }
2284
2298
  function cloneTypedArray(value, depth, references) {
2285
2299
  if (depth >= MAX_CLONE_DEPTH) return value;
2286
2300
  const cloned = new value.constructor(value);
@@ -2301,9 +2315,9 @@ function cloneValue(value, depth, references) {
2301
2315
  case value instanceof DataView: return cloneDataView(value, depth, references);
2302
2316
  case value instanceof Date: return new Date(value.getTime());
2303
2317
  case value instanceof RegExp: return cloneRegularExpression(value, depth, references);
2304
- case value instanceof Map:
2305
- case value instanceof Set: return cloneMapOrSet(value, depth, references);
2306
- case value instanceof Node: return cloneNode(value, depth, references);
2318
+ case value instanceof Map: return cloneMap(value, depth, references);
2319
+ case typeof Node !== "undefined" && value instanceof Node: return cloneNode(value, depth, references);
2320
+ case value instanceof Set: return cloneSet(value, depth, references);
2307
2321
  case isArrayOrPlainObject(value): return clonePlainObject(value, depth, references);
2308
2322
  case isTypedArray(value): return cloneTypedArray(value, depth, references);
2309
2323
  default: return clone.handlers.handle(value, depth, references);
@@ -2351,7 +2365,7 @@ function diff(first, second, options) {
2351
2365
  diffResult.type = DIFF_FULL;
2352
2366
  return diffResult;
2353
2367
  }
2354
- const diffs = getDiffs(first, second, relaxedNullish);
2368
+ const diffs = getDiffs(first, second, { relaxedNullish });
2355
2369
  const { length } = diffs;
2356
2370
  if (length === 0) diffResult.type = DIFF_NONE;
2357
2371
  for (let index = 0; index < length; index += 1) {
@@ -2363,7 +2377,7 @@ function diff(first, second, options) {
2363
2377
  }
2364
2378
  return diffResult;
2365
2379
  }
2366
- function getChanges(changes, first, second, relaxedNullish, prefix) {
2380
+ function getChanges(changes, first, second, options, prefix) {
2367
2381
  const checked = /* @__PURE__ */ new Set();
2368
2382
  for (let outerIndex = 0; outerIndex < 2; outerIndex += 1) {
2369
2383
  const value = (outerIndex === 0 ? first : second) ?? {};
@@ -2376,7 +2390,7 @@ function getChanges(changes, first, second, relaxedNullish, prefix) {
2376
2390
  setChanges({
2377
2391
  changes,
2378
2392
  key,
2379
- relaxedNullish,
2393
+ options,
2380
2394
  prefix,
2381
2395
  values: {
2382
2396
  first,
@@ -2387,7 +2401,7 @@ function getChanges(changes, first, second, relaxedNullish, prefix) {
2387
2401
  }
2388
2402
  return changes;
2389
2403
  }
2390
- function getDiffs(first, second, relaxedNullish, prefix) {
2404
+ function getDiffs(first, second, options, prefix) {
2391
2405
  const changes = [];
2392
2406
  if (Array.isArray(first) && Array.isArray(second)) {
2393
2407
  const maximumLength = Math.max(first.length, second.length);
@@ -2401,20 +2415,21 @@ function getDiffs(first, second, relaxedNullish, prefix) {
2401
2415
  });
2402
2416
  }
2403
2417
  }
2404
- return getChanges(changes, first, second, relaxedNullish, prefix);
2418
+ return getChanges(changes, first, second, options, prefix);
2405
2419
  }
2406
2420
  function setChanges(parameters) {
2407
- const { changes, key, prefix, relaxedNullish, values } = parameters;
2421
+ const { changes, key, prefix, options, values } = parameters;
2422
+ const prefixed = join([prefix, key], ".");
2408
2423
  const from = values.first?.[key];
2409
2424
  const to = values.second?.[key];
2410
- if (equal(from, to, { relaxedNullish })) return;
2411
- const prefixed = join([prefix, key], ".");
2425
+ const nested = isArrayOrPlainObject(from) || isArrayOrPlainObject(to);
2426
+ const diffs = nested ? getDiffs(from, to, options, prefixed) : [];
2427
+ if (nested ? diffs.length === 0 : equal(from, to, options)) return;
2412
2428
  const change = {
2413
2429
  from,
2414
2430
  to,
2415
2431
  key: prefixed
2416
2432
  };
2417
- const diffs = isArrayOrPlainObject(from) || isArrayOrPlainObject(to) ? getDiffs(from, to, relaxedNullish, prefixed) : [];
2418
2433
  changes.push(change);
2419
2434
  const diffsLength = diffs.length;
2420
2435
  for (let diffIndex = 0; diffIndex < diffsLength; diffIndex += 1) changes.push(diffs[diffIndex]);
@@ -3484,15 +3499,6 @@ function isNumerical(value) {
3484
3499
  function isObject(value) {
3485
3500
  return typeof value === "object" && value !== null || typeof value === "function";
3486
3501
  }
3487
- /**
3488
- * - Is the value a primitive value?
3489
- * @param value Value to check
3490
- * @returns `true` if the value matches, otherwise `false`
3491
- */
3492
- function isPrimitive(value) {
3493
- return value == null || EXPRESSION_PRIMITIVE.test(typeof value);
3494
- }
3495
- const EXPRESSION_PRIMITIVE = /^(bigint|boolean|number|string|symbol)$/;
3496
3502
  const EXPRESSION_WHITESPACE = /^\s*$/;
3497
3503
  //#endregion
3498
3504
  //#region src/logger.ts
@@ -4427,8 +4433,8 @@ var SizedSet = class extends Set {
4427
4433
  * @inheritdoc
4428
4434
  */
4429
4435
  add(value) {
4430
- if (this.has(value)) this.delete(value);
4431
- else if (this.size >= this.#maximumSize) this.delete(this.values().next().value);
4436
+ if (super.has(value)) super.delete(value);
4437
+ else if (this.size >= this.#maximumSize) super.delete(this.values().next().value);
4432
4438
  return super.add(value);
4433
4439
  }
4434
4440
  /**
@@ -4438,9 +4444,9 @@ var SizedSet = class extends Set {
4438
4444
  * @returns Found value if it exists, otherwise `undefined`
4439
4445
  */
4440
4446
  get(value, update) {
4441
- if (this.has(value)) {
4447
+ if (super.has(value)) {
4442
4448
  if (update ?? false) {
4443
- this.delete(value);
4449
+ super.delete(value);
4444
4450
  this.add(value);
4445
4451
  }
4446
4452
  return value;
@@ -4,24 +4,25 @@ function getInterval(value) {
4
4
  }
5
5
  function getTimer(type, callback, time) {
6
6
  const interval = getInterval(time);
7
- function run(now) {
7
+ function run() {
8
+ const now = performance.now();
8
9
  start ??= now;
9
10
  if (interval === 0 || now - start >= interval - OFFSET) {
10
11
  start = throttle ? now : void 0;
11
12
  callback(...args);
12
- } else frame = requestAnimationFrame(run);
13
+ } else id = startTimer(run);
13
14
  }
14
15
  const throttle = type === TIMER_THROTTLE;
15
16
  let args;
16
- let frame;
17
+ let id;
17
18
  let start;
18
19
  const timer = (...parameters) => {
19
20
  timer.cancel();
20
21
  args = parameters;
21
- frame = requestAnimationFrame(run);
22
+ id = startTimer(run);
22
23
  };
23
24
  timer.cancel = () => {
24
- cancelAnimationFrame(frame);
25
+ clearTimer(id);
25
26
  };
26
27
  return timer;
27
28
  }
@@ -29,5 +30,7 @@ const OFFSET = 5;
29
30
  const TIMER_DEBOUNCE = "debounce";
30
31
  const TIMER_THROTTLE = "throttle";
31
32
  const TIMER_WAIT = "wait";
33
+ const clearTimer = typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : clearTimeout;
34
+ const startTimer = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout;
32
35
  //#endregion
33
36
  export { TIMER_DEBOUNCE, TIMER_THROTTLE, TIMER_WAIT, getTimer };
@@ -1,4 +1,4 @@
1
- import { ArrayOrPlainObject, Constructor, Key, PlainObject, TypedArray } from "../models.mjs";
1
+ import { ArrayOrPlainObject, Constructor, Key, PlainObject, Primitive, TypedArray } from "../models.mjs";
2
2
 
3
3
  //#region src/internal/is.d.ts
4
4
  /**
@@ -38,6 +38,12 @@ declare function isNumber(value: unknown): value is number;
38
38
  * @returns `true` if the value is a plain object, otherwise `false`
39
39
  */
40
40
  declare function isPlainObject(value: unknown): value is PlainObject;
41
+ /**
42
+ * - Is the value a primitive value?
43
+ * @param value Value to check
44
+ * @returns `true` if the value matches, otherwise `false`
45
+ */
46
+ declare function isPrimitive(value: unknown): value is Primitive;
41
47
  /**
42
48
  * Is the value a typed array?
43
49
  * @param value Value to check
@@ -45,4 +51,4 @@ declare function isPlainObject(value: unknown): value is PlainObject;
45
51
  */
46
52
  declare function isTypedArray(value: unknown): value is TypedArray;
47
53
  //#endregion
48
- export { isArrayOrPlainObject, isConstructor, isInstanceOf, isKey, isNumber, isPlainObject, isTypedArray };
54
+ export { isArrayOrPlainObject, isConstructor, isInstanceOf, isKey, isNumber, isPlainObject, isPrimitive, isTypedArray };
@@ -52,6 +52,14 @@ function isPlainObject(value) {
52
52
  return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
53
53
  }
54
54
  /**
55
+ * - Is the value a primitive value?
56
+ * @param value Value to check
57
+ * @returns `true` if the value matches, otherwise `false`
58
+ */
59
+ function isPrimitive(value) {
60
+ return value == null || EXPRESSION_PRIMITIVE.test(typeof value);
61
+ }
62
+ /**
55
63
  * Is the value a typed array?
56
64
  * @param value Value to check
57
65
  * @returns `true` if the value is a typed array, otherwise `false`
@@ -72,6 +80,7 @@ function isTypedArray(value) {
72
80
  ]);
73
81
  return TYPED_ARRAYS.has(value?.constructor);
74
82
  }
83
+ const EXPRESSION_PRIMITIVE = /^(bigint|boolean|number|string|symbol)$/;
75
84
  let TYPED_ARRAYS;
76
85
  //#endregion
77
- export { isArrayOrPlainObject, isConstructor, isInstanceOf, isKey, isNumber, isPlainObject, isTypedArray };
86
+ export { isArrayOrPlainObject, isConstructor, isInstanceOf, isKey, isNumber, isPlainObject, isPrimitive, isTypedArray };
@@ -1,5 +1,4 @@
1
- import { isPlainObject, isTypedArray } from "../is.mjs";
2
- import { chunk } from "../array/chunk.mjs";
1
+ import { isPlainObject, isPrimitive, isTypedArray } from "../is.mjs";
3
2
  import { getCompareHandlers } from "./handlers.mjs";
4
3
  //#region src/internal/value/equal.ts
5
4
  function equal(first, second, options) {
@@ -18,15 +17,8 @@ function equalArray(first, second, options) {
18
17
  offset = offset > ARRAY_THRESHOLD ? ARRAY_THRESHOLD : offset;
19
18
  for (let index = 0; index < offset; index += 1) if (!(equalValue(first[index], second[index], options) && equalValue(first[length - index - 1], second[length - index - 1], options))) return false;
20
19
  }
21
- const firstChunks = chunk(first.slice(offset, length - offset), ARRAY_THRESHOLD);
22
- const secondChunks = chunk(second.slice(offset, length - offset), ARRAY_THRESHOLD);
23
- const chunksLength = firstChunks.length;
24
- for (let chunkIndex = 0; chunkIndex < chunksLength; chunkIndex += 1) {
25
- const firstChunk = firstChunks[chunkIndex];
26
- const secondChunk = secondChunks[chunkIndex];
27
- const chunkLength = firstChunk.length;
28
- for (let index = 0; index < chunkLength; index += 1) if (!equalValue(firstChunk[index], secondChunk[index], options)) return false;
29
- }
20
+ const end = length - offset;
21
+ for (let index = offset; index < end; index += 1) if (!equalValue(first[index], second[index], options)) return false;
30
22
  return true;
31
23
  }
32
24
  function equalArrayBuffer(first, second, options) {
@@ -39,11 +31,9 @@ function equalMap(first, second, options) {
39
31
  const { size } = first;
40
32
  if (size !== second.size) return false;
41
33
  const firstKeys = [...first.keys()];
42
- const secondKeys = [...second.keys()];
43
- if (firstKeys.some((key) => !secondKeys.includes(key))) return false;
44
34
  for (let index = 0; index < size; index += 1) {
45
35
  const key = firstKeys[index];
46
- if (!equalValue(first.get(key), second.get(key), options)) return false;
36
+ if (!second.has(key) || !equalValue(first.get(key), second.get(key), options)) return false;
47
37
  }
48
38
  return true;
49
39
  }
@@ -54,11 +44,12 @@ function equalPlainObject(first, second, options) {
54
44
  firstKeys = firstKeys.filter((key) => filterKey(key, options));
55
45
  secondKeys = secondKeys.filter((key) => filterKey(key, options));
56
46
  }
47
+ const secondSet = secondKeys.length >= MINIMUM_LENGTH_FOR_SET ? new Set(secondKeys) : void 0;
57
48
  const { length } = firstKeys;
58
- if (length !== secondKeys.length || firstKeys.some((key) => !secondKeys.includes(key))) return false;
49
+ if (length !== secondKeys.length) return false;
59
50
  for (let index = 0; index < length; index += 1) {
60
51
  const key = firstKeys[index];
61
- if (!equalValue(first[key], second[key], options)) return false;
52
+ if (!(secondSet?.has(key) ?? secondKeys.includes(key)) || !equalValue(first[key], second[key], options)) return false;
62
53
  }
63
54
  return true;
64
55
  }
@@ -77,7 +68,7 @@ function equalSet(first, second, options) {
77
68
  const secondValues = [...second];
78
69
  for (let index = 0; index < size; index += 1) {
79
70
  const firstValue = firstValues[index];
80
- if (!secondValues.some((secondValue) => equalValue(firstValue, secondValue, options))) return false;
71
+ if (isPrimitive(firstValue) ? !second.has(firstValue) : !secondValues.some((secondValue) => equalValue(firstValue, secondValue, options))) return false;
81
72
  }
82
73
  return true;
83
74
  }
@@ -171,5 +162,6 @@ const ARRAY_PEEK_PERCENTAGE = 10;
171
162
  const ARRAY_THRESHOLD = 100;
172
163
  const ERROR_PROPERTIES = ["name", "message"];
173
164
  const EXPRESSION_PROPERTIES = ["source", "flags"];
165
+ const MINIMUM_LENGTH_FOR_SET = 16;
174
166
  //#endregion
175
167
  export { equal };
package/dist/is.d.mts CHANGED
@@ -1,5 +1,4 @@
1
- import { Primitive } from "./models.mjs";
2
- import { isArrayOrPlainObject, isConstructor, isInstanceOf, isKey, isNumber, isPlainObject, isTypedArray } from "./internal/is.mjs";
1
+ import { isArrayOrPlainObject, isConstructor, isInstanceOf, isKey, isNumber, isPlainObject, isPrimitive, isTypedArray } from "./internal/is.mjs";
3
2
 
4
3
  //#region src/is.d.ts
5
4
  /**
@@ -44,11 +43,5 @@ declare function isNumerical(value: unknown): value is number | `${number}`;
44
43
  * @returns `true` if the value matches, otherwise `false`
45
44
  */
46
45
  declare function isObject(value: unknown): value is object;
47
- /**
48
- * - Is the value a primitive value?
49
- * @param value Value to check
50
- * @returns `true` if the value matches, otherwise `false`
51
- */
52
- declare function isPrimitive(value: unknown): value is Primitive;
53
46
  //#endregion
54
47
  export { isArrayOrPlainObject, isConstructor, isEmpty, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isPlainObject, isPrimitive, isTypedArray };
package/dist/is.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { isArrayOrPlainObject, isConstructor, isInstanceOf, isKey, isNumber, isPlainObject, isTypedArray } from "./internal/is.mjs";
1
+ import { isArrayOrPlainObject, isConstructor, isInstanceOf, isKey, isNumber, isPlainObject, isPrimitive, isTypedArray } from "./internal/is.mjs";
2
2
  import { getArray } from "./array/get.mjs";
3
3
  import { getString } from "./internal/string.mjs";
4
4
  //#region src/is.ts
@@ -63,15 +63,6 @@ function isNumerical(value) {
63
63
  function isObject(value) {
64
64
  return typeof value === "object" && value !== null || typeof value === "function";
65
65
  }
66
- /**
67
- * - Is the value a primitive value?
68
- * @param value Value to check
69
- * @returns `true` if the value matches, otherwise `false`
70
- */
71
- function isPrimitive(value) {
72
- return value == null || EXPRESSION_PRIMITIVE.test(typeof value);
73
- }
74
- const EXPRESSION_PRIMITIVE = /^(bigint|boolean|number|string|symbol)$/;
75
66
  const EXPRESSION_WHITESPACE = /^\s*$/;
76
67
  //#endregion
77
68
  export { isArrayOrPlainObject, isConstructor, isEmpty, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isPlainObject, isPrimitive, isTypedArray };
@@ -14,7 +14,7 @@ var SizedMap = class extends Map {
14
14
  * Is the Map full?
15
15
  */
16
16
  get full() {
17
- return this.size >= this.#maximumSize;
17
+ return super.size >= this.#maximumSize;
18
18
  }
19
19
  get maximum() {
20
20
  return this.#maximumSize;
@@ -33,17 +33,23 @@ var SizedMap = class extends Map {
33
33
  * @inheritdoc
34
34
  */
35
35
  get(key) {
36
- const value = super.get(key);
37
- if (value !== void 0 || this.has(key)) this.set(key, value);
38
- return value;
36
+ if (super.has(key)) {
37
+ const value = super.get(key);
38
+ this.#setValue(key, value, true);
39
+ return value;
40
+ }
39
41
  }
40
42
  /**
41
43
  * @inheritdoc
42
44
  */
43
45
  set(key, value) {
44
- if (this.has(key)) this.delete(key);
45
- else if (this.size >= this.#maximumSize) this.delete(this.keys().next().value);
46
- return super.set(key, value);
46
+ return this.#setValue(key, value, super.has(key));
47
+ }
48
+ #setValue(key, value, has) {
49
+ if (has) super.delete(key);
50
+ else if (super.size >= this.#maximumSize) super.delete(super.keys().next().value);
51
+ super.set(key, value);
52
+ return this;
47
53
  }
48
54
  };
49
55
  //#endregion
@@ -32,8 +32,8 @@ var SizedSet = class extends Set {
32
32
  * @inheritdoc
33
33
  */
34
34
  add(value) {
35
- if (this.has(value)) this.delete(value);
36
- else if (this.size >= this.#maximumSize) this.delete(this.values().next().value);
35
+ if (super.has(value)) super.delete(value);
36
+ else if (this.size >= this.#maximumSize) super.delete(this.values().next().value);
37
37
  return super.add(value);
38
38
  }
39
39
  /**
@@ -43,9 +43,9 @@ var SizedSet = class extends Set {
43
43
  * @returns Found value if it exists, otherwise `undefined`
44
44
  */
45
45
  get(value, update) {
46
- if (this.has(value)) {
46
+ if (super.has(value)) {
47
47
  if (update ?? false) {
48
- this.delete(value);
48
+ super.delete(value);
49
49
  this.add(value);
50
50
  }
51
51
  return value;
@@ -40,18 +40,12 @@ function cloneDataView(value, depth, references) {
40
40
  references.set(value, cloned);
41
41
  return cloned;
42
42
  }
43
- function cloneMapOrSet(value, depth, references) {
44
- if (depth >= MAX_CLONE_DEPTH) return value;
45
- const isMap = value instanceof Map;
46
- const cloned = isMap ? /* @__PURE__ */ new Map() : /* @__PURE__ */ new Set();
47
- const entries = [...value.entries()];
48
- const { length } = entries;
49
- for (let index = 0; index < length; index += 1) {
50
- const entry = entries[index];
51
- if (isMap) cloned.set(cloneValue(entry[0], depth + 1, references), cloneValue(entry[1], depth + 1, references));
52
- else cloned.add(cloneValue(entry[0], depth + 1, references));
53
- }
54
- references.set(value, cloned);
43
+ function cloneMap(map, depth, references) {
44
+ if (depth >= MAX_CLONE_DEPTH) return map;
45
+ const cloned = /* @__PURE__ */ new Map();
46
+ const entries = map.entries();
47
+ for (const entry of entries) cloned.set(cloneValue(entry[0], depth + 1, references), cloneValue(entry[1], depth + 1, references));
48
+ references.set(map, cloned);
55
49
  return cloned;
56
50
  }
57
51
  function cloneNode(node, depth, references) {
@@ -79,6 +73,15 @@ function cloneRegularExpression(value, depth, references) {
79
73
  references.set(value, cloned);
80
74
  return cloned;
81
75
  }
76
+ function cloneSet(set, depth, references) {
77
+ if (depth >= MAX_CLONE_DEPTH) return set;
78
+ const cloned = /* @__PURE__ */ new Set();
79
+ const values = [...set.values()];
80
+ const { length } = values;
81
+ for (let index = 0; index < length; index += 1) cloned.add(cloneValue(values[index], depth + 1, references));
82
+ references.set(set, cloned);
83
+ return cloned;
84
+ }
82
85
  function cloneTypedArray(value, depth, references) {
83
86
  if (depth >= MAX_CLONE_DEPTH) return value;
84
87
  const cloned = new value.constructor(value);
@@ -99,9 +102,9 @@ function cloneValue(value, depth, references) {
99
102
  case value instanceof DataView: return cloneDataView(value, depth, references);
100
103
  case value instanceof Date: return new Date(value.getTime());
101
104
  case value instanceof RegExp: return cloneRegularExpression(value, depth, references);
102
- case value instanceof Map:
103
- case value instanceof Set: return cloneMapOrSet(value, depth, references);
104
- case value instanceof Node: return cloneNode(value, depth, references);
105
+ case value instanceof Map: return cloneMap(value, depth, references);
106
+ case typeof Node !== "undefined" && value instanceof Node: return cloneNode(value, depth, references);
107
+ case value instanceof Set: return cloneSet(value, depth, references);
105
108
  case isArrayOrPlainObject(value): return clonePlainObject(value, depth, references);
106
109
  case isTypedArray(value): return cloneTypedArray(value, depth, references);
107
110
  default: return clone.handlers.handle(value, depth, references);
@@ -30,7 +30,7 @@ function diff(first, second, options) {
30
30
  diffResult.type = DIFF_FULL;
31
31
  return diffResult;
32
32
  }
33
- const diffs = getDiffs(first, second, relaxedNullish);
33
+ const diffs = getDiffs(first, second, { relaxedNullish });
34
34
  const { length } = diffs;
35
35
  if (length === 0) diffResult.type = DIFF_NONE;
36
36
  for (let index = 0; index < length; index += 1) {
@@ -42,7 +42,7 @@ function diff(first, second, options) {
42
42
  }
43
43
  return diffResult;
44
44
  }
45
- function getChanges(changes, first, second, relaxedNullish, prefix) {
45
+ function getChanges(changes, first, second, options, prefix) {
46
46
  const checked = /* @__PURE__ */ new Set();
47
47
  for (let outerIndex = 0; outerIndex < 2; outerIndex += 1) {
48
48
  const value = (outerIndex === 0 ? first : second) ?? {};
@@ -55,7 +55,7 @@ function getChanges(changes, first, second, relaxedNullish, prefix) {
55
55
  setChanges({
56
56
  changes,
57
57
  key,
58
- relaxedNullish,
58
+ options,
59
59
  prefix,
60
60
  values: {
61
61
  first,
@@ -66,7 +66,7 @@ function getChanges(changes, first, second, relaxedNullish, prefix) {
66
66
  }
67
67
  return changes;
68
68
  }
69
- function getDiffs(first, second, relaxedNullish, prefix) {
69
+ function getDiffs(first, second, options, prefix) {
70
70
  const changes = [];
71
71
  if (Array.isArray(first) && Array.isArray(second)) {
72
72
  const maximumLength = Math.max(first.length, second.length);
@@ -80,20 +80,21 @@ function getDiffs(first, second, relaxedNullish, prefix) {
80
80
  });
81
81
  }
82
82
  }
83
- return getChanges(changes, first, second, relaxedNullish, prefix);
83
+ return getChanges(changes, first, second, options, prefix);
84
84
  }
85
85
  function setChanges(parameters) {
86
- const { changes, key, prefix, relaxedNullish, values } = parameters;
86
+ const { changes, key, prefix, options, values } = parameters;
87
+ const prefixed = join([prefix, key], ".");
87
88
  const from = values.first?.[key];
88
89
  const to = values.second?.[key];
89
- if (equal(from, to, { relaxedNullish })) return;
90
- const prefixed = join([prefix, key], ".");
90
+ const nested = isArrayOrPlainObject(from) || isArrayOrPlainObject(to);
91
+ const diffs = nested ? getDiffs(from, to, options, prefixed) : [];
92
+ if (nested ? diffs.length === 0 : equal(from, to, options)) return;
91
93
  const change = {
92
94
  from,
93
95
  to,
94
96
  key: prefixed
95
97
  };
96
- const diffs = isArrayOrPlainObject(from) || isArrayOrPlainObject(to) ? getDiffs(from, to, relaxedNullish, prefixed) : [];
97
98
  changes.push(change);
98
99
  const diffsLength = diffs.length;
99
100
  for (let diffIndex = 0; diffIndex < diffsLength; diffIndex += 1) changes.push(diffs[diffIndex]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/atoms",
3
- "version": "0.168.0",
3
+ "version": "0.170.0",
4
4
  "description": "Atomic utilities for making your JavaScript better.",
5
5
  "keywords": [
6
6
  "helper",
@@ -235,4 +235,4 @@
235
235
  "vitest": "npm:@voidzero-dev/vite-plus-test@latest"
236
236
  },
237
237
  "packageManager": "npm@11.11.1"
238
- }
238
+ }
@@ -19,7 +19,9 @@ export function getTimer<Callback extends GenericCallback>(
19
19
  ): CancelableCallback<Callback> {
20
20
  const interval = getInterval(time);
21
21
 
22
- function run(now: DOMHighResTimeStamp): void {
22
+ function run(): void {
23
+ const now = performance.now();
24
+
23
25
  start ??= now;
24
26
 
25
27
  if (interval === 0 || now - start >= interval - OFFSET) {
@@ -27,25 +29,26 @@ export function getTimer<Callback extends GenericCallback>(
27
29
 
28
30
  callback(...args);
29
31
  } else {
30
- frame = requestAnimationFrame(run);
32
+ id = startTimer(run);
31
33
  }
32
34
  }
33
35
 
34
36
  const throttle = type === TIMER_THROTTLE;
35
37
 
36
38
  let args: Parameters<Callback>;
37
- let frame: DOMHighResTimeStamp | undefined;
38
- let start: DOMHighResTimeStamp | undefined;
39
+ let id: number;
40
+ let start: number | undefined;
39
41
 
40
42
  const timer = (...parameters: Parameters<Callback>): void => {
41
43
  timer.cancel();
42
44
 
43
45
  args = parameters;
44
- frame = requestAnimationFrame(run);
46
+
47
+ id = startTimer(run);
45
48
  };
46
49
 
47
50
  timer.cancel = (): void => {
48
- cancelAnimationFrame(frame!);
51
+ clearTimer(id);
49
52
  };
50
53
 
51
54
  return timer as CancelableCallback<Callback>;
@@ -63,4 +66,8 @@ export const TIMER_THROTTLE: TimerType = 'throttle';
63
66
 
64
67
  export const TIMER_WAIT: TimerType = 'wait';
65
68
 
69
+ const clearTimer = typeof cancelAnimationFrame === 'function' ? cancelAnimationFrame : clearTimeout;
70
+
71
+ const startTimer = typeof requestAnimationFrame === 'function' ? requestAnimationFrame : setTimeout;
72
+
66
73
  // #endregion
@@ -1,4 +1,11 @@
1
- import type {ArrayOrPlainObject, Constructor, Key, PlainObject, TypedArray} from '../models';
1
+ import type {
2
+ ArrayOrPlainObject,
3
+ Constructor,
4
+ Key,
5
+ PlainObject,
6
+ Primitive,
7
+ TypedArray,
8
+ } from '../models';
2
9
 
3
10
  // #region Functions
4
11
 
@@ -74,6 +81,15 @@ export function isPlainObject(value: unknown): value is PlainObject {
74
81
  );
75
82
  }
76
83
 
84
+ /**
85
+ * - Is the value a primitive value?
86
+ * @param value Value to check
87
+ * @returns `true` if the value matches, otherwise `false`
88
+ */
89
+ export function isPrimitive(value: unknown): value is Primitive {
90
+ return value == null || EXPRESSION_PRIMITIVE.test(typeof value);
91
+ }
92
+
77
93
  /**
78
94
  * Is the value a typed array?
79
95
  * @param value Value to check
@@ -101,6 +117,8 @@ export function isTypedArray(value: unknown): value is TypedArray {
101
117
 
102
118
  // #region Variables
103
119
 
120
+ const EXPRESSION_PRIMITIVE = /^(bigint|boolean|number|string|symbol)$/;
121
+
104
122
  let TYPED_ARRAYS: Set<unknown>;
105
123
 
106
124
  // #endregion
@@ -1,5 +1,5 @@
1
+ import {isPrimitive} from '../is';
1
2
  import type {ArrayOrPlainObject, Constructor, PlainObject, TypedArray} from '../../models';
2
- import {chunk} from '../array/chunk';
3
3
  import {isPlainObject, isTypedArray} from '../is';
4
4
  import {getCompareHandlers} from './handlers';
5
5
 
@@ -122,21 +122,11 @@ function equalArray(first: unknown[], second: unknown[], options: Options): bool
122
122
  }
123
123
  }
124
124
 
125
- const firstChunks = chunk(first.slice(offset, length - offset), ARRAY_THRESHOLD);
125
+ const end = length - offset;
126
126
 
127
- const secondChunks = chunk(second.slice(offset, length - offset), ARRAY_THRESHOLD);
128
-
129
- const chunksLength = firstChunks.length;
130
-
131
- for (let chunkIndex = 0; chunkIndex < chunksLength; chunkIndex += 1) {
132
- const firstChunk = firstChunks[chunkIndex];
133
- const secondChunk = secondChunks[chunkIndex];
134
- const chunkLength = firstChunk.length;
135
-
136
- for (let index = 0; index < chunkLength; index += 1) {
137
- if (!equalValue(firstChunk[index], secondChunk[index], options)) {
138
- return false;
139
- }
127
+ for (let index = offset; index < end; index += 1) {
128
+ if (!equalValue(first[index], second[index], options)) {
129
+ return false;
140
130
  }
141
131
  }
142
132
 
@@ -167,16 +157,11 @@ function equalMap(
167
157
  }
168
158
 
169
159
  const firstKeys = [...first.keys()];
170
- const secondKeys = [...second.keys()];
171
-
172
- if (firstKeys.some(key => !secondKeys.includes(key))) {
173
- return false;
174
- }
175
160
 
176
161
  for (let index = 0; index < size; index += 1) {
177
162
  const key = firstKeys[index];
178
163
 
179
- if (!equalValue(first.get(key), second.get(key), options)) {
164
+ if (!second.has(key) || !equalValue(first.get(key), second.get(key), options)) {
180
165
  return false;
181
166
  }
182
167
  }
@@ -197,16 +182,22 @@ function equalPlainObject(
197
182
  secondKeys = secondKeys.filter(key => filterKey(key, options));
198
183
  }
199
184
 
185
+ const useSet = secondKeys.length >= MINIMUM_LENGTH_FOR_SET;
186
+ const secondSet = useSet ? new Set(secondKeys) : undefined;
187
+
200
188
  const {length} = firstKeys;
201
189
 
202
- if (length !== secondKeys.length || firstKeys.some(key => !secondKeys.includes(key))) {
190
+ if (length !== secondKeys.length) {
203
191
  return false;
204
192
  }
205
193
 
206
194
  for (let index = 0; index < length; index += 1) {
207
195
  const key = firstKeys[index];
208
196
 
209
- if (!equalValue(first[key as never], second[key as never], options)) {
197
+ if (
198
+ !(secondSet?.has(key) ?? secondKeys.includes(key)) ||
199
+ !equalValue(first[key as never], second[key as never], options)
200
+ ) {
210
201
  return false;
211
202
  }
212
203
  }
@@ -246,7 +237,11 @@ function equalSet(first: Set<unknown>, second: Set<unknown>, options: Options):
246
237
  for (let index = 0; index < size; index += 1) {
247
238
  const firstValue = firstValues[index];
248
239
 
249
- if (!secondValues.some(secondValue => equalValue(firstValue, secondValue, options))) {
240
+ if (
241
+ isPrimitive(firstValue)
242
+ ? !second.has(firstValue)
243
+ : !secondValues.some(secondValue => equalValue(firstValue, secondValue, options))
244
+ ) {
250
245
  return false;
251
246
  }
252
247
  }
@@ -439,4 +434,6 @@ const ERROR_PROPERTIES: string[] = ['name', 'message'];
439
434
 
440
435
  const EXPRESSION_PROPERTIES: string[] = ['source', 'flags'];
441
436
 
437
+ const MINIMUM_LENGTH_FOR_SET = 16;
438
+
442
439
  // #endregion
package/src/is.ts CHANGED
@@ -88,21 +88,10 @@ export function isObject(value: unknown): value is object {
88
88
  return (typeof value === 'object' && value !== null) || typeof value === 'function';
89
89
  }
90
90
 
91
- /**
92
- * - Is the value a primitive value?
93
- * @param value Value to check
94
- * @returns `true` if the value matches, otherwise `false`
95
- */
96
- export function isPrimitive(value: unknown): value is Primitive {
97
- return value == null || EXPRESSION_PRIMITIVE.test(typeof value);
98
- }
99
-
100
91
  // #endregion
101
92
 
102
93
  // #region Variables
103
94
 
104
- const EXPRESSION_PRIMITIVE = /^(bigint|boolean|number|string|symbol)$/;
105
-
106
95
  const EXPRESSION_WHITESPACE = /^\s*$/;
107
96
 
108
97
  // #endregion
@@ -116,6 +105,7 @@ export {
116
105
  isKey,
117
106
  isNumber,
118
107
  isPlainObject,
108
+ isPrimitive,
119
109
  isTypedArray,
120
110
  } from './internal/is';
121
111
 
package/src/sized/map.ts CHANGED
@@ -17,7 +17,7 @@ export class SizedMap<SizedKey = unknown, SizedValue = unknown> extends Map<Size
17
17
  * Is the Map full?
18
18
  */
19
19
  get full(): boolean {
20
- return this.size >= this.#maximumSize;
20
+ return super.size >= this.#maximumSize;
21
21
  }
22
22
 
23
23
  get maximum(): number {
@@ -75,26 +75,32 @@ export class SizedMap<SizedKey = unknown, SizedValue = unknown> extends Map<Size
75
75
  * @inheritdoc
76
76
  */
77
77
  override get(key: SizedKey): SizedValue | undefined {
78
- const value = super.get(key);
78
+ if (super.has(key)) {
79
+ const value = super.get(key) as SizedValue;
79
80
 
80
- if (value !== undefined || this.has(key)) {
81
- this.set(key, value as SizedValue);
82
- }
81
+ this.#setValue(key, value, true);
83
82
 
84
- return value;
83
+ return value;
84
+ }
85
85
  }
86
86
 
87
87
  /**
88
88
  * @inheritdoc
89
89
  */
90
90
  override set(key: SizedKey, value: SizedValue): this {
91
- if (this.has(key)) {
92
- this.delete(key);
93
- } else if (this.size >= this.#maximumSize) {
94
- this.delete(this.keys().next().value as SizedKey);
91
+ return this.#setValue(key, value, super.has(key));
92
+ }
93
+
94
+ #setValue(key: SizedKey, value: SizedValue, has: boolean): this {
95
+ if (has) {
96
+ super.delete(key);
97
+ } else if (super.size >= this.#maximumSize) {
98
+ super.delete(super.keys().next().value as SizedKey);
95
99
  }
96
100
 
97
- return super.set(key, value);
101
+ super.set(key, value);
102
+
103
+ return this;
98
104
  }
99
105
  }
100
106
 
package/src/sized/set.ts CHANGED
@@ -71,10 +71,10 @@ export class SizedSet<Value = unknown> extends Set<Value> {
71
71
  * @inheritdoc
72
72
  */
73
73
  override add(value: Value): this {
74
- if (this.has(value)) {
75
- this.delete(value);
74
+ if (super.has(value)) {
75
+ super.delete(value);
76
76
  } else if (this.size >= this.#maximumSize) {
77
- this.delete(this.values().next().value as Value);
77
+ super.delete(this.values().next().value as Value);
78
78
  }
79
79
 
80
80
  return super.add(value);
@@ -87,9 +87,10 @@ export class SizedSet<Value = unknown> extends Set<Value> {
87
87
  * @returns Found value if it exists, otherwise `undefined`
88
88
  */
89
89
  get(value: Value, update?: boolean): Value | undefined {
90
- if (this.has(value)) {
90
+ if (super.has(value)) {
91
91
  if (update ?? false) {
92
- this.delete(value);
92
+ super.delete(value);
93
+
93
94
  this.add(value);
94
95
  }
95
96
 
@@ -86,36 +86,28 @@ function cloneDataView(
86
86
  return cloned;
87
87
  }
88
88
 
89
- function cloneMapOrSet<Value extends Map<unknown, unknown> | Set<unknown>>(
90
- value: Value,
89
+ function cloneMap(
90
+ map: Map<unknown, unknown>,
91
91
  depth: number,
92
92
  references: WeakMap<WeakKey, unknown>,
93
- ): Value {
93
+ ): Map<unknown, unknown> {
94
94
  if (depth >= MAX_CLONE_DEPTH) {
95
- return value;
95
+ return map;
96
96
  }
97
97
 
98
- const isMap = value instanceof Map;
99
- const cloned = isMap ? new Map<unknown, unknown>() : new Set<unknown>();
100
- const entries = [...value.entries()];
101
- const {length} = entries;
98
+ const cloned = new Map<unknown, unknown>();
99
+ const entries = map.entries();
102
100
 
103
- for (let index = 0; index < length; index += 1) {
104
- const entry = entries[index];
105
-
106
- if (isMap) {
107
- (cloned as Map<unknown, unknown>).set(
108
- cloneValue(entry[0], depth + 1, references),
109
- cloneValue(entry[1], depth + 1, references),
110
- );
111
- } else {
112
- (cloned as Set<unknown>).add(cloneValue(entry[0], depth + 1, references));
113
- }
101
+ for (const entry of entries) {
102
+ cloned.set(
103
+ cloneValue(entry[0], depth + 1, references),
104
+ cloneValue(entry[1], depth + 1, references),
105
+ );
114
106
  }
115
107
 
116
- references.set(value, cloned);
108
+ references.set(map, cloned);
117
109
 
118
- return cloned as Value;
110
+ return cloned;
119
111
  }
120
112
 
121
113
  function cloneNode(node: Node, depth: number, references: WeakMap<WeakKey, unknown>): Node {
@@ -172,6 +164,28 @@ function cloneRegularExpression(
172
164
  return cloned;
173
165
  }
174
166
 
167
+ function cloneSet(
168
+ set: Set<unknown>,
169
+ depth: number,
170
+ references: WeakMap<WeakKey, unknown>,
171
+ ): Set<unknown> {
172
+ if (depth >= MAX_CLONE_DEPTH) {
173
+ return set;
174
+ }
175
+
176
+ const cloned = new Set<unknown>();
177
+ const values = [...set.values()];
178
+ const {length} = values;
179
+
180
+ for (let index = 0; index < length; index += 1) {
181
+ cloned.add(cloneValue(values[index], depth + 1, references));
182
+ }
183
+
184
+ references.set(set, cloned);
185
+
186
+ return cloned;
187
+ }
188
+
175
189
  function cloneTypedArray(
176
190
  value: TypedArray,
177
191
  depth: number,
@@ -227,12 +241,14 @@ function cloneValue(value: unknown, depth: number, references: WeakMap<WeakKey,
227
241
  return cloneRegularExpression(value, depth, references);
228
242
 
229
243
  case value instanceof Map:
230
- case value instanceof Set:
231
- return cloneMapOrSet(value, depth, references);
244
+ return cloneMap(value, depth, references);
232
245
 
233
- case value instanceof Node:
246
+ case typeof Node !== 'undefined' && value instanceof Node:
234
247
  return cloneNode(value, depth, references);
235
248
 
249
+ case value instanceof Set:
250
+ return cloneSet(value, depth, references);
251
+
236
252
  case isArrayOrPlainObject(value):
237
253
  return clonePlainObject(value, depth, references);
238
254
 
package/src/value/diff.ts CHANGED
@@ -57,8 +57,8 @@ type KeyedDiffValue = {
57
57
  type Parameters = {
58
58
  changes: KeyedDiffValue[];
59
59
  key: PropertyKey;
60
+ options: Required<DiffOptions>;
60
61
  values: {first: unknown; second: unknown};
61
- relaxedNullish: boolean;
62
62
  prefix?: string;
63
63
  };
64
64
 
@@ -106,7 +106,7 @@ export function diff<First, Second = First>(
106
106
  return diffResult;
107
107
  }
108
108
 
109
- const diffs = getDiffs(first, second, relaxedNullish);
109
+ const diffs = getDiffs(first, second, {relaxedNullish});
110
110
 
111
111
  const {length} = diffs;
112
112
 
@@ -127,7 +127,7 @@ function getChanges(
127
127
  changes: KeyedDiffValue[],
128
128
  first: unknown,
129
129
  second: unknown,
130
- relaxedNullish: boolean,
130
+ options: Required<DiffOptions>,
131
131
  prefix?: string,
132
132
  ): KeyedDiffValue[] {
133
133
  const checked = new Set<PropertyKey>();
@@ -151,7 +151,7 @@ function getChanges(
151
151
  setChanges({
152
152
  changes,
153
153
  key,
154
- relaxedNullish,
154
+ options,
155
155
  prefix,
156
156
  values: {first, second},
157
157
  });
@@ -164,7 +164,7 @@ function getChanges(
164
164
  function getDiffs(
165
165
  first: unknown,
166
166
  second: unknown,
167
- relaxedNullish: boolean,
167
+ options: Required<DiffOptions>,
168
168
  prefix?: string,
169
169
  ): KeyedDiffValue[] {
170
170
  const changes: KeyedDiffValue[] = [];
@@ -184,31 +184,30 @@ function getDiffs(
184
184
  }
185
185
  }
186
186
 
187
- return getChanges(changes, first, second, relaxedNullish, prefix);
187
+ return getChanges(changes, first, second, options, prefix);
188
188
  }
189
189
 
190
190
  function setChanges(parameters: Parameters): void {
191
- const {changes, key, prefix, relaxedNullish, values} = parameters;
191
+ const {changes, key, prefix, options, values} = parameters;
192
192
 
193
- const from = values.first?.[key as never];
194
- const to = values.second?.[key as never];
193
+ const prefixed = join([prefix, key], '.');
194
+
195
+ const from: unknown = values.first?.[key as never];
196
+ const to: unknown = values.second?.[key as never];
195
197
 
196
- if (equal(from, to, {relaxedNullish})) {
198
+ const nested = isArrayOrPlainObject(from) || isArrayOrPlainObject(to);
199
+ const diffs = nested ? getDiffs(from, to, options, prefixed) : [];
200
+
201
+ if (nested ? diffs.length === 0 : equal(from, to, options)) {
197
202
  return;
198
203
  }
199
204
 
200
- const prefixed = join([prefix, key], '.');
201
-
202
205
  const change = {
203
206
  from,
204
207
  to,
205
208
  key: prefixed,
206
209
  };
207
210
 
208
- const nested = isArrayOrPlainObject(from) || isArrayOrPlainObject(to);
209
-
210
- const diffs = nested ? getDiffs(from, to, relaxedNullish, prefixed) : [];
211
-
212
211
  changes.push(change);
213
212
 
214
213
  const diffsLength = diffs.length;