@ooneex/utils 0.1.0 → 0.2.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/README.md CHANGED
@@ -1,90 +1,90 @@
1
1
  # @ooneex/utils
2
2
 
3
- A comprehensive TypeScript/JavaScript utility library providing essential helper functions for string manipulation, time formatting, data parsing, and more. This package offers a collection of lightweight, type-safe utilities designed to streamline common development tasks across web applications.
3
+ General-purpose utility functions including unique ID generation with nanoid, type guards, and common helper methods.
4
4
 
5
5
  ![Browser](https://img.shields.io/badge/Browser-Compatible-green?style=flat-square&logo=googlechrome)
6
6
  ![Bun](https://img.shields.io/badge/Bun-Compatible-orange?style=flat-square&logo=bun)
7
- ![Deno](https://img.shields.io/badge/Deno-Compatible-blue?style=flat-square&logo=deno)
8
- ![Node.js](https://img.shields.io/badge/Node.js-Compatible-green?style=flat-square&logo=node.js)
9
7
  ![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square&logo=typescript)
10
8
  ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)
11
9
 
12
10
  ## Features
13
11
 
14
- ✅ **String Manipulation** - Case conversion utilities (camelCase, PascalCase, kebab-case)
12
+ ✅ **ID Generation** - Generate unique IDs using nanoid with configurable length
15
13
 
16
- ✅ **Time Formatting** - Convert seconds/milliseconds to human-readable formats
14
+ ✅ **String Case Conversion** - Convert between camelCase, kebab-case, snake_case, and PascalCase
17
15
 
18
- ✅ **Data Parsing** - Intelligent string parsing with type inference
16
+ ✅ **String Utilities** - `trim`, `splitToWords`, `capitalizeWord` for common string operations
19
17
 
20
- ✅ **Type-Safe** - Full TypeScript support with proper type definitions
18
+ ✅ **Value Parsing** - `parseString` to convert string values to boolean, number, or string types
21
19
 
22
- ✅ **Lightweight** - Minimal dependencies and optimized bundle size
20
+ ✅ **Time Formatting** - `secondsToHMS`, `secondsToMS`, and `millisecondsToHMS` for duration display
23
21
 
24
- ✅ **Cross-Platform** - Works in Browser, Node.js, Bun, and Deno
22
+ ✅ **Number Formatting** - `formatRelativeNumber` for human-readable numbers with K, M, B suffixes
25
23
 
26
- ✅ **Environment Variables** - Parse and transform environment variables
24
+ ✅ **Data Conversion** - `dataURLtoFile` to convert data URLs to File objects
27
25
 
28
- ✅ **File Utilities** - Convert data URLs to File objects
26
+ ✅ **Environment Variables** - `parseEnvVars` to parse .env file content into key-value pairs
29
27
 
30
- ✅ **Random Generation** - Generate random IDs and strings
28
+ ✅ **Async Utilities** - `sleep` function for async/await workflows
31
29
 
32
- ✅ **Number Formatting** - Format numbers with locale-aware compact notation
33
-
34
- ✅ **Zero Dependencies** - Only one small dependency (nanoid) for random generation
30
+ ✅ **Zero Config** - Simple, pure functions with no configuration needed
35
31
 
36
32
  ## Installation
37
33
 
38
- ### Bun
39
34
  ```bash
40
35
  bun add @ooneex/utils
41
36
  ```
42
37
 
43
- ### pnpm
44
- ```bash
45
- pnpm add @ooneex/utils
46
- ```
38
+ ## Usage
47
39
 
48
- ### Yarn
49
- ```bash
50
- yarn add @ooneex/utils
51
- ```
40
+ ### Unique ID Generation
52
41
 
53
- ### npm
54
- ```bash
55
- npm install @ooneex/utils
56
- ```
42
+ ```typescript
43
+ import { random } from '@ooneex/utils';
57
44
 
58
- ## Usage
45
+ // Generate a unique ID (default length: 21)
46
+ const id = random();
47
+ console.log(id); // "V1StGXR8_Z5jdHi6B-myT"
48
+
49
+ // Generate with custom length
50
+ const shortId = random(10);
51
+ console.log(shortId); // "V1StGXR8_Z"
52
+ ```
59
53
 
60
- ### String Manipulation
54
+ ### String Case Conversion
61
55
 
62
56
  ```typescript
63
57
  import {
64
- capitalizeWord,
65
58
  toCamelCase,
66
- toPascalCase,
67
59
  toKebabCase,
68
- splitToWords,
69
- trim
60
+ toSnakeCase,
61
+ toPascalCase,
62
+ capitalizeWord
70
63
  } from '@ooneex/utils';
71
64
 
72
- // Capitalize words
73
- console.log(capitalizeWord('hello')); // 'Hello'
74
- console.log(capitalizeWord('WORLD')); // 'World'
75
-
76
- // Case conversions
77
- console.log(toCamelCase('hello world')); // 'helloWorld'
78
- console.log(toPascalCase('hello world')); // 'HelloWorld'
79
- console.log(toKebabCase('Hello World')); // 'hello-world'
80
-
81
- // Split strings to words
82
- console.log(splitToWords('HelloWorldExample')); // ['Hello', 'World', 'Example']
83
- console.log(splitToWords('hello-world_example')); // ['hello', 'world', 'example']
84
-
85
- // Advanced trimming
86
- console.log(trim('...hello...', '\\.')); // 'hello'
87
- console.log(trim('[test]', '\\[|\\]')); // 'test'
65
+ // Convert to camelCase
66
+ toCamelCase('hello world'); // "helloWorld"
67
+ toCamelCase('hello-world'); // "helloWorld"
68
+ toCamelCase('hello_world'); // "helloWorld"
69
+
70
+ // Convert to kebab-case
71
+ toKebabCase('helloWorld'); // "hello-world"
72
+ toKebabCase('HelloWorld'); // "hello-world"
73
+ toKebabCase('hello_world'); // "hello-world"
74
+
75
+ // Convert to snake_case
76
+ toSnakeCase('helloWorld'); // "hello_world"
77
+ toSnakeCase('HelloWorld'); // "hello_world"
78
+ toSnakeCase('hello-world'); // "hello_world"
79
+
80
+ // Convert to PascalCase
81
+ toPascalCase('hello world'); // "HelloWorld"
82
+ toPascalCase('hello-world'); // "HelloWorld"
83
+ toPascalCase('hello_world'); // "HelloWorld"
84
+
85
+ // Capitalize first letter
86
+ capitalizeWord('hello'); // "Hello"
87
+ capitalizeWord('hello world'); // "Hello world"
88
88
  ```
89
89
 
90
90
  ### Time Formatting
@@ -93,555 +93,391 @@ console.log(trim('[test]', '\\[|\\]')); // 'test'
93
93
  import {
94
94
  secondsToHMS,
95
95
  secondsToMS,
96
- millisecondsToHMS,
97
- sleep
96
+ millisecondsToHMS
98
97
  } from '@ooneex/utils';
99
98
 
100
- // Convert seconds to time formats
101
- console.log(secondsToHMS(3661)); // '1:01:01'
102
- console.log(secondsToHMS(125)); // '2:05'
103
- console.log(secondsToHMS(45)); // '45'
99
+ // Seconds to Hours:Minutes:Seconds
100
+ secondsToHMS(3661); // "1:01:01"
101
+ secondsToHMS(125); // "0:02:05"
102
+
103
+ // Seconds to Minutes:Seconds
104
+ secondsToMS(125); // "2:05"
105
+ secondsToMS(65); // "1:05"
106
+
107
+ // Milliseconds to Hours:Minutes:Seconds
108
+ millisecondsToHMS(3661000); // "1:01:01"
109
+ millisecondsToHMS(125000); // "0:02:05"
110
+ ```
104
111
 
105
- console.log(secondsToMS(125)); // '2:05'
106
- console.log(secondsToMS(45)); // '0:45'
112
+ ### Number Formatting
107
113
 
108
- // Convert milliseconds to time format
109
- console.log(millisecondsToHMS(3661000)); // '1:01:01'
110
- console.log(millisecondsToHMS(125000)); // '2:05'
114
+ ```typescript
115
+ import { formatRelativeNumber } from '@ooneex/utils';
111
116
 
112
- // Async sleep utility
113
- await sleep(1000); // Wait 1 second
117
+ // Format large numbers with suffixes
118
+ formatRelativeNumber(1000); // "1K"
119
+ formatRelativeNumber(1500); // "1.5K"
120
+ formatRelativeNumber(1000000); // "1M"
121
+ formatRelativeNumber(1500000); // "1.5M"
122
+ formatRelativeNumber(1000000000); // "1B"
123
+ formatRelativeNumber(999); // "999"
114
124
  ```
115
125
 
116
- ### Data Parsing
126
+ ### Async Sleep
117
127
 
118
128
  ```typescript
119
- import { parseString, parseEnvVars } from '@ooneex/utils';
120
-
121
- // Intelligent string parsing with type inference
122
- console.log(parseString('123')); // 123 (number)
123
- console.log(parseString('12.34')); // 12.34 (number)
124
- console.log(parseString('true')); // true (boolean)
125
- console.log(parseString('false')); // false (boolean)
126
- console.log(parseString('null')); // null
127
- console.log(parseString('[1,2,3]')); // [1, 2, 3] (array)
128
- console.log(parseString('{"name":"John"}')); // {name: "John"} (object)
129
- console.log(parseString('1e5')); // 100000 (scientific notation)
130
- console.log(parseString('hello')); // 'hello' (string fallback)
131
-
132
- // Parse environment variables
133
- const envs = {
134
- 'API_PORT': '3000',
135
- 'DEBUG_MODE': 'true',
136
- 'ALLOWED_HOSTS': '["localhost", "127.0.0.1"]'
137
- };
138
-
139
- const parsed = parseEnvVars(envs);
140
- // Result: { apiPort: 3000, debugMode: true, allowedHosts: ['localhost', '127.0.0.1'] }
129
+ import { sleep } from '@ooneex/utils';
130
+
131
+ async function example() {
132
+ console.log('Starting...');
133
+
134
+ // Wait for 2 seconds
135
+ await sleep(2000);
136
+
137
+ console.log('2 seconds later...');
138
+ }
141
139
  ```
142
140
 
143
- ### Number Formatting
141
+ ### String Utilities
144
142
 
145
143
  ```typescript
146
- import { formatRelativeNumber } from '@ooneex/utils';
144
+ import { trim, splitToWords, parseString } from '@ooneex/utils';
147
145
 
148
- // Format numbers with compact notation
149
- console.log(formatRelativeNumber(1000)); // '1K'
150
- console.log(formatRelativeNumber(1500)); // '1.5K'
151
- console.log(formatRelativeNumber(1000000)); // '1M'
152
- console.log(formatRelativeNumber(2500000)); // '2.5M'
153
- console.log(formatRelativeNumber(1000000000)); // '1B'
154
-
155
- // Custom precision
156
- console.log(formatRelativeNumber(1234, { precision: 2 })); // '1.23K'
157
- console.log(formatRelativeNumber(1234, { precision: 0 })); // '1K'
158
-
159
- // Different locales
160
- console.log(formatRelativeNumber(1500, { lang: 'de-DE' })); // '1500'
161
- console.log(formatRelativeNumber(1500000, { lang: 'de-DE' })); // '1,5 Mio.'
162
- console.log(formatRelativeNumber(1500, { lang: 'fr-FR' })); // '1,5 k'
146
+ // Trim whitespace and normalize
147
+ trim(' hello world '); // "hello world"
148
+
149
+ // Split string into words
150
+ splitToWords('helloWorld'); // ["hello", "World"]
151
+ splitToWords('hello-world'); // ["hello", "world"]
152
+ splitToWords('hello_world'); // ["hello", "world"]
153
+
154
+ // Parse string values
155
+ parseString('true'); // true (boolean)
156
+ parseString('false'); // false (boolean)
157
+ parseString('123'); // 123 (number)
158
+ parseString('hello'); // "hello" (string)
163
159
  ```
164
160
 
165
- ### File Utilities
161
+ ### Data URL Conversion
166
162
 
167
163
  ```typescript
168
164
  import { dataURLtoFile } from '@ooneex/utils';
169
165
 
170
- // Convert data URL to File object
171
- const dataUrl = 'data:text/plain;base64,SGVsbG8gV29ybGQ=';
172
- const file = dataURLtoFile(dataUrl, 'hello.txt');
166
+ // Convert a data URL to a File object
167
+ const dataUrl = 'data:image/png;base64,iVBORw0KGgo...';
168
+ const file = dataURLtoFile(dataUrl, 'image.png');
173
169
 
174
- console.log(file.name); // 'hello.txt'
175
- console.log(file.type); // 'text/plain'
176
- console.log(file.size); // 11
170
+ console.log(file.name); // "image.png"
171
+ console.log(file.type); // "image/png"
177
172
  ```
178
173
 
179
- ### Random Generation
174
+ ### Environment Variable Parsing
180
175
 
181
176
  ```typescript
182
- import { random } from '@ooneex/utils';
183
-
184
- // Generate random hex strings
185
- console.log(random.nanoid()); // 'a1b2c3d4e5' (10 chars default)
186
- console.log(random.nanoid(8)); // 'f6e5d4c3' (8 chars)
177
+ import { parseEnvVars } from '@ooneex/utils';
187
178
 
188
- // Generate numeric strings
189
- console.log(random.stringInt()); // '1234567890' (10 digits default)
190
- console.log(random.stringInt(6)); // '123456' (6 digits)
179
+ // Parse environment variable content
180
+ const envContent = `
181
+ DATABASE_URL=postgresql://localhost:5432/mydb
182
+ API_KEY=secret-key-123
183
+ DEBUG=true
184
+ PORT=3000
185
+ `;
191
186
 
192
- // Create a factory function
193
- const generateId = random.nanoidFactory(12);
194
- console.log(generateId()); // 12-character hex string
195
- console.log(generateId(8)); // 8-character hex string (overrides factory size)
187
+ const vars = parseEnvVars(envContent);
188
+ // {
189
+ // DATABASE_URL: 'postgresql://localhost:5432/mydb',
190
+ // API_KEY: 'secret-key-123',
191
+ // DEBUG: 'true',
192
+ // PORT: '3000'
193
+ // }
196
194
  ```
197
195
 
198
196
  ## API Reference
199
197
 
200
- ### String Utilities
198
+ ### Functions
201
199
 
202
- #### `capitalizeWord(word: string): string`
203
- Capitalizes the first letter and lowercases the rest.
200
+ #### `random(size?: number): string`
201
+
202
+ Generates a unique ID using nanoid.
204
203
 
205
204
  **Parameters:**
206
- - `word` - The word to capitalize
205
+ - `size` - Optional length of the ID (default: 21)
207
206
 
208
- **Returns:** Capitalized word
207
+ **Returns:** A unique string ID
209
208
 
210
209
  **Example:**
211
210
  ```typescript
212
- capitalizeWord('hello'); // 'Hello'
213
- capitalizeWord('WORLD'); // 'World'
214
- capitalizeWord(''); // ''
211
+ const id = random(); // "V1StGXR8_Z5jdHi6B-myT"
212
+ const short = random(8); // "V1StGXR8"
215
213
  ```
216
214
 
217
- #### `toCamelCase(input: string): string`
218
- Converts string to camelCase.
215
+ ---
216
+
217
+ #### `toCamelCase(str: string): string`
218
+
219
+ Converts a string to camelCase.
219
220
 
220
221
  **Parameters:**
221
- - `input` - The string to convert
222
+ - `str` - The input string
222
223
 
223
- **Returns:** camelCase string
224
+ **Returns:** camelCase formatted string
224
225
 
225
- **Example:**
226
- ```typescript
227
- toCamelCase('hello world'); // 'helloWorld'
228
- toCamelCase('Hello-World_Example'); // 'helloWorldExample'
229
- toCamelCase('API_KEY'); // 'apiKey'
230
- ```
226
+ ---
227
+
228
+ #### `toKebabCase(str: string): string`
231
229
 
232
- #### `toPascalCase(input: string): string`
233
- Converts string to PascalCase.
230
+ Converts a string to kebab-case.
234
231
 
235
232
  **Parameters:**
236
- - `input` - The string to convert
233
+ - `str` - The input string
237
234
 
238
- **Returns:** PascalCase string
235
+ **Returns:** kebab-case formatted string
239
236
 
240
- **Example:**
241
- ```typescript
242
- toPascalCase('hello world'); // 'HelloWorld'
243
- toPascalCase('api-key'); // 'ApiKey'
244
- toPascalCase('user_name'); // 'UserName'
245
- ```
237
+ ---
238
+
239
+ #### `toSnakeCase(str: string): string`
246
240
 
247
- #### `toKebabCase(input: string): string`
248
- Converts string to kebab-case.
241
+ Converts a string to snake_case.
249
242
 
250
243
  **Parameters:**
251
- - `input` - The string to convert
244
+ - `str` - The input string
252
245
 
253
- **Returns:** kebab-case string
246
+ **Returns:** snake_case formatted string
254
247
 
255
- **Example:**
256
- ```typescript
257
- toKebabCase('Hello World'); // 'hello-world'
258
- toKebabCase('camelCaseString'); // 'camel-case-string'
259
- toKebabCase('PascalCaseString'); // 'pascal-case-string'
260
- ```
248
+ ---
249
+
250
+ #### `toPascalCase(str: string): string`
261
251
 
262
- #### `splitToWords(input: string): string[]`
263
- Splits a string into individual words, handling various naming conventions.
252
+ Converts a string to PascalCase.
264
253
 
265
254
  **Parameters:**
266
- - `input` - The string to split
255
+ - `str` - The input string
267
256
 
268
- **Returns:** Array of words
257
+ **Returns:** PascalCase formatted string
269
258
 
270
- **Example:**
271
- ```typescript
272
- splitToWords('HelloWorld'); // ['Hello', 'World']
273
- splitToWords('hello-world_example'); // ['hello', 'world', 'example']
274
- splitToWords('XMLHttpRequest'); // ['XML', 'Http', 'Request']
275
- splitToWords('user123Name'); // ['user', '123', 'Name']
276
- ```
259
+ ---
260
+
261
+ #### `capitalizeWord(str: string): string`
277
262
 
278
- #### `trim(text: string, char?: string): string`
279
- Trims specified characters from the beginning and end of a string.
263
+ Capitalizes the first letter of a string.
280
264
 
281
265
  **Parameters:**
282
- - `text` - The string to trim
283
- - `char` - Characters to trim (default: space). Supports regex patterns.
266
+ - `str` - The input string
284
267
 
285
- **Returns:** Trimmed string
268
+ **Returns:** String with first letter capitalized
286
269
 
287
- **Example:**
288
- ```typescript
289
- trim(' hello '); // 'hello'
290
- trim('...hello...', '\\.'); // 'hello'
291
- trim('[test]', '\\[|\\]'); // 'test'
292
- trim('!!hello!!', '!'); // 'hello'
293
- ```
270
+ ---
294
271
 
295
- ### Time Utilities
272
+ #### `splitToWords(str: string): string[]`
296
273
 
297
- #### `secondsToHMS(seconds: number): string`
298
- Converts seconds to HH:MM:SS or MM:SS or SS format.
274
+ Splits a string into an array of words.
299
275
 
300
276
  **Parameters:**
301
- - `seconds` - Number of seconds
277
+ - `str` - The input string (camelCase, kebab-case, snake_case, or space-separated)
302
278
 
303
- **Returns:** Formatted time string
279
+ **Returns:** Array of words
304
280
 
305
- **Example:**
306
- ```typescript
307
- secondsToHMS(3661); // '1:01:01' (1 hour, 1 minute, 1 second)
308
- secondsToHMS(125); // '2:05' (2 minutes, 5 seconds)
309
- secondsToHMS(45); // '45' (45 seconds)
310
- secondsToHMS(0); // '0'
311
- ```
281
+ ---
312
282
 
313
- #### `secondsToMS(seconds: number): string`
314
- Converts seconds to MM:SS format.
283
+ #### `trim(str: string): string`
284
+
285
+ Trims whitespace and normalizes internal spacing.
315
286
 
316
287
  **Parameters:**
317
- - `seconds` - Number of seconds
288
+ - `str` - The input string
318
289
 
319
- **Returns:** MM:SS formatted string
290
+ **Returns:** Trimmed and normalized string
320
291
 
321
- **Example:**
322
- ```typescript
323
- secondsToMS(125); // '2:05'
324
- secondsToMS(45); // '0:45'
325
- secondsToMS(3661); // '61:01'
326
- ```
292
+ ---
293
+
294
+ #### `secondsToHMS(seconds: number): string`
327
295
 
328
- #### `millisecondsToHMS(ms: number): string`
329
- Converts milliseconds to HH:MM:SS or MM:SS or SS format.
296
+ Converts seconds to H:MM:SS format.
330
297
 
331
298
  **Parameters:**
332
- - `ms` - Number of milliseconds
299
+ - `seconds` - Number of seconds
333
300
 
334
301
  **Returns:** Formatted time string
335
302
 
336
- **Example:**
337
- ```typescript
338
- millisecondsToHMS(3661000); // '1:01:01'
339
- millisecondsToHMS(125000); // '2:05'
340
- millisecondsToHMS(45000); // '45'
341
- millisecondsToHMS(500); // '0'
342
- ```
303
+ ---
343
304
 
344
- #### `sleep(ms: number): Promise<void>`
345
- Creates a promise that resolves after the specified number of milliseconds.
305
+ #### `secondsToMS(seconds: number): string`
346
306
 
347
- **Parameters:**
348
- - `ms` - Number of milliseconds to wait
307
+ Converts seconds to M:SS format.
349
308
 
350
- **Returns:** Promise that resolves after the delay
309
+ **Parameters:**
310
+ - `seconds` - Number of seconds
351
311
 
352
- **Example:**
353
- ```typescript
354
- await sleep(1000); // Wait 1 second
355
- await sleep(500); // Wait 0.5 seconds
312
+ **Returns:** Formatted time string
356
313
 
357
- // Usage in async function
358
- async function delayedLog() {
359
- console.log('First');
360
- await sleep(2000);
361
- console.log('Second (2 seconds later)');
362
- }
363
- ```
314
+ ---
364
315
 
365
- ### Data Parsing
316
+ #### `millisecondsToHMS(milliseconds: number): string`
366
317
 
367
- #### `parseString<T>(text: string): T`
368
- Intelligently parses a string and returns the appropriate type.
318
+ Converts milliseconds to H:MM:SS format.
369
319
 
370
320
  **Parameters:**
371
- - `text` - The string to parse
321
+ - `milliseconds` - Number of milliseconds
372
322
 
373
- **Returns:** Parsed value with inferred type
323
+ **Returns:** Formatted time string
374
324
 
375
- **Supported Formats:**
376
- - Integers: `"123"` → `123`
377
- - Floats: `"12.34"` → `12.34`
378
- - Scientific notation: `"1e5"` → `100000`
379
- - Booleans: `"true"`, `"false"` (case insensitive)
380
- - Null: `"null"` (case insensitive)
381
- - Arrays: `"[1,2,3]"` → `[1, 2, 3]`
382
- - Objects: `'{"key":"value"}'` → `{key: "value"}`
383
- - JSON strings: `'"hello"'` → `"hello"`
325
+ ---
384
326
 
385
- **Example:**
386
- ```typescript
387
- parseString('123'); // 123 (number)
388
- parseString('12.34'); // 12.34 (number)
389
- parseString('1e3'); // 1000 (number)
390
- parseString('true'); // true (boolean)
391
- parseString('null'); // null
392
- parseString('[1,2,3]'); // [1, 2, 3] (array)
393
- parseString('{"name":"John"}'); // {name: "John"} (object)
394
- parseString('hello'); // 'hello' (string fallback)
395
-
396
- // With type annotation
397
- const num = parseString<number>('123'); // TypeScript knows it's a number
398
- const arr = parseString<number[]>('[1,2,3]'); // TypeScript knows it's number[]
399
- ```
327
+ #### `formatRelativeNumber(num: number): string`
400
328
 
401
- #### `parseEnvVars<T>(envs: Record<string, string>): T`
402
- Parses environment variables, converting keys to camelCase and values using `parseString`.
329
+ Formats a number with K, M, or B suffix.
403
330
 
404
331
  **Parameters:**
405
- - `envs` - Object with environment variable key-value pairs
332
+ - `num` - The number to format
406
333
 
407
- **Returns:** Object with camelCase keys and parsed values
334
+ **Returns:** Formatted number string with suffix
408
335
 
409
- **Example:**
410
- ```typescript
411
- const envVars = {
412
- 'API_PORT': '3000',
413
- 'DEBUG_MODE': 'true',
414
- 'ALLOWED_HOSTS': '["localhost", "127.0.0.1"]',
415
- 'MAX_CONNECTIONS': '100',
416
- 'ENABLE_SSL': 'false'
417
- };
418
-
419
- const config = parseEnvVars(envVars);
420
- // Result:
421
- // {
422
- // apiPort: 3000,
423
- // debugMode: true,
424
- // allowedHosts: ['localhost', '127.0.0.1'],
425
- // maxConnections: 100,
426
- // enableSsl: false
427
- // }
428
-
429
- // With type annotation
430
- interface Config {
431
- apiPort: number;
432
- debugMode: boolean;
433
- allowedHosts: string[];
434
- }
435
- const typedConfig = parseEnvVars<Config>(envVars);
436
- ```
336
+ ---
437
337
 
438
- ### Number Utilities
338
+ #### `sleep(ms: number): Promise<void>`
439
339
 
440
- #### `formatRelativeNumber(num: number, config?: { precision?: number; lang?: string }): string`
441
- Formats numbers using compact notation with locale support.
340
+ Pauses execution for the specified duration.
442
341
 
443
342
  **Parameters:**
444
- - `num` - The number to format
445
- - `config.precision` - Maximum decimal places (default: 1)
446
- - `config.lang` - Locale code (default: 'en-GB')
343
+ - `ms` - Duration in milliseconds
447
344
 
448
- **Returns:** Formatted number string
345
+ **Returns:** Promise that resolves after the duration
449
346
 
450
- **Example:**
451
- ```typescript
452
- formatRelativeNumber(1000); // '1K'
453
- formatRelativeNumber(1500); // '1.5K'
454
- formatRelativeNumber(1000000); // '1M'
455
- formatRelativeNumber(1000000000); // '1B'
456
-
457
- // Custom precision
458
- formatRelativeNumber(1234, { precision: 2 }); // '1.23K'
459
- formatRelativeNumber(1234, { precision: 0 }); // '1K'
460
-
461
- // Different locales
462
- formatRelativeNumber(1500, { lang: 'de-DE' }); // '1500'
463
- formatRelativeNumber(1500000, { lang: 'de-DE' }); // '1,5 Mio.'
464
- formatRelativeNumber(1500, { lang: 'fr-FR' }); // '1,5 k'
465
- formatRelativeNumber(1500, { lang: 'es-ES' }); // '1,5 mil'
466
- ```
347
+ ---
467
348
 
468
- ### File Utilities
349
+ #### `dataURLtoFile(dataUrl: string, filename: string): File`
469
350
 
470
- #### `dataURLtoFile(dataurl: string, filename: string): File`
471
351
  Converts a data URL to a File object.
472
352
 
473
353
  **Parameters:**
474
- - `dataurl` - The data URL string
475
- - `filename` - The desired filename for the File object
354
+ - `dataUrl` - The data URL string
355
+ - `filename` - Name for the resulting file
476
356
 
477
357
  **Returns:** File object
478
358
 
479
- **Example:**
480
- ```typescript
481
- // Text file
482
- const textDataUrl = 'data:text/plain;base64,SGVsbG8gV29ybGQ=';
483
- const textFile = dataURLtoFile(textDataUrl, 'hello.txt');
484
- console.log(textFile.name); // 'hello.txt'
485
- console.log(textFile.type); // 'text/plain'
486
- console.log(textFile.size); // 11
487
-
488
- // Image file
489
- const imgDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';
490
- const imgFile = dataURLtoFile(imgDataUrl, 'pixel.png');
491
- console.log(imgFile.type); // 'image/png'
492
-
493
- // Usage with FileReader
494
- const reader = new FileReader();
495
- reader.onload = (e) => console.log(e.target?.result);
496
- reader.readAsText(textFile);
497
- ```
359
+ ---
498
360
 
499
- ### Random Generation
361
+ #### `parseString(value: string): string | number | boolean`
500
362
 
501
- #### `random.nanoid(size?: number): string`
502
- Generates a random hexadecimal string.
363
+ Parses a string value to its appropriate type.
503
364
 
504
365
  **Parameters:**
505
- - `size` - Length of the generated string (default: 10)
506
-
507
- **Returns:** Random hex string
508
-
509
- **Example:**
510
- ```typescript
511
- random.nanoid(); // 'a1b2c3d4e5' (10 characters)
512
- random.nanoid(8); // 'f6e5d4c3' (8 characters)
513
- random.nanoid(16); // '1a2b3c4d5e6f7890' (16 characters)
514
- ```
366
+ - `value` - The string to parse
515
367
 
516
- #### `random.stringInt(size?: number): string`
517
- Generates a random numeric string.
368
+ **Returns:** Parsed value (boolean, number, or string)
518
369
 
519
- **Parameters:**
520
- - `size` - Length of the generated string (default: 10)
521
-
522
- **Returns:** Random numeric string
370
+ ---
523
371
 
524
- **Example:**
525
- ```typescript
526
- random.stringInt(); // '1234567890' (10 digits)
527
- random.stringInt(6); // '123456' (6 digits)
528
- random.stringInt(4); // '9876' (4 digits)
529
- ```
372
+ #### `parseEnvVars(content: string): Record<string, string>`
530
373
 
531
- #### `random.nanoidFactory(size?: number): (size?: number) => string`
532
- Creates a factory function for generating random hex strings.
374
+ Parses environment variable content.
533
375
 
534
376
  **Parameters:**
535
- - `size` - Default length for the factory (default: 10)
377
+ - `content` - Raw environment variable content
536
378
 
537
- **Returns:** Factory function that accepts optional size parameter
538
-
539
- **Example:**
540
- ```typescript
541
- const generateId = random.nanoidFactory(12);
542
- generateId(); // 12-character hex string
543
- generateId(8); // 8-character hex string (overrides factory default)
544
- generateId(16); // 16-character hex string
545
-
546
- const generateShortId = random.nanoidFactory(6);
547
- generateShortId(); // 6-character hex string
548
- ```
379
+ **Returns:** Object with key-value pairs
549
380
 
550
381
  ## Advanced Usage
551
382
 
552
- ### Environment Configuration
383
+ ### Building File Names
553
384
 
554
385
  ```typescript
555
- import { parseEnvVars } from '@ooneex/utils';
386
+ import { toKebabCase, random } from '@ooneex/utils';
556
387
 
557
- // Define your configuration interface
558
- interface AppConfig {
559
- port: number;
560
- host: string;
561
- debug: boolean;
562
- features: string[];
563
- dbConfig: {
564
- host: string;
565
- port: number;
566
- };
388
+ function generateFileName(title: string, extension: string): string {
389
+ const slug = toKebabCase(title);
390
+ const uniqueId = random(8);
391
+ return `${slug}-${uniqueId}.${extension}`;
567
392
  }
568
393
 
569
- // Parse environment variables
570
- const envConfig = parseEnvVars<Partial<AppConfig>>(process.env);
571
-
572
- // Merge with defaults
573
- const config: AppConfig = {
574
- port: 3000,
575
- host: 'localhost',
576
- debug: false,
577
- features: [],
578
- dbConfig: { host: 'localhost', port: 5432 },
579
- ...envConfig
580
- };
394
+ const fileName = generateFileName('My Awesome Photo', 'jpg');
395
+ // "my-awesome-photo-V1StGXR8.jpg"
581
396
  ```
582
397
 
583
- ### String Processing Pipeline
398
+ ### Formatting Display Values
584
399
 
585
400
  ```typescript
586
- import { splitToWords, toCamelCase, capitalizeWord } from '@ooneex/utils';
401
+ import { formatRelativeNumber, capitalizeWord } from '@ooneex/utils';
587
402
 
588
- function processUserInput(input: string): {
589
- words: string[];
590
- camelCase: string;
591
- title: string;
592
- kebabCase: string;
593
- } {
594
- const words = splitToWords(input);
403
+ interface SocialStats {
404
+ followers: number;
405
+ likes: number;
406
+ views: number;
407
+ }
595
408
 
409
+ function formatStats(stats: SocialStats): Record<string, string> {
596
410
  return {
597
- words,
598
- camelCase: toCamelCase(input),
599
- title: words.map(capitalizeWord).join(' '),
600
- kebabCase: toKebabCase(input)
411
+ followers: formatRelativeNumber(stats.followers),
412
+ likes: formatRelativeNumber(stats.likes),
413
+ views: formatRelativeNumber(stats.views)
601
414
  };
602
415
  }
603
416
 
604
- const result = processUserInput('user-profile_settings');
605
- // {
606
- // words: ['user', 'profile', 'settings'],
607
- // camelCase: 'userProfileSettings',
608
- // title: 'User Profile Settings',
609
- // kebabCase: 'user-profile-settings'
610
- // }
417
+ const stats = formatStats({
418
+ followers: 15600,
419
+ likes: 1200000,
420
+ views: 45000
421
+ });
422
+ // { followers: "15.6K", likes: "1.2M", views: "45K" }
611
423
  ```
612
424
 
613
- ### Time-based Progress Tracking
425
+ ### Video Duration Display
614
426
 
615
427
  ```typescript
616
- import { millisecondsToHMS, formatRelativeNumber } from '@ooneex/utils';
428
+ import { secondsToHMS, secondsToMS } from '@ooneex/utils';
617
429
 
618
- class ProgressTracker {
619
- private startTime: number;
620
- private itemsProcessed: number = 0;
621
- private totalItems: number;
430
+ function formatDuration(seconds: number): string {
431
+ // Use H:MM:SS for videos over an hour, otherwise M:SS
432
+ return seconds >= 3600
433
+ ? secondsToHMS(seconds)
434
+ : secondsToMS(seconds);
435
+ }
622
436
 
623
- constructor(totalItems: number) {
624
- this.startTime = Date.now();
625
- this.totalItems = totalItems;
626
- }
437
+ console.log(formatDuration(90)); // "1:30"
438
+ console.log(formatDuration(3700)); // "1:01:40"
439
+ ```
440
+
441
+ ### Retry with Delay
627
442
 
628
- update(processed: number): string {
629
- this.itemsProcessed = processed;
630
- const elapsed = Date.now() - this.startTime;
631
- const rate = processed / (elapsed / 1000);
632
- const remaining = (this.totalItems - processed) / rate * 1000;
633
-
634
- return [
635
- `Processed: ${formatRelativeNumber(processed)}/${formatRelativeNumber(this.totalItems)}`,
636
- `Elapsed: ${millisecondsToHMS(elapsed)}`,
637
- `ETA: ${millisecondsToHMS(remaining)}`
638
- ].join(' | ');
443
+ ```typescript
444
+ import { sleep } from '@ooneex/utils';
445
+
446
+ async function retryWithBackoff<T>(
447
+ fn: () => Promise<T>,
448
+ maxRetries: number = 3,
449
+ baseDelay: number = 1000
450
+ ): Promise<T> {
451
+ let lastError: Error;
452
+
453
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
454
+ try {
455
+ return await fn();
456
+ } catch (error) {
457
+ lastError = error as Error;
458
+ const delay = baseDelay * Math.pow(2, attempt);
459
+ console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`);
460
+ await sleep(delay);
461
+ }
639
462
  }
463
+
464
+ throw lastError!;
465
+ }
466
+ ```
467
+
468
+ ### API Route Slug Generation
469
+
470
+ ```typescript
471
+ import { toKebabCase } from '@ooneex/utils';
472
+
473
+ function generateApiSlug(resourceName: string, action: string): string {
474
+ const resource = toKebabCase(resourceName);
475
+ const actionSlug = toKebabCase(action);
476
+ return `/api/${resource}/${actionSlug}`;
640
477
  }
641
478
 
642
- const tracker = new ProgressTracker(100000);
643
- console.log(tracker.update(15000));
644
- // "Processed: 15K/100K | Elapsed: 2:30 | ETA: 14:10"
479
+ generateApiSlug('UserProfile', 'getById'); // "/api/user-profile/get-by-id"
480
+ generateApiSlug('BlogPost', 'create'); // "/api/blog-post/create"
645
481
  ```
646
482
 
647
483
  ## License
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  declare const capitalizeWord: (word: string) => string;
2
- declare const dataURLtoFile: (dataurl: string, filename: string) => File;
2
+ declare const dataURLtoFile: (dataUrl: string, filename: string) => File;
3
3
  declare const formatRelativeNumber: (num: number, config?: {
4
4
  precision?: number;
5
5
  lang?: string;
package/dist/index.js.map CHANGED
@@ -3,7 +3,7 @@
3
3
  "sources": ["src/capitalizeWord.ts", "src/dataURLtoFile.ts", "src/formatRelativeNumber.ts", "src/millisecondsToHMS.ts", "src/trim.ts", "src/parseString.ts", "src/splitToWords.ts", "src/toCamelCase.ts", "src/parseEnvVars.ts", "src/random.ts", "src/secondsToHMS.ts", "src/secondsToMS.ts", "src/sleep.ts", "src/toKebabCase.ts", "src/toPascalCase.ts", "src/toSnakeCase.ts"],
4
4
  "sourcesContent": [
5
5
  "export const capitalizeWord = (word: string): string =>\n word ? word[0]?.toUpperCase() + word.slice(1).toLowerCase() : word;\n",
6
- "export const dataURLtoFile = (dataurl: string, filename: string): File => {\n const arr = dataurl.split(\",\");\n const mimeMatch = arr[0]?.match(/:(.*?);/);\n const mime = mimeMatch?.[1] || \"\";\n const bstr = atob(arr[1] as string);\n let n = bstr.length;\n const u8arr = new Uint8Array(n);\n while (n--) {\n u8arr[n] = bstr.charCodeAt(n);\n }\n return new File([u8arr], filename, { type: mime });\n};\n",
6
+ "export const dataURLtoFile = (dataUrl: string, filename: string): File => {\n const arr = dataUrl.split(\",\");\n const mimeMatch = arr[0]?.match(/:(.*?);/);\n const mime = mimeMatch?.[1] || \"\";\n const bstr = atob(arr[1] as string);\n let n = bstr.length;\n const u8arr = new Uint8Array(n);\n while (n--) {\n u8arr[n] = bstr.charCodeAt(n);\n }\n return new File([u8arr], filename, { type: mime });\n};\n",
7
7
  "export const formatRelativeNumber = (num: number, config?: { precision?: number; lang?: string }): string =>\n new Intl.NumberFormat(config?.lang ?? \"en-GB\", {\n notation: \"compact\",\n compactDisplay: \"short\",\n maximumFractionDigits: config?.precision ?? 1,\n }).format(num);\n",
8
8
  "export const millisecondsToHMS = (ms: number): string => {\n const totalSeconds = Math.floor(ms / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n if (hours > 0) {\n return `${hours}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\n }\n\n if (minutes > 0) {\n return `${minutes}:${seconds.toString().padStart(2, \"0\")}`;\n }\n\n return seconds.toString();\n};\n",
9
9
  "export const trim = (text: string, char = \" \"): string => {\n if ([\".\", \"[\", \"]\", \"(\", \")\", \"+\", \"*\", \"^\", \"$\", \"?\", \"/\", \"\\\\\"].includes(char)) {\n char = `\\\\${char}`;\n }\n\n const reg = new RegExp(`^${char}+|${char}+$`, \"g\");\n return text.replace(reg, \"\");\n};\n",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ooneex/utils",
3
- "description": "Common utility functions including unique ID generation with nanoid and helper methods",
4
- "version": "0.1.0",
3
+ "description": "General-purpose utility functions including unique ID generation with nanoid, type guards, and common helper methods",
4
+ "version": "0.2.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
@@ -25,10 +25,20 @@
25
25
  "test": "bun test tests",
26
26
  "build": "bunup",
27
27
  "lint": "tsgo --noEmit && bunx biome lint",
28
- "publish": "bun publish --tolerate-republish --access public"
28
+ "npm:publish": "bun publish --tolerate-republish --force --production --access public"
29
29
  },
30
30
  "dependencies": {
31
31
  "nanoid": "^5.1.6"
32
32
  },
33
- "devDependencies": {}
33
+ "devDependencies": {},
34
+ "keywords": [
35
+ "bun",
36
+ "helpers",
37
+ "nanoid",
38
+ "ooneex",
39
+ "tools",
40
+ "typescript",
41
+ "utilities",
42
+ "utils"
43
+ ]
34
44
  }