@oscarpalmer/atoms 0.183.0 → 0.184.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/queue.mjs CHANGED
@@ -1,9 +1,159 @@
1
1
  //#region src/queue.ts
2
+ var KeyedQueue = class {
3
+ #callback;
4
+ #options;
5
+ #queues = /* @__PURE__ */ new Map();
6
+ /**
7
+ * Is any queue active?
8
+ */
9
+ get active() {
10
+ return this.#getStatus(STATUS_ACTIVE);
11
+ }
12
+ /**
13
+ * Does the queue automatically start when the first item is added?
14
+ */
15
+ get autostart() {
16
+ return this.#options.autostart;
17
+ }
18
+ /**
19
+ * Maximum number of runners to process the queue concurrently
20
+ */
21
+ get concurrency() {
22
+ return this.#options.concurrency;
23
+ }
24
+ /**
25
+ * Are all queues empty?
26
+ */
27
+ get empty() {
28
+ return this.#getStatus(STATUS_EMPTY);
29
+ }
30
+ /**
31
+ * Are all queues full?
32
+ */
33
+ get full() {
34
+ return this.#getStatus(STATUS_FULL);
35
+ }
36
+ /**
37
+ * Number of items in all queues
38
+ */
39
+ get items() {
40
+ const size = {};
41
+ const queues = this.#queues.entries();
42
+ for (const [key, queue] of queues) size[key] = queue.size;
43
+ return size;
44
+ }
45
+ /**
46
+ * Keys of all queues
47
+ */
48
+ get keys() {
49
+ return [...this.#queues.keys()];
50
+ }
51
+ /**
52
+ * Maximum number of items allowed in the queue
53
+ */
54
+ get maximum() {
55
+ return this.#options.maximum;
56
+ }
57
+ /**
58
+ * Are all queues paused?
59
+ */
60
+ get paused() {
61
+ return this.#getStatus(STATUS_PAUSED);
62
+ }
63
+ /**
64
+ * Number of queues
65
+ */
66
+ get queues() {
67
+ return this.#queues.size;
68
+ }
69
+ constructor(callback, options) {
70
+ this.#callback = callback;
71
+ this.#options = options;
72
+ }
73
+ /**
74
+ * Queue an item for a specific key
75
+ * @param key Key to queue the item for
76
+ * @param parameters Parameters to use when item runs
77
+ * @param signal Optional signal to abort the item
78
+ * @returns Queued item
79
+ */
80
+ add(key, parameters, signal) {
81
+ return this.#getQueue(key, true).add(parameters, signal);
82
+ }
83
+ /**
84
+ * Clear all items for a specific key _(or all items for all keys, if no key is provided)_
85
+ * @param key Optional key to clear the queue for
86
+ */
87
+ clear(key) {
88
+ this.#handleQueues(HANDLE_CLEAR, key);
89
+ }
90
+ /**
91
+ * Get the queue for a specific key
92
+ * @param key Key to get the queue for
93
+ * @returns Queue for the key, or `undefined` if it doesn't exist
94
+ */
95
+ get(key) {
96
+ return this.#getQueue(key);
97
+ }
98
+ /**
99
+ * Pause the queue for a specific key _(or all queues, if no key is provided)_
100
+ * @param key Optional key to pause the queue for
101
+ */
102
+ pause(key) {
103
+ this.#handleQueues(HANDLE_PAUSE, key);
104
+ }
105
+ remove(key, id) {
106
+ if (key == null) {
107
+ this.#handleQueues(HANDLE_CLEAR);
108
+ this.#queues.clear();
109
+ return;
110
+ }
111
+ const queue = this.#getQueue(key);
112
+ if (queue == null) return;
113
+ if (typeof id === "number") {
114
+ queue.remove(id);
115
+ return;
116
+ }
117
+ queue.clear();
118
+ this.#queues.delete(key);
119
+ }
120
+ /**
121
+ * Resume the queue for a specific key _(or all queues, if no key is provided)_
122
+ * @param key Optional key to resume the queue for
123
+ */
124
+ resume(key) {
125
+ this.#handleQueues(HANDLE_RESUME, key);
126
+ }
127
+ #getQueue(key, add) {
128
+ if (typeof key !== "string" || key.trim().length === 0) throw new TypeError(MESSAGE_KEY);
129
+ let queue = this.#queues.get(key);
130
+ if (queue == null && add === true) {
131
+ queue = new Queue(this.#callback, this.#options, key);
132
+ this.#queues.set(key, queue);
133
+ }
134
+ return queue;
135
+ }
136
+ #getStatus(status) {
137
+ const queues = this.#queues.entries();
138
+ const result = [];
139
+ for (const [key, queue] of queues) if (queue[status]) result.push(key);
140
+ return result;
141
+ }
142
+ #handleQueues(type, key) {
143
+ if (typeof key === "string") {
144
+ this.#getQueue(key)?.[type]();
145
+ return;
146
+ }
147
+ const queues = this.#queues.values();
148
+ for (const queue of queues) queue[type]();
149
+ }
150
+ };
2
151
  var Queue = class {
3
152
  #callback;
4
153
  #handled = [];
5
154
  #id = 0;
6
155
  #items = [];
156
+ #key;
7
157
  #options;
8
158
  #paused;
9
159
  #runners = 0;
@@ -55,8 +205,9 @@ var Queue = class {
55
205
  get size() {
56
206
  return this.#items.length;
57
207
  }
58
- constructor(callback, options) {
208
+ constructor(callback, options, key) {
59
209
  this.#callback = callback;
210
+ this.#key = key;
60
211
  this.#options = options;
61
212
  this.#paused = !options.autostart;
62
213
  }
@@ -84,6 +235,7 @@ var Queue = class {
84
235
  parameters,
85
236
  promise,
86
237
  abort: aborter,
238
+ key: this.#key,
87
239
  reject: rejector,
88
240
  resolve: resolver,
89
241
  signal: abortSignal
@@ -152,7 +304,10 @@ var Queue = class {
152
304
  let error = false;
153
305
  let result;
154
306
  try {
155
- if (!(item.signal?.aborted ?? false)) result = await this.#callback(...item.parameters);
307
+ if (!(item.signal?.aborted ?? false)) {
308
+ const parameters = item.key == null ? item.parameters : [item.key, ...item.parameters];
309
+ result = await this.#callback(...parameters);
310
+ }
156
311
  } catch (thrown) {
157
312
  error = true;
158
313
  result = thrown;
@@ -199,16 +354,29 @@ function handleResult(item, error, result, finished) {
199
354
  value: result
200
355
  });
201
356
  }
357
+ function keyedQueue(callback, options) {
358
+ if (typeof callback !== "function") throw new TypeError(MESSAGE_CALLBACK);
359
+ return new KeyedQueue(callback, getOptions(options));
360
+ }
202
361
  function queue(callback, options) {
203
362
  if (typeof callback !== "function") throw new TypeError(MESSAGE_CALLBACK);
204
363
  return new Queue(callback, getOptions(options));
205
364
  }
365
+ queue.keyed = keyedQueue;
206
366
  const ERROR_NAME = "QueueError";
207
367
  const EVENT_NAME = "abort";
208
368
  const EVENT_OPTIONS = { once: true };
369
+ const HANDLE_CLEAR = "clear";
370
+ const HANDLE_PAUSE = "pause";
371
+ const HANDLE_RESUME = "resume";
209
372
  const MESSAGE_CALLBACK = "A Queue requires a callback function";
210
373
  const MESSAGE_CLEAR = "Queue was cleared";
374
+ const MESSAGE_KEY = "Key must be a non-empty string";
211
375
  const MESSAGE_MAXIMUM = "Queue has reached its maximum size";
212
376
  const MESSAGE_REMOVE = "Item removed from queue";
377
+ const STATUS_ACTIVE = "active";
378
+ const STATUS_EMPTY = "empty";
379
+ const STATUS_FULL = "full";
380
+ const STATUS_PAUSED = "paused";
213
381
  //#endregion
214
- export { QueueError, queue };
382
+ export { keyedQueue, queue };
@@ -45,6 +45,8 @@ type Normalizer = {
45
45
  declare function deburr(value: string): string;
46
46
  /**
47
47
  * Initialize a string normalizer
48
+ *
49
+ * Available as `initializeNormalizer` and `normalize.initialize`
48
50
  * @param options Normalization options
49
51
  * @returns Normalizer function
50
52
  */
@@ -28,6 +28,8 @@ function getNormalizeOptions(input) {
28
28
  }
29
29
  /**
30
30
  * Initialize a string normalizer
31
+ *
32
+ * Available as `initializeNormalizer` and `normalize.initialize`
31
33
  * @param options Normalization options
32
34
  * @returns Normalizer function
33
35
  */
@@ -0,0 +1,35 @@
1
+ import { ArrayOrPlainObject, GenericCallback, PlainObject } from "../models.mjs";
2
+
3
+ //#region src/value/freeze.d.ts
4
+ /**
5
+ * A frozen value with readonly properties _(going as deep as possible)_
6
+ */
7
+ type Frozen<Value extends ArrayOrPlainObject> = { readonly [Key in keyof Value]: Value[Key] extends ArrayOrPlainObject ? Frozen<Value[Key]> : Value[Key] };
8
+ /**
9
+ * Freeze an array and all its indices recursively
10
+ * @param array Array to freeze
11
+ * @returns Frozen array
12
+ */
13
+ declare function freeze<Item>(array: Item[]): Frozen<Item[]>;
14
+ /**
15
+ * Freeze a callback
16
+ * @param callback Function to freeze
17
+ * @returns Frozen function
18
+ */
19
+ declare function freeze<Fn extends GenericCallback>(fn: Fn): Readonly<Fn>;
20
+ /**
21
+ * Freeze an object and all its properties recursively
22
+ * @param object Object to freeze
23
+ * @returns Frozen object
24
+ */
25
+ declare function freeze<Value extends PlainObject>(object: Value): Frozen<Value>;
26
+ /**
27
+ * Freeze any value, if possible
28
+ *
29
+ * _(Only arrays, functions, and plain objects are freezable)_
30
+ * @param value Value to freeze
31
+ * @returns Frozen value
32
+ */
33
+ declare function freeze<Value>(value: Value): Value;
34
+ //#endregion
35
+ export { Frozen, freeze };
@@ -0,0 +1,38 @@
1
+ import { isPlainObject } from "../internal/is.mjs";
2
+ //#region src/value/freeze.ts
3
+ function freeze(value) {
4
+ return freezeValue(value, /* @__PURE__ */ new WeakSet());
5
+ }
6
+ function freezeArray(array, references) {
7
+ references.add(array);
8
+ const { length } = array;
9
+ for (let index = 0; index < length; index += 1) {
10
+ const value = array[index];
11
+ if (!references.has(value)) array[index] = freezeValue(array[index], references);
12
+ }
13
+ return Object.freeze(array);
14
+ }
15
+ function freezeFunction(fn, references) {
16
+ references.add(fn);
17
+ return Object.freeze(fn);
18
+ }
19
+ function freezeObject(object, references) {
20
+ references.add(object);
21
+ const keys = Object.keys(object);
22
+ const { length } = keys;
23
+ for (let index = 0; index < length; index += 1) {
24
+ const key = keys[index];
25
+ if (!references.has(object[key])) object[key] = freezeValue(object[key], references);
26
+ }
27
+ return Object.freeze(object);
28
+ }
29
+ function freezeValue(value, references) {
30
+ switch (true) {
31
+ case typeof value === "function": return freezeFunction(value, references);
32
+ case Array.isArray(value): return freezeArray(value, references);
33
+ case isPlainObject(value): return freezeObject(value, references);
34
+ default: return value;
35
+ }
36
+ }
37
+ //#endregion
38
+ export { freeze };
@@ -1,6 +1,7 @@
1
+ import { Frozen, freeze } from "./freeze.mjs";
1
2
  import { omit } from "./omit.mjs";
2
3
  import { pick } from "./pick.mjs";
3
4
  import { Shaken, shake } from "./shake.mjs";
4
5
  import { Smushed, smush } from "./smush.mjs";
5
6
  import { Unsmushed, unsmush } from "./unsmush.mjs";
6
- export { type Shaken, type Smushed, type Unsmushed, omit, pick, shake, smush, unsmush };
7
+ export { type Frozen, type Shaken, type Smushed, type Unsmushed, freeze, omit, pick, shake, smush, unsmush };
@@ -1,6 +1,7 @@
1
+ import { freeze } from "./freeze.mjs";
1
2
  import { omit } from "./omit.mjs";
2
3
  import { pick } from "./pick.mjs";
3
4
  import { shake } from "./shake.mjs";
4
5
  import { smush } from "./smush.mjs";
5
6
  import { unsmush } from "./unsmush.mjs";
6
- export { omit, pick, shake, smush, unsmush };
7
+ export { freeze, omit, pick, shake, smush, unsmush };
@@ -1,6 +1,17 @@
1
1
  import { ArrayOrPlainObject, NestedPartial } from "../models.mjs";
2
2
 
3
3
  //#region src/value/merge.d.ts
4
+ /**
5
+ * Options for assigning values
6
+ */
7
+ type AssignOptions = Omit<MergeOptions, 'assignValues'>;
8
+ /**
9
+ * Assign values from multiple arrays or objects to the first one
10
+ * @param to Value to assign to
11
+ * @param from Values to assign
12
+ * @returns Assigned value
13
+ */
14
+ type Assigner<Model extends ArrayOrPlainObject = ArrayOrPlainObject> = (to: NestedPartial<Model>, from: NestedPartial<Model>[]) => Model;
4
15
  /**
5
16
  * Options for merging values
6
17
  */
@@ -40,6 +51,25 @@ type MergeOptions = {
40
51
  * @returns Merged value
41
52
  */
42
53
  type Merger<Model extends ArrayOrPlainObject = ArrayOrPlainObject> = (values: NestedPartial<Model>[]) => Model;
54
+ /**
55
+ * Assign values from multiple arrays or objects to the first one
56
+ * @param to Value to assign to
57
+ * @param from Values to assign
58
+ * @param options Assigning options
59
+ * @returns Assigned value
60
+ */
61
+ declare function assign<Model extends ArrayOrPlainObject>(to: NestedPartial<Model>, from: NestedPartial<Model>[], options?: AssignOptions): Model;
62
+ declare namespace assign {
63
+ var initialize: typeof initializeAssigner;
64
+ }
65
+ /**
66
+ * Create an assigner with predefined options
67
+ *
68
+ * Available as `initializeAssigner` and `assign.initialize`
69
+ * @param options Assigning options
70
+ * @returns Assigner function
71
+ */
72
+ declare function initializeAssigner<Model extends ArrayOrPlainObject>(options?: AssignOptions): Assigner<Model>;
43
73
  /**
44
74
  * Create a merger with predefined options
45
75
  *
@@ -63,7 +93,8 @@ declare function merge<Model extends ArrayOrPlainObject>(values: NestedPartial<M
63
93
  */
64
94
  declare function merge(values: NestedPartial<ArrayOrPlainObject>[], options?: MergeOptions): ArrayOrPlainObject;
65
95
  declare namespace merge {
96
+ var assign: typeof assign;
66
97
  var initialize: typeof initializeMerger;
67
98
  }
68
99
  //#endregion
69
- export { MergeOptions, Merger, initializeMerger, merge };
100
+ export { AssignOptions, Assigner, MergeOptions, Merger, assign, initializeAssigner, initializeMerger, merge };
@@ -1,6 +1,19 @@
1
1
  import { isArrayOrPlainObject } from "../internal/is.mjs";
2
2
  import { join } from "../internal/string.mjs";
3
3
  //#region src/value/merge.ts
4
+ /**
5
+ * Assign values from multiple arrays or objects to the first one
6
+ * @param to Value to assign to
7
+ * @param from Values to assign
8
+ * @param options Assigning options
9
+ * @returns Assigned value
10
+ */
11
+ function assign(to, from, options) {
12
+ const actual = getMergeOptions(options);
13
+ actual.assignValues = true;
14
+ return mergeValues([to, ...from], actual, true);
15
+ }
16
+ assign.initialize = initializeAssigner;
4
17
  function getMergeOptions(options) {
5
18
  const actual = {
6
19
  assignValues: false,
@@ -23,6 +36,18 @@ function handleMerge(values, options) {
23
36
  return !Array.isArray(values) || values.length === 0 ? {} : mergeValues(values, options, true);
24
37
  }
25
38
  /**
39
+ * Create an assigner with predefined options
40
+ *
41
+ * Available as `initializeAssigner` and `assign.initialize`
42
+ * @param options Assigning options
43
+ * @returns Assigner function
44
+ */
45
+ function initializeAssigner(options) {
46
+ const actual = getMergeOptions(options);
47
+ actual.assignValues = true;
48
+ return ((to, from) => mergeValues([to, ...from], actual, true));
49
+ }
50
+ /**
26
51
  * Create a merger with predefined options
27
52
  *
28
53
  * Available as `initializeMerger` and `merge.initialize`
@@ -36,6 +61,7 @@ function initializeMerger(options) {
36
61
  function merge(values, options) {
37
62
  return handleMerge(values, getMergeOptions(options));
38
63
  }
64
+ merge.assign = assign;
39
65
  merge.initialize = initializeMerger;
40
66
  function mergeObjects(values, options, prefix) {
41
67
  const { length } = values;
@@ -62,4 +88,4 @@ function mergeValues(values, options, validate, prefix) {
62
88
  return actual.length > 1 ? mergeObjects(actual, options, prefix) : actual[0] ?? {};
63
89
  }
64
90
  //#endregion
65
- export { initializeMerger, merge };
91
+ export { assign, initializeAssigner, initializeMerger, merge };
@@ -2,6 +2,11 @@ import { PlainObject } from "../models.mjs";
2
2
 
3
3
  //#region src/value/shake.d.ts
4
4
  type Shaken<Value extends PlainObject> = { [Key in keyof Value]: Value[Key] extends undefined ? never : Value[Key] };
5
+ /**
6
+ * Shake an object, removing all keys with `undefined` values
7
+ * @param value Object to shake
8
+ * @returns Shaken object
9
+ */
5
10
  declare function shake<Value extends PlainObject>(value: Value): Shaken<Value>;
6
11
  //#endregion
7
12
  export { Shaken, shake };
@@ -1,5 +1,10 @@
1
1
  import { isNonPlainObject } from "../internal/is.mjs";
2
2
  //#region src/value/shake.ts
3
+ /**
4
+ * Shake an object, removing all keys with `undefined` values
5
+ * @param value Object to shake
6
+ * @returns Shaken object
7
+ */
3
8
  function shake(value) {
4
9
  const shaken = {};
5
10
  if (isNonPlainObject(value)) return shaken;
@@ -0,0 +1,43 @@
1
+ import { PlainObject } from "../models.mjs";
2
+
3
+ //#region src/value/transform.d.ts
4
+ type TransformCallback<Value extends PlainObject, Key extends keyof Value> = (key: Key, value: Value[Key]) => Value[Key];
5
+ type TransformCallbacks<Value extends PlainObject> = Partial<{ [Key in keyof Value]: (value: Value[Key]) => Value[Key] }>;
6
+ type Transformer<Value extends PlainObject> = {
7
+ (value: Value): Value;
8
+ };
9
+ /**
10
+ * Initialize a transformer for an object with a transformer function
11
+ *
12
+ * Available as `initializeTransformer` and `transform.initialize`
13
+ * @param transform Transformer function
14
+ * @returns Transformer
15
+ */
16
+ declare function initializeTransformer<Value extends PlainObject>(transform: TransformCallback<Value, keyof Value>): Transformer<Value>;
17
+ /**
18
+ * Initialize a transformer for an object with transformer functions
19
+ *
20
+ * Available as `initializeTransformer` and `transform.initialize`
21
+ * @param transformers Keyed transformer functions
22
+ * @return Transformer
23
+ */
24
+ declare function initializeTransformer<Value extends PlainObject>(transformers: TransformCallbacks<Value>): Transformer<Value>;
25
+ /**
26
+ * Transform and objects properties using a transformer functior
27
+ * @param value Object to transform
28
+ * @param transform Transformer function
29
+ * @returns Transformed object
30
+ */
31
+ declare function transform<Value extends PlainObject, Key extends keyof Value>(value: Value, transform: TransformCallback<Value, Key>): Value;
32
+ /**
33
+ * Transform and objects properties using a transformer object
34
+ * @param value Object to transform
35
+ * @param transformers Keyed transformer functions
36
+ * @returns Transformed object
37
+ */
38
+ declare function transform<Value extends PlainObject>(value: Value, transformers: TransformCallbacks<Value>): Value;
39
+ declare namespace transform {
40
+ var initialize: typeof initializeTransformer;
41
+ }
42
+ //#endregion
43
+ export { Transformer, initializeTransformer, transform };
@@ -0,0 +1,38 @@
1
+ import { isNonPlainObject } from "../internal/is.mjs";
2
+ //#region src/value/transform.ts
3
+ function getTransformer(input) {
4
+ if (typeof input === "function") return input;
5
+ if (isNonPlainObject(input)) return;
6
+ const keys = Object.keys(input);
7
+ const { length } = keys;
8
+ const transformer = {};
9
+ for (let index = 0; index < length; index += 1) {
10
+ const key = keys[index];
11
+ const value = input[key];
12
+ if (typeof value === "function") transformer[key] = value;
13
+ }
14
+ if (Object.keys(transformer).length > 0) return transformer;
15
+ }
16
+ function initializeTransformer(transform) {
17
+ const transformer = getTransformer(transform);
18
+ return (value) => transformValue(value, transformer);
19
+ }
20
+ function transform(value, transform) {
21
+ return transformValue(value, getTransformer(transform));
22
+ }
23
+ transform.initialize = initializeTransformer;
24
+ function transformValue(value, transformer) {
25
+ if (isNonPlainObject(value)) return {};
26
+ if (transformer == null) return value;
27
+ const keys = Object.keys(value);
28
+ const { length } = keys;
29
+ for (let index = 0; index < length; index += 1) {
30
+ const key = keys[index];
31
+ const val = value[key];
32
+ if (typeof transformer === "function") value[key] = transformer(key, val);
33
+ else value[key] = transformer[key]?.(val) ?? val;
34
+ }
35
+ return value;
36
+ }
37
+ //#endregion
38
+ export { initializeTransformer, transform };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/atoms",
3
- "version": "0.183.0",
3
+ "version": "0.184.0",
4
4
  "description": "Atomic utilities for making your JavaScript better.",
5
5
  "keywords": [
6
6
  "helper",
package/plugin/index.js CHANGED
@@ -30,8 +30,10 @@ export const miscPlugins = [
30
30
  tryCatchPlugin,
31
31
  getPlugin('number', 'getNumber', new Set(['Number']), true, true),
32
32
  getPlugin('promise', 'promises', new Set(['all', 'allSettled']), true),
33
+ getPlugin('value', 'assign', new Set(['assign']), true),
33
34
  getPlugin('value', 'clone', new Set(['structuredClone']), true, true),
34
35
  getPlugin('value', 'equal', new Set(['is']), true),
36
+ getPlugin('value', 'freeze', new Set(['freeze']), true),
35
37
  ];
36
38
 
37
39
  export const stringPlugins = [
package/plugin/rules.js CHANGED
@@ -11,8 +11,9 @@ const rules = {
11
11
  '@oscarpalmer/atoms/array.slice': 'warn',
12
12
  '@oscarpalmer/atoms/array.sort': 'warn',
13
13
  '@oscarpalmer/atoms/array.splice': 'warn',
14
- '@oscarpalmer/atoms/array.times': 'warn',
14
+ // '@oscarpalmer/atoms/array.times': 'warn',
15
15
  '@oscarpalmer/atoms/attempt': 'warn',
16
+ '@oscarpalmer/atoms/math.ceil': 'warn',
16
17
  '@oscarpalmer/atoms/math.floor': 'warn',
17
18
  '@oscarpalmer/atoms/math.max': 'warn',
18
19
  '@oscarpalmer/atoms/math.min': 'warn',
@@ -25,8 +26,10 @@ const rules = {
25
26
  '@oscarpalmer/atoms/string.lowerCase': 'warn',
26
27
  '@oscarpalmer/atoms/string.startsWith': 'warn',
27
28
  '@oscarpalmer/atoms/string.upperCase': 'warn',
29
+ '@oscarpalmer/atoms/value.assign': 'warn',
28
30
  '@oscarpalmer/atoms/value.clone': 'warn',
29
31
  '@oscarpalmer/atoms/value.equal': 'warn',
32
+ '@oscarpalmer/atoms/value.freeze': 'warn',
30
33
  };
31
34
 
32
35
  export default rules;
package/src/array/sort.ts CHANGED
@@ -493,6 +493,19 @@ function isSortedArray(array: unknown[], sorters: InternalSorter[]): boolean {
493
493
  return true;
494
494
  }
495
495
 
496
+ /**
497
+ * Sort an array of items using a comparison callback
498
+ * @param array Array to sort
499
+ * @param comparator Comparator to use for sorting
500
+ * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
501
+ * @returns Sorted array
502
+ */
503
+ export function sort<Item>(
504
+ array: Item[],
505
+ comparator: (first: Item, second: Item) => number,
506
+ descending?: boolean,
507
+ ): Item[];
508
+
496
509
  /**
497
510
  * Sort an array of items, using multiple sorters to sort by specific values
498
511
  * @param array Array to sort
@@ -507,7 +520,7 @@ export function sort<Item>(
507
520
  ): Item[];
508
521
 
509
522
  /**
510
- * Sort an array of items, using multiple sorters to sort by specific values
523
+ * Sort an array of items, using a single sorter to sort by a specific value
511
524
  * @param array Array to sort
512
525
  * @param sorter Sorter to use for sorting
513
526
  * @param descending Sort in descending order? _(defaults to `false`; overridden by individual sorters)_
package/src/index.ts CHANGED
@@ -39,6 +39,7 @@ export * from './value/collection';
39
39
  export * from './value/diff';
40
40
  export * from './value/index';
41
41
  export * from './value/merge';
42
+ export * from './value/transform';
42
43
 
43
44
  export * from './beacon';
44
45
  export * from './color';