@sylphx/flow 2.18.0 → 2.18.2

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,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
- };
@@ -1,281 +0,0 @@
1
- /**
2
- * Functional string utilities
3
- * Pure string transformation functions
4
- *
5
- * DESIGN RATIONALE:
6
- * - Pure functions for string operations
7
- * - Composable transformations
8
- * - Type-safe operations
9
- * - No side effects
10
- */
11
-
12
- /**
13
- * Trim whitespace from string
14
- */
15
- export const trim = (str: string): string => str.trim();
16
-
17
- /**
18
- * Trim start of string
19
- */
20
- export const trimStart = (str: string): string => str.trimStart();
21
-
22
- /**
23
- * Trim end of string
24
- */
25
- export const trimEnd = (str: string): string => str.trimEnd();
26
-
27
- /**
28
- * Convert to lowercase
29
- */
30
- export const toLowerCase = (str: string): string => str.toLowerCase();
31
-
32
- /**
33
- * Convert to uppercase
34
- */
35
- export const toUpperCase = (str: string): string => str.toUpperCase();
36
-
37
- /**
38
- * Split string by delimiter
39
- */
40
- export const split =
41
- (delimiter: string | RegExp) =>
42
- (str: string): string[] =>
43
- str.split(delimiter);
44
-
45
- /**
46
- * Join array of strings
47
- */
48
- export const join =
49
- (delimiter: string) =>
50
- (arr: string[]): string =>
51
- arr.join(delimiter);
52
-
53
- /**
54
- * Replace pattern in string
55
- */
56
- export const replace =
57
- (pattern: string | RegExp, replacement: string) =>
58
- (str: string): string =>
59
- str.replace(pattern, replacement);
60
-
61
- /**
62
- * Replace all occurrences
63
- */
64
- export const replaceAll =
65
- (pattern: string | RegExp, replacement: string) =>
66
- (str: string): string =>
67
- str.replaceAll(pattern, replacement);
68
-
69
- /**
70
- * Check if string starts with prefix
71
- */
72
- export const startsWith =
73
- (prefix: string) =>
74
- (str: string): boolean =>
75
- str.startsWith(prefix);
76
-
77
- /**
78
- * Check if string ends with suffix
79
- */
80
- export const endsWith =
81
- (suffix: string) =>
82
- (str: string): boolean =>
83
- str.endsWith(suffix);
84
-
85
- /**
86
- * Check if string includes substring
87
- */
88
- export const includes =
89
- (substring: string) =>
90
- (str: string): boolean =>
91
- str.includes(substring);
92
-
93
- /**
94
- * Test string against regex
95
- */
96
- export const test =
97
- (pattern: RegExp) =>
98
- (str: string): boolean =>
99
- pattern.test(str);
100
-
101
- /**
102
- * Match string against regex
103
- */
104
- export const match =
105
- (pattern: RegExp) =>
106
- (str: string): RegExpMatchArray | null =>
107
- str.match(pattern);
108
-
109
- /**
110
- * Slice string
111
- */
112
- export const slice =
113
- (start: number, end?: number) =>
114
- (str: string): string =>
115
- str.slice(start, end);
116
-
117
- /**
118
- * Substring
119
- */
120
- export const substring =
121
- (start: number, end?: number) =>
122
- (str: string): string =>
123
- str.substring(start, end);
124
-
125
- /**
126
- * Pad start of string
127
- */
128
- export const padStart =
129
- (length: number, fillString = ' ') =>
130
- (str: string): string =>
131
- str.padStart(length, fillString);
132
-
133
- /**
134
- * Pad end of string
135
- */
136
- export const padEnd =
137
- (length: number, fillString = ' ') =>
138
- (str: string): string =>
139
- str.padEnd(length, fillString);
140
-
141
- /**
142
- * Repeat string n times
143
- */
144
- export const repeat =
145
- (count: number) =>
146
- (str: string): string =>
147
- str.repeat(count);
148
-
149
- /**
150
- * Check if string is empty
151
- */
152
- export const isEmpty = (str: string): boolean => str.length === 0;
153
-
154
- /**
155
- * Check if string is blank (empty or whitespace)
156
- */
157
- export const isBlank = (str: string): boolean => str.trim().length === 0;
158
-
159
- /**
160
- * Check if string is not empty
161
- */
162
- export const isNotEmpty = (str: string): boolean => str.length > 0;
163
-
164
- /**
165
- * Check if string is not blank
166
- */
167
- export const isNotBlank = (str: string): boolean => str.trim().length > 0;
168
-
169
- /**
170
- * Capitalize first letter
171
- */
172
- export const capitalize = (str: string): string => {
173
- if (str.length === 0) {
174
- return str;
175
- }
176
- return str.charAt(0).toUpperCase() + str.slice(1);
177
- };
178
-
179
- /**
180
- * Capitalize all words
181
- */
182
- export const capitalizeWords = (str: string): string => {
183
- return str
184
- .split(' ')
185
- .map((word) => capitalize(word))
186
- .join(' ');
187
- };
188
-
189
- /**
190
- * Convert to camelCase
191
- */
192
- export const toCamelCase = (str: string): string => {
193
- return str
194
- .replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))
195
- .replace(/^[A-Z]/, (c) => c.toLowerCase());
196
- };
197
-
198
- /**
199
- * Convert to PascalCase
200
- */
201
- export const toPascalCase = (str: string): string => {
202
- const camel = toCamelCase(str);
203
- return capitalize(camel);
204
- };
205
-
206
- /**
207
- * Convert to kebab-case
208
- */
209
- export const toKebabCase = (str: string): string => {
210
- return str
211
- .replace(/([a-z])([A-Z])/g, '$1-$2')
212
- .replace(/[\s_]+/g, '-')
213
- .toLowerCase();
214
- };
215
-
216
- /**
217
- * Convert to snake_case
218
- */
219
- export const toSnakeCase = (str: string): string => {
220
- return str
221
- .replace(/([a-z])([A-Z])/g, '$1_$2')
222
- .replace(/[\s-]+/g, '_')
223
- .toLowerCase();
224
- };
225
-
226
- /**
227
- * Truncate string to max length
228
- */
229
- export const truncate =
230
- (maxLength: number, suffix = '...') =>
231
- (str: string): string => {
232
- if (str.length <= maxLength) {
233
- return str;
234
- }
235
- return str.slice(0, maxLength - suffix.length) + suffix;
236
- };
237
-
238
- /**
239
- * Extract lines from string
240
- */
241
- export const lines = (str: string): string[] => str.split(/\r?\n/);
242
-
243
- /**
244
- * Remove empty lines
245
- */
246
- export const removeEmptyLines = (str: string): string => {
247
- return lines(str).filter(isNotBlank).join('\n');
248
- };
249
-
250
- /**
251
- * Indent each line
252
- */
253
- export const indent =
254
- (spaces: number) =>
255
- (str: string): string => {
256
- const indentation = ' '.repeat(spaces);
257
- return lines(str)
258
- .map((line) => indentation + line)
259
- .join('\n');
260
- };
261
-
262
- /**
263
- * Remove indentation
264
- */
265
- export const dedent = (str: string): string => {
266
- const linesArray = lines(str);
267
-
268
- // Find minimum indentation
269
- const minIndent = linesArray.filter(isNotBlank).reduce((min, line) => {
270
- const match = line.match(/^(\s*)/);
271
- const indent = match ? match[1].length : 0;
272
- return Math.min(min, indent);
273
- }, Number.POSITIVE_INFINITY);
274
-
275
- if (minIndent === 0 || minIndent === Number.POSITIVE_INFINITY) {
276
- return str;
277
- }
278
-
279
- // Remove minimum indentation from each line
280
- return linesArray.map((line) => line.slice(minIndent)).join('\n');
281
- };