@oscarpalmer/atoms 0.176.0 → 0.178.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.
@@ -0,0 +1,109 @@
1
+ import {findAbsoluteValueOrDefault} from '../internal/array/find';
2
+ import type {PlainObject} from '../models';
3
+
4
+ // #region Functions
5
+
6
+ /**
7
+ * Get the last items matching the given value
8
+ * @param array Array to search in
9
+ * @param callback Callback to get an item's value for matching
10
+ * @param value Value to match against
11
+ * @returns Last item that matches the value, or `undefined` if no match is found
12
+ */
13
+ export function last<Item, Callback extends (item: Item, index: number, array: Item[]) => unknown>(
14
+ array: Item[],
15
+ callback: Callback,
16
+ value: ReturnType<Callback>,
17
+ ): Item | undefined;
18
+
19
+ /**
20
+ * Get the first item matching the given value by key
21
+ * @param array Array to search in
22
+ * @param key Key to get an item's value for matching
23
+ * @param value Value to match against
24
+ * @returns Last item that matches the value, or `undefined` if no match is found
25
+ */
26
+ export function last<Item extends PlainObject, ItemKey extends keyof Item>(
27
+ array: Item[],
28
+ key: ItemKey,
29
+ value: Item[ItemKey],
30
+ ): Item | undefined;
31
+
32
+ /**
33
+ * Get the last item matching the filter
34
+ * @param array Array to search in
35
+ * @param filter Filter callback to match items
36
+ * @returns Last item that matches the filter, or `undefined` if no match is found
37
+ */
38
+ export function last<Item>(
39
+ array: Item[],
40
+ filter: (item: Item, index: number, array: Item[]) => boolean,
41
+ ): Item | undefined;
42
+
43
+ /**
44
+ * Get the last item from an array
45
+ * @param array Array to get from
46
+ * @return Last item from the array, or `undefined` if the array is empty
47
+ */
48
+ export function last<Item>(array: Item[]): Item | undefined;
49
+
50
+ export function last(array: unknown[], ...parameters: unknown[]): unknown {
51
+ return findAbsoluteValueOrDefault(array, parameters, undefined, false, true);
52
+ }
53
+
54
+ last.default = lastOrDefault;
55
+
56
+ /**
57
+ * Get the last item matching the given value
58
+ * @param array Array to search in
59
+ * @param defaultValue Default value to return if no match is found
60
+ * @param callback Callback to get an item's value for matching
61
+ * @param value Value to match against
62
+ * @returns Last item that matches the value, or the default value if no match is found
63
+ */
64
+ function lastOrDefault<
65
+ Item,
66
+ Callback extends (item: Item, index: number, array: Item[]) => unknown,
67
+ >(array: Item[], defaultValue: Item, callback: Callback, value: ReturnType<Callback>): Item;
68
+
69
+ /**
70
+ * Get the last item matching the given value by key
71
+ * @param array Array to search in
72
+ * @param defaultValue Default value to return if no match is found
73
+ * @param key Key to get an item's value for matching
74
+ * @param value Value to match against
75
+ * @returns Last item that matches the value, or the default value if no match is found
76
+ */
77
+ function lastOrDefault<Item extends PlainObject, ItemKey extends keyof Item>(
78
+ array: Item[],
79
+ defaultValue: Item,
80
+ key: ItemKey,
81
+ value: Item[ItemKey],
82
+ ): Item;
83
+
84
+ /**
85
+ * Get the last item matching the filter
86
+ * @param array Array to search in
87
+ * @param defaultValue Default value to return if no match is found
88
+ * @param filter Filter callback to match items
89
+ * @returns Last item that matches the filter, or the default value if no match is found
90
+ */
91
+ function lastOrDefault<Item>(
92
+ array: Item[],
93
+ defaultValue: Item,
94
+ filter: (item: Item, index: number, array: Item[]) => boolean,
95
+ ): Item;
96
+
97
+ /**
98
+ * Get the last item from an array
99
+ * @param array Array to get from
100
+ * @param defaultValue Default value to return if the array is empty
101
+ * @return Last item from the array, or the default value if the array is empty
102
+ */
103
+ function lastOrDefault<Item>(array: Item[], defaultValue: Item): Item;
104
+
105
+ function lastOrDefault(array: unknown[], defaultValue: unknown, ...parameters: unknown[]): unknown {
106
+ return findAbsoluteValueOrDefault(array, parameters, defaultValue, true, true);
107
+ }
108
+
109
+ // #endregion
@@ -0,0 +1,23 @@
1
+ export function reverse<Item>(array: Item[]): Item[] {
2
+ if (!Array.isArray(array)) {
3
+ return [];
4
+ }
5
+
6
+ const {length} = array;
7
+
8
+ if (length < 2) {
9
+ return array;
10
+ }
11
+
12
+ const half = Math.floor(length / 2);
13
+
14
+ for (let firstIndex = 0; firstIndex < half; firstIndex += 1) {
15
+ const temporaryItem = array[firstIndex];
16
+ const secondIndex = length - 1 - firstIndex;
17
+
18
+ array[firstIndex] = array[secondIndex];
19
+ array[secondIndex] = temporaryItem;
20
+ }
21
+
22
+ return array;
23
+ }
@@ -20,6 +20,25 @@ export function select<
20
20
  mapCallback: MapCallback,
21
21
  ): Array<ReturnType<MapCallback>>;
22
22
 
23
+ /**
24
+ * Get a filtered and mapped array of items
25
+ * @param array Array to search in
26
+ * @param filterCallback Callback to get an item's value for matching
27
+ * @param filterValue Value to match against
28
+ * @param mapKey Key to get an item's value for mapping
29
+ * @returns Filtered and mapped array of items
30
+ */
31
+ export function select<
32
+ Item extends PlainObject,
33
+ FilterCallback extends (item: Item, index: number, array: Item[]) => unknown,
34
+ MapKey extends keyof Item,
35
+ >(
36
+ array: Item[],
37
+ filterCallback: FilterCallback,
38
+ filterValue: ReturnType<FilterCallback>,
39
+ mapKey: MapKey,
40
+ ): Array<Item[MapKey]>;
41
+
23
42
  /**
24
43
  * Get a filtered and mapped array of items
25
44
  * @param array Array to search in
@@ -39,6 +58,25 @@ export function select<
39
58
  mapCallback: MapCallback,
40
59
  ): Array<ReturnType<MapCallback>>;
41
60
 
61
+ /**
62
+ * Get a filtered and mapped array of items
63
+ * @param array Array to search in
64
+ * @param filterKey Key to get an item's value for matching
65
+ * @param filterValue Value to match against
66
+ * @param mapKey Key to get an item's value for mapping
67
+ * @returns Filtered and mapped array of items
68
+ */
69
+ export function select<
70
+ Item extends PlainObject,
71
+ ItemKey extends keyof Item,
72
+ MapKey extends keyof Item,
73
+ >(
74
+ array: Item[],
75
+ filterKey: ItemKey,
76
+ filterValue: Item[ItemKey],
77
+ mapKey: MapKey,
78
+ ): Array<Item[MapKey]>;
79
+
42
80
  /**
43
81
  * Get a filtered and mapped array of items
44
82
  * @param array Array to search in
@@ -57,6 +95,24 @@ export function select<
57
95
  mapCallback: MapCallback,
58
96
  ): Array<ReturnType<MapCallback>>;
59
97
 
98
+ /**
99
+ * Get a filtered and mapped array of items
100
+ * @param array Array to search in
101
+ * @param filterCallback Filter callback to match items
102
+ * @param mapKey Key to get an item's value for mapping
103
+ * @returns Filtered and mapped array of items
104
+ */
105
+ export function select<
106
+ Item extends PlainObject,
107
+ FilterCallback extends (item: Item, index: number, array: Item[]) => unknown,
108
+ MapKey extends keyof Item,
109
+ >(
110
+ array: Item[],
111
+ filterCallback: FilterCallback,
112
+ filterValue: ReturnType<FilterCallback>,
113
+ mapKey: MapKey,
114
+ ): Array<Item[MapKey]>;
115
+
60
116
  /**
61
117
  * Get a filtered and mapped array of items
62
118
  * @param array Array to search in
@@ -73,6 +129,19 @@ export function select<
73
129
  map: MapCallback,
74
130
  ): Array<ReturnType<MapCallback>>;
75
131
 
132
+ /**
133
+ * Get a filtered and mapped array of items
134
+ * @param array Array to search in
135
+ * @param filter Filter callback to match items
136
+ * @param map Key to get an item's value for mapping
137
+ * @returns Filtered and mapped array of items
138
+ */
139
+ export function select<Item extends PlainObject, MapKey extends keyof Item>(
140
+ array: Item[],
141
+ filter: (item: Item, index: number, array: Item[]) => boolean,
142
+ map: MapKey,
143
+ ): Array<Item[MapKey]>;
144
+
76
145
  /**
77
146
  * Get a filtered and mapped array of items
78
147
  * @param array Array to search in
@@ -85,8 +154,23 @@ export function select<
85
154
  MapCallback extends (item: Item, index: number, array: Item[]) => unknown,
86
155
  >(array: Item[], filter: Item, map: MapCallback): Array<ReturnType<MapCallback>>;
87
156
 
157
+ /**
158
+ * Get a filtered and mapped array of items
159
+ * @param array Array to search in
160
+ * @param item Item to match against
161
+ * @param map Key to get an item's value for mapping
162
+ * @returns Filtered and mapped array of items
163
+ */
164
+ export function select<Item extends PlainObject, MapKey extends keyof Item>(
165
+ array: Item[],
166
+ filter: Item,
167
+ map: MapKey,
168
+ ): Array<Item[MapKey]>;
169
+
88
170
  export function select(array: unknown[], ...parameters: unknown[]): unknown[] {
89
171
  const mapper = parameters.pop();
90
172
 
91
173
  return findValues(FIND_VALUES_ALL, array, parameters, mapper).matched;
92
174
  }
175
+
176
+ // #endregion
@@ -0,0 +1,64 @@
1
+ import {FIND_VALUES_ALL, findValues} from '../internal/array/find';
2
+ import type {PlainObject} from '../models';
3
+
4
+ // #region Functions
5
+
6
+ /**
7
+ * Get the _only_ item matching the given value
8
+ *
9
+ * Throws an error if multiple items match the value
10
+ * @param array Array to search in
11
+ * @param callback Callback to get an item's value for matching
12
+ * @param value Value to match against
13
+ * @returns Only item that matches the value, or `undefined` if no match is found
14
+ */
15
+ export function single<
16
+ Item,
17
+ Callback extends (item: Item, index: number, array: Item[]) => unknown,
18
+ >(array: Item[], callback: Callback, value: ReturnType<Callback>): Item | undefined;
19
+
20
+ /**
21
+ * Get the _only_ item matching the given value by key
22
+ *
23
+ * Throws an error if multiple items match the value
24
+ * @param array Array to search in
25
+ * @param key Key to get an item's value for matching
26
+ * @param value Value to match against
27
+ * @returns Only item that matches the value, or `undefined` if no match is found
28
+ */
29
+ export function single<Item extends PlainObject, ItemKey extends keyof Item>(
30
+ array: Item[],
31
+ key: ItemKey,
32
+ value: Item[ItemKey],
33
+ ): Item | undefined;
34
+
35
+ /**
36
+ * Get the _only_ item matching the filter
37
+ *
38
+ * Throws an error if multiple items match the filter
39
+ * @param array Array to search in
40
+ * @param filter Filter callback to match items
41
+ * @returns Only item that matches the filter, or `undefined` if no match is found
42
+ */
43
+ export function single<Item>(
44
+ array: Item[],
45
+ filter: (item: Item, index: number, array: Item[]) => boolean,
46
+ ): Item | undefined;
47
+
48
+ export function single(array: unknown[], ...parameters: unknown[]): unknown {
49
+ const {matched} = findValues(FIND_VALUES_ALL, array, parameters);
50
+
51
+ if (matched.length > 1) {
52
+ throw new Error(MESSAGE);
53
+ }
54
+
55
+ return matched[0];
56
+ }
57
+
58
+ // #endregion
59
+
60
+ // #region Variables
61
+
62
+ const MESSAGE = 'Multiple items were found';
63
+
64
+ // #endregion
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from './array/filter';
2
+ export * from './array/first';
2
3
  export * from './array/group-by';
3
4
  export * from './array/index';
5
+ export * from './array/last';
4
6
  export * from './array/move';
5
7
  export * from './array/sort';
6
8
  export * from './array/swap';
@@ -1,8 +1,8 @@
1
- import {getArrayCallbacks} from './callbacks';
1
+ import {getArrayCallback, getArrayCallbacks} from './callbacks';
2
2
 
3
3
  // #region Types
4
4
 
5
- type FindValueType = 'index' | 'value';
5
+ type FindValueType = 'index' | 'item';
6
6
 
7
7
  type FindValuesResult = {
8
8
  matched: unknown[];
@@ -21,14 +21,19 @@ type Parameters = {
21
21
 
22
22
  // #region Functions
23
23
 
24
- export function findValue(type: FindValueType, array: unknown[], parameters: unknown[]): unknown {
24
+ export function findValue(
25
+ type: FindValueType,
26
+ array: unknown[],
27
+ parameters: unknown[],
28
+ reversed: boolean,
29
+ ): unknown {
25
30
  const findIndex = type === FIND_VALUE_INDEX;
26
31
 
27
32
  if (!Array.isArray(array) || array.length === 0) {
28
33
  return findIndex ? -1 : undefined;
29
34
  }
30
35
 
31
- const {bool, key, value} = getParameters(parameters);
36
+ const {bool, key, value} = getFindParameters(parameters);
32
37
 
33
38
  const callbacks = getArrayCallbacks(bool, key);
34
39
 
@@ -42,7 +47,7 @@ export function findValue(type: FindValueType, array: unknown[], parameters: unk
42
47
  return findIndex ? index : array[index];
43
48
  }
44
49
 
45
- return findValueInArray(array, callbacks.keyed, value, findIndex);
50
+ return findValueInArray(array, callbacks.keyed, value, findIndex, reversed);
46
51
  }
47
52
 
48
53
  function findValueInArray(
@@ -50,11 +55,12 @@ function findValueInArray(
50
55
  callback: ((item: unknown, index: number, array: unknown[]) => boolean) | undefined,
51
56
  value: unknown,
52
57
  findIndex: boolean,
58
+ reversed: boolean,
53
59
  ): unknown {
54
60
  const {length} = array;
55
61
 
56
62
  for (let index = 0; index < length; index += 1) {
57
- const item = array[index];
63
+ const item = reversed ? array.at(-(index + 1)) : array[index];
58
64
 
59
65
  if (Object.is(callback?.(item, index, array), value)) {
60
66
  return findIndex ? index : item;
@@ -64,6 +70,26 @@ function findValueInArray(
64
70
  return findIndex ? -1 : undefined;
65
71
  }
66
72
 
73
+ export function findAbsoluteValueOrDefault(
74
+ array: unknown[],
75
+ parameters: unknown[],
76
+ defaultValue: unknown,
77
+ useDefaultValue: boolean,
78
+ reversed: boolean,
79
+ ): unknown {
80
+ if (parameters.length === 0) {
81
+ if (Array.isArray(array) && array.length > 0) {
82
+ return reversed ? array.at(-1) : array[0];
83
+ }
84
+
85
+ return useDefaultValue ? defaultValue : undefined;
86
+ }
87
+
88
+ const index = findValue(FIND_VALUE_INDEX, array, parameters, reversed) as number;
89
+
90
+ return index > -1 ? array[index] : useDefaultValue ? defaultValue : undefined;
91
+ }
92
+
67
93
  export function findValues(
68
94
  type: FindValuesType,
69
95
  array: unknown[],
@@ -80,7 +106,7 @@ export function findValues(
80
106
  }
81
107
 
82
108
  const {length} = array;
83
- const {bool, key, value} = getParameters(parameters);
109
+ const {bool, key, value} = getFindParameters(parameters);
84
110
  const callbacks = getArrayCallbacks(bool, key);
85
111
 
86
112
  if (type === FIND_VALUES_UNIQUE && callbacks?.keyed == null && length >= UNIQUE_THRESHOLD) {
@@ -89,7 +115,7 @@ export function findValues(
89
115
  return result;
90
116
  }
91
117
 
92
- const mapCallback = typeof mapper === 'function' ? mapper : undefined;
118
+ const mapCallback = getArrayCallback(mapper);
93
119
 
94
120
  if (callbacks?.bool != null || (type === FIND_VALUES_ALL && key == null)) {
95
121
  const callback = callbacks?.bool ?? (item => Object.is(item, value));
@@ -127,7 +153,7 @@ export function findValues(
127
153
  return result;
128
154
  }
129
155
 
130
- function getParameters(original: unknown[]): Parameters {
156
+ export function getFindParameters(original: unknown[]): Parameters {
131
157
  const {length} = original;
132
158
 
133
159
  return {
@@ -143,7 +169,7 @@ function getParameters(original: unknown[]): Parameters {
143
169
 
144
170
  export const FIND_VALUE_INDEX: FindValueType = 'index';
145
171
 
146
- export const FIND_VALUE_VALUE: FindValueType = 'value';
172
+ export const FIND_VALUE_ITEM: FindValueType = 'item';
147
173
 
148
174
  export const FIND_VALUES_ALL: FindValuesType = 'all';
149
175
 
@@ -49,6 +49,95 @@ export function isKey(value: unknown): value is Key {
49
49
  return typeof value === 'number' || typeof value === 'string';
50
50
  }
51
51
 
52
+ /**
53
+ * Is the value not an array or a plain object?
54
+ * @param value Value to check
55
+ * @returns `true` if the value is not an array or a plain object, otherwise `false`
56
+ */
57
+ export function isNonArrayOrPlainObject<Value>(
58
+ value: Value,
59
+ ): value is Exclude<Value, ArrayOrPlainObject> {
60
+ return !isArrayOrPlainObject(value);
61
+ }
62
+
63
+ /**
64
+ * Is the value not a constructor function?
65
+ * @param value Value to check
66
+ * @returns `true` if the value is not a constructor function, otherwise `false`
67
+ */
68
+ export function isNonConstructor<Value>(value: Value): value is Exclude<Value, Constructor> {
69
+ return !isConstructor(value);
70
+ }
71
+
72
+ /**
73
+ * Is the value not an instance of the constructor?
74
+ * @param constructor Class constructor
75
+ * @param value Value to check
76
+ * @returns `true` if the value is not an instance of the constructor, otherwise `false`
77
+ */
78
+ export function isNonInstanceOf<Instance, Value>(
79
+ constructor: Constructor<Instance>,
80
+ value: Value,
81
+ ): value is Exclude<Value, Instance> {
82
+ return !isInstanceOf(constructor, value);
83
+ }
84
+
85
+ /**
86
+ * Is the value not a key?
87
+ * @param value Value to check
88
+ * @returns `true` if the value is not a `Key` _(`number` or `string`)_, otherwise `false`
89
+ */
90
+ export function isNonKey<Value>(value: Value): value is Exclude<Value, Key> {
91
+ return !isKey(value);
92
+ }
93
+
94
+ /**
95
+ * Is the value not a number?
96
+ * @param value Value to check
97
+ * @returns `true` if the value is not a `number`, otherwise `false`
98
+ */
99
+ export function isNonNumber<Value>(value: Value): value is Exclude<Value, number> {
100
+ return !isNumber(value);
101
+ }
102
+
103
+ /**
104
+ * Is the value not a plain object?
105
+ * @param value Value to check
106
+ * @returns `true` if the value is not a plain object, otherwise `false`
107
+ */
108
+ export function isNonPlainObject<Value>(value: Value): value is Exclude<Value, PlainObject> {
109
+ return !isPlainObject(value);
110
+ }
111
+
112
+ /**
113
+ * Is the value not a primitive value?
114
+ * @param value Value to check
115
+ * @returns `true` if the value is not a primitive value, otherwise `false`
116
+ */
117
+ export function isNonPrimitive<Value>(value: Value): value is Exclude<Value, Primitive> {
118
+ return !isPrimitive(value);
119
+ }
120
+
121
+ /**
122
+ * Is the value not a template strings array?
123
+ * @param value Value to check
124
+ * @returns `true` if the value is not a `TemplateStringsArray`, otherwise `false`
125
+ */
126
+ export function isNonTemplateStringsArray<Value>(
127
+ value: Value,
128
+ ): value is Exclude<Value, TemplateStringsArray> {
129
+ return !isTemplateStringsArray(value);
130
+ }
131
+
132
+ /**
133
+ * Is the value not a typed array?
134
+ * @param value Value to check
135
+ * @returns `true` if the value is not a typed array, otherwise `false`
136
+ */
137
+ export function isNonTypedArray<Value>(value: Value): value is Exclude<Value, TypedArray> {
138
+ return !isTypedArray(value);
139
+ }
140
+
52
141
  /**
53
142
  * Is the value a number?
54
143
  * @param value Value to check
@@ -87,7 +176,28 @@ export function isPlainObject(value: unknown): value is PlainObject {
87
176
  * @returns `true` if the value matches, otherwise `false`
88
177
  */
89
178
  export function isPrimitive(value: unknown): value is Primitive {
90
- return value == null || EXPRESSION_PRIMITIVE.test(typeof value);
179
+ if (value == null) {
180
+ return true;
181
+ }
182
+
183
+ const type = typeof value;
184
+
185
+ return (
186
+ type === 'bigint' ||
187
+ type === 'boolean' ||
188
+ type === 'number' ||
189
+ type === 'string' ||
190
+ type === 'symbol'
191
+ );
192
+ }
193
+
194
+ /**
195
+ * Is the value a template strings array?
196
+ * @param value Value to check
197
+ * @returns `true` if the value is a `TemplateStringsArray`, otherwise `false`
198
+ */
199
+ export function isTemplateStringsArray(value: unknown): value is TemplateStringsArray {
200
+ return Array.isArray(value) && Array.isArray((value as unknown as TemplateStringsArray).raw);
91
201
  }
92
202
 
93
203
  /**
@@ -96,7 +206,7 @@ export function isPrimitive(value: unknown): value is Primitive {
96
206
  * @returns `true` if the value is a typed array, otherwise `false`
97
207
  */
98
208
  export function isTypedArray(value: unknown): value is TypedArray {
99
- TYPED_ARRAYS ??= new Set<unknown>([
209
+ (isTypedArray as any).types ??= new Set<unknown>([
100
210
  Int8Array,
101
211
  Uint8Array,
102
212
  Uint8ClampedArray,
@@ -110,15 +220,7 @@ export function isTypedArray(value: unknown): value is TypedArray {
110
220
  BigUint64Array,
111
221
  ]);
112
222
 
113
- return TYPED_ARRAYS.has((value as TypedArray)?.constructor);
223
+ return (isTypedArray as any).types.has((value as TypedArray)?.constructor);
114
224
  }
115
225
 
116
226
  // #endregion
117
-
118
- // #region Variables
119
-
120
- const EXPRESSION_PRIMITIVE = /^(bigint|boolean|number|string|symbol)$/;
121
-
122
- let TYPED_ARRAYS: Set<unknown>;
123
-
124
- // #endregion