utilitish 0.0.6 → 0.0.7
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/array/array-constructor.js +5 -5
- package/dist/array/array-constructor.spec.d.ts +2 -0
- package/dist/array/array-constructor.spec.js +130 -0
- package/dist/array/array-prototype.d.ts +341 -84
- package/dist/array/array-prototype.js +38 -53
- package/dist/array/array-prototype.spec.d.ts +1 -0
- package/dist/array/array-prototype.spec.js +536 -0
- package/dist/map/map-prototype.d.ts +69 -9
- package/dist/map/map-prototype.js +16 -3
- package/dist/map/map-prototype.spec.d.ts +1 -0
- package/dist/map/map-prototype.spec.js +261 -0
- package/dist/object/object-prototype.d.ts +61 -8
- package/dist/object/object-prototype.js +9 -0
- package/dist/object/object-prototype.spec.d.ts +1 -0
- package/dist/object/object-prototype.spec.js +110 -0
- package/dist/set/set-prototype.d.ts +83 -5
- package/dist/set/set-prototype.js +21 -6
- package/dist/set/set-prototype.spec.d.ts +1 -0
- package/dist/set/set-prototype.spec.js +122 -0
- package/dist/string/string-prototype.d.ts +143 -24
- package/dist/string/string-prototype.js +41 -11
- package/dist/string/string-prototype.spec.d.ts +1 -0
- package/dist/string/string-prototype.spec.js +115 -0
- package/dist/utils/logic.utils.d.ts +3 -0
- package/dist/utils/logic.utils.js +41 -0
- package/package.json +1 -1
- /package/dist/{utils.d.ts → utils/core.utils.d.ts} +0 -0
- /package/dist/{utils.js → utils/core.utils.js} +0 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
require("./array-prototype");
|
|
4
|
+
describe('Array.prototype', () => {
|
|
5
|
+
describe('first()', () => {
|
|
6
|
+
it('should return first element of non-empty array', () => {
|
|
7
|
+
expect([1, 2, 3].first()).toBe(1);
|
|
8
|
+
});
|
|
9
|
+
it('should return undefined for empty array', () => {
|
|
10
|
+
expect([].first()).toBe(undefined);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
describe('last()', () => {
|
|
14
|
+
it('should return last element of non-empty array', () => {
|
|
15
|
+
expect([1, 2, 3].last()).toBe(3);
|
|
16
|
+
});
|
|
17
|
+
it('should return undefined for empty array', () => {
|
|
18
|
+
expect([].last()).toBe(undefined);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe('sum()', () => {
|
|
22
|
+
describe('with number arrays', () => {
|
|
23
|
+
it('should return sum of all numbers', () => {
|
|
24
|
+
expect([1, 2, 3].sum()).toBe(6);
|
|
25
|
+
});
|
|
26
|
+
it('should return 0 for empty array', () => {
|
|
27
|
+
expect([].sum()).toBe(0);
|
|
28
|
+
});
|
|
29
|
+
it('should return 0 when array contains only 0', () => {
|
|
30
|
+
expect([0].sum()).toBe(0);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('with selector function', () => {
|
|
34
|
+
it('should return the sum when using selector function', () => {
|
|
35
|
+
const items = [{ x: 1 }, { x: 2 }];
|
|
36
|
+
expect(items.sum((item) => item.x)).toBe(3);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('with selector string key', () => {
|
|
40
|
+
it('should return the sum when using property key', () => {
|
|
41
|
+
const items = [{ x: 1 }, { x: 2 }];
|
|
42
|
+
expect(items.sum('x')).toBe(3);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('error handling', () => {
|
|
46
|
+
it('should throw TypeError when called on non-number array without selector', () => {
|
|
47
|
+
const items = [{ x: 2 }, { x: 4 }];
|
|
48
|
+
expect(() => items.sum()).toThrow(TypeError);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('average()', () => {
|
|
53
|
+
describe('with number arrays', () => {
|
|
54
|
+
it('should return average of all numbers', () => {
|
|
55
|
+
expect([2, 4, 6].average()).toBe(4);
|
|
56
|
+
});
|
|
57
|
+
it('should return 0 for empty array', () => {
|
|
58
|
+
expect([].average()).toBe(0);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe('with selector function', () => {
|
|
62
|
+
it('should return the average when using selector function', () => {
|
|
63
|
+
const items = [{ x: 2 }, { x: 4 }];
|
|
64
|
+
expect(items.average((item) => item.x)).toBe(3);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('with selector string key', () => {
|
|
68
|
+
it('should return the average when using property key', () => {
|
|
69
|
+
const items = [{ x: 2 }, { x: 4 }];
|
|
70
|
+
expect(items.average('x')).toBe(3);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe('error handling', () => {
|
|
74
|
+
it('should throw TypeError when called on non-number array without selector', () => {
|
|
75
|
+
const items = [{ x: 2 }, { x: 4 }];
|
|
76
|
+
expect(() => items.average()).toThrow(TypeError);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('unique()', () => {
|
|
81
|
+
it('should return array with unique values', () => {
|
|
82
|
+
expect([1, 1, 2, 2, 3].unique()).toEqual([1, 2, 3]);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe('chunk()', () => {
|
|
86
|
+
describe('with valid size', () => {
|
|
87
|
+
it('should split array into chunks of even elements', () => {
|
|
88
|
+
expect([1, 2, 3, 4].chunk(2)).toEqual([
|
|
89
|
+
[1, 2],
|
|
90
|
+
[3, 4],
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
93
|
+
it('should include partial chunk at end when array does not divide evenly', () => {
|
|
94
|
+
expect([1, 2, 3].chunk(2)).toEqual([[1, 2], [3]]);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe('error handling', () => {
|
|
98
|
+
it('should throw TypeError when size is not a positive integer', () => {
|
|
99
|
+
const arr = [1, 2, 3];
|
|
100
|
+
expect(() => arr.chunk(0)).toThrow(TypeError);
|
|
101
|
+
expect(() => arr.chunk(-1)).toThrow(TypeError);
|
|
102
|
+
expect(() => arr.chunk(1.5)).toThrow(TypeError);
|
|
103
|
+
expect(() => arr.chunk('a')).toThrow(TypeError);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe('groupBy()', () => {
|
|
108
|
+
it('should group by property key', () => {
|
|
109
|
+
const arr = [
|
|
110
|
+
{ type: 'a', value: 1 },
|
|
111
|
+
{ type: 'b', value: 2 },
|
|
112
|
+
{ type: 'a', value: 3 },
|
|
113
|
+
];
|
|
114
|
+
const map = arr.groupBy('type');
|
|
115
|
+
expect(map instanceof Map).toBe(true);
|
|
116
|
+
expect(map.get('a')).toEqual([
|
|
117
|
+
{ type: 'a', value: 1 },
|
|
118
|
+
{ type: 'a', value: 3 },
|
|
119
|
+
]);
|
|
120
|
+
expect(map.get('b')).toEqual([{ type: 'b', value: 2 }]);
|
|
121
|
+
});
|
|
122
|
+
it('should group by selector function', () => {
|
|
123
|
+
const arr = [1, 2, 3, 4, 5, 6];
|
|
124
|
+
const map = arr.groupBy((x) => (x % 2 === 0 ? 'even' : 'odd'));
|
|
125
|
+
expect(map instanceof Map).toBe(true);
|
|
126
|
+
expect(map.get('even')).toEqual([2, 4, 6]);
|
|
127
|
+
expect(map.get('odd')).toEqual([1, 3, 5]);
|
|
128
|
+
});
|
|
129
|
+
it('should return an empty Map when array is empty', () => {
|
|
130
|
+
expect([].groupBy((x) => x)).toEqual(new Map());
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe('compact()', () => {
|
|
134
|
+
it('should remove all falsy values', () => {
|
|
135
|
+
expect([0, 1, false, 2, '', 3, null].compact()).toEqual([1, 2, 3]);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe('enumerate()', () => {
|
|
139
|
+
it('should return array of [value, index] tuples', () => {
|
|
140
|
+
const result = ['a', 'b', 'c'].enumerate();
|
|
141
|
+
expect(result).toEqual([
|
|
142
|
+
['a', 0],
|
|
143
|
+
['b', 1],
|
|
144
|
+
['c', 2],
|
|
145
|
+
]);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe('sortAsc()', () => {
|
|
149
|
+
describe('with primitive arrays', () => {
|
|
150
|
+
it('should sort numbers in ascending order', () => {
|
|
151
|
+
expect([3, 1, 2].sortAsc()).toEqual([1, 2, 3]);
|
|
152
|
+
});
|
|
153
|
+
it('should sort strings in ascending order', () => {
|
|
154
|
+
expect(['b', 'a', 'c'].sortAsc()).toEqual(['a', 'b', 'c']);
|
|
155
|
+
});
|
|
156
|
+
it('should return empty array when empty', () => {
|
|
157
|
+
expect([].sortAsc()).toEqual([]);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('with selector function', () => {
|
|
161
|
+
it('should sort using selector function', () => {
|
|
162
|
+
const arr = [{ v: 2 }, { v: 1 }];
|
|
163
|
+
expect(arr.sortAsc((x) => x.v)).toEqual([{ v: 1 }, { v: 2 }]);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
describe('with selector string key', () => {
|
|
167
|
+
it('should sort using property key', () => {
|
|
168
|
+
const arr = [{ v: 2 }, { v: 1 }];
|
|
169
|
+
expect(arr.sortAsc('v')).toEqual([{ v: 1 }, { v: 2 }]);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
describe('error handling', () => {
|
|
173
|
+
it('should throw TypeError when selector returns non-sortable type', () => {
|
|
174
|
+
expect(() => [{ v: {} }, { v: {} }].sortAsc((x) => x.v)).toThrow(TypeError);
|
|
175
|
+
});
|
|
176
|
+
it('should throw TypeError when elements are not sortable without selector', () => {
|
|
177
|
+
expect(() => [{ v: 1 }].sortAsc()).toThrow(TypeError);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
describe('sortDesc()', () => {
|
|
182
|
+
describe('with primitive arrays', () => {
|
|
183
|
+
it('should sort numbers in descending order', () => {
|
|
184
|
+
expect([1, 3, 2, 4].sortDesc()).toEqual([4, 3, 2, 1]);
|
|
185
|
+
});
|
|
186
|
+
it('should sort strings in descending order', () => {
|
|
187
|
+
expect(['b', 'a', 'c'].sortDesc()).toEqual(['c', 'b', 'a']);
|
|
188
|
+
});
|
|
189
|
+
it('should return empty array when empty', () => {
|
|
190
|
+
expect([].sortDesc()).toEqual([]);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
describe('with selector function', () => {
|
|
194
|
+
it('should sort using selector function', () => {
|
|
195
|
+
const arr = [{ v: 1 }, { v: 2 }];
|
|
196
|
+
expect(arr.sortDesc((x) => x.v)).toEqual([{ v: 2 }, { v: 1 }]);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
describe('with selector string key', () => {
|
|
200
|
+
it('should sort using property key', () => {
|
|
201
|
+
const arr = [{ v: 1 }, { v: 2 }];
|
|
202
|
+
expect(arr.sortDesc('v')).toEqual([{ v: 2 }, { v: 1 }]);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
describe('error handling', () => {
|
|
206
|
+
it('should throw TypeError when selector returns non-sortable type', () => {
|
|
207
|
+
expect(() => [{ v: {} }, { v: {} }].sortDesc((x) => x.v)).toThrow(TypeError);
|
|
208
|
+
});
|
|
209
|
+
it('should throw TypeError when elements are not sortable without selector', () => {
|
|
210
|
+
expect(() => [{ v: 1 }].sortDesc()).toThrow(TypeError);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
describe('swap()', () => {
|
|
215
|
+
describe('with valid indices', () => {
|
|
216
|
+
it('should swap two elements at given indices', () => {
|
|
217
|
+
const arr = [1, 2, 3];
|
|
218
|
+
arr.swap(0, 2);
|
|
219
|
+
expect(arr).toEqual([3, 2, 1]);
|
|
220
|
+
});
|
|
221
|
+
it('should do nothing when indices are identical', () => {
|
|
222
|
+
const arr = [1, 2, 3];
|
|
223
|
+
arr.swap(1, 1);
|
|
224
|
+
expect(arr).toEqual([1, 2, 3]);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
describe('error handling', () => {
|
|
228
|
+
it('should throw RangeError when index is out of bounds', () => {
|
|
229
|
+
const arr = [1, 2, 3];
|
|
230
|
+
expect(() => arr.swap(-1, 2)).toThrow(RangeError);
|
|
231
|
+
expect(() => arr.swap(0, 3)).toThrow(RangeError);
|
|
232
|
+
});
|
|
233
|
+
it('should throw TypeError when indices are not integers', () => {
|
|
234
|
+
const arr = [1, 2, 3];
|
|
235
|
+
expect(() => arr.swap(0.5, 2)).toThrow(TypeError);
|
|
236
|
+
expect(() => arr.swap(0, 'a')).toThrow(TypeError);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
describe('shuffle()', () => {
|
|
241
|
+
it('should return a new array with same elements in different order', () => {
|
|
242
|
+
const arr = [1, 2, 3, 4, 5];
|
|
243
|
+
const shuffled = arr.shuffle();
|
|
244
|
+
expect(shuffled).toHaveLength(arr.length);
|
|
245
|
+
expect(shuffled.sort()).toEqual(arr.sort());
|
|
246
|
+
});
|
|
247
|
+
it('should not mutate the original array', () => {
|
|
248
|
+
const arr = [1, 2, 3];
|
|
249
|
+
const copy = arr.slice();
|
|
250
|
+
arr.shuffle();
|
|
251
|
+
expect(arr).toEqual(copy);
|
|
252
|
+
});
|
|
253
|
+
it('should return a new array instance', () => {
|
|
254
|
+
const arr = [1, 2, 3];
|
|
255
|
+
const shuffled = arr.shuffle();
|
|
256
|
+
expect(shuffled).not.toBe(arr);
|
|
257
|
+
});
|
|
258
|
+
it('should return an empty array when called on empty array', () => {
|
|
259
|
+
expect([].shuffle()).toEqual([]);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
describe('toMap()', () => {
|
|
263
|
+
describe('with pairs array', () => {
|
|
264
|
+
it('should convert array of pairs to Map', () => {
|
|
265
|
+
const arr = [
|
|
266
|
+
['a', 1],
|
|
267
|
+
['b', 2],
|
|
268
|
+
];
|
|
269
|
+
const map = arr.toMap();
|
|
270
|
+
expect(map instanceof Map).toBe(true);
|
|
271
|
+
expect(map.size).toBe(2);
|
|
272
|
+
expect(map.get('a')).toBe(1);
|
|
273
|
+
expect(map.get('b')).toBe(2);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
describe('with selector string key and no value selector', () => {
|
|
277
|
+
it('should convert array of objects using property key', () => {
|
|
278
|
+
const arr = [
|
|
279
|
+
{ id: 1, name: 'foo' },
|
|
280
|
+
{ id: 2, name: 'bar' },
|
|
281
|
+
];
|
|
282
|
+
const map = arr.toMap('id');
|
|
283
|
+
expect(map instanceof Map).toBe(true);
|
|
284
|
+
expect(map.size).toBe(2);
|
|
285
|
+
expect(map.get(1)).toEqual({ id: 1, name: 'foo' });
|
|
286
|
+
expect(map.get(2)).toEqual({ id: 2, name: 'bar' });
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
describe('with selector functions', () => {
|
|
290
|
+
it('should convert array using key and value selectors', () => {
|
|
291
|
+
const arr = [
|
|
292
|
+
{ id: 1, name: 'foo' },
|
|
293
|
+
{ id: 2, name: 'bar' },
|
|
294
|
+
];
|
|
295
|
+
const map = arr.toMap((x) => x.id, (x) => x.name);
|
|
296
|
+
expect(map instanceof Map).toBe(true);
|
|
297
|
+
expect(map.size).toBe(2);
|
|
298
|
+
expect(map.get(1)).toBe('foo');
|
|
299
|
+
expect(map.get(2)).toBe('bar');
|
|
300
|
+
});
|
|
301
|
+
it('should convert array using key selector only', () => {
|
|
302
|
+
const arr = [
|
|
303
|
+
{ id: 1, name: 'foo' },
|
|
304
|
+
{ id: 2, name: 'bar' },
|
|
305
|
+
];
|
|
306
|
+
const map = arr.toMap((x) => x.id);
|
|
307
|
+
expect(map instanceof Map).toBe(true);
|
|
308
|
+
expect(map.size).toBe(2);
|
|
309
|
+
expect(map.get(1)).toEqual({ id: 1, name: 'foo' });
|
|
310
|
+
expect(map.get(2)).toEqual({ id: 2, name: 'bar' });
|
|
311
|
+
});
|
|
312
|
+
it('should convert array using string key and value selector', () => {
|
|
313
|
+
const arr = [
|
|
314
|
+
{ id: 1, name: 'foo' },
|
|
315
|
+
{ id: 2, name: 'bar' },
|
|
316
|
+
];
|
|
317
|
+
const map = arr.toMap('id', (x) => x.name);
|
|
318
|
+
expect(map instanceof Map).toBe(true);
|
|
319
|
+
expect(map.size).toBe(2);
|
|
320
|
+
expect(map.get(1)).toBe('foo');
|
|
321
|
+
expect(map.get(2)).toBe('bar');
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
describe('with no selectors', () => {
|
|
325
|
+
it('should use index as key', () => {
|
|
326
|
+
const arr = [
|
|
327
|
+
{ id: 1, name: 'foo' },
|
|
328
|
+
{ id: 2, name: 'bar' },
|
|
329
|
+
];
|
|
330
|
+
const map = arr.toMap();
|
|
331
|
+
expect(map instanceof Map).toBe(true);
|
|
332
|
+
expect(map.size).toBe(2);
|
|
333
|
+
expect(map.get(0)).toEqual({ id: 1, name: 'foo' });
|
|
334
|
+
expect(map.get(1)).toEqual({ id: 2, name: 'bar' });
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
describe('error handling', () => {
|
|
338
|
+
it('should throw Error when key selector is invalid', () => {
|
|
339
|
+
expect(() => [{ id: 1 }].toMap(123)).toThrow(Error);
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
describe('toSet()', () => {
|
|
344
|
+
describe('without selector', () => {
|
|
345
|
+
it('should return Set of unique elements', () => {
|
|
346
|
+
expect([1, 2, 2, 3].toSet()).toEqual(new Set([1, 2, 3]));
|
|
347
|
+
});
|
|
348
|
+
it('should return empty Set when array is empty', () => {
|
|
349
|
+
expect([].toSet()).toEqual(new Set());
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
describe('with selector function', () => {
|
|
353
|
+
it('should return Set of selected values', () => {
|
|
354
|
+
const arr = [{ id: 1 }, { id: 2 }, { id: 1 }];
|
|
355
|
+
expect(arr.toSet((x) => x.id)).toEqual(new Set([1, 2]));
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
describe('with selector string key', () => {
|
|
359
|
+
it('should return Set of property key values', () => {
|
|
360
|
+
const arr = [{ id: 1 }, { id: 2 }, { id: 1 }];
|
|
361
|
+
expect(arr.toSet('id')).toEqual(new Set([1, 2]));
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
describe('countBy()', () => {
|
|
366
|
+
describe('without selector', () => {
|
|
367
|
+
it('should count elements directly', () => {
|
|
368
|
+
const arr = ['a', 'b', 'a', 'c', 'b', 'a'];
|
|
369
|
+
expect(arr.countBy()).toEqual(new Map([
|
|
370
|
+
['a', 3],
|
|
371
|
+
['b', 2],
|
|
372
|
+
['c', 1],
|
|
373
|
+
]));
|
|
374
|
+
});
|
|
375
|
+
it('should return empty Map when array is empty', () => {
|
|
376
|
+
expect([].countBy((x) => x)).toEqual(new Map());
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
describe('with selector function', () => {
|
|
380
|
+
it('should count elements by selector result', () => {
|
|
381
|
+
const arr = ['a', 'b', 'a', 'c', 'b', 'a'];
|
|
382
|
+
expect(arr.countBy((x) => x)).toEqual(new Map([
|
|
383
|
+
['a', 3],
|
|
384
|
+
['b', 2],
|
|
385
|
+
['c', 1],
|
|
386
|
+
]));
|
|
387
|
+
});
|
|
388
|
+
it('should count objects by extracted value', () => {
|
|
389
|
+
const arr = [{ type: 'x' }, { type: 'y' }, { type: 'x' }];
|
|
390
|
+
expect(arr.countBy((x) => x.type)).toEqual(new Map([
|
|
391
|
+
['x', 2],
|
|
392
|
+
['y', 1],
|
|
393
|
+
]));
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
describe('with selector string key', () => {
|
|
397
|
+
it('should count objects by property key', () => {
|
|
398
|
+
const arr = [{ type: 'x' }, { type: 'y' }, { type: 'x' }];
|
|
399
|
+
expect(arr.countBy('type')).toEqual(new Map([
|
|
400
|
+
['x', 2],
|
|
401
|
+
['y', 1],
|
|
402
|
+
]));
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
describe('error handling', () => {
|
|
406
|
+
it('should throw Error for invalid selector', () => {
|
|
407
|
+
expect(() => [{ id: 1 }].toMap(123)).toThrow(Error);
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
describe('Array.prototype.toObject', () => {
|
|
412
|
+
it('converts array of pairs to object', () => {
|
|
413
|
+
const arr = [
|
|
414
|
+
['a', 1],
|
|
415
|
+
['b', 2],
|
|
416
|
+
['c', 3],
|
|
417
|
+
];
|
|
418
|
+
const obj = arr.toObject();
|
|
419
|
+
expect(obj).toEqual({ a: 1, b: 2, c: 3 });
|
|
420
|
+
expect(typeof obj).toBe('object');
|
|
421
|
+
});
|
|
422
|
+
it('converts array of pairs with numeric keys to object', () => {
|
|
423
|
+
const arr = [
|
|
424
|
+
[1, 'a'],
|
|
425
|
+
[2, 'b'],
|
|
426
|
+
[3, 'c'],
|
|
427
|
+
];
|
|
428
|
+
const obj = arr.toObject();
|
|
429
|
+
expect(obj).toEqual({ 1: 'a', 2: 'b', 3: 'c' });
|
|
430
|
+
});
|
|
431
|
+
it('converts array of objects to object using key string', () => {
|
|
432
|
+
const arr = [
|
|
433
|
+
{ id: 1, name: 'foo' },
|
|
434
|
+
{ id: 2, name: 'bar' },
|
|
435
|
+
];
|
|
436
|
+
const obj = arr.toObject('id');
|
|
437
|
+
expect(obj).toEqual({
|
|
438
|
+
1: { id: 1, name: 'foo' },
|
|
439
|
+
2: { id: 2, name: 'bar' },
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
it('converts array of objects to object using key callback', () => {
|
|
443
|
+
const arr = [
|
|
444
|
+
{ id: 1, name: 'foo' },
|
|
445
|
+
{ id: 2, name: 'bar' },
|
|
446
|
+
];
|
|
447
|
+
const obj = arr.toObject((x) => x.id);
|
|
448
|
+
expect(obj).toEqual({
|
|
449
|
+
1: { id: 1, name: 'foo' },
|
|
450
|
+
2: { id: 2, name: 'bar' },
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
it('converts array of objects using key callback and value callback', () => {
|
|
454
|
+
const arr = [
|
|
455
|
+
{ id: 1, name: 'foo' },
|
|
456
|
+
{ id: 2, name: 'bar' },
|
|
457
|
+
];
|
|
458
|
+
const obj = arr.toObject((x) => x.id, (x) => x.name);
|
|
459
|
+
expect(obj).toEqual({
|
|
460
|
+
1: 'foo',
|
|
461
|
+
2: 'bar',
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
it('converts array without selector (uses index as key)', () => {
|
|
465
|
+
const arr = ['a', 'b', 'c'];
|
|
466
|
+
const obj = arr.toObject();
|
|
467
|
+
expect(obj).toEqual({
|
|
468
|
+
0: 'a',
|
|
469
|
+
1: 'b',
|
|
470
|
+
2: 'c',
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
it('converts empty array to empty object', () => {
|
|
474
|
+
const arr = [];
|
|
475
|
+
const obj = arr.toObject();
|
|
476
|
+
expect(obj).toEqual({});
|
|
477
|
+
});
|
|
478
|
+
it('handles objects with string and numeric keys', () => {
|
|
479
|
+
const arr = [
|
|
480
|
+
{ key: 'name', value: 'Alice' },
|
|
481
|
+
{ key: 'age', value: 30 },
|
|
482
|
+
];
|
|
483
|
+
const obj = arr.toObject((x) => x.key, (x) => x.value);
|
|
484
|
+
expect(obj).toEqual({
|
|
485
|
+
name: 'Alice',
|
|
486
|
+
age: 30,
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
it('throws error when key selector returns null', () => {
|
|
490
|
+
const arr = [{ id: 1, name: 'foo' }];
|
|
491
|
+
expect(() => arr.toObject((x) => null, (x) => x.name)).toThrow(TypeError);
|
|
492
|
+
});
|
|
493
|
+
it('throws error when key selector returns undefined', () => {
|
|
494
|
+
const arr = [{ id: 1, name: 'foo' }];
|
|
495
|
+
expect(() => arr.toObject((x) => undefined, (x) => x.name)).toThrow(TypeError);
|
|
496
|
+
});
|
|
497
|
+
it('throws error when key is not a string or number', () => {
|
|
498
|
+
const arr = [{ id: { nested: 1 }, name: 'foo' }];
|
|
499
|
+
expect(() => arr.toObject((x) => x.id)).toThrow(TypeError);
|
|
500
|
+
});
|
|
501
|
+
it('overwrites duplicate keys with the last value', () => {
|
|
502
|
+
const arr = [
|
|
503
|
+
{ id: 1, value: 'first' },
|
|
504
|
+
{ id: 1, value: 'second' },
|
|
505
|
+
];
|
|
506
|
+
const obj = arr.toObject((x) => x.id, (x) => x.value);
|
|
507
|
+
expect(obj).toEqual({
|
|
508
|
+
1: 'second',
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
it('handles mixed types in array', () => {
|
|
512
|
+
const arr = [
|
|
513
|
+
{ id: 'x', value: 10 },
|
|
514
|
+
{ id: 'y', value: 20 },
|
|
515
|
+
];
|
|
516
|
+
const obj = arr.toObject((x) => x.id, (x) => x.value);
|
|
517
|
+
expect(obj).toEqual({
|
|
518
|
+
x: 10,
|
|
519
|
+
y: 20,
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
it('converts with string key and different value types', () => {
|
|
523
|
+
const arr = [
|
|
524
|
+
{ id: 1, data: 'text' },
|
|
525
|
+
{ id: 2, data: 42 },
|
|
526
|
+
{ id: 3, data: null },
|
|
527
|
+
];
|
|
528
|
+
const obj = arr.toObject('id', (x) => x.data);
|
|
529
|
+
expect(obj).toEqual({
|
|
530
|
+
1: 'text',
|
|
531
|
+
2: 42,
|
|
532
|
+
3: null,
|
|
533
|
+
});
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
});
|
|
@@ -2,11 +2,28 @@ export {};
|
|
|
2
2
|
declare global {
|
|
3
3
|
interface Map<K, V> {
|
|
4
4
|
/**
|
|
5
|
-
* Converts the Map into a list or
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* Converts the Map into a list or specific structure based on the selected conversion type.
|
|
6
|
+
* Supports multiple output formats: entries, keys, values, or a plain object.
|
|
7
|
+
*
|
|
8
|
+
* @template K The type of keys in the Map
|
|
9
|
+
* @template V The type of values in the Map
|
|
10
|
+
* @this {Map<K, V>} The Map to convert
|
|
11
|
+
* @param {string} [type='entries'] - The conversion type ('keys' | 'values' | 'entries' | 'object')
|
|
12
|
+
* @returns {any} Converted output as specified by the type parameter
|
|
13
|
+
* @throws {TypeError} If type is 'object' with non-compatible keys or if type is unknown
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const map = new Map([['a', 1], ['b', 2]]);
|
|
17
|
+
* map.toList(); // [['a', 1], ['b', 2]]
|
|
18
|
+
* map.toList('keys'); // ['a', 'b']
|
|
19
|
+
* map.toList('values'); // [1, 2]
|
|
20
|
+
* map.toList('object'); // { a: 1, b: 2 }
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* - `entries` (default): Returns array of [K, V] pairs
|
|
24
|
+
* - `keys`: Returns array of all keys
|
|
25
|
+
* - `values`: Returns array of all values
|
|
26
|
+
* - `object`: Returns Record with string keys (requires keys to be string/number/symbol)
|
|
10
27
|
*/
|
|
11
28
|
toList(type: 'keys'): K[];
|
|
12
29
|
toList(type: 'values'): V[];
|
|
@@ -14,11 +31,54 @@ declare global {
|
|
|
14
31
|
toList(type: 'entries'): [K, V][];
|
|
15
32
|
toList(): [K, V][];
|
|
16
33
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
34
|
+
* Converts a Map to a plain JavaScript object.
|
|
35
|
+
* Each key/value pair in the Map becomes a property/value in the resulting object.
|
|
36
|
+
* Validates that all keys are valid PropertyKey types.
|
|
37
|
+
*
|
|
38
|
+
* @template K Type of keys (must extend PropertyKey: string | number | symbol)
|
|
39
|
+
* @template V Type of values in the Map
|
|
40
|
+
* @this {Map<K, V>} The Map to convert
|
|
41
|
+
* @returns {Record<K, V>} A plain object with Map entries as properties
|
|
42
|
+
* @throws {TypeError} If any key is null, undefined, or not a PropertyKey type
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const map = new Map<string, number>([['a', 1], ['b', 2]]);
|
|
46
|
+
* map.toObject(); // { a: 1, b: 2 }
|
|
47
|
+
*
|
|
48
|
+
* const numKeyMap = new Map<number, string>([[1, 'one'], [2, 'two']]);
|
|
49
|
+
* numKeyMap.toObject(); // { 1: 'one', 2: 'two' }
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* - Provides validation and error handling for property key compatibility
|
|
53
|
+
* - Supports string, number, and symbol keys
|
|
54
|
+
* - Returns a new object instance each time (no modification to original)
|
|
55
|
+
*/
|
|
56
|
+
toObject<K extends PropertyKey, V>(this: Map<K, V>): Record<K, V>;
|
|
57
|
+
/**
|
|
58
|
+
* Ensures that the Map has an entry for the given key with an array as value.
|
|
59
|
+
* If the key doesn't exist, initializes it with an empty array.
|
|
60
|
+
* Validates that the existing value (if any) is indeed an array.
|
|
61
|
+
*
|
|
62
|
+
* @template K Type of keys in the Map
|
|
63
|
+
* @template L The array type stored as values (extends Array<any>)
|
|
64
|
+
* @this {Map<K, L>} The Map where values must be arrays
|
|
65
|
+
* @param {K} key - The key to look up or initialize
|
|
66
|
+
* @returns {L} The array associated with the key (either existing or newly created)
|
|
67
|
+
* @throws {TypeError} If key is null/undefined or if the existing value is not an array
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* const map = new Map<string, number[]>();
|
|
71
|
+
* const arr1 = map.ensureArray('items'); // Returns [], and ['items'] => [] is set in map
|
|
72
|
+
* arr1.push(42);
|
|
73
|
+
*
|
|
74
|
+
* const arr2 = map.ensureArray('items'); // Returns same array with [42]
|
|
75
|
+
* arr1 === arr2; // true (same reference)
|
|
19
76
|
*
|
|
20
|
-
* @
|
|
21
|
-
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* - Modifies the Map in place (lazy initialization pattern)
|
|
79
|
+
* - Useful for Maps that accumulate items by key
|
|
80
|
+
* - Throws if the existing value for a key is not an array
|
|
81
|
+
* - Key must not be null or undefined
|
|
22
82
|
*/
|
|
23
83
|
ensureArray<L extends Array<any>>(this: Map<K, L>, key: K): L;
|
|
24
84
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
4
|
-
|
|
3
|
+
const core_utils_1 = require("../utils/core.utils");
|
|
4
|
+
const logic_utils_1 = require("../utils/logic.utils");
|
|
5
|
+
/**
|
|
6
|
+
* @see Map.prototype.toList
|
|
7
|
+
*/
|
|
8
|
+
(0, core_utils_1.defineIfNotExists)(Map.prototype, 'toList', function (type = 'entries') {
|
|
5
9
|
switch (type) {
|
|
6
10
|
case 'keys':
|
|
7
11
|
return Array.from(this.keys());
|
|
@@ -26,7 +30,16 @@ const utils_1 = require("../utils");
|
|
|
26
30
|
throw new TypeError(`Unknown type "${type}" for Map.prototype.toList`);
|
|
27
31
|
}
|
|
28
32
|
});
|
|
29
|
-
|
|
33
|
+
/**
|
|
34
|
+
* @see Map.prototype.toObject
|
|
35
|
+
*/
|
|
36
|
+
(0, core_utils_1.defineIfNotExists)(Map.prototype, 'toObject', function () {
|
|
37
|
+
return (0, logic_utils_1.mapToObject)(this);
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* @see Map.prototype.ensureArray
|
|
41
|
+
*/
|
|
42
|
+
(0, core_utils_1.defineIfNotExists)(Map.prototype, 'ensureArray', function (key) {
|
|
30
43
|
if (key === null || key === undefined) {
|
|
31
44
|
throw new TypeError('Key cannot be null or undefined');
|
|
32
45
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '../map/map-prototype';
|