@akadenia/helpers 1.9.1 → 1.9.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.
- package/README.MD +342 -592
- package/package.json +19 -14
package/README.MD
CHANGED
|
@@ -1,28 +1,17 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<img src="https://cdn.akadenia.com/images/akadenia-webp/logo/horizontal-logo.svg" alt="Akadenia" width="200" />
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
<h2><code>@akadenia/helpers</code></h2>
|
|
5
5
|
|
|
6
6
|
<img src="https://cdn.akadenia.com/images/badges/npm-version-helpers.svg" alt="npm version" />
|
|
7
7
|
<img src="https://cdn.akadenia.com/images/badges/license-mit.svg" alt="License: MIT" />
|
|
8
8
|
<img src="https://cdn.akadenia.com/images/badges/typescript.svg" alt="TypeScript" />
|
|
9
9
|
|
|
10
|
-
A
|
|
10
|
+
A zero-dependency TypeScript utility library covering the common ground every project needs — dates, strings, objects, geography, files, and more. Modular by design, so you only import what you use.
|
|
11
11
|
|
|
12
|
-
[Documentation](https://akadenia.com/packages/akadenia-helpers)
|
|
12
|
+
[Documentation](https://akadenia.com/packages/akadenia-helpers) · [GitHub](https://github.com/akadenia/AkadeniaHelpers) · [Issues](https://github.com/akadenia/AkadeniaHelpers/issues)
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
-
## Features
|
|
16
|
-
|
|
17
|
-
- **Date Helpers**: Comprehensive date manipulation and formatting utilities
|
|
18
|
-
- **Text Helpers**: String processing, validation, and transformation functions
|
|
19
|
-
- **Object Helpers**: Object manipulation, filtering, and utility functions
|
|
20
|
-
- **Map Helpers**: Geographical calculations and coordinate operations
|
|
21
|
-
- **Generic Helpers**: General utility functions for common operations
|
|
22
|
-
- **File Helpers**: File validation and processing utilities
|
|
23
|
-
- **TypeScript Support**: Full type definitions included
|
|
24
|
-
- **Zero Dependencies**: Lightweight with no external dependencies
|
|
25
|
-
|
|
26
15
|
## Installation
|
|
27
16
|
|
|
28
17
|
```bash
|
|
@@ -37,8 +26,6 @@ import { DateHelpers, TextHelpers, ObjectHelpers, MapHelpers, GenericHelpers, Fi
|
|
|
37
26
|
|
|
38
27
|
## Table of Contents
|
|
39
28
|
|
|
40
|
-
- [Installation](#installation)
|
|
41
|
-
- [Usage](#usage)
|
|
42
29
|
- [DateHelpers](#datehelpers)
|
|
43
30
|
- [TextHelpers](#texthelpers)
|
|
44
31
|
- [ObjectHelpers](#objecthelpers)
|
|
@@ -46,913 +33,715 @@ import { DateHelpers, TextHelpers, ObjectHelpers, MapHelpers, GenericHelpers, Fi
|
|
|
46
33
|
- [GenericHelpers](#generichelpers)
|
|
47
34
|
- [FileHelpers](#filehelpers)
|
|
48
35
|
- [Contributing](#contributing)
|
|
49
|
-
- [License](#license)
|
|
50
36
|
|
|
51
|
-
|
|
37
|
+
---
|
|
52
38
|
|
|
53
|
-
|
|
39
|
+
## DateHelpers
|
|
54
40
|
|
|
55
41
|
### `getReadableDateTime(datetime?)`
|
|
56
42
|
|
|
57
43
|
Returns the date in `yyyy-mm-dd hh:mm:ss` format.
|
|
58
44
|
|
|
59
45
|
**Parameters:**
|
|
60
|
-
- `datetime` (optional): `Date`
|
|
46
|
+
- `datetime` (optional): `Date` — The date to convert. Defaults to current date.
|
|
61
47
|
|
|
62
48
|
**Example:**
|
|
63
49
|
```typescript
|
|
64
50
|
import { DateHelpers } from '@akadenia/helpers'
|
|
65
51
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
console.log(now) // "2024-01-15 14:30:25"
|
|
52
|
+
DateHelpers.getReadableDateTime()
|
|
53
|
+
// "2026-02-27 15:30:25"
|
|
69
54
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
console.log(specificDate) // "2024-01-15 10:30:00"
|
|
55
|
+
DateHelpers.getReadableDateTime(new Date('2024-01-15T10:30:00Z'))
|
|
56
|
+
// "2024-01-15 10:30:00"
|
|
73
57
|
```
|
|
74
58
|
|
|
59
|
+
---
|
|
60
|
+
|
|
75
61
|
### `getReadableDate(datetime?)`
|
|
76
62
|
|
|
77
63
|
Returns the date in `yyyy-mm-dd` format.
|
|
78
64
|
|
|
79
65
|
**Parameters:**
|
|
80
|
-
- `datetime` (optional): `Date`
|
|
66
|
+
- `datetime` (optional): `Date` — The date to convert. Defaults to current date.
|
|
81
67
|
|
|
82
68
|
**Example:**
|
|
83
69
|
```typescript
|
|
84
|
-
|
|
85
|
-
|
|
70
|
+
DateHelpers.getReadableDate()
|
|
71
|
+
// "2026-02-27"
|
|
86
72
|
|
|
87
|
-
|
|
88
|
-
|
|
73
|
+
DateHelpers.getReadableDate(new Date('2024-01-15T10:30:00Z'))
|
|
74
|
+
// "2024-01-15"
|
|
89
75
|
```
|
|
90
76
|
|
|
77
|
+
---
|
|
78
|
+
|
|
91
79
|
### `getDateString(date)`
|
|
92
80
|
|
|
93
|
-
Returns a
|
|
81
|
+
Returns a locale-formatted date string.
|
|
94
82
|
|
|
95
83
|
**Parameters:**
|
|
96
|
-
- `date`: `string | Date`
|
|
84
|
+
- `date`: `string | Date` — The date to convert.
|
|
97
85
|
|
|
98
86
|
**Example:**
|
|
99
87
|
```typescript
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const dateString2 = DateHelpers.getDateString(new Date('2024-01-15T10:30:00Z'))
|
|
104
|
-
console.log(dateString2) // "1/15/2024"
|
|
88
|
+
DateHelpers.getDateString('2024-01-15')
|
|
89
|
+
// "1/15/2024" (locale-dependent)
|
|
105
90
|
```
|
|
106
91
|
|
|
92
|
+
---
|
|
93
|
+
|
|
107
94
|
### `formatDateTime(date, options, localTimezone?)`
|
|
108
95
|
|
|
109
|
-
Returns a formatted date string using Intl.DateTimeFormat options.
|
|
96
|
+
Returns a formatted date string using `Intl.DateTimeFormat` options.
|
|
110
97
|
|
|
111
98
|
**Parameters:**
|
|
112
|
-
- `date`: `string | Date`
|
|
113
|
-
- `options`: `Intl.DateTimeFormatOptions`
|
|
114
|
-
- `localTimezone` (optional): `string | Intl.Locale`
|
|
99
|
+
- `date`: `string | Date` — The date to format.
|
|
100
|
+
- `options`: `Intl.DateTimeFormatOptions` — Formatting options.
|
|
101
|
+
- `localTimezone` (optional): `string | Intl.Locale` — Locale. Defaults to `"en-US"`.
|
|
115
102
|
|
|
116
103
|
**Example:**
|
|
117
104
|
```typescript
|
|
118
|
-
|
|
105
|
+
DateHelpers.formatDateTime(
|
|
119
106
|
new Date('2024-01-15T10:30:00Z'),
|
|
120
|
-
{
|
|
121
|
-
year: 'numeric',
|
|
122
|
-
month: 'long',
|
|
123
|
-
day: 'numeric',
|
|
124
|
-
hour: '2-digit',
|
|
125
|
-
minute: '2-digit'
|
|
126
|
-
},
|
|
107
|
+
{ year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' },
|
|
127
108
|
'en-US'
|
|
128
109
|
)
|
|
129
|
-
|
|
110
|
+
// "January 15, 2024 at 10:30 AM"
|
|
130
111
|
```
|
|
131
112
|
|
|
113
|
+
---
|
|
114
|
+
|
|
132
115
|
### `parseDate(date)`
|
|
133
116
|
|
|
134
|
-
|
|
117
|
+
Parses a string or Date into a `Date` object. Throws on invalid input.
|
|
135
118
|
|
|
136
119
|
**Parameters:**
|
|
137
|
-
- `date`: `string | Date`
|
|
120
|
+
- `date`: `string | Date` — The date to parse.
|
|
138
121
|
|
|
139
122
|
**Example:**
|
|
140
123
|
```typescript
|
|
141
|
-
|
|
142
|
-
|
|
124
|
+
DateHelpers.parseDate('2024-01-15')
|
|
125
|
+
// Date object
|
|
143
126
|
|
|
144
|
-
|
|
145
|
-
//
|
|
127
|
+
DateHelpers.parseDate('invalid-date')
|
|
128
|
+
// throws Error: Cannot parse date: "invalid-date"
|
|
146
129
|
```
|
|
147
130
|
|
|
131
|
+
---
|
|
132
|
+
|
|
148
133
|
### `getShortOrdinalDate(date, appendTime?)`
|
|
149
134
|
|
|
150
|
-
Returns a
|
|
135
|
+
Returns a date in short ordinal format, e.g. `"Feb 27th 2026"`.
|
|
151
136
|
|
|
152
137
|
**Parameters:**
|
|
153
|
-
- `date`: `string | Date`
|
|
154
|
-
- `appendTime` (optional): `boolean`
|
|
138
|
+
- `date`: `string | Date` — The date to format.
|
|
139
|
+
- `appendTime` (optional): `boolean` — Whether to include time. Defaults to `false`.
|
|
155
140
|
|
|
156
141
|
**Example:**
|
|
157
142
|
```typescript
|
|
158
|
-
|
|
159
|
-
|
|
143
|
+
DateHelpers.getShortOrdinalDate('2024-01-15')
|
|
144
|
+
// "Jan 15th 2024"
|
|
160
145
|
|
|
161
|
-
|
|
162
|
-
|
|
146
|
+
DateHelpers.getShortOrdinalDate('2024-01-15T10:30:00Z', true)
|
|
147
|
+
// "Jan 15th 2024 10:30:00"
|
|
163
148
|
```
|
|
164
149
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
Utility functions for geographical calculations and map operations.
|
|
150
|
+
---
|
|
168
151
|
|
|
169
|
-
|
|
152
|
+
## TextHelpers
|
|
170
153
|
|
|
171
|
-
|
|
154
|
+
### `uuidv4()`
|
|
172
155
|
|
|
173
|
-
|
|
174
|
-
- `point1`: `number[] | undefined` - First point coordinates [longitude, latitude].
|
|
175
|
-
- `point2`: `number[] | undefined` - Second point coordinates [longitude, latitude].
|
|
156
|
+
Generates a random UUID v4 string.
|
|
176
157
|
|
|
177
158
|
**Example:**
|
|
178
159
|
```typescript
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const la = [-118.2437, 34.0522] // [lng, lat]
|
|
182
|
-
|
|
183
|
-
const distance = MapHelpers.getDistanceBetweenPoints(nyc, la)
|
|
184
|
-
console.log(distance) // 3944419.5 (meters, approximately 3944 km)
|
|
185
|
-
|
|
186
|
-
// Returns null for invalid points
|
|
187
|
-
const invalid = MapHelpers.getDistanceBetweenPoints(nyc, undefined)
|
|
188
|
-
console.log(invalid) // null
|
|
160
|
+
TextHelpers.uuidv4()
|
|
161
|
+
// "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
|
189
162
|
```
|
|
190
163
|
|
|
191
|
-
|
|
164
|
+
---
|
|
192
165
|
|
|
193
|
-
|
|
166
|
+
### `formatPosition(position)`
|
|
167
|
+
|
|
168
|
+
Returns a position number with the appropriate ordinal suffix.
|
|
194
169
|
|
|
195
170
|
**Parameters:**
|
|
196
|
-
- `
|
|
197
|
-
- `location2`: `number[] | undefined` - Second location coordinates [longitude, latitude].
|
|
198
|
-
- `precision` (optional): `number` - Decimal precision for comparison. Defaults to 6.
|
|
171
|
+
- `position`: `number` — The position.
|
|
199
172
|
|
|
200
173
|
**Example:**
|
|
201
174
|
```typescript
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
console.log(MapHelpers.compareLocations(loc1, loc3)) // false
|
|
208
|
-
console.log(MapHelpers.compareLocations(loc1, loc2, 3)) // true (within 3 decimal precision)
|
|
209
|
-
|
|
210
|
-
// Throws error for undefined locations
|
|
211
|
-
MapHelpers.compareLocations(loc1, undefined) // Error: location1 and location2 are required
|
|
175
|
+
TextHelpers.formatPosition(1) // "1st"
|
|
176
|
+
TextHelpers.formatPosition(2) // "2nd"
|
|
177
|
+
TextHelpers.formatPosition(3) // "3rd"
|
|
178
|
+
TextHelpers.formatPosition(4) // "4th"
|
|
179
|
+
TextHelpers.formatPosition(21) // "21st"
|
|
212
180
|
```
|
|
213
181
|
|
|
214
|
-
|
|
182
|
+
---
|
|
215
183
|
|
|
216
|
-
|
|
184
|
+
### `truncateText(text, characterLimit)`
|
|
185
|
+
|
|
186
|
+
Truncates text to the character limit, appending `"..."`.
|
|
217
187
|
|
|
218
188
|
**Parameters:**
|
|
219
|
-
- `
|
|
220
|
-
- `
|
|
189
|
+
- `text`: `string` — Text to truncate.
|
|
190
|
+
- `characterLimit`: `number` — Maximum number of characters.
|
|
221
191
|
|
|
222
192
|
**Example:**
|
|
223
193
|
```typescript
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const bearing = MapHelpers.getBearingToCoordinate({ startCoordinate: start, endCoordinate: end })
|
|
228
|
-
console.log(bearing) // 277.5 (degrees, approximately west)
|
|
229
|
-
|
|
230
|
-
// Throws error for undefined coordinates
|
|
231
|
-
MapHelpers.getBearingToCoordinate({ startCoordinate: start, endCoordinate: undefined })
|
|
232
|
-
// Error: startCoordinate and endCoordinate are required
|
|
194
|
+
TextHelpers.truncateText("Hello World", 5) // "He..."
|
|
195
|
+
TextHelpers.truncateText("Hello World", 20) // "Hello World"
|
|
233
196
|
```
|
|
234
197
|
|
|
235
|
-
|
|
198
|
+
---
|
|
236
199
|
|
|
237
|
-
|
|
200
|
+
### `fileNameFromPath(path)`
|
|
238
201
|
|
|
239
|
-
|
|
202
|
+
Extracts the filename from a file path.
|
|
240
203
|
|
|
241
|
-
|
|
204
|
+
**Parameters:**
|
|
205
|
+
- `path`: `string` — The file path.
|
|
242
206
|
|
|
243
207
|
**Example:**
|
|
244
208
|
```typescript
|
|
245
|
-
|
|
246
|
-
console.log(id) // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
|
209
|
+
TextHelpers.fileNameFromPath('/uploads/documents/file.pdf') // "file.pdf"
|
|
247
210
|
```
|
|
248
211
|
|
|
249
|
-
|
|
212
|
+
---
|
|
250
213
|
|
|
251
|
-
|
|
214
|
+
### `replaceSpacesWithUnderscore(s?)`
|
|
252
215
|
|
|
253
|
-
|
|
254
|
-
- `position`: `number` - The position number.
|
|
216
|
+
Replaces spaces with underscores.
|
|
255
217
|
|
|
256
218
|
**Example:**
|
|
257
219
|
```typescript
|
|
258
|
-
|
|
259
|
-
console.log(TextHelpers.formatPosition(2)) // "2nd"
|
|
260
|
-
console.log(TextHelpers.formatPosition(3)) // "3rd"
|
|
261
|
-
console.log(TextHelpers.formatPosition(4)) // "4th"
|
|
262
|
-
console.log(TextHelpers.formatPosition(21)) // "21st"
|
|
220
|
+
TextHelpers.replaceSpacesWithUnderscore("hello world") // "hello_world"
|
|
263
221
|
```
|
|
264
222
|
|
|
265
|
-
|
|
223
|
+
---
|
|
266
224
|
|
|
267
|
-
|
|
225
|
+
### `replaceUnderscoreWithSpaces(s?)`
|
|
268
226
|
|
|
269
|
-
|
|
270
|
-
- `text`: `string` - The text to truncate.
|
|
271
|
-
- `characterLimit`: `number` - Maximum number of characters.
|
|
227
|
+
Replaces underscores with spaces.
|
|
272
228
|
|
|
273
229
|
**Example:**
|
|
274
230
|
```typescript
|
|
275
|
-
|
|
276
|
-
console.log(short) // "He..."
|
|
277
|
-
|
|
278
|
-
const long = TextHelpers.truncateText("Hello World", 20)
|
|
279
|
-
console.log(long) // "Hello World"
|
|
231
|
+
TextHelpers.replaceUnderscoreWithSpaces("hello_world") // "hello world"
|
|
280
232
|
```
|
|
281
233
|
|
|
282
|
-
|
|
234
|
+
---
|
|
283
235
|
|
|
284
|
-
|
|
236
|
+
### `pluralizeOnCondition(word, condition)`
|
|
237
|
+
|
|
238
|
+
Pluralizes a word when the condition is `true`. Handles common English rules (`-y → -ies`, `-s/-sh/-ch/-x → -es`).
|
|
285
239
|
|
|
286
240
|
**Parameters:**
|
|
287
|
-
- `
|
|
241
|
+
- `word`: `string` — The word to pluralize.
|
|
242
|
+
- `condition`: `boolean` — Whether to pluralize.
|
|
288
243
|
|
|
289
244
|
**Example:**
|
|
290
245
|
```typescript
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
console.log(filename2) // "file.pdf"
|
|
246
|
+
TextHelpers.pluralizeOnCondition("item", true) // "items"
|
|
247
|
+
TextHelpers.pluralizeOnCondition("address", true) // "addresses"
|
|
248
|
+
TextHelpers.pluralizeOnCondition("library", true) // "libraries"
|
|
249
|
+
TextHelpers.pluralizeOnCondition("item", false) // "item"
|
|
296
250
|
```
|
|
297
251
|
|
|
298
|
-
|
|
252
|
+
---
|
|
299
253
|
|
|
300
|
-
|
|
254
|
+
### `convertSnakeToCamelCase(data)`
|
|
301
255
|
|
|
302
|
-
|
|
303
|
-
- `s` (optional): `string` - The string to process.
|
|
256
|
+
Converts `snake_case` to `camelCase` for strings, objects, or arrays of objects (deep).
|
|
304
257
|
|
|
305
258
|
**Example:**
|
|
306
259
|
```typescript
|
|
307
|
-
|
|
308
|
-
|
|
260
|
+
TextHelpers.convertSnakeToCamelCase("hello_world")
|
|
261
|
+
// "helloWorld"
|
|
309
262
|
|
|
310
|
-
|
|
311
|
-
|
|
263
|
+
TextHelpers.convertSnakeToCamelCase({ first_name: "John", user_info: { phone_number: "123" } })
|
|
264
|
+
// { firstName: "John", userInfo: { phoneNumber: "123" } }
|
|
312
265
|
```
|
|
313
266
|
|
|
314
|
-
|
|
267
|
+
---
|
|
315
268
|
|
|
316
|
-
|
|
269
|
+
### `convertCamelToSnakeCase(data)`
|
|
317
270
|
|
|
318
|
-
|
|
319
|
-
- `s` (optional): `string` - The string to process.
|
|
271
|
+
Converts `camelCase` to `snake_case` for strings, objects, or arrays of objects (deep).
|
|
320
272
|
|
|
321
273
|
**Example:**
|
|
322
274
|
```typescript
|
|
323
|
-
|
|
324
|
-
|
|
275
|
+
TextHelpers.convertCamelToSnakeCase("helloWorld")
|
|
276
|
+
// "hello_world"
|
|
277
|
+
|
|
278
|
+
TextHelpers.convertCamelToSnakeCase({ firstName: "John", userInfo: { phoneNumber: "123" } })
|
|
279
|
+
// { first_name: "John", user_info: { phone_number: "123" } }
|
|
325
280
|
```
|
|
326
281
|
|
|
327
|
-
|
|
282
|
+
---
|
|
328
283
|
|
|
329
|
-
|
|
284
|
+
### `convertCamelToKebabCase(word)`
|
|
330
285
|
|
|
331
|
-
|
|
332
|
-
- `word`: `string` - The word to pluralize.
|
|
333
|
-
- `condition`: `boolean` - Whether to pluralize.
|
|
286
|
+
Converts `camelCase` to `kebab-case`.
|
|
334
287
|
|
|
335
288
|
**Example:**
|
|
336
289
|
```typescript
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const plural2 = TextHelpers.pluralizeOnCondition("address", true)
|
|
341
|
-
console.log(plural2) // "addresses"
|
|
342
|
-
|
|
343
|
-
const plural3 = TextHelpers.pluralizeOnCondition("library", true)
|
|
344
|
-
console.log(plural3) // "libraries"
|
|
345
|
-
|
|
346
|
-
const singular = TextHelpers.pluralizeOnCondition("item", false)
|
|
347
|
-
console.log(singular) // "item"
|
|
290
|
+
TextHelpers.convertCamelToKebabCase("helloWorld") // "hello-world"
|
|
291
|
+
TextHelpers.convertCamelToKebabCase("XMLHttpRequest") // "xml-http-request"
|
|
348
292
|
```
|
|
349
293
|
|
|
350
|
-
|
|
294
|
+
---
|
|
351
295
|
|
|
352
|
-
|
|
296
|
+
### `convertKebabToCamelCase(word)`
|
|
353
297
|
|
|
354
|
-
|
|
355
|
-
- `data`: `string | Object | Array<Object>` - The data to convert.
|
|
298
|
+
Converts `kebab-case` to `CamelCase`.
|
|
356
299
|
|
|
357
300
|
**Example:**
|
|
358
301
|
```typescript
|
|
359
|
-
//
|
|
360
|
-
|
|
361
|
-
console.log(camelString) // "helloWorld"
|
|
362
|
-
|
|
363
|
-
// Object conversion
|
|
364
|
-
const camelObject = TextHelpers.convertSnakeToCamelCase({
|
|
365
|
-
first_name: "John",
|
|
366
|
-
last_name: "Doe",
|
|
367
|
-
user_info: {
|
|
368
|
-
phone_number: "123-456-7890"
|
|
369
|
-
}
|
|
370
|
-
})
|
|
371
|
-
console.log(camelObject)
|
|
372
|
-
// {
|
|
373
|
-
// firstName: "John",
|
|
374
|
-
// lastName: "Doe",
|
|
375
|
-
// userInfo: {
|
|
376
|
-
// phoneNumber: "123-456-7890"
|
|
377
|
-
// }
|
|
378
|
-
// }
|
|
302
|
+
TextHelpers.convertKebabToCamelCase("hello-world") // "HelloWorld"
|
|
303
|
+
TextHelpers.convertKebabToCamelCase("xml-http-request") // "XmlHttpRequest"
|
|
379
304
|
```
|
|
380
305
|
|
|
381
|
-
|
|
306
|
+
---
|
|
382
307
|
|
|
383
|
-
|
|
308
|
+
### `convertCamelCaseToReadableText(name)`
|
|
384
309
|
|
|
385
|
-
|
|
386
|
-
- `data`: `string | Object | Array<Object>` - The data to convert.
|
|
310
|
+
Converts `camelCase` to a space-separated readable string.
|
|
387
311
|
|
|
388
312
|
**Example:**
|
|
389
313
|
```typescript
|
|
390
|
-
//
|
|
391
|
-
|
|
392
|
-
console.log(snakeString) // "hello_world"
|
|
393
|
-
|
|
394
|
-
// Object conversion
|
|
395
|
-
const snakeObject = TextHelpers.convertCamelToSnakeCase({
|
|
396
|
-
firstName: "John",
|
|
397
|
-
lastName: "Doe",
|
|
398
|
-
userInfo: {
|
|
399
|
-
phoneNumber: "123-456-7890"
|
|
400
|
-
}
|
|
401
|
-
})
|
|
402
|
-
console.log(snakeObject)
|
|
403
|
-
// {
|
|
404
|
-
// first_name: "John",
|
|
405
|
-
// last_name: "Doe",
|
|
406
|
-
// user_info: {
|
|
407
|
-
// phone_number: "123-456-7890"
|
|
408
|
-
// }
|
|
409
|
-
// }
|
|
314
|
+
TextHelpers.convertCamelCaseToReadableText("helloWorld") // "Hello World"
|
|
315
|
+
TextHelpers.convertCamelCaseToReadableText("XMLHttpRequest") // "XML Http Request"
|
|
410
316
|
```
|
|
411
317
|
|
|
412
|
-
|
|
318
|
+
---
|
|
413
319
|
|
|
414
|
-
|
|
320
|
+
### `generateAcronym(term)`
|
|
415
321
|
|
|
416
|
-
|
|
417
|
-
- `word`: `string` - The word to convert.
|
|
322
|
+
Generates an acronym from the first letter of each word.
|
|
418
323
|
|
|
419
324
|
**Example:**
|
|
420
325
|
```typescript
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
const kebab2 = TextHelpers.convertCamelToKebabCase("XMLHttpRequest")
|
|
425
|
-
console.log(kebab2) // "xml-http-request"
|
|
326
|
+
TextHelpers.generateAcronym("Hyper Text Markup Language") // "HTML"
|
|
327
|
+
TextHelpers.generateAcronym("Application Programming Interface") // "API"
|
|
426
328
|
```
|
|
427
329
|
|
|
428
|
-
|
|
330
|
+
---
|
|
429
331
|
|
|
430
|
-
|
|
332
|
+
### `isAcronym(word)`
|
|
431
333
|
|
|
432
|
-
|
|
433
|
-
- `word`: `string` - The word to convert.
|
|
334
|
+
Returns `true` if the word is all uppercase (i.e. an acronym).
|
|
434
335
|
|
|
435
336
|
**Example:**
|
|
436
337
|
```typescript
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
const camel2 = TextHelpers.convertKebabToCamelCase("xml-http-request")
|
|
441
|
-
console.log(camel2) // "XmlHttpRequest"
|
|
338
|
+
TextHelpers.isAcronym("HTML") // true
|
|
339
|
+
TextHelpers.isAcronym("JavaScript") // false
|
|
442
340
|
```
|
|
443
341
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
Converts camelCase to readable text format with proper capitalization.
|
|
342
|
+
---
|
|
447
343
|
|
|
448
|
-
|
|
344
|
+
### `acronymToKebabCase(word)`
|
|
449
345
|
|
|
450
|
-
|
|
346
|
+
Converts an acronym to kebab-case. Throws if input is not an acronym.
|
|
451
347
|
|
|
452
348
|
**Example:**
|
|
453
|
-
|
|
454
349
|
```typescript
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
const readable2 = TextHelpers.convertCamelCaseToReadableText("XMLHttpRequest")
|
|
459
|
-
console.log(readable2) // "XML Http Request"
|
|
460
|
-
|
|
461
|
-
const readable3 = TextHelpers.convertCamelCaseToReadableText("userName")
|
|
462
|
-
console.log(readable3) // "User Name"
|
|
350
|
+
TextHelpers.acronymToKebabCase("HTML") // "h-t-m-l"
|
|
351
|
+
TextHelpers.acronymToKebabCase("API") // "a-p-i"
|
|
352
|
+
TextHelpers.acronymToKebabCase("html") // throws Error
|
|
463
353
|
```
|
|
464
354
|
|
|
465
|
-
|
|
355
|
+
---
|
|
466
356
|
|
|
467
|
-
|
|
357
|
+
### `handleNullDisplay(value, defaultValue?)`
|
|
358
|
+
|
|
359
|
+
Returns the value, or a default string if `null` or `undefined`.
|
|
468
360
|
|
|
469
361
|
**Parameters:**
|
|
470
|
-
- `
|
|
362
|
+
- `value`: `string | null | undefined`
|
|
363
|
+
- `defaultValue` (optional): `string` — Defaults to `"N/A"`.
|
|
471
364
|
|
|
472
365
|
**Example:**
|
|
473
366
|
```typescript
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
const acronym2 = TextHelpers.generateAcronym("JavaScript Object Notation")
|
|
478
|
-
console.log(acronym2) // "JSON"
|
|
367
|
+
TextHelpers.handleNullDisplay("Hello") // "Hello"
|
|
368
|
+
TextHelpers.handleNullDisplay(null) // "N/A"
|
|
369
|
+
TextHelpers.handleNullDisplay(null, "—") // "—"
|
|
479
370
|
```
|
|
480
371
|
|
|
481
|
-
|
|
372
|
+
---
|
|
482
373
|
|
|
483
|
-
|
|
374
|
+
### `capitalizeText(text?)`
|
|
484
375
|
|
|
485
|
-
|
|
486
|
-
- `word`: `string` - The word to validate.
|
|
376
|
+
Capitalizes the first letter, lowercases the rest.
|
|
487
377
|
|
|
488
378
|
**Example:**
|
|
489
379
|
```typescript
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
380
|
+
TextHelpers.capitalizeText("hello world") // "Hello world"
|
|
381
|
+
TextHelpers.capitalizeText("HELLO") // "Hello"
|
|
382
|
+
TextHelpers.capitalizeText() // ""
|
|
493
383
|
```
|
|
494
384
|
|
|
495
|
-
|
|
385
|
+
---
|
|
496
386
|
|
|
497
|
-
|
|
387
|
+
### `enforceCharacterLimit({ text, characterLimit, onCharacterLimit })`
|
|
498
388
|
|
|
499
|
-
|
|
500
|
-
- `word`: `string` - The acronym to convert.
|
|
389
|
+
Truncates text to the limit and calls a callback when the limit is hit.
|
|
501
390
|
|
|
502
391
|
**Example:**
|
|
503
392
|
```typescript
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
// Throws error if not an acronym
|
|
511
|
-
TextHelpers.acronymToKebabCase("html") // Error: The text passed: html is not an acronym.
|
|
393
|
+
TextHelpers.enforceCharacterLimit({
|
|
394
|
+
text: "This is a long text",
|
|
395
|
+
characterLimit: 10,
|
|
396
|
+
onCharacterLimit: () => console.log("Limit hit!"),
|
|
397
|
+
})
|
|
398
|
+
// "This is a" (and logs "Limit hit!")
|
|
512
399
|
```
|
|
513
400
|
|
|
514
|
-
|
|
401
|
+
---
|
|
515
402
|
|
|
516
|
-
|
|
403
|
+
### `isValidEmail(email)`
|
|
517
404
|
|
|
518
|
-
|
|
519
|
-
- `value`: `string | null | undefined` - The value to display.
|
|
520
|
-
- `defaultValue` (optional): `string` - Default value. Defaults to "N/A".
|
|
405
|
+
Validates an email address against RFC-compliant rules.
|
|
521
406
|
|
|
522
407
|
**Example:**
|
|
523
408
|
```typescript
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
409
|
+
TextHelpers.isValidEmail("user@example.com") // true
|
|
410
|
+
TextHelpers.isValidEmail("user@domain.co.uk") // true
|
|
411
|
+
TextHelpers.isValidEmail("invalid-email") // false
|
|
412
|
+
TextHelpers.isValidEmail("") // false
|
|
528
413
|
```
|
|
529
414
|
|
|
530
|
-
|
|
415
|
+
---
|
|
531
416
|
|
|
532
|
-
|
|
417
|
+
### `generateIDFromWord(text)`
|
|
533
418
|
|
|
534
|
-
|
|
535
|
-
- `text` (optional): `string` - The text to capitalize.
|
|
419
|
+
Converts a phrase to a lowercase hyphenated ID.
|
|
536
420
|
|
|
537
421
|
**Example:**
|
|
538
422
|
```typescript
|
|
539
|
-
|
|
540
|
-
console.log(TextHelpers.capitalizeText("HELLO")) // "Hello"
|
|
541
|
-
console.log(TextHelpers.capitalizeText()) // ""
|
|
423
|
+
TextHelpers.generateIDFromWord("My Awesome Feature") // "my-awesome-feature"
|
|
542
424
|
```
|
|
543
425
|
|
|
544
|
-
|
|
426
|
+
---
|
|
545
427
|
|
|
546
|
-
|
|
428
|
+
### `generateWordFromId(id, customList?)`
|
|
547
429
|
|
|
548
|
-
|
|
549
|
-
- `text`: `string` - The text to limit.
|
|
550
|
-
- `characterLimit`: `number` - Maximum characters allowed.
|
|
551
|
-
- `onCharacterLimit`: `() => void` - Callback when limit is exceeded.
|
|
430
|
+
Converts a hyphenated ID back to a readable title. Supports a custom lookup map.
|
|
552
431
|
|
|
553
432
|
**Example:**
|
|
554
433
|
```typescript
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
console.log(result) // "This is a" (truncated)
|
|
561
|
-
// Console: "Character limit exceeded!"
|
|
434
|
+
TextHelpers.generateWordFromId("hello-world-test")
|
|
435
|
+
// "Hello World Test"
|
|
436
|
+
|
|
437
|
+
TextHelpers.generateWordFromId("api", { api: "Application Programming Interface" })
|
|
438
|
+
// "Application Programming Interface"
|
|
562
439
|
```
|
|
563
440
|
|
|
564
|
-
|
|
441
|
+
---
|
|
565
442
|
|
|
566
|
-
|
|
443
|
+
### `generateSlugFromWordsWithID(id, ...words)`
|
|
567
444
|
|
|
568
|
-
|
|
569
|
-
- `email`: `string` - The email to validate.
|
|
445
|
+
Generates a URL-safe slug combining words and an ID.
|
|
570
446
|
|
|
571
447
|
**Example:**
|
|
572
448
|
```typescript
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
console.log(TextHelpers.isValidEmail("user@domain.co.uk")) // true
|
|
576
|
-
console.log(TextHelpers.isValidEmail("")) // false
|
|
449
|
+
TextHelpers.generateSlugFromWordsWithID("123", "Blog Post", "Tech")
|
|
450
|
+
// "blog-post-tech-123"
|
|
577
451
|
```
|
|
578
452
|
|
|
579
|
-
|
|
453
|
+
---
|
|
580
454
|
|
|
581
|
-
|
|
455
|
+
### `extractIDfromSlug(slug)`
|
|
582
456
|
|
|
583
|
-
|
|
584
|
-
- `text`: `string` - The text to convert to ID.
|
|
457
|
+
Extracts the last segment of a hyphenated slug (the ID).
|
|
585
458
|
|
|
586
459
|
**Example:**
|
|
587
460
|
```typescript
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
const id2 = TextHelpers.generateIDFromWord("My Awesome Feature")
|
|
592
|
-
console.log(id2) // "my-awesome-feature"
|
|
461
|
+
TextHelpers.extractIDfromSlug("my-blog-post-42") // "42"
|
|
462
|
+
TextHelpers.extractIDfromSlug("") // throws Error
|
|
593
463
|
```
|
|
594
464
|
|
|
595
|
-
|
|
465
|
+
---
|
|
596
466
|
|
|
597
|
-
|
|
467
|
+
### `abbreviateNumber(number)`
|
|
598
468
|
|
|
599
|
-
|
|
600
|
-
- `id`: `string` - The ID to convert.
|
|
601
|
-
- `customList` (optional): `Record<string, string>` - Custom mapping for specific IDs.
|
|
469
|
+
Abbreviates large numbers with K / M / B suffixes.
|
|
602
470
|
|
|
603
471
|
**Example:**
|
|
604
472
|
```typescript
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
473
|
+
TextHelpers.abbreviateNumber(500) // "500"
|
|
474
|
+
TextHelpers.abbreviateNumber(1500) // "1.5K"
|
|
475
|
+
TextHelpers.abbreviateNumber(1500000) // "1.5M"
|
|
476
|
+
TextHelpers.abbreviateNumber(1500000000) // "1.5B"
|
|
477
|
+
TextHelpers.abbreviateNumber(null) // null
|
|
610
478
|
```
|
|
611
479
|
|
|
612
|
-
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## ObjectHelpers
|
|
613
483
|
|
|
614
|
-
|
|
484
|
+
### `isPureObject(object)`
|
|
615
485
|
|
|
616
|
-
|
|
617
|
-
- `id`: `string` - The ID to include in the slug.
|
|
618
|
-
- `...words`: `string[]` - Additional words to include.
|
|
486
|
+
Returns `true` if the value is a plain object (not an array, Date, or function).
|
|
619
487
|
|
|
620
488
|
**Example:**
|
|
621
489
|
```typescript
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
console.log(slug2) // "hello%20world-test-123"
|
|
490
|
+
ObjectHelpers.isPureObject({}) // true
|
|
491
|
+
ObjectHelpers.isPureObject([]) // false
|
|
492
|
+
ObjectHelpers.isPureObject(new Date()) // false
|
|
493
|
+
ObjectHelpers.isPureObject(() => {}) // false
|
|
627
494
|
```
|
|
628
495
|
|
|
629
|
-
|
|
496
|
+
---
|
|
630
497
|
|
|
631
|
-
|
|
498
|
+
### `parseCookie(str)`
|
|
632
499
|
|
|
633
|
-
|
|
634
|
-
- `slug`: `string` - The slug to extract ID from.
|
|
500
|
+
Parses a `Cookie` header string into a key-value object.
|
|
635
501
|
|
|
636
502
|
**Example:**
|
|
637
503
|
```typescript
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
const id2 = TextHelpers.extractIDfromSlug("user-profile-abc")
|
|
642
|
-
console.log(id2) // "abc"
|
|
643
|
-
|
|
644
|
-
// Throws error for empty slug
|
|
645
|
-
TextHelpers.extractIDfromSlug("") // Error: slug cannot be empty, null or undefined string
|
|
504
|
+
ObjectHelpers.parseCookie("name=John; age=30; city=New York")
|
|
505
|
+
// { name: "John", age: "30", city: "New York" }
|
|
646
506
|
```
|
|
647
507
|
|
|
648
|
-
|
|
508
|
+
---
|
|
649
509
|
|
|
650
|
-
|
|
510
|
+
### `filterObjectsByProperty(array, propertyName, propertyValue)`
|
|
651
511
|
|
|
652
|
-
|
|
653
|
-
- `number`: `number | undefined | null` - The number to abbreviate.
|
|
512
|
+
Filters an array of objects by a specific property value.
|
|
654
513
|
|
|
655
514
|
**Example:**
|
|
656
515
|
```typescript
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
```
|
|
516
|
+
const users = [
|
|
517
|
+
{ id: 1, name: "John", role: "admin" },
|
|
518
|
+
{ id: 2, name: "Jane", role: "user" },
|
|
519
|
+
{ id: 3, name: "Bob", role: "admin" },
|
|
520
|
+
]
|
|
663
521
|
|
|
664
|
-
|
|
522
|
+
ObjectHelpers.filterObjectsByProperty(users, "role", "admin")
|
|
523
|
+
// [{ id: 1, ... }, { id: 3, ... }]
|
|
524
|
+
```
|
|
665
525
|
|
|
666
|
-
|
|
526
|
+
---
|
|
667
527
|
|
|
668
|
-
### `
|
|
528
|
+
### `containsSubObject(mainObject, subObject)`
|
|
669
529
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
**Parameters:**
|
|
673
|
-
- `object`: `any` - The object to check.
|
|
530
|
+
Returns `true` if the main object contains all the key-value pairs of the sub-object.
|
|
674
531
|
|
|
675
532
|
**Example:**
|
|
676
533
|
```typescript
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
console.log(ObjectHelpers.isPureObject("string")) // false
|
|
534
|
+
const user = { id: 1, name: "John", age: 30, city: "New York" }
|
|
535
|
+
|
|
536
|
+
ObjectHelpers.containsSubObject(user, { name: "John", age: 30 }) // true
|
|
537
|
+
ObjectHelpers.containsSubObject(user, { name: "Jane" }) // false
|
|
682
538
|
```
|
|
683
539
|
|
|
684
|
-
|
|
540
|
+
---
|
|
685
541
|
|
|
686
|
-
|
|
542
|
+
### `findObjectBySubObject(array, subObject)`
|
|
687
543
|
|
|
688
|
-
|
|
689
|
-
- `str`: `string` - The cookie string to parse.
|
|
544
|
+
Finds the first object in an array containing the specified sub-object. Returns `null` if not found.
|
|
690
545
|
|
|
691
546
|
**Example:**
|
|
692
547
|
```typescript
|
|
693
|
-
const
|
|
694
|
-
|
|
548
|
+
const users = [
|
|
549
|
+
{ id: 1, name: "John", city: "New York" },
|
|
550
|
+
{ id: 2, name: "Jane", city: "Boston" },
|
|
551
|
+
]
|
|
552
|
+
|
|
553
|
+
ObjectHelpers.findObjectBySubObject(users, { city: "Boston" })
|
|
554
|
+
// { id: 2, name: "Jane", city: "Boston" }
|
|
695
555
|
|
|
696
|
-
|
|
697
|
-
|
|
556
|
+
ObjectHelpers.findObjectBySubObject(users, { name: "Alice" })
|
|
557
|
+
// null
|
|
698
558
|
```
|
|
699
559
|
|
|
700
|
-
|
|
560
|
+
---
|
|
701
561
|
|
|
702
|
-
|
|
562
|
+
### `filterObjectsBySubObject(array, subObject)`
|
|
703
563
|
|
|
704
|
-
|
|
705
|
-
- `array`: `T[]` - Array of objects to filter.
|
|
706
|
-
- `propertyName`: `keyof T` - Name of the property to filter on.
|
|
707
|
-
- `propertyValue`: `T[keyof T]` - Value to match.
|
|
564
|
+
Filters an array of objects to those containing the specified sub-object.
|
|
708
565
|
|
|
709
566
|
**Example:**
|
|
710
567
|
```typescript
|
|
711
568
|
const users = [
|
|
712
569
|
{ id: 1, name: "John", age: 30 },
|
|
713
570
|
{ id: 2, name: "Jane", age: 25 },
|
|
714
|
-
{ id: 3, name: "
|
|
571
|
+
{ id: 3, name: "Bob", age: 30 },
|
|
715
572
|
]
|
|
716
573
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
const adults = ObjectHelpers.filterObjectsByProperty(users, "age", 30)
|
|
721
|
-
console.log(adults) // [{ id: 1, name: "John", age: 30 }]
|
|
574
|
+
ObjectHelpers.filterObjectsBySubObject(users, { age: 30 })
|
|
575
|
+
// [{ id: 1, ... }, { id: 3, ... }]
|
|
722
576
|
```
|
|
723
577
|
|
|
724
|
-
|
|
578
|
+
---
|
|
725
579
|
|
|
726
|
-
|
|
580
|
+
### `objectPropHasValue({ object, propName, value })`
|
|
727
581
|
|
|
728
|
-
|
|
729
|
-
- `mainObject`: `T` - The main object to check.
|
|
730
|
-
- `subObject`: `Partial<T>` - The sub-object to search for.
|
|
582
|
+
Checks if a specific property on an object equals a given value.
|
|
731
583
|
|
|
732
584
|
**Example:**
|
|
733
585
|
```typescript
|
|
734
|
-
const
|
|
735
|
-
const subObj = { name: "John", age: 30 }
|
|
736
|
-
|
|
737
|
-
console.log(ObjectHelpers.containsSubObject(mainObj, subObj)) // true
|
|
586
|
+
const user = { id: 1, name: "John", age: 30 }
|
|
738
587
|
|
|
739
|
-
|
|
740
|
-
|
|
588
|
+
ObjectHelpers.objectPropHasValue({ object: user, propName: "name", value: "John" }) // true
|
|
589
|
+
ObjectHelpers.objectPropHasValue({ object: user, propName: "age", value: 25 }) // false
|
|
741
590
|
```
|
|
742
591
|
|
|
743
|
-
|
|
592
|
+
---
|
|
744
593
|
|
|
745
|
-
|
|
594
|
+
### `findEntry(array, predicate)`
|
|
746
595
|
|
|
747
|
-
|
|
748
|
-
- `array`: `T[]` - Array of objects to search.
|
|
749
|
-
- `subObject`: `Partial<T>` - The sub-object to search for.
|
|
596
|
+
Returns the first array entry satisfying the predicate, or `null`.
|
|
750
597
|
|
|
751
598
|
**Example:**
|
|
752
599
|
```typescript
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
{ id: 2, name: "Jane", age: 25, city: "Boston" },
|
|
756
|
-
{ id: 3, name: "Bob", age: 30, city: "Chicago" }
|
|
757
|
-
]
|
|
758
|
-
|
|
759
|
-
const result = ObjectHelpers.findObjectBySubObject(users, { age: 30, city: "New York" })
|
|
760
|
-
console.log(result) // { id: 1, name: "John", age: 30, city: "New York" }
|
|
761
|
-
|
|
762
|
-
const result2 = ObjectHelpers.findObjectBySubObject(users, { name: "Alice" })
|
|
763
|
-
console.log(result2) // null
|
|
600
|
+
ObjectHelpers.findEntry([1, 2, 3, 4], (n) => n % 2 === 0) // 2
|
|
601
|
+
ObjectHelpers.findEntry([1, 2, 3], (n) => n > 10) // null
|
|
764
602
|
```
|
|
765
603
|
|
|
766
|
-
|
|
604
|
+
---
|
|
767
605
|
|
|
768
|
-
|
|
606
|
+
### `convertArrayToMap(arrayData, keyProp)`
|
|
769
607
|
|
|
770
|
-
|
|
771
|
-
- `array`: `T[]` - Array of objects to filter.
|
|
772
|
-
- `subObject`: `Partial<T>` - The sub-object to search for.
|
|
608
|
+
Converts an array of objects into a keyed map using a specified property.
|
|
773
609
|
|
|
774
610
|
**Example:**
|
|
775
611
|
```typescript
|
|
776
612
|
const users = [
|
|
777
|
-
{ id: 1, name: "John"
|
|
778
|
-
{ id: 2, name: "Jane"
|
|
779
|
-
{ id: 3, name: "Bob", age: 30, city: "Chicago" }
|
|
613
|
+
{ id: 1, name: "John" },
|
|
614
|
+
{ id: 2, name: "Jane" },
|
|
780
615
|
]
|
|
781
616
|
|
|
782
|
-
|
|
783
|
-
|
|
617
|
+
ObjectHelpers.convertArrayToMap(users, "id")
|
|
618
|
+
// { "1": { id: 1, name: "John" }, "2": { id: 2, name: "Jane" } }
|
|
784
619
|
```
|
|
785
620
|
|
|
786
|
-
|
|
621
|
+
---
|
|
787
622
|
|
|
788
|
-
|
|
623
|
+
### `convertObjectKeysToKebabCase(obj)`
|
|
789
624
|
|
|
790
|
-
|
|
791
|
-
- `object`: `ObjectType` - The object to check.
|
|
792
|
-
- `propName`: `keyof ObjectType` - The property name.
|
|
793
|
-
- `value`: `ObjectType[keyof ObjectType]` - The expected value.
|
|
625
|
+
Converts all camelCase keys of an object to kebab-case. Returns `undefined` for `undefined` input.
|
|
794
626
|
|
|
795
627
|
**Example:**
|
|
796
628
|
```typescript
|
|
797
|
-
|
|
629
|
+
ObjectHelpers.convertObjectKeysToKebabCase({ firstName: "John", lastName: "Doe" })
|
|
630
|
+
// { "first-name": "John", "last-name": "Doe" }
|
|
798
631
|
|
|
799
|
-
|
|
800
|
-
|
|
632
|
+
ObjectHelpers.convertObjectKeysToKebabCase(undefined)
|
|
633
|
+
// undefined
|
|
801
634
|
```
|
|
802
635
|
|
|
803
|
-
|
|
636
|
+
---
|
|
804
637
|
|
|
805
|
-
|
|
638
|
+
## MapHelpers
|
|
806
639
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
640
|
+
### `getDistanceBetweenPoints(point1, point2)`
|
|
641
|
+
|
|
642
|
+
Calculates the distance between two `[lat, lng]` points using the [Haversine formula](https://en.wikipedia.org/wiki/Haversine_formula). Returns metres, or `null` for undefined input.
|
|
810
643
|
|
|
811
644
|
**Example:**
|
|
812
645
|
```typescript
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
console.log(even) // 2
|
|
646
|
+
// New York → Los Angeles
|
|
647
|
+
MapHelpers.getDistanceBetweenPoints([40.7128, -74.006], [34.0522, -118.2437])
|
|
648
|
+
// ~3,944,419 metres (~3,944 km)
|
|
817
649
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
const greaterThan10 = ObjectHelpers.findEntry(numbers, (n) => n > 10)
|
|
822
|
-
console.log(greaterThan10) // null
|
|
650
|
+
MapHelpers.getDistanceBetweenPoints([40.7128, -74.006], undefined)
|
|
651
|
+
// null
|
|
823
652
|
```
|
|
824
653
|
|
|
825
|
-
|
|
654
|
+
---
|
|
826
655
|
|
|
827
|
-
|
|
656
|
+
### `compareLocations(location1, location2, precision?)`
|
|
657
|
+
|
|
658
|
+
Compares two `[lat, lng]` coordinates within a decimal precision. Throws if either is `undefined`.
|
|
828
659
|
|
|
829
660
|
**Parameters:**
|
|
830
|
-
- `
|
|
831
|
-
- `keyProp`: `keyof T` - Property to use as the key.
|
|
661
|
+
- `precision` (optional): `number` — Decimal places. Defaults to `6`.
|
|
832
662
|
|
|
833
663
|
**Example:**
|
|
834
664
|
```typescript
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
{ id: 3, name: "Bob", age: 35 }
|
|
839
|
-
]
|
|
840
|
-
|
|
841
|
-
const userMap = ObjectHelpers.convertArrayToMap(users, "id")
|
|
842
|
-
console.log(userMap)
|
|
843
|
-
// {
|
|
844
|
-
// "1": { id: 1, name: "John", age: 30 },
|
|
845
|
-
// "2": { id: 2, name: "Jane", age: 25 },
|
|
846
|
-
// "3": { id: 3, name: "Bob", age: 35 }
|
|
847
|
-
// }
|
|
665
|
+
MapHelpers.compareLocations([51.5074, -0.1278], [51.5074, -0.1278]) // true
|
|
666
|
+
MapHelpers.compareLocations([51.5074, -0.1278], [51.5074001, -0.127801]) // true (within 6 decimals)
|
|
667
|
+
MapHelpers.compareLocations([51.5074, -0.1278], [51.51, -0.13], 2) // false
|
|
848
668
|
```
|
|
849
669
|
|
|
850
|
-
|
|
670
|
+
---
|
|
851
671
|
|
|
852
|
-
|
|
672
|
+
### `getBearingToCoordinate({ startCoordinate, endCoordinate })`
|
|
853
673
|
|
|
854
|
-
|
|
674
|
+
Returns the compass bearing (0–360°) from start to end coordinate. Throws if either is `undefined`.
|
|
855
675
|
|
|
856
676
|
**Example:**
|
|
857
|
-
|
|
858
677
|
```typescript
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
const result2 = ObjectHelpers.convertObjectKeysToKebabCase(mixedObj)
|
|
866
|
-
console.log(result2) // { "first-name": "John", "last-name": "Doe", "user-name": "johndoe" }
|
|
867
|
-
|
|
868
|
-
// Returns undefined for undefined input
|
|
869
|
-
const result3 = ObjectHelpers.convertObjectKeysToKebabCase(undefined)
|
|
870
|
-
console.log(result3) // undefined
|
|
678
|
+
// New York → Los Angeles
|
|
679
|
+
MapHelpers.getBearingToCoordinate({
|
|
680
|
+
startCoordinate: [40.7128, -74.006],
|
|
681
|
+
endCoordinate: [34.0522, -118.2437],
|
|
682
|
+
})
|
|
683
|
+
// ~277.5 (roughly west)
|
|
871
684
|
```
|
|
872
685
|
|
|
873
|
-
|
|
686
|
+
---
|
|
874
687
|
|
|
875
|
-
|
|
688
|
+
## GenericHelpers
|
|
876
689
|
|
|
877
690
|
### `delay(ms)`
|
|
878
691
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
**Parameters:**
|
|
882
|
-
- `ms`: `number` - Number of milliseconds to wait.
|
|
692
|
+
Async sleep for the specified number of milliseconds.
|
|
883
693
|
|
|
884
694
|
**Example:**
|
|
885
695
|
```typescript
|
|
886
|
-
//
|
|
887
|
-
async function example() {
|
|
888
|
-
console.log("Starting...")
|
|
889
|
-
await GenericHelpers.delay(2000) // Wait 2 seconds
|
|
890
|
-
console.log("Done!")
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
// Using with promises
|
|
894
|
-
GenericHelpers.delay(1000).then(() => {
|
|
895
|
-
console.log("1 second has passed")
|
|
896
|
-
})
|
|
696
|
+
await GenericHelpers.delay(1000) // wait 1 second
|
|
897
697
|
```
|
|
898
698
|
|
|
899
|
-
|
|
699
|
+
---
|
|
900
700
|
|
|
901
|
-
|
|
701
|
+
### `getPreferredUriScheme(host)`
|
|
902
702
|
|
|
903
|
-
|
|
904
|
-
- `host`: `string` - IP address or domain name.
|
|
703
|
+
Returns `"http"` for local/private hosts, `"https"` for everything else.
|
|
905
704
|
|
|
906
705
|
**Example:**
|
|
907
706
|
```typescript
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
console.log(GenericHelpers.getPreferredUriScheme("10.0.0.1")) // "http"
|
|
707
|
+
GenericHelpers.getPreferredUriScheme("api.example.com") // "https"
|
|
708
|
+
GenericHelpers.getPreferredUriScheme("localhost") // "http"
|
|
709
|
+
GenericHelpers.getPreferredUriScheme("192.168.1.1") // "http"
|
|
710
|
+
GenericHelpers.getPreferredUriScheme("10.0.0.1") // "http"
|
|
913
711
|
```
|
|
914
712
|
|
|
915
|
-
|
|
713
|
+
---
|
|
916
714
|
|
|
917
|
-
|
|
715
|
+
## FileHelpers
|
|
918
716
|
|
|
919
717
|
### `checkFileExtension(filePath, validExtensions)`
|
|
920
718
|
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
**Parameters:**
|
|
924
|
-
- `filePath`: `string` - The file path to check.
|
|
925
|
-
- `validExtensions`: `string[]` - Array of valid file extensions.
|
|
719
|
+
Returns `true` if the file has one of the allowed extensions.
|
|
926
720
|
|
|
927
721
|
**Example:**
|
|
928
722
|
```typescript
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
console.log(FileHelpers.checkFileExtension("script.js", ["js", "ts", "jsx"])) // true
|
|
933
|
-
console.log(FileHelpers.checkFileExtension("file", ["txt", "md"])) // false (no extension)
|
|
723
|
+
FileHelpers.checkFileExtension("report.pdf", ["pdf", "docx"]) // true
|
|
724
|
+
FileHelpers.checkFileExtension("data.geojson", ["geojson"]) // true
|
|
725
|
+
FileHelpers.checkFileExtension("photo.txt", ["jpg", "png"]) // false
|
|
934
726
|
```
|
|
935
727
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
Formats a file size in bytes to a human-readable string with appropriate units.
|
|
728
|
+
---
|
|
939
729
|
|
|
940
|
-
|
|
730
|
+
### `formatFileSize(bytes)`
|
|
941
731
|
|
|
942
|
-
|
|
732
|
+
Formats a byte count into a human-readable size string.
|
|
943
733
|
|
|
944
734
|
**Example:**
|
|
945
|
-
|
|
946
735
|
```typescript
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
console.log(FileHelpers.formatFileSize(0)) // "0 B"
|
|
953
|
-
console.log(FileHelpers.formatFileSize(null)) // "0 B"
|
|
736
|
+
FileHelpers.formatFileSize(512) // "512 B"
|
|
737
|
+
FileHelpers.formatFileSize(1024) // "1.0 KB"
|
|
738
|
+
FileHelpers.formatFileSize(1024 * 1024 * 2) // "2.0 MB"
|
|
739
|
+
FileHelpers.formatFileSize(0) // "0 B"
|
|
740
|
+
FileHelpers.formatFileSize(null) // "0 B"
|
|
954
741
|
```
|
|
955
742
|
|
|
743
|
+
---
|
|
744
|
+
|
|
956
745
|
## Contributing
|
|
957
746
|
|
|
958
747
|
We welcome contributions! Please feel free to submit a Pull Request.
|
|
@@ -969,60 +758,21 @@ npm test
|
|
|
969
758
|
|
|
970
759
|
### Commit Message Guidelines
|
|
971
760
|
|
|
972
|
-
We follow [Conventional Commits](https://www.conventionalcommits.org/)
|
|
761
|
+
We follow [Conventional Commits](https://www.conventionalcommits.org/). Scope is required.
|
|
973
762
|
|
|
974
|
-
|
|
975
|
-
```
|
|
763
|
+
```text
|
|
976
764
|
type(scope): description
|
|
977
|
-
|
|
978
|
-
[optional body]
|
|
979
|
-
|
|
980
|
-
[optional footer]
|
|
981
765
|
```
|
|
982
766
|
|
|
983
|
-
|
|
984
|
-
```bash
|
|
985
|
-
## ✅ Preferred - with scope
|
|
986
|
-
feat(date): add new date formatting options
|
|
987
|
-
fix(text): resolve string validation issue
|
|
988
|
-
docs(readme): add troubleshooting section
|
|
989
|
-
chore(deps): update dependencies
|
|
990
|
-
|
|
991
|
-
## ❌ Less preferred - without scope
|
|
992
|
-
feat: add new date formatting options
|
|
993
|
-
fix: resolve string validation issue
|
|
994
|
-
docs: add troubleshooting section
|
|
995
|
-
chore: update dependencies
|
|
996
|
-
```
|
|
767
|
+
**Common scopes:** `date` · `text` · `object` · `map` · `generic` · `file` · `docs` · `deps` · `test` · `build` · `ci`
|
|
997
768
|
|
|
998
|
-
|
|
999
|
-
- `date` - Date manipulation functions
|
|
1000
|
-
- `text` - Text processing functions
|
|
1001
|
-
- `object` - Object manipulation functions
|
|
1002
|
-
- `map` - Map and geographical functions
|
|
1003
|
-
- `generic` - Generic utility functions
|
|
1004
|
-
- `file` - File processing functions
|
|
1005
|
-
- `docs` - Documentation updates
|
|
1006
|
-
- `deps` - Dependency updates
|
|
1007
|
-
- `test` - Test-related changes
|
|
1008
|
-
- `build` - Build and build tooling
|
|
1009
|
-
- `ci` - CI/CD configuration
|
|
1010
|
-
|
|
1011
|
-
### Commit Types
|
|
1012
|
-
- `feat` - New features
|
|
1013
|
-
- `fix` - Bug fixes
|
|
1014
|
-
- `docs` - Documentation changes
|
|
1015
|
-
- `style` - Code style changes (formatting, etc.)
|
|
1016
|
-
- `refactor` - Code refactoring
|
|
1017
|
-
- `test` - Adding or updating tests
|
|
1018
|
-
- `chore` - Maintenance tasks
|
|
1019
|
-
|
|
1020
|
-
If you introduce a breaking change, please add `BREAKING CHANGE` in the pull request description.
|
|
769
|
+
**Types:** `feat` · `fix` · `docs` · `style` · `refactor` · `test` · `chore`
|
|
1021
770
|
|
|
1022
|
-
##
|
|
771
|
+
## Requirements
|
|
1023
772
|
|
|
1024
|
-
|
|
773
|
+
- Node.js >= 20
|
|
774
|
+
- Zero runtime dependencies
|
|
1025
775
|
|
|
1026
|
-
##
|
|
776
|
+
## License
|
|
1027
777
|
|
|
1028
|
-
|
|
778
|
+
[MIT](LICENSE)
|