@mark1russell7/collections 0.9.5 → 0.9.6

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@mark1russell7/collections",
4
- "version": "0.9.5",
4
+ "version": "0.9.6",
5
5
  "description": "Collections with no dependencies: lists, maps, queues, a summary tree, channels, lazy operations and dependency graphs.",
6
6
  "keywords": [
7
7
  "collections",
@@ -368,25 +368,29 @@ export const hashBy = <T>(accessor: (value: T) => any): Hash<T> => {
368
368
  // Default Comparison
369
369
  // ============================================================================
370
370
 
371
+ /** This function gives the place of `null` and `undefined` in the order of `defaultCompare`: `null`, then `undefined`, then each other value. */
372
+ const nullishRank = (value: unknown): number => (value === null ? 0 : value === undefined ? 1 : 2);
373
+
371
374
  /**
372
- * Natural ordering comparison for primitives.
373
- * Numbers, strings, booleans, dates are compared naturally.
375
+ * This comparator gives the natural order of primitives.
376
+ * - `null` comes first, then `undefined`, then each other value.
377
+ * - Numbers and dates compare as `numberCompare` and `dateCompare` compare them.
378
+ * - Strings compare by `localeCompare`, and `false` comes before `true`.
379
+ * - Two values of different types compare by their text, with `String`.
374
380
  */
375
381
  export const defaultCompare: Compare<any> = (a, b) => {
376
382
  if (a === b) return 0;
377
- if (a === null || a === undefined) return -1;
378
- if (b === null || b === undefined) return 1;
383
+ const nullish = nullishRank(a) - nullishRank(b);
384
+ if (nullish !== 0) return nullish;
379
385
 
380
386
  // Handle dates
381
387
  if (a instanceof Date && b instanceof Date) {
382
- return a.getTime() - b.getTime();
388
+ return dateCompare(a, b);
383
389
  }
384
390
 
385
391
  // Handle numbers
386
392
  if (typeof a === "number" && typeof b === "number") {
387
- if (Number.isNaN(a)) return Number.isNaN(b) ? 0 : -1;
388
- if (Number.isNaN(b)) return 1;
389
- return a - b;
393
+ return numberCompare(a, b);
390
394
  }
391
395
 
392
396
  // Handle strings
@@ -404,12 +408,14 @@ export const defaultCompare: Compare<any> = (a, b) => {
404
408
  };
405
409
 
406
410
  /**
407
- * Numeric comparison (for numbers).
411
+ * This comparator gives the order of numbers by value. It gives -1, 0 or 1.
412
+ * - `NaN` comes first, and two `NaN` values give 0.
413
+ * - Two equal infinities give 0, and 0 equals -0.
408
414
  */
409
415
  export const numberCompare: Compare<number> = (a, b) => {
410
416
  if (Number.isNaN(a)) return Number.isNaN(b) ? 0 : -1;
411
417
  if (Number.isNaN(b)) return 1;
412
- return a - b;
418
+ return a < b ? -1 : a > b ? 1 : 0;
413
419
  };
414
420
 
415
421
  /**
@@ -424,10 +430,10 @@ export const stringCompareIgnoreCase: Compare<string> = (a, b) =>
424
430
  a.toLowerCase().localeCompare(b.toLowerCase());
425
431
 
426
432
  /**
427
- * Date comparison.
433
+ * This comparator gives the order of dates by time, with `numberCompare`. An invalid date has the time `NaN`, so it comes
434
+ * first, and two invalid dates give 0.
428
435
  */
429
- export const dateCompare: Compare<Date> = (a, b) =>
430
- a.getTime() - b.getTime();
436
+ export const dateCompare: Compare<Date> = (a, b) => numberCompare(a.getTime(), b.getTime());
431
437
 
432
438
  /**
433
439
  * Boolean comparison (false < true).