@oscarpalmer/atoms 0.167.0 → 0.168.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.
@@ -15,11 +15,10 @@ import { ArrayPosition, endsWithArray, getArrayPosition, includesArray, indexOfA
15
15
  import { push } from "./push.mjs";
16
16
  import { select } from "./select.mjs";
17
17
  import { drop, slice, take } from "./slice.mjs";
18
- import { ArrayComparisonSorter, ArrayKeySorter, ArrayValueSorter, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, SortDirection, sort } from "./sort.mjs";
19
18
  import { splice } from "./splice.mjs";
20
19
  import { toSet } from "./to-set.mjs";
21
20
  import { toggle } from "./toggle.mjs";
22
21
  import { union } from "./union.mjs";
23
22
  import { unique } from "./unique.mjs";
24
23
  import { update } from "./update.mjs";
25
- export { ArrayComparisonSorter, ArrayKeySorter, ArrayPosition, ArrayValueSorter, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, SortDirection, chunk, compact, difference, drop, endsWithArray, exists, find, flatten, getArray, getArrayPosition, includesArray, indexOf, indexOfArray, insert, intersection, partition, push, range, select, shuffle, slice, sort, splice, startsWithArray, take, times, toSet, toggle, union, unique, update };
24
+ export { ArrayPosition, chunk, compact, difference, drop, endsWithArray, exists, find, flatten, getArray, getArrayPosition, includesArray, indexOf, indexOfArray, insert, intersection, partition, push, range, select, shuffle, slice, splice, startsWithArray, take, times, toSet, toggle, union, unique, update };
@@ -15,11 +15,10 @@ import { endsWithArray, getArrayPosition, includesArray, indexOfArray, startsWit
15
15
  import { push } from "./push.mjs";
16
16
  import { select } from "./select.mjs";
17
17
  import { drop, slice, take } from "./slice.mjs";
18
- import { SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, sort } from "./sort.mjs";
19
18
  import { splice } from "./splice.mjs";
20
19
  import { toSet } from "./to-set.mjs";
21
20
  import { toggle } from "./toggle.mjs";
22
21
  import { union } from "./union.mjs";
23
22
  import { unique } from "./unique.mjs";
24
23
  import { update } from "./update.mjs";
25
- export { SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, chunk, compact, difference, drop, endsWithArray, exists, find, flatten, getArray, getArrayPosition, includesArray, indexOf, indexOfArray, insert, intersection, partition, push, range, select, shuffle, slice, sort, splice, startsWithArray, take, times, toSet, toggle, union, unique, update };
24
+ export { chunk, compact, difference, drop, endsWithArray, exists, find, flatten, getArray, getArrayPosition, includesArray, indexOf, indexOfArray, insert, intersection, partition, push, range, select, shuffle, slice, splice, startsWithArray, take, times, toSet, toggle, union, unique, update };
@@ -35,6 +35,10 @@ type ArrayKeySorter<Item extends PlainObject, ItemKey extends keyof Item> = {
35
35
  * Sorters based on keys in an object
36
36
  */
37
37
  type ArrayKeySorters<Item extends PlainObject> = { [ItemKey in keyof Item]: ArrayKeySorter<Item, ItemKey> }[keyof Item];
38
+ /**
39
+ * Sorter to use for sorting
40
+ */
41
+ type ArraySorter<Item> = Item extends PlainObject ? keyof Item | ArrayComparisonSorter<Item> | ArrayKeySorters<Item> | ArrayValueSorter<Item> | ComparisonSorter<Item> : ArrayComparisonSorter<Item> | ArrayValueSorter<Item> | ComparisonSorter<Item>;
38
42
  /**
39
43
  * Sorting information for arrays _(using a value callback and built-in comparison)_
40
44
  */
@@ -61,10 +65,27 @@ type ComparisonSorter<Item> = (first: Item, second: Item) => number;
61
65
  * Direction to sort by
62
66
  */
63
67
  type SortDirection = 'ascending' | 'descending';
68
+ type Sorter<Item> = (array: Item[]) => Item[];
64
69
  /**
65
- * Sorter to use for sorting
70
+ * Initialize a sort handler with sorters _(and an optional default direction)_
71
+ * @param sorters Sorters to use for sorting
72
+ * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
73
+ * @returns Sort handler
74
+ */
75
+ declare function initializeSort<Item>(sorters: Array<ArraySorter<Item>>, descending?: boolean): Sorter<Item>;
76
+ /**
77
+ * Initialize a sort handler with a sorter _(and an optional default direction)_
78
+ * @param sorter Sorter to use for sorting
79
+ * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
80
+ * @returns Sort handler
81
+ */
82
+ declare function initializeSort<Item>(sorter: ArraySorter<Item>, descending?: boolean): Sorter<Item>;
83
+ /**
84
+ * Initialize a sort handler _(with an optional default direction)_
85
+ * @param descending Sort in descending order? _(defaults to `false`)_
86
+ * @returns Sort handler
66
87
  */
67
- type Sorter<Item> = Item extends PlainObject ? keyof Item | ArrayComparisonSorter<Item> | ArrayKeySorters<Item> | ArrayValueSorter<Item> | ComparisonSorter<Item> : ArrayComparisonSorter<Item> | ArrayValueSorter<Item> | ComparisonSorter<Item>;
88
+ declare function initializeSort<Item>(descending?: boolean): Sorter<Item>;
68
89
  /**
69
90
  * Sort an array of items, using multiple sorters to sort by specific values
70
91
  * @param array Array to sort
@@ -72,7 +93,7 @@ type Sorter<Item> = Item extends PlainObject ? keyof Item | ArrayComparisonSorte
72
93
  * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
73
94
  * @returns Sorted array
74
95
  */
75
- declare function sort<Item>(array: Item[], sorters: Array<Sorter<Item>>, descending?: boolean): Item[];
96
+ declare function sort<Item>(array: Item[], sorters: Array<ArraySorter<Item>>, descending?: boolean): Item[];
76
97
  /**
77
98
  * Sort an array of items, using multiple sorters to sort by specific values
78
99
  * @param array Array to sort
@@ -80,7 +101,7 @@ declare function sort<Item>(array: Item[], sorters: Array<Sorter<Item>>, descend
80
101
  * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
81
102
  * @returns Sorted array
82
103
  */
83
- declare function sort<Item>(array: Item[], sorter: Sorter<Item>, descending?: boolean): Item[];
104
+ declare function sort<Item>(array: Item[], sorter: ArraySorter<Item>, descending?: boolean): Item[];
84
105
  /**
85
106
  * Sort an array of items
86
107
  * @param array Array to sort
@@ -88,7 +109,10 @@ declare function sort<Item>(array: Item[], sorter: Sorter<Item>, descending?: bo
88
109
  * @returns Sorted array
89
110
  */
90
111
  declare function sort<Item>(array: Item[], descending?: boolean): Item[];
112
+ declare namespace sort {
113
+ var initialize: typeof initializeSort;
114
+ }
91
115
  declare const SORT_DIRECTION_ASCENDING: SortDirection;
92
116
  declare const SORT_DIRECTION_DESCENDING: SortDirection;
93
117
  //#endregion
94
- export { ArrayComparisonSorter, ArrayKeySorter, ArrayValueSorter, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, SortDirection, sort };
118
+ export { ArrayComparisonSorter, ArrayKeySorter, ArrayValueSorter, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, SortDirection, Sorter, sort };
@@ -9,6 +9,9 @@ function getComparisonSorter(callback, modifier) {
9
9
  identifier: String(callback)
10
10
  };
11
11
  }
12
+ function getModifier(first, second) {
13
+ return modifiers[first === true || second === true ? SORT_DIRECTION_DESCENDING : SORT_DIRECTION_ASCENDING];
14
+ }
12
15
  function getObjectSorter(obj, modifier) {
13
16
  let sorter;
14
17
  if (typeof obj.comparison === "function") sorter = getComparisonSorter(obj.comparison, modifier);
@@ -27,6 +30,17 @@ function getSorter(value, modifier) {
27
30
  default: break;
28
31
  }
29
32
  }
33
+ function getSorters(value, modifier) {
34
+ const array = Array.isArray(value) ? value : [value];
35
+ const { length } = array;
36
+ const sorters = [];
37
+ for (let index = 0; index < length; index += 1) {
38
+ const item = array[index];
39
+ const sorter = getSorter(item, modifier);
40
+ if (sorter != null) sorters.push(sorter);
41
+ }
42
+ return sorters.filter((value, index, array) => array.findIndex((next) => next.identifier === value.identifier) === index);
43
+ }
30
44
  function getValueSorter(value, modifier) {
31
45
  return {
32
46
  modifier,
@@ -35,32 +49,31 @@ function getValueSorter(value, modifier) {
35
49
  value: typeof value === "function" ? value : (item) => item[value]
36
50
  };
37
51
  }
52
+ function initializeSort(first, second) {
53
+ const modifier = getModifier(first, second);
54
+ const sorters = getSorters(first, modifier);
55
+ return (array) => work(array, sorters, modifier);
56
+ }
38
57
  function sort(array, first, second) {
58
+ const modifier = getModifier(first, second);
59
+ return work(array, getSorters(first, modifier), modifier);
60
+ }
61
+ function work(array, sorters, modifier) {
39
62
  if (!Array.isArray(array)) return [];
40
63
  if (array.length < 2) return array;
41
- const modifier = modifiers[first === true || second === true ? SORT_DIRECTION_DESCENDING : SORT_DIRECTION_ASCENDING];
42
- const sorters = (Array.isArray(first) ? first : [first]).map((item) => getSorter(item, modifier)).filter((sorter) => sorter != null).filter((current, index, filtered) => filtered.findIndex((next) => next.identifier === current.identifier) === index);
43
64
  const { length } = sorters;
44
65
  if (length === 0) return array.sort((first, second) => compare(first, second) * modifier);
45
- if (length === 1) {
46
- const sorter = sorters[0];
47
- return array.sort((firstItem, secondItem) => {
48
- const firstValue = sorter.get ? sorter.value(firstItem) : firstItem;
49
- const secondValue = sorter.get ? sorter.value(secondItem) : secondItem;
50
- return (sorter.compare?.complex?.(firstItem, firstValue, secondItem, secondValue) ?? sorter.compare?.simple?.(firstItem, secondItem) ?? compare(firstValue, secondValue)) * sorter.modifier;
51
- });
52
- }
53
- return array.sort((firstItem, secondItem) => {
66
+ return array.sort((first, second) => {
54
67
  for (let index = 0; index < length; index += 1) {
55
68
  const sorter = sorters[index];
56
- const firstValue = sorter.value?.(firstItem) ?? firstItem;
57
- const secondValue = sorter.value?.(secondItem) ?? secondItem;
58
- const comparison = (sorter.compare?.complex?.(firstItem, firstValue, secondItem, secondValue) ?? sorter.compare?.simple?.(firstItem, secondItem) ?? compare(firstValue, secondValue)) * sorter.modifier;
69
+ const values = [sorter.get ? sorter.value(first) : first, sorter.get ? sorter.value(second) : second];
70
+ const comparison = (sorter.compare?.complex?.(first, values[0], second, values[1]) ?? sorter.compare?.simple?.(values[0], values[1]) ?? compare(values[0], values[1])) * sorter.modifier;
59
71
  if (comparison !== 0) return comparison;
60
72
  }
61
73
  return 0;
62
74
  });
63
75
  }
76
+ sort.initialize = initializeSort;
64
77
  const SORT_DIRECTION_ASCENDING = "ascending";
65
78
  const SORT_DIRECTION_DESCENDING = "descending";
66
79
  const modifiers = {
package/dist/index.d.mts CHANGED
@@ -853,97 +853,6 @@ declare function take<Item extends PlainObject>(array: Item[], callback: (item:
853
853
  */
854
854
  declare function take(array: unknown[], count: number): unknown[];
855
855
  //#endregion
856
- //#region src/array/sort.d.ts
857
- /**
858
- * Sorting information for arrays _(using a comparison callback)_
859
- */
860
- type ArrayComparisonSorter<Item> = {
861
- /**
862
- * Callback to use when comparing items and values
863
- */
864
- comparison: ComparisonSorter<Item>;
865
- /**
866
- * Direction to sort by
867
- */
868
- direction?: SortDirection;
869
- };
870
- /**
871
- * Sorting information for arrays _(using a key)_
872
- */
873
- type ArrayKeySorter<Item extends PlainObject, ItemKey extends keyof Item> = {
874
- /**
875
- * Comparator to use when comparing items and values
876
- */
877
- compare?: CompareCallback<Item, Item[ItemKey]>;
878
- /**
879
- * Direction to sort by
880
- */
881
- direction?: SortDirection;
882
- /**
883
- * Key to sort by
884
- */
885
- key: ItemKey;
886
- };
887
- /**
888
- * Sorters based on keys in an object
889
- */
890
- type ArrayKeySorters<Item extends PlainObject> = { [ItemKey in keyof Item]: ArrayKeySorter<Item, ItemKey> }[keyof Item];
891
- /**
892
- * Sorting information for arrays _(using a value callback and built-in comparison)_
893
- */
894
- type ArrayValueSorter<Item> = {
895
- /**
896
- * Direction to sort by
897
- */
898
- direction?: SortDirection;
899
- /**
900
- * Value to sort by
901
- */
902
- value: (item: Item) => unknown;
903
- };
904
- /**
905
- * Comparator to use when comparing items and values
906
- */
907
- type CompareCallback<Item, Value = CompareCallbackValue<Item>> = (first: Item, firstValue: Value, second: Item, secondValue: Value) => number;
908
- type CompareCallbackValue<Item> = Item extends Primitive ? Item : unknown;
909
- /**
910
- * Callback to use when comparing items and values
911
- */
912
- type ComparisonSorter<Item> = (first: Item, second: Item) => number;
913
- /**
914
- * Direction to sort by
915
- */
916
- type SortDirection = 'ascending' | 'descending';
917
- /**
918
- * Sorter to use for sorting
919
- */
920
- type Sorter<Item> = Item extends PlainObject ? keyof Item | ArrayComparisonSorter<Item> | ArrayKeySorters<Item> | ArrayValueSorter<Item> | ComparisonSorter<Item> : ArrayComparisonSorter<Item> | ArrayValueSorter<Item> | ComparisonSorter<Item>;
921
- /**
922
- * Sort an array of items, using multiple sorters to sort by specific values
923
- * @param array Array to sort
924
- * @param sorters Sorters to use for sorting
925
- * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
926
- * @returns Sorted array
927
- */
928
- declare function sort<Item>(array: Item[], sorters: Array<Sorter<Item>>, descending?: boolean): Item[];
929
- /**
930
- * Sort an array of items, using multiple sorters to sort by specific values
931
- * @param array Array to sort
932
- * @param sorter Sorter to use for sorting
933
- * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
934
- * @returns Sorted array
935
- */
936
- declare function sort<Item>(array: Item[], sorter: Sorter<Item>, descending?: boolean): Item[];
937
- /**
938
- * Sort an array of items
939
- * @param array Array to sort
940
- * @param descending Sort in descending order? _(defaults to `false`)_
941
- * @returns Sorted array
942
- */
943
- declare function sort<Item>(array: Item[], descending?: boolean): Item[];
944
- declare const SORT_DIRECTION_ASCENDING: SortDirection;
945
- declare const SORT_DIRECTION_DESCENDING: SortDirection;
946
- //#endregion
947
856
  //#region src/array/splice.d.ts
948
857
  /**
949
858
  * Adds items into an array at a specific index and removes a specific amount of items
@@ -1183,6 +1092,121 @@ declare function moveToIndex<Item>(array: Item[], value: Item | Item[], index: n
1183
1092
  */
1184
1093
  declare function moveToIndex<Item>(array: Item[], value: Item | Item[], index: number): Item[];
1185
1094
  //#endregion
1095
+ //#region src/array/sort.d.ts
1096
+ /**
1097
+ * Sorting information for arrays _(using a comparison callback)_
1098
+ */
1099
+ type ArrayComparisonSorter<Item> = {
1100
+ /**
1101
+ * Callback to use when comparing items and values
1102
+ */
1103
+ comparison: ComparisonSorter<Item>;
1104
+ /**
1105
+ * Direction to sort by
1106
+ */
1107
+ direction?: SortDirection;
1108
+ };
1109
+ /**
1110
+ * Sorting information for arrays _(using a key)_
1111
+ */
1112
+ type ArrayKeySorter<Item extends PlainObject, ItemKey extends keyof Item> = {
1113
+ /**
1114
+ * Comparator to use when comparing items and values
1115
+ */
1116
+ compare?: CompareCallback<Item, Item[ItemKey]>;
1117
+ /**
1118
+ * Direction to sort by
1119
+ */
1120
+ direction?: SortDirection;
1121
+ /**
1122
+ * Key to sort by
1123
+ */
1124
+ key: ItemKey;
1125
+ };
1126
+ /**
1127
+ * Sorters based on keys in an object
1128
+ */
1129
+ type ArrayKeySorters<Item extends PlainObject> = { [ItemKey in keyof Item]: ArrayKeySorter<Item, ItemKey> }[keyof Item];
1130
+ /**
1131
+ * Sorter to use for sorting
1132
+ */
1133
+ type ArraySorter<Item> = Item extends PlainObject ? keyof Item | ArrayComparisonSorter<Item> | ArrayKeySorters<Item> | ArrayValueSorter<Item> | ComparisonSorter<Item> : ArrayComparisonSorter<Item> | ArrayValueSorter<Item> | ComparisonSorter<Item>;
1134
+ /**
1135
+ * Sorting information for arrays _(using a value callback and built-in comparison)_
1136
+ */
1137
+ type ArrayValueSorter<Item> = {
1138
+ /**
1139
+ * Direction to sort by
1140
+ */
1141
+ direction?: SortDirection;
1142
+ /**
1143
+ * Value to sort by
1144
+ */
1145
+ value: (item: Item) => unknown;
1146
+ };
1147
+ /**
1148
+ * Comparator to use when comparing items and values
1149
+ */
1150
+ type CompareCallback<Item, Value = CompareCallbackValue<Item>> = (first: Item, firstValue: Value, second: Item, secondValue: Value) => number;
1151
+ type CompareCallbackValue<Item> = Item extends Primitive ? Item : unknown;
1152
+ /**
1153
+ * Callback to use when comparing items and values
1154
+ */
1155
+ type ComparisonSorter<Item> = (first: Item, second: Item) => number;
1156
+ /**
1157
+ * Direction to sort by
1158
+ */
1159
+ type SortDirection = 'ascending' | 'descending';
1160
+ type Sorter<Item> = (array: Item[]) => Item[];
1161
+ /**
1162
+ * Initialize a sort handler with sorters _(and an optional default direction)_
1163
+ * @param sorters Sorters to use for sorting
1164
+ * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
1165
+ * @returns Sort handler
1166
+ */
1167
+ declare function initializeSort<Item>(sorters: Array<ArraySorter<Item>>, descending?: boolean): Sorter<Item>;
1168
+ /**
1169
+ * Initialize a sort handler with a sorter _(and an optional default direction)_
1170
+ * @param sorter Sorter to use for sorting
1171
+ * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
1172
+ * @returns Sort handler
1173
+ */
1174
+ declare function initializeSort<Item>(sorter: ArraySorter<Item>, descending?: boolean): Sorter<Item>;
1175
+ /**
1176
+ * Initialize a sort handler _(with an optional default direction)_
1177
+ * @param descending Sort in descending order? _(defaults to `false`)_
1178
+ * @returns Sort handler
1179
+ */
1180
+ declare function initializeSort<Item>(descending?: boolean): Sorter<Item>;
1181
+ /**
1182
+ * Sort an array of items, using multiple sorters to sort by specific values
1183
+ * @param array Array to sort
1184
+ * @param sorters Sorters to use for sorting
1185
+ * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
1186
+ * @returns Sorted array
1187
+ */
1188
+ declare function sort<Item>(array: Item[], sorters: Array<ArraySorter<Item>>, descending?: boolean): Item[];
1189
+ /**
1190
+ * Sort an array of items, using multiple sorters to sort by specific values
1191
+ * @param array Array to sort
1192
+ * @param sorter Sorter to use for sorting
1193
+ * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
1194
+ * @returns Sorted array
1195
+ */
1196
+ declare function sort<Item>(array: Item[], sorter: ArraySorter<Item>, descending?: boolean): Item[];
1197
+ /**
1198
+ * Sort an array of items
1199
+ * @param array Array to sort
1200
+ * @param descending Sort in descending order? _(defaults to `false`)_
1201
+ * @returns Sorted array
1202
+ */
1203
+ declare function sort<Item>(array: Item[], descending?: boolean): Item[];
1204
+ declare namespace sort {
1205
+ var initialize: typeof initializeSort;
1206
+ }
1207
+ declare const SORT_DIRECTION_ASCENDING: SortDirection;
1208
+ declare const SORT_DIRECTION_DESCENDING: SortDirection;
1209
+ //#endregion
1186
1210
  //#region src/array/swap.d.ts
1187
1211
  /**
1188
1212
  * Swap two smaller arrays within a larger array
@@ -4327,4 +4351,4 @@ declare class SizedSet<Value = unknown> extends Set<Value> {
4327
4351
  get(value: Value, update?: boolean): Value | undefined;
4328
4352
  }
4329
4353
  //#endregion
4330
- export { AnyResult, ArrayComparisonSorter, ArrayKeySorter, ArrayOrPlainObject, ArrayPosition, ArrayValueSorter, Asserter, AttemptFlow, AttemptFlowPromise, type Beacon, type BeaconOptions, BuiltIns, CancelableCallback, CancelablePromise, type Color, Constructor, DiffOptions, DiffResult, DiffValue, EqualOptions, Err, EventPosition, ExtendedErr, ExtendedResult, Flow, FlowPromise, FulfilledPromise, GenericAsyncCallback, GenericCallback, type HSLAColor, type HSLColor, HasValue, Key, KeyedValue, type Logger, type Memoized, type MemoizedOptions, MergeOptions, Merger, NestedArray, NestedKeys, NestedPartial, NestedValue, NestedValues, NumericalKeys, NumericalValues, type Observable, type Observer, Ok, OnceAsyncCallback, OnceCallback, PROMISE_ABORT_EVENT, PROMISE_ABORT_OPTIONS, PROMISE_ERROR_NAME, PROMISE_MESSAGE_EXPECTATION_ATTEMPT, PROMISE_MESSAGE_EXPECTATION_RESULT, PROMISE_MESSAGE_EXPECTATION_TIMED, PROMISE_MESSAGE_TIMEOUT, PROMISE_STRATEGY_ALL, PROMISE_STRATEGY_DEFAULT, PROMISE_TYPE_FULFILLED, PROMISE_TYPE_REJECTED, PlainObject, Primitive, PromiseData, PromiseHandlers, PromiseOptions, PromiseParameters, PromiseStrategy, PromiseTimeoutError, PromisesItems, PromisesOptions, PromisesResult, PromisesUnwrapped, PromisesValue, PromisesValues, type Queue, QueueError, type QueueOptions, type Queued, type RGBAColor, type RGBColor, RejectedPromise, RequiredKeys, Result, ResultMatch, RetryError, RetryOptions, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, Simplify, SizedMap, SizedSet, Smushed, SortDirection, type Subscription, TemplateOptions, type Time, ToString, TypedArray, Unsmushed, UnwrapValue, assert, attempt, attemptFlow, attemptPipe, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, difference, drop, endsWith, endsWithArray, equal, error, exists, filter, find, flatten, floor, flow, fromQuery, toPromise as fromResult, toPromise, getArray, getArrayPosition, getColor, getError, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getTimedPromise, getUuid, getValue, groupBy, handleResult, hasValue, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, includesArray, indexOf, indexOfArray, insert, intersection, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, matchResult, max, median, memoize, merge, min, move, noop, ok, omit, once, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, retry, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, settlePromise, shuffle, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toQuery, toRecord, toResult, toSet, toggle, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
4354
+ export { AnyResult, ArrayComparisonSorter, ArrayKeySorter, ArrayOrPlainObject, ArrayPosition, ArrayValueSorter, Asserter, AttemptFlow, AttemptFlowPromise, type Beacon, type BeaconOptions, BuiltIns, CancelableCallback, CancelablePromise, type Color, Constructor, DiffOptions, DiffResult, DiffValue, EqualOptions, Err, EventPosition, ExtendedErr, ExtendedResult, Flow, FlowPromise, FulfilledPromise, GenericAsyncCallback, GenericCallback, type HSLAColor, type HSLColor, HasValue, Key, KeyedValue, type Logger, type Memoized, type MemoizedOptions, MergeOptions, Merger, NestedArray, NestedKeys, NestedPartial, NestedValue, NestedValues, NumericalKeys, NumericalValues, type Observable, type Observer, Ok, OnceAsyncCallback, OnceCallback, PROMISE_ABORT_EVENT, PROMISE_ABORT_OPTIONS, PROMISE_ERROR_NAME, PROMISE_MESSAGE_EXPECTATION_ATTEMPT, PROMISE_MESSAGE_EXPECTATION_RESULT, PROMISE_MESSAGE_EXPECTATION_TIMED, PROMISE_MESSAGE_TIMEOUT, PROMISE_STRATEGY_ALL, PROMISE_STRATEGY_DEFAULT, PROMISE_TYPE_FULFILLED, PROMISE_TYPE_REJECTED, PlainObject, Primitive, PromiseData, PromiseHandlers, PromiseOptions, PromiseParameters, PromiseStrategy, PromiseTimeoutError, PromisesItems, PromisesOptions, PromisesResult, PromisesUnwrapped, PromisesValue, PromisesValues, type Queue, QueueError, type QueueOptions, type Queued, type RGBAColor, type RGBColor, RejectedPromise, RequiredKeys, Result, ResultMatch, RetryError, RetryOptions, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, Simplify, SizedMap, SizedSet, Smushed, SortDirection, Sorter, type Subscription, TemplateOptions, type Time, ToString, TypedArray, Unsmushed, UnwrapValue, assert, attempt, attemptFlow, attemptPipe, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, difference, drop, endsWith, endsWithArray, equal, error, exists, filter, find, flatten, floor, flow, fromQuery, toPromise as fromResult, toPromise, getArray, getArrayPosition, getColor, getError, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getTimedPromise, getUuid, getValue, groupBy, handleResult, hasValue, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, includesArray, indexOf, indexOfArray, insert, intersection, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, matchResult, max, median, memoize, merge, min, move, noop, ok, omit, once, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, retry, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, settlePromise, shuffle, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toQuery, toRecord, toResult, toSet, toggle, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
package/dist/index.mjs CHANGED
@@ -538,6 +538,146 @@ function take(array, first, second) {
538
538
  const EXTRACT_DROP = "drop";
539
539
  const EXTRACT_TAKE = "take";
540
540
  //#endregion
541
+ //#region src/array/splice.ts
542
+ function splice(array, start, deleteCountOrItems, items) {
543
+ return insertValues(INSERT_TYPE_SPLICE, array, typeof deleteCountOrItems === "number" ? items : deleteCountOrItems, start, typeof deleteCountOrItems === "number" ? deleteCountOrItems : 0);
544
+ }
545
+ //#endregion
546
+ //#region src/array/to-set.ts
547
+ function toSet(array, value) {
548
+ if (!Array.isArray(array)) return /* @__PURE__ */ new Set();
549
+ const callbacks = getArrayCallbacks(void 0, void 0, value);
550
+ if (callbacks?.value == null) return new Set(array);
551
+ const { length } = array;
552
+ const set = /* @__PURE__ */ new Set();
553
+ for (let index = 0; index < length; index += 1) set.add(callbacks.value(array[index], index, array));
554
+ return set;
555
+ }
556
+ //#endregion
557
+ //#region src/internal/array/update.ts
558
+ function updateInArray(array, items, key, replace) {
559
+ if (!Array.isArray(array)) return [];
560
+ const itemsIsArray = Array.isArray(items);
561
+ if (array.length === 0 || !itemsIsArray) {
562
+ if (itemsIsArray) array.push(...items);
563
+ return array;
564
+ }
565
+ const { length } = items;
566
+ if (length === 0) return array;
567
+ const callback = getArrayCallback(key);
568
+ for (let valuesIndex = 0; valuesIndex < length; valuesIndex += 1) {
569
+ const item = items[valuesIndex];
570
+ const value = callback?.(item) ?? item;
571
+ const arrayIndex = callback == null ? array.indexOf(value) : array.findIndex((arrayItem, arrayIndex) => callback(arrayItem, arrayIndex, array) === value);
572
+ if (arrayIndex === -1) array.push(item);
573
+ else if (replace) array[arrayIndex] = item;
574
+ else array.splice(arrayIndex, 1);
575
+ }
576
+ return array;
577
+ }
578
+ //#endregion
579
+ //#region src/array/toggle.ts
580
+ function toggle(array, values, key) {
581
+ return updateInArray(array, values, key, false);
582
+ }
583
+ //#endregion
584
+ //#region src/array/union.ts
585
+ function union(first, second, key) {
586
+ return compareSets(COMPARE_SETS_UNION, first, second, key);
587
+ }
588
+ //#endregion
589
+ //#region src/array/unique.ts
590
+ function unique(array, key) {
591
+ if (!Array.isArray(array)) return [];
592
+ return array.length > 1 ? findValues(FIND_VALUES_UNIQUE, array, [key, void 0]).matched : array;
593
+ }
594
+ //#endregion
595
+ //#region src/array/update.ts
596
+ function update(array, values, key) {
597
+ return updateInArray(array, values, key, true);
598
+ }
599
+ //#endregion
600
+ //#region src/internal/array/overlap.ts
601
+ function arraysOverlap(first, second) {
602
+ const firstArray = first.index < second.index ? first.array : second.array;
603
+ const secondArray = first.index < second.index ? second.array : first.array;
604
+ const firstIndex = firstArray === first.array ? first.index : second.index;
605
+ const secondIndex = firstArray === first.array ? second.index : first.index;
606
+ const firstEnd = firstIndex + firstArray.length - 1;
607
+ return {
608
+ overlap: firstIndex <= secondIndex + secondArray.length - 1 && firstEnd >= secondIndex,
609
+ first: {
610
+ array: firstArray,
611
+ index: firstIndex
612
+ },
613
+ second: {
614
+ array: secondArray,
615
+ index: secondIndex
616
+ }
617
+ };
618
+ }
619
+ //#endregion
620
+ //#region src/array/move.ts
621
+ function move(array, from, to, key) {
622
+ if (!Array.isArray(array)) return [];
623
+ const firstArray = Array.isArray(from) ? from : [from];
624
+ const secondArray = Array.isArray(to) ? to : [to];
625
+ if (firstArray.length === 0 || secondArray.length === 0) return array;
626
+ const firstPosition = indexOfArray(array, firstArray, key);
627
+ const secondPosition = indexOfArray(array, secondArray, key);
628
+ if (firstPosition === -1 || secondPosition === -1 || firstPosition === secondPosition) return array;
629
+ const { overlap } = arraysOverlap({
630
+ array: firstArray,
631
+ index: firstPosition
632
+ }, {
633
+ array: secondArray,
634
+ index: secondPosition
635
+ });
636
+ if (overlap) return array;
637
+ array.splice(firstPosition, firstArray.length);
638
+ const next = secondPosition < firstPosition ? secondPosition : secondPosition + secondArray.length - firstArray.length;
639
+ if (next >= array.length) array.push(...firstArray);
640
+ else array.splice(next, 0, ...firstArray);
641
+ return array;
642
+ }
643
+ move.indices = moveIndices;
644
+ move.toIndex = moveToIndex;
645
+ /**
646
+ * Move an item from one index to another within an array
647
+ *
648
+ * If the from index is out of bounds, the array will be returned unchanged
649
+ * @param array Array to move within
650
+ * @param from Index to move from
651
+ * @param to Index to move to
652
+ * @returns Original array with item moved _(or unchanged if unable to move)_
653
+ */
654
+ function moveIndices(array, from, to) {
655
+ if (!Array.isArray(array)) return [];
656
+ const { length } = array;
657
+ if (length === 0 || typeof from !== "number" || typeof to !== "number") return array;
658
+ const fromIndex = from < 0 ? length + from : from;
659
+ const toIndex = to < 0 ? length + to : to;
660
+ if (fromIndex === toIndex || fromIndex >= length || toIndex >= length) return array;
661
+ const spliced = array.splice(fromIndex, 1);
662
+ if (toIndex >= array.length) array.push(...spliced);
663
+ else array.splice(toIndex, 0, ...spliced);
664
+ return array;
665
+ }
666
+ function moveToIndex(array, value, index, key) {
667
+ if (!Array.isArray(array)) return [];
668
+ const { length } = array;
669
+ if (length === 0 || typeof index !== "number") return array;
670
+ const next = index < 0 ? length + index : index;
671
+ if (next >= length) return array;
672
+ const values = Array.isArray(value) ? value : [value];
673
+ const position = indexOfArray(array, values, key);
674
+ if (position === -1 || position === next) return array;
675
+ array.splice(position, values.length);
676
+ if (next >= array.length) array.push(...values);
677
+ else array.splice(next, 0, ...values);
678
+ return array;
679
+ }
680
+ //#endregion
541
681
  //#region src/internal/math/aggregate.ts
542
682
  function aggregate(type, array, key) {
543
683
  const length = Array.isArray(array) ? array.length : 0;
@@ -770,6 +910,9 @@ function getComparisonSorter(callback, modifier) {
770
910
  identifier: String(callback)
771
911
  };
772
912
  }
913
+ function getModifier(first, second) {
914
+ return modifiers[first === true || second === true ? SORT_DIRECTION_DESCENDING : SORT_DIRECTION_ASCENDING];
915
+ }
773
916
  function getObjectSorter(obj, modifier) {
774
917
  let sorter;
775
918
  if (typeof obj.comparison === "function") sorter = getComparisonSorter(obj.comparison, modifier);
@@ -788,6 +931,17 @@ function getSorter(value, modifier) {
788
931
  default: break;
789
932
  }
790
933
  }
934
+ function getSorters(value, modifier) {
935
+ const array = Array.isArray(value) ? value : [value];
936
+ const { length } = array;
937
+ const sorters = [];
938
+ for (let index = 0; index < length; index += 1) {
939
+ const item = array[index];
940
+ const sorter = getSorter(item, modifier);
941
+ if (sorter != null) sorters.push(sorter);
942
+ }
943
+ return sorters.filter((value, index, array) => array.findIndex((next) => next.identifier === value.identifier) === index);
944
+ }
791
945
  function getValueSorter(value, modifier) {
792
946
  return {
793
947
  modifier,
@@ -796,32 +950,31 @@ function getValueSorter(value, modifier) {
796
950
  value: typeof value === "function" ? value : (item) => item[value]
797
951
  };
798
952
  }
953
+ function initializeSort(first, second) {
954
+ const modifier = getModifier(first, second);
955
+ const sorters = getSorters(first, modifier);
956
+ return (array) => work$1(array, sorters, modifier);
957
+ }
799
958
  function sort(array, first, second) {
959
+ const modifier = getModifier(first, second);
960
+ return work$1(array, getSorters(first, modifier), modifier);
961
+ }
962
+ function work$1(array, sorters, modifier) {
800
963
  if (!Array.isArray(array)) return [];
801
964
  if (array.length < 2) return array;
802
- const modifier = modifiers[first === true || second === true ? SORT_DIRECTION_DESCENDING : SORT_DIRECTION_ASCENDING];
803
- const sorters = (Array.isArray(first) ? first : [first]).map((item) => getSorter(item, modifier)).filter((sorter) => sorter != null).filter((current, index, filtered) => filtered.findIndex((next) => next.identifier === current.identifier) === index);
804
965
  const { length } = sorters;
805
966
  if (length === 0) return array.sort((first, second) => compare(first, second) * modifier);
806
- if (length === 1) {
807
- const sorter = sorters[0];
808
- return array.sort((firstItem, secondItem) => {
809
- const firstValue = sorter.get ? sorter.value(firstItem) : firstItem;
810
- const secondValue = sorter.get ? sorter.value(secondItem) : secondItem;
811
- return (sorter.compare?.complex?.(firstItem, firstValue, secondItem, secondValue) ?? sorter.compare?.simple?.(firstItem, secondItem) ?? compare(firstValue, secondValue)) * sorter.modifier;
812
- });
813
- }
814
- return array.sort((firstItem, secondItem) => {
967
+ return array.sort((first, second) => {
815
968
  for (let index = 0; index < length; index += 1) {
816
969
  const sorter = sorters[index];
817
- const firstValue = sorter.value?.(firstItem) ?? firstItem;
818
- const secondValue = sorter.value?.(secondItem) ?? secondItem;
819
- const comparison = (sorter.compare?.complex?.(firstItem, firstValue, secondItem, secondValue) ?? sorter.compare?.simple?.(firstItem, secondItem) ?? compare(firstValue, secondValue)) * sorter.modifier;
970
+ const values = [sorter.get ? sorter.value(first) : first, sorter.get ? sorter.value(second) : second];
971
+ const comparison = (sorter.compare?.complex?.(first, values[0], second, values[1]) ?? sorter.compare?.simple?.(values[0], values[1]) ?? compare(values[0], values[1])) * sorter.modifier;
820
972
  if (comparison !== 0) return comparison;
821
973
  }
822
974
  return 0;
823
975
  });
824
976
  }
977
+ sort.initialize = initializeSort;
825
978
  const SORT_DIRECTION_ASCENDING = "ascending";
826
979
  const SORT_DIRECTION_DESCENDING = "descending";
827
980
  const modifiers = {
@@ -829,146 +982,6 @@ const modifiers = {
829
982
  [SORT_DIRECTION_DESCENDING]: -1
830
983
  };
831
984
  //#endregion
832
- //#region src/array/splice.ts
833
- function splice(array, start, deleteCountOrItems, items) {
834
- return insertValues(INSERT_TYPE_SPLICE, array, typeof deleteCountOrItems === "number" ? items : deleteCountOrItems, start, typeof deleteCountOrItems === "number" ? deleteCountOrItems : 0);
835
- }
836
- //#endregion
837
- //#region src/array/to-set.ts
838
- function toSet(array, value) {
839
- if (!Array.isArray(array)) return /* @__PURE__ */ new Set();
840
- const callbacks = getArrayCallbacks(void 0, void 0, value);
841
- if (callbacks?.value == null) return new Set(array);
842
- const { length } = array;
843
- const set = /* @__PURE__ */ new Set();
844
- for (let index = 0; index < length; index += 1) set.add(callbacks.value(array[index], index, array));
845
- return set;
846
- }
847
- //#endregion
848
- //#region src/internal/array/update.ts
849
- function updateInArray(array, items, key, replace) {
850
- if (!Array.isArray(array)) return [];
851
- const itemsIsArray = Array.isArray(items);
852
- if (array.length === 0 || !itemsIsArray) {
853
- if (itemsIsArray) array.push(...items);
854
- return array;
855
- }
856
- const { length } = items;
857
- if (length === 0) return array;
858
- const callback = getArrayCallback(key);
859
- for (let valuesIndex = 0; valuesIndex < length; valuesIndex += 1) {
860
- const item = items[valuesIndex];
861
- const value = callback?.(item) ?? item;
862
- const arrayIndex = callback == null ? array.indexOf(value) : array.findIndex((arrayItem, arrayIndex) => callback(arrayItem, arrayIndex, array) === value);
863
- if (arrayIndex === -1) array.push(item);
864
- else if (replace) array[arrayIndex] = item;
865
- else array.splice(arrayIndex, 1);
866
- }
867
- return array;
868
- }
869
- //#endregion
870
- //#region src/array/toggle.ts
871
- function toggle(array, values, key) {
872
- return updateInArray(array, values, key, false);
873
- }
874
- //#endregion
875
- //#region src/array/union.ts
876
- function union(first, second, key) {
877
- return compareSets(COMPARE_SETS_UNION, first, second, key);
878
- }
879
- //#endregion
880
- //#region src/array/unique.ts
881
- function unique(array, key) {
882
- if (!Array.isArray(array)) return [];
883
- return array.length > 1 ? findValues(FIND_VALUES_UNIQUE, array, [key, void 0]).matched : array;
884
- }
885
- //#endregion
886
- //#region src/array/update.ts
887
- function update(array, values, key) {
888
- return updateInArray(array, values, key, true);
889
- }
890
- //#endregion
891
- //#region src/internal/array/overlap.ts
892
- function arraysOverlap(first, second) {
893
- const firstArray = first.index < second.index ? first.array : second.array;
894
- const secondArray = first.index < second.index ? second.array : first.array;
895
- const firstIndex = firstArray === first.array ? first.index : second.index;
896
- const secondIndex = firstArray === first.array ? second.index : first.index;
897
- const firstEnd = firstIndex + firstArray.length - 1;
898
- return {
899
- overlap: firstIndex <= secondIndex + secondArray.length - 1 && firstEnd >= secondIndex,
900
- first: {
901
- array: firstArray,
902
- index: firstIndex
903
- },
904
- second: {
905
- array: secondArray,
906
- index: secondIndex
907
- }
908
- };
909
- }
910
- //#endregion
911
- //#region src/array/move.ts
912
- function move(array, from, to, key) {
913
- if (!Array.isArray(array)) return [];
914
- const firstArray = Array.isArray(from) ? from : [from];
915
- const secondArray = Array.isArray(to) ? to : [to];
916
- if (firstArray.length === 0 || secondArray.length === 0) return array;
917
- const firstPosition = indexOfArray(array, firstArray, key);
918
- const secondPosition = indexOfArray(array, secondArray, key);
919
- if (firstPosition === -1 || secondPosition === -1 || firstPosition === secondPosition) return array;
920
- const { overlap } = arraysOverlap({
921
- array: firstArray,
922
- index: firstPosition
923
- }, {
924
- array: secondArray,
925
- index: secondPosition
926
- });
927
- if (overlap) return array;
928
- array.splice(firstPosition, firstArray.length);
929
- const next = secondPosition < firstPosition ? secondPosition : secondPosition + secondArray.length - firstArray.length;
930
- if (next >= array.length) array.push(...firstArray);
931
- else array.splice(next, 0, ...firstArray);
932
- return array;
933
- }
934
- move.indices = moveIndices;
935
- move.toIndex = moveToIndex;
936
- /**
937
- * Move an item from one index to another within an array
938
- *
939
- * If the from index is out of bounds, the array will be returned unchanged
940
- * @param array Array to move within
941
- * @param from Index to move from
942
- * @param to Index to move to
943
- * @returns Original array with item moved _(or unchanged if unable to move)_
944
- */
945
- function moveIndices(array, from, to) {
946
- if (!Array.isArray(array)) return [];
947
- const { length } = array;
948
- if (length === 0 || typeof from !== "number" || typeof to !== "number") return array;
949
- const fromIndex = from < 0 ? length + from : from;
950
- const toIndex = to < 0 ? length + to : to;
951
- if (fromIndex === toIndex || fromIndex >= length || toIndex >= length) return array;
952
- const spliced = array.splice(fromIndex, 1);
953
- if (toIndex >= array.length) array.push(...spliced);
954
- else array.splice(toIndex, 0, ...spliced);
955
- return array;
956
- }
957
- function moveToIndex(array, value, index, key) {
958
- if (!Array.isArray(array)) return [];
959
- const { length } = array;
960
- if (length === 0 || typeof index !== "number") return array;
961
- const next = index < 0 ? length + index : index;
962
- if (next >= length) return array;
963
- const values = Array.isArray(value) ? value : [value];
964
- const position = indexOfArray(array, values, key);
965
- if (position === -1 || position === next) return array;
966
- array.splice(position, values.length);
967
- if (next >= array.length) array.push(...values);
968
- else array.splice(next, 0, ...values);
969
- return array;
970
- }
971
- //#endregion
972
985
  //#region src/array/swap.ts
973
986
  function swap(array, first, second, third) {
974
987
  if (!Array.isArray(array)) return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/atoms",
3
- "version": "0.167.0",
3
+ "version": "0.168.0",
4
4
  "description": "Atomic utilities for making your JavaScript better.",
5
5
  "keywords": [
6
6
  "helper",
@@ -44,6 +44,10 @@
44
44
  "types": "./dist/array/move.d.mts",
45
45
  "default": "./dist/array/move.mjs"
46
46
  },
47
+ "./array/sort": {
48
+ "types": "./dist/array/sort.d.mts",
49
+ "default": "./dist/array/sort.mjs"
50
+ },
47
51
  "./array/swap": {
48
52
  "types": "./dist/array/swap.d.mts",
49
53
  "default": "./dist/array/swap.mjs"
@@ -16,7 +16,6 @@ export * from './position';
16
16
  export * from './push';
17
17
  export * from './select';
18
18
  export * from './slice';
19
- export * from './sort';
20
19
  export * from './splice';
21
20
  export * from './to-set';
22
21
  export * from './toggle';
package/src/array/sort.ts CHANGED
@@ -43,6 +43,18 @@ type ArrayKeySorters<Item extends PlainObject> = {
43
43
  [ItemKey in keyof Item]: ArrayKeySorter<Item, ItemKey>;
44
44
  }[keyof Item];
45
45
 
46
+ /**
47
+ * Sorter to use for sorting
48
+ */
49
+ type ArraySorter<Item> = Item extends PlainObject
50
+ ?
51
+ | keyof Item
52
+ | ArrayComparisonSorter<Item>
53
+ | ArrayKeySorters<Item>
54
+ | ArrayValueSorter<Item>
55
+ | ComparisonSorter<Item>
56
+ : ArrayComparisonSorter<Item> | ArrayValueSorter<Item> | ComparisonSorter<Item>;
57
+
46
58
  /**
47
59
  * Sorting information for arrays _(using a value callback and built-in comparison)_
48
60
  */
@@ -74,41 +86,25 @@ type CompareCallbackValue<Item> = Item extends Primitive ? Item : unknown;
74
86
  */
75
87
  type ComparisonSorter<Item> = (first: Item, second: Item) => number;
76
88
 
77
- /**
78
- * Internal sorter information
79
- */
80
89
  type InternalSorter = {
81
- compare?: SorterCompare;
90
+ compare?: InternalSorterCompare;
82
91
  get: boolean;
83
92
  identifier: string;
84
93
  modifier: number;
85
- value?: (item: PlainObject) => unknown;
94
+ value?: Function;
86
95
  };
87
96
 
88
- /**
89
- * Direction to sort by
90
- */
91
- export type SortDirection = 'ascending' | 'descending';
92
-
93
- /**
94
- * Comparison callbacks for sorter
95
- */
96
- type SorterCompare = {
97
+ type InternalSorterCompare = {
97
98
  complex?: Function;
98
99
  simple?: Function;
99
100
  };
100
101
 
101
102
  /**
102
- * Sorter to use for sorting
103
+ * Direction to sort by
103
104
  */
104
- type Sorter<Item> = Item extends PlainObject
105
- ?
106
- | keyof Item
107
- | ArrayComparisonSorter<Item>
108
- | ArrayKeySorters<Item>
109
- | ArrayValueSorter<Item>
110
- | ComparisonSorter<Item>
111
- : ArrayComparisonSorter<Item> | ArrayValueSorter<Item> | ComparisonSorter<Item>;
105
+ export type SortDirection = 'ascending' | 'descending';
106
+
107
+ export type Sorter<Item> = (array: Item[]) => Item[];
112
108
 
113
109
  // #endregion
114
110
 
@@ -125,6 +121,13 @@ function getComparisonSorter(callback: Function, modifier: number): InternalSort
125
121
  };
126
122
  }
127
123
 
124
+ function getModifier(first: unknown, second: unknown): number {
125
+ const direction =
126
+ first === true || second === true ? SORT_DIRECTION_DESCENDING : SORT_DIRECTION_ASCENDING;
127
+
128
+ return modifiers[direction];
129
+ }
130
+
128
131
  function getObjectSorter(obj: PlainObject, modifier: number): InternalSorter | undefined {
129
132
  let sorter: InternalSorter | undefined;
130
133
 
@@ -165,18 +168,70 @@ function getSorter(value: unknown, modifier: number): InternalSorter | undefined
165
168
  }
166
169
  }
167
170
 
171
+ function getSorters(value: unknown, modifier: number): InternalSorter[] {
172
+ const array = Array.isArray(value) ? value : [value];
173
+ const {length} = array;
174
+
175
+ const sorters: InternalSorter[] = [];
176
+
177
+ for (let index = 0; index < length; index += 1) {
178
+ const item = array[index];
179
+
180
+ const sorter = getSorter(item, modifier);
181
+
182
+ if (sorter != null) {
183
+ sorters.push(sorter);
184
+ }
185
+ }
186
+
187
+ return sorters.filter(
188
+ (value, index, array) =>
189
+ array.findIndex(next => next.identifier === value.identifier) === index,
190
+ );
191
+ }
192
+
168
193
  function getValueSorter(value: string | Function, modifier: number): InternalSorter {
169
194
  return {
170
195
  modifier,
171
196
  get: true,
172
197
  identifier: String(value),
173
- value:
174
- typeof value === 'function'
175
- ? (value as (item: PlainObject) => unknown)
176
- : item => (item as PlainObject)[value],
198
+ value: typeof value === 'function' ? value : (item: unknown) => (item as PlainObject)[value],
177
199
  };
178
200
  }
179
201
 
202
+ /**
203
+ * Initialize a sort handler with sorters _(and an optional default direction)_
204
+ * @param sorters Sorters to use for sorting
205
+ * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
206
+ * @returns Sort handler
207
+ */
208
+ function initializeSort<Item>(
209
+ sorters: Array<ArraySorter<Item>>,
210
+ descending?: boolean,
211
+ ): Sorter<Item>;
212
+
213
+ /**
214
+ * Initialize a sort handler with a sorter _(and an optional default direction)_
215
+ * @param sorter Sorter to use for sorting
216
+ * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
217
+ * @returns Sort handler
218
+ */
219
+ function initializeSort<Item>(sorter: ArraySorter<Item>, descending?: boolean): Sorter<Item>;
220
+
221
+ /**
222
+ * Initialize a sort handler _(with an optional default direction)_
223
+ * @param descending Sort in descending order? _(defaults to `false`)_
224
+ * @returns Sort handler
225
+ */
226
+ function initializeSort<Item>(descending?: boolean): Sorter<Item>;
227
+
228
+ function initializeSort(first?: unknown, second?: unknown): Sorter<unknown> {
229
+ const modifier = getModifier(first, second);
230
+ const sorters = getSorters(first, modifier);
231
+
232
+ return array => work(array, sorters, modifier);
233
+ }
234
+
180
235
  /**
181
236
  * Sort an array of items, using multiple sorters to sort by specific values
182
237
  * @param array Array to sort
@@ -186,7 +241,7 @@ function getValueSorter(value: string | Function, modifier: number): InternalSor
186
241
  */
187
242
  export function sort<Item>(
188
243
  array: Item[],
189
- sorters: Array<Sorter<Item>>,
244
+ sorters: Array<ArraySorter<Item>>,
190
245
  descending?: boolean,
191
246
  ): Item[];
192
247
 
@@ -197,7 +252,7 @@ export function sort<Item>(
197
252
  * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
198
253
  * @returns Sorted array
199
254
  */
200
- export function sort<Item>(array: Item[], sorter: Sorter<Item>, descending?: boolean): Item[];
255
+ export function sort<Item>(array: Item[], sorter: ArraySorter<Item>, descending?: boolean): Item[];
201
256
 
202
257
  /**
203
258
  * Sort an array of items
@@ -208,6 +263,12 @@ export function sort<Item>(array: Item[], sorter: Sorter<Item>, descending?: boo
208
263
  export function sort<Item>(array: Item[], descending?: boolean): Item[];
209
264
 
210
265
  export function sort(array: unknown[], first?: unknown, second?: unknown): unknown[] {
266
+ const modifier = getModifier(first, second);
267
+
268
+ return work(array, getSorters(first, modifier), modifier);
269
+ }
270
+
271
+ function work(array: unknown[], sorters: InternalSorter[], modifier: number): unknown[] {
211
272
  if (!Array.isArray(array)) {
212
273
  return [];
213
274
  }
@@ -216,51 +277,25 @@ export function sort(array: unknown[], first?: unknown, second?: unknown): unkno
216
277
  return array;
217
278
  }
218
279
 
219
- const direction =
220
- first === true || second === true ? SORT_DIRECTION_DESCENDING : SORT_DIRECTION_ASCENDING;
221
-
222
- const modifier = modifiers[direction];
223
-
224
- const sorters = (Array.isArray(first) ? first : [first])
225
- .map(item => getSorter(item, modifier))
226
- .filter(sorter => sorter != null)
227
- .filter(
228
- (current, index, filtered) =>
229
- filtered.findIndex(next => next.identifier === current.identifier) === index,
230
- );
231
-
232
280
  const {length} = sorters;
233
281
 
234
282
  if (length === 0) {
235
283
  return array.sort((first, second) => compare(first, second) * modifier);
236
284
  }
237
285
 
238
- if (length === 1) {
239
- const sorter = sorters[0];
240
-
241
- return array.sort((firstItem, secondItem) => {
242
- const firstValue = sorter.get ? sorter.value!(firstItem as PlainObject) : firstItem;
243
- const secondValue = sorter.get ? sorter.value!(secondItem as PlainObject) : secondItem;
244
-
245
- return (
246
- (sorter.compare?.complex?.(firstItem, firstValue, secondItem, secondValue) ??
247
- sorter.compare?.simple?.(firstItem, secondItem) ??
248
- compare(firstValue, secondValue)) * sorter.modifier
249
- );
250
- });
251
- }
252
-
253
- return array.sort((firstItem, secondItem) => {
286
+ return array.sort((first, second) => {
254
287
  for (let index = 0; index < length; index += 1) {
255
288
  const sorter = sorters[index];
256
289
 
257
- const firstValue = sorter.value?.(firstItem as PlainObject) ?? firstItem;
258
- const secondValue = sorter.value?.(secondItem as PlainObject) ?? secondItem;
290
+ const values = [
291
+ sorter.get ? sorter.value!(first as PlainObject) : first,
292
+ sorter.get ? sorter.value!(second as PlainObject) : second,
293
+ ];
259
294
 
260
295
  const comparison =
261
- (sorter.compare?.complex?.(firstItem, firstValue, secondItem, secondValue) ??
262
- sorter.compare?.simple?.(firstItem, secondItem) ??
263
- compare(firstValue, secondValue)) * sorter.modifier;
296
+ (sorter.compare?.complex?.(first, values[0], second, values[1]) ??
297
+ sorter.compare?.simple?.(values[0], values[1]) ??
298
+ compare(values[0], values[1])) * sorter.modifier;
264
299
 
265
300
  if (comparison !== 0) {
266
301
  return comparison;
@@ -271,6 +306,8 @@ export function sort(array: unknown[], first?: unknown, second?: unknown): unkno
271
306
  });
272
307
  }
273
308
 
309
+ sort.initialize = initializeSort;
310
+
274
311
  // #endregion
275
312
 
276
313
  // #region Variables
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export * from './array/filter';
2
2
  export * from './array/group-by';
3
3
  export * from './array/index';
4
4
  export * from './array/move';
5
+ export * from './array/sort';
5
6
  export * from './array/swap';
6
7
  export * from './array/to-map';
7
8
  export * from './array/to-record';