@sylphx/flow 2.18.1 → 2.18.3

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.
@@ -1,355 +0,0 @@
1
- /**
2
- * Functional array utilities
3
- * Pure array transformation functions
4
- *
5
- * DESIGN RATIONALE:
6
- * - Pure functions for array operations
7
- * - Composable transformations
8
- * - Type-safe operations
9
- * - No side effects (no mutations)
10
- */
11
-
12
- /**
13
- * Map over array
14
- */
15
- export const map =
16
- <T, U>(fn: (item: T, index: number) => U) =>
17
- (arr: T[]): U[] =>
18
- arr.map(fn);
19
-
20
- /**
21
- * Filter array
22
- */
23
- export const filter =
24
- <T>(predicate: (item: T, index: number) => boolean) =>
25
- (arr: T[]): T[] =>
26
- arr.filter(predicate);
27
-
28
- /**
29
- * Reduce array
30
- */
31
- export const reduce =
32
- <T, U>(fn: (acc: U, item: T, index: number) => U, initial: U) =>
33
- (arr: T[]): U =>
34
- arr.reduce(fn, initial);
35
-
36
- /**
37
- * Find first element matching predicate
38
- */
39
- export const find =
40
- <T>(predicate: (item: T, index: number) => boolean) =>
41
- (arr: T[]): T | undefined =>
42
- arr.find(predicate);
43
-
44
- /**
45
- * Find index of first element matching predicate
46
- */
47
- export const findIndex =
48
- <T>(predicate: (item: T, index: number) => boolean) =>
49
- (arr: T[]): number =>
50
- arr.findIndex(predicate);
51
-
52
- /**
53
- * Check if any element matches predicate
54
- */
55
- export const some =
56
- <T>(predicate: (item: T, index: number) => boolean) =>
57
- (arr: T[]): boolean =>
58
- arr.some(predicate);
59
-
60
- /**
61
- * Check if all elements match predicate
62
- */
63
- export const every =
64
- <T>(predicate: (item: T, index: number) => boolean) =>
65
- (arr: T[]): boolean =>
66
- arr.every(predicate);
67
-
68
- /**
69
- * Flatten array one level
70
- */
71
- export const flatten = <T>(arr: T[][]): T[] => arr.flat();
72
-
73
- /**
74
- * Flatten array deeply
75
- */
76
- export const flattenDeep = <T>(arr: any[]): T[] => arr.flat(Number.POSITIVE_INFINITY);
77
-
78
- /**
79
- * Map and flatten (flatMap)
80
- */
81
- export const flatMap =
82
- <T, U>(fn: (item: T, index: number) => U[]) =>
83
- (arr: T[]): U[] =>
84
- arr.flatMap(fn);
85
-
86
- /**
87
- * Take first n elements
88
- */
89
- export const take =
90
- (n: number) =>
91
- <T>(arr: T[]): T[] =>
92
- arr.slice(0, n);
93
-
94
- /**
95
- * Skip first n elements
96
- */
97
- export const skip =
98
- (n: number) =>
99
- <T>(arr: T[]): T[] =>
100
- arr.slice(n);
101
-
102
- /**
103
- * Take while predicate is true
104
- */
105
- export const takeWhile =
106
- <T>(predicate: (item: T) => boolean) =>
107
- (arr: T[]): T[] => {
108
- const index = arr.findIndex((item) => !predicate(item));
109
- return index === -1 ? arr : arr.slice(0, index);
110
- };
111
-
112
- /**
113
- * Skip while predicate is true
114
- */
115
- export const skipWhile =
116
- <T>(predicate: (item: T) => boolean) =>
117
- (arr: T[]): T[] => {
118
- const index = arr.findIndex((item) => !predicate(item));
119
- return index === -1 ? [] : arr.slice(index);
120
- };
121
-
122
- /**
123
- * Reverse array
124
- */
125
- export const reverse = <T>(arr: T[]): T[] => [...arr].reverse();
126
-
127
- /**
128
- * Sort array
129
- */
130
- export const sort =
131
- <T>(compareFn?: (a: T, b: T) => number) =>
132
- (arr: T[]): T[] =>
133
- [...arr].sort(compareFn);
134
-
135
- /**
136
- * Sort by key
137
- */
138
- export const sortBy =
139
- <T, K extends keyof T>(key: K, order: 'asc' | 'desc' = 'asc') =>
140
- (arr: T[]): T[] => {
141
- return [...arr].sort((a, b) => {
142
- const aVal = a[key];
143
- const bVal = b[key];
144
-
145
- if (aVal < bVal) {
146
- return order === 'asc' ? -1 : 1;
147
- }
148
- if (aVal > bVal) {
149
- return order === 'asc' ? 1 : -1;
150
- }
151
- return 0;
152
- });
153
- };
154
-
155
- /**
156
- * Remove duplicates
157
- */
158
- export const unique = <T>(arr: T[]): T[] => [...new Set(arr)];
159
-
160
- /**
161
- * Remove duplicates by key
162
- */
163
- export const uniqueBy =
164
- <T, K extends keyof T>(key: K) =>
165
- (arr: T[]): T[] => {
166
- const seen = new Set();
167
- return arr.filter((item) => {
168
- const value = item[key];
169
- if (seen.has(value)) {
170
- return false;
171
- }
172
- seen.add(value);
173
- return true;
174
- });
175
- };
176
-
177
- /**
178
- * Partition array into two based on predicate
179
- */
180
- export const partition =
181
- <T>(predicate: (item: T) => boolean) =>
182
- (arr: T[]): [T[], T[]] => {
183
- const pass: T[] = [];
184
- const fail: T[] = [];
185
-
186
- for (const item of arr) {
187
- if (predicate(item)) {
188
- pass.push(item);
189
- } else {
190
- fail.push(item);
191
- }
192
- }
193
-
194
- return [pass, fail];
195
- };
196
-
197
- /**
198
- * Group by key
199
- */
200
- export const groupBy =
201
- <T, K extends keyof T>(key: K) =>
202
- (arr: T[]): Record<string, T[]> => {
203
- return arr.reduce(
204
- (acc, item) => {
205
- const groupKey = String(item[key]);
206
- if (!acc[groupKey]) {
207
- acc[groupKey] = [];
208
- }
209
- acc[groupKey].push(item);
210
- return acc;
211
- },
212
- {} as Record<string, T[]>
213
- );
214
- };
215
-
216
- /**
217
- * Count occurrences
218
- */
219
- export const countBy =
220
- <T>(fn: (item: T) => string) =>
221
- (arr: T[]): Record<string, number> => {
222
- return arr.reduce(
223
- (acc, item) => {
224
- const key = fn(item);
225
- acc[key] = (acc[key] || 0) + 1;
226
- return acc;
227
- },
228
- {} as Record<string, number>
229
- );
230
- };
231
-
232
- /**
233
- * Chunk array into smaller arrays
234
- */
235
- export const chunk =
236
- (size: number) =>
237
- <T>(arr: T[]): T[][] => {
238
- const chunks: T[][] = [];
239
- for (let i = 0; i < arr.length; i += size) {
240
- chunks.push(arr.slice(i, i + size));
241
- }
242
- return chunks;
243
- };
244
-
245
- /**
246
- * Zip arrays together
247
- */
248
- export const zip = <T, U>(arr1: T[], arr2: U[]): [T, U][] => {
249
- const length = Math.min(arr1.length, arr2.length);
250
- const result: [T, U][] = [];
251
-
252
- for (let i = 0; i < length; i++) {
253
- result.push([arr1[i], arr2[i]]);
254
- }
255
-
256
- return result;
257
- };
258
-
259
- /**
260
- * Unzip array of tuples
261
- */
262
- export const unzip = <T, U>(arr: [T, U][]): [T[], U[]] => {
263
- const first: T[] = [];
264
- const second: U[] = [];
265
-
266
- for (const [a, b] of arr) {
267
- first.push(a);
268
- second.push(b);
269
- }
270
-
271
- return [first, second];
272
- };
273
-
274
- /**
275
- * Intersperse value between array elements
276
- */
277
- export const intersperse =
278
- <T>(separator: T) =>
279
- (arr: T[]): T[] => {
280
- if (arr.length === 0) {
281
- return [];
282
- }
283
-
284
- const result: T[] = [arr[0]];
285
- for (let i = 1; i < arr.length; i++) {
286
- result.push(separator, arr[i]);
287
- }
288
-
289
- return result;
290
- };
291
-
292
- /**
293
- * Get first element
294
- */
295
- export const head = <T>(arr: T[]): T | undefined => arr[0];
296
-
297
- /**
298
- * Get last element
299
- */
300
- export const last = <T>(arr: T[]): T | undefined => arr[arr.length - 1];
301
-
302
- /**
303
- * Get all but first element
304
- */
305
- export const tail = <T>(arr: T[]): T[] => arr.slice(1);
306
-
307
- /**
308
- * Get all but last element
309
- */
310
- export const init = <T>(arr: T[]): T[] => arr.slice(0, -1);
311
-
312
- /**
313
- * Check if array is empty
314
- */
315
- export const isEmpty = <T>(arr: T[]): boolean => arr.length === 0;
316
-
317
- /**
318
- * Check if array is not empty
319
- */
320
- export const isNotEmpty = <T>(arr: T[]): boolean => arr.length > 0;
321
-
322
- /**
323
- * Sum numbers in array
324
- */
325
- export const sum = (arr: number[]): number => arr.reduce((a, b) => a + b, 0);
326
-
327
- /**
328
- * Get average of numbers in array
329
- */
330
- export const average = (arr: number[]): number => {
331
- if (arr.length === 0) {
332
- return 0;
333
- }
334
- return sum(arr) / arr.length;
335
- };
336
-
337
- /**
338
- * Get min value
339
- */
340
- export const min = (arr: number[]): number | undefined => {
341
- if (arr.length === 0) {
342
- return undefined;
343
- }
344
- return Math.min(...arr);
345
- };
346
-
347
- /**
348
- * Get max value
349
- */
350
- export const max = (arr: number[]): number | undefined => {
351
- if (arr.length === 0) {
352
- return undefined;
353
- }
354
- return Math.max(...arr);
355
- };
@@ -1,15 +0,0 @@
1
- /**
2
- * Functional utilities
3
- * Pure, composable utility functions
4
- *
5
- * DESIGN RATIONALE:
6
- * - Pure functions for common operations
7
- * - Composable through currying
8
- * - Type-safe
9
- * - No side effects
10
- * - Point-free style support
11
- */
12
-
13
- export * as Arr from './array.js';
14
- export * as Obj from './object.js';
15
- export * as Str from './string.js';
@@ -1,279 +0,0 @@
1
- /**
2
- * Functional object utilities
3
- * Pure object transformation functions
4
- *
5
- * DESIGN RATIONALE:
6
- * - Pure functions for object operations
7
- * - Immutable transformations
8
- * - Type-safe operations
9
- * - No side effects
10
- */
11
-
12
- /**
13
- * Get keys of object
14
- */
15
- export const keys = <T extends object>(obj: T): Array<keyof T> => {
16
- return Object.keys(obj) as Array<keyof T>;
17
- };
18
-
19
- /**
20
- * Get values of object
21
- */
22
- export const values = <T extends object>(obj: T): T[keyof T][] => {
23
- return Object.values(obj);
24
- };
25
-
26
- /**
27
- * Get entries of object
28
- */
29
- export const entries = <T extends object>(obj: T): [keyof T, T[keyof T]][] => {
30
- return Object.entries(obj) as [keyof T, T[keyof T]][];
31
- };
32
-
33
- /**
34
- * Create object from entries
35
- */
36
- export const fromEntries = <K extends string | number | symbol, V>(
37
- entries: [K, V][]
38
- ): Record<K, V> => {
39
- return Object.fromEntries(entries) as Record<K, V>;
40
- };
41
-
42
- /**
43
- * Pick properties from object
44
- */
45
- export const pick =
46
- <T extends object, K extends keyof T>(keys: K[]) =>
47
- (obj: T): Pick<T, K> => {
48
- const result = {} as Pick<T, K>;
49
- for (const key of keys) {
50
- if (key in obj) {
51
- result[key] = obj[key];
52
- }
53
- }
54
- return result;
55
- };
56
-
57
- /**
58
- * Omit properties from object
59
- */
60
- export const omit =
61
- <T extends object, K extends keyof T>(keys: K[]) =>
62
- (obj: T): Omit<T, K> => {
63
- const result = { ...obj };
64
- for (const key of keys) {
65
- delete result[key];
66
- }
67
- return result;
68
- };
69
-
70
- /**
71
- * Map over object values
72
- */
73
- export const mapValues =
74
- <T extends object, U>(fn: (value: T[keyof T], key: keyof T) => U) =>
75
- (obj: T): Record<keyof T, U> => {
76
- const result = {} as Record<keyof T, U>;
77
- for (const [key, value] of entries(obj)) {
78
- result[key] = fn(value, key);
79
- }
80
- return result;
81
- };
82
-
83
- /**
84
- * Map over object keys
85
- */
86
- export const mapKeys =
87
- <T extends object, K extends string | number | symbol>(
88
- fn: (key: keyof T, value: T[keyof T]) => K
89
- ) =>
90
- (obj: T): Record<K, T[keyof T]> => {
91
- const result = {} as Record<K, T[keyof T]>;
92
- for (const [key, value] of entries(obj)) {
93
- const newKey = fn(key, value);
94
- result[newKey] = value;
95
- }
96
- return result;
97
- };
98
-
99
- /**
100
- * Filter object by predicate
101
- */
102
- export const filterObj =
103
- <T extends object>(predicate: (value: T[keyof T], key: keyof T) => boolean) =>
104
- (obj: T): Partial<T> => {
105
- const result = {} as Partial<T>;
106
- for (const [key, value] of entries(obj)) {
107
- if (predicate(value, key)) {
108
- result[key] = value;
109
- }
110
- }
111
- return result;
112
- };
113
-
114
- /**
115
- * Merge objects (shallow)
116
- */
117
- export const merge = <T extends object, U extends object>(obj1: T, obj2: U): T & U => {
118
- return { ...obj1, ...obj2 };
119
- };
120
-
121
- /**
122
- * Deep merge objects
123
- */
124
- export const deepMerge = <T extends object>(target: T, source: Partial<T>): T => {
125
- const result = { ...target };
126
-
127
- for (const key of keys(source)) {
128
- const sourceValue = source[key];
129
- const targetValue = result[key];
130
-
131
- if (
132
- typeof sourceValue === 'object' &&
133
- sourceValue !== null &&
134
- !Array.isArray(sourceValue) &&
135
- typeof targetValue === 'object' &&
136
- targetValue !== null &&
137
- !Array.isArray(targetValue)
138
- ) {
139
- result[key] = deepMerge(targetValue, sourceValue as any);
140
- } else if (sourceValue !== undefined) {
141
- result[key] = sourceValue as T[Extract<keyof T, string>];
142
- }
143
- }
144
-
145
- return result;
146
- };
147
-
148
- /**
149
- * Check if object has property
150
- */
151
- export const has =
152
- <T extends object>(key: PropertyKey) =>
153
- (obj: T): boolean => {
154
- return key in obj;
155
- };
156
-
157
- /**
158
- * Get property safely
159
- */
160
- export const get =
161
- <T extends object, K extends keyof T>(key: K) =>
162
- (obj: T): T[K] | undefined => {
163
- return obj[key];
164
- };
165
-
166
- /**
167
- * Get nested property safely
168
- */
169
- export const getPath =
170
- (path: string) =>
171
- (obj: any): any => {
172
- const keys = path.split('.');
173
- let current = obj;
174
-
175
- for (const key of keys) {
176
- if (current === null || current === undefined) {
177
- return undefined;
178
- }
179
- current = current[key];
180
- }
181
-
182
- return current;
183
- };
184
-
185
- /**
186
- * Set property immutably
187
- */
188
- export const set =
189
- <T extends object, K extends keyof T>(key: K, value: T[K]) =>
190
- (obj: T): T => {
191
- return { ...obj, [key]: value };
192
- };
193
-
194
- /**
195
- * Update property immutably
196
- */
197
- export const update =
198
- <T extends object, K extends keyof T>(key: K, fn: (value: T[K]) => T[K]) =>
199
- (obj: T): T => {
200
- return { ...obj, [key]: fn(obj[key]) };
201
- };
202
-
203
- /**
204
- * Check if object is empty
205
- */
206
- export const isEmpty = <T extends object>(obj: T): boolean => {
207
- return keys(obj).length === 0;
208
- };
209
-
210
- /**
211
- * Check if object is not empty
212
- */
213
- export const isNotEmpty = <T extends object>(obj: T): boolean => {
214
- return keys(obj).length > 0;
215
- };
216
-
217
- /**
218
- * Remove undefined values
219
- */
220
- export const compact = <T extends object>(obj: T): Partial<T> => {
221
- return filterObj((value: any) => value !== undefined)(obj);
222
- };
223
-
224
- /**
225
- * Remove null and undefined values
226
- */
227
- export const compactAll = <T extends object>(obj: T): Partial<T> => {
228
- return filterObj((value: any) => value !== null && value !== undefined)(obj);
229
- };
230
-
231
- /**
232
- * Invert object (swap keys and values)
233
- */
234
- export const invert = <T extends Record<string, string | number>>(
235
- obj: T
236
- ): Record<string, string> => {
237
- const result: Record<string, string> = {};
238
- for (const [key, value] of Object.entries(obj)) {
239
- result[String(value)] = key;
240
- }
241
- return result;
242
- };
243
-
244
- /**
245
- * Deep clone object
246
- */
247
- export const clone = <T>(obj: T): T => {
248
- if (obj === null || typeof obj !== 'object') {
249
- return obj;
250
- }
251
-
252
- if (Array.isArray(obj)) {
253
- return obj.map(clone) as any;
254
- }
255
-
256
- const cloned = {} as T;
257
- for (const key in obj) {
258
- if (Object.hasOwn(obj, key)) {
259
- cloned[key] = clone(obj[key]);
260
- }
261
- }
262
-
263
- return cloned;
264
- };
265
-
266
- /**
267
- * Freeze object deeply (make immutable)
268
- */
269
- export const deepFreeze = <T extends object>(obj: T): Readonly<T> => {
270
- Object.freeze(obj);
271
-
272
- for (const value of values(obj)) {
273
- if (typeof value === 'object' && value !== null) {
274
- deepFreeze(value);
275
- }
276
- }
277
-
278
- return obj;
279
- };