@akadenia/helpers 1.9.0 → 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.
Files changed (3) hide show
  1. package/README.MD +342 -592
  2. package/dist/index.js +17 -7
  3. package/package.json +22 -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
- ## @akadenia/helpers
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 comprehensive collection of utility functions for common JavaScript/TypeScript operations including date manipulation, text processing, object handling, map calculations, and more.
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) [GitHub](https://github.com/akadenia/AkadeniaHelpers) [Issues](https://github.com/akadenia/AkadeniaHelpers/issues)
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
- ## DateHelpers
37
+ ---
52
38
 
53
- Utility functions for date and time operations.
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` - The date to convert. Defaults to current 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
- // Using current date
67
- const now = DateHelpers.getReadableDateTime()
68
- console.log(now) // "2024-01-15 14:30:25"
52
+ DateHelpers.getReadableDateTime()
53
+ // "2026-02-27 15:30:25"
69
54
 
70
- // Using specific date
71
- const specificDate = DateHelpers.getReadableDateTime(new Date('2024-01-15T10:30:00Z'))
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` - The date to convert. Defaults to current date.
66
+ - `datetime` (optional): `Date` The date to convert. Defaults to current date.
81
67
 
82
68
  **Example:**
83
69
  ```typescript
84
- const date = DateHelpers.getReadableDate()
85
- console.log(date) // "2024-01-15"
70
+ DateHelpers.getReadableDate()
71
+ // "2026-02-27"
86
72
 
87
- const specificDate = DateHelpers.getReadableDate(new Date('2024-01-15T10:30:00Z'))
88
- console.log(specificDate) // "2024-01-15"
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 string representing the date in the user's local timezone.
81
+ Returns a locale-formatted date string.
94
82
 
95
83
  **Parameters:**
96
- - `date`: `string | Date` - The date to convert.
84
+ - `date`: `string | Date` The date to convert.
97
85
 
98
86
  **Example:**
99
87
  ```typescript
100
- const dateString = DateHelpers.getDateString('2024-01-15')
101
- console.log(dateString) // "1/15/2024" (format depends on locale)
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` - The date to format.
113
- - `options`: `Intl.DateTimeFormatOptions` - Formatting options.
114
- - `localTimezone` (optional): `string | Intl.Locale` - Locale for formatting. Defaults to "en-US".
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
- const formatted = DateHelpers.formatDateTime(
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
- console.log(formatted) // "January 15, 2024 at 10:30 AM"
110
+ // "January 15, 2024 at 10:30 AM"
130
111
  ```
131
112
 
113
+ ---
114
+
132
115
  ### `parseDate(date)`
133
116
 
134
- Returns a Date object from a string or Date input. Throws an error for invalid dates.
117
+ Parses a string or Date into a `Date` object. Throws on invalid input.
135
118
 
136
119
  **Parameters:**
137
- - `date`: `string | Date` - The date to parse.
120
+ - `date`: `string | Date` The date to parse.
138
121
 
139
122
  **Example:**
140
123
  ```typescript
141
- const parsedDate = DateHelpers.parseDate('2024-01-15')
142
- console.log(parsedDate) // Date object for 2024-01-15
124
+ DateHelpers.parseDate('2024-01-15')
125
+ // Date object
143
126
 
144
- const parsedDate2 = DateHelpers.parseDate('invalid-date')
145
- // Throws: Error: Cannot parse date: "invalid-date"
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 string representing the date in short ordinal format.
135
+ Returns a date in short ordinal format, e.g. `"Feb 27th 2026"`.
151
136
 
152
137
  **Parameters:**
153
- - `date`: `string | Date` - The date to format.
154
- - `appendTime` (optional): `boolean` - Whether to include time. Defaults to false.
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
- const ordinalDate = DateHelpers.getShortOrdinalDate('2024-01-15')
159
- console.log(ordinalDate) // "Jan 15th 2024"
143
+ DateHelpers.getShortOrdinalDate('2024-01-15')
144
+ // "Jan 15th 2024"
160
145
 
161
- const ordinalDateTime = DateHelpers.getShortOrdinalDate('2024-01-15T10:30:00Z', true)
162
- console.log(ordinalDateTime) // "Jan 15th 2024 10:30:00"
146
+ DateHelpers.getShortOrdinalDate('2024-01-15T10:30:00Z', true)
147
+ // "Jan 15th 2024 10:30:00"
163
148
  ```
164
149
 
165
- ## MapHelpers
166
-
167
- Utility functions for geographical calculations and map operations.
150
+ ---
168
151
 
169
- ### `getDistanceBetweenPoints(point1, point2)`
152
+ ## TextHelpers
170
153
 
171
- Calculates the distance between two geographical points using the Haversine formula.
154
+ ### `uuidv4()`
172
155
 
173
- **Parameters:**
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
- // Distance between New York and Los Angeles
180
- const nyc = [-74.006, 40.7128] // [lng, lat]
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
- ### `compareLocations(location1, location2, precision?)`
164
+ ---
192
165
 
193
- Compares two locations to see if they are the same within a specified precision.
166
+ ### `formatPosition(position)`
167
+
168
+ Returns a position number with the appropriate ordinal suffix.
194
169
 
195
170
  **Parameters:**
196
- - `location1`: `number[] | undefined` - First location coordinates [longitude, latitude].
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
- const loc1 = [-74.006, 40.7128]
203
- const loc2 = [-74.006001, 40.712801] // Very close to loc1
204
- const loc3 = [-74.01, 40.72] // Further from loc1
205
-
206
- console.log(MapHelpers.compareLocations(loc1, loc2)) // true (within 6 decimal precision)
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
- ### `getBearingToCoordinate({startCoordinate, endCoordinate})`
182
+ ---
215
183
 
216
- Calculates the bearing (direction) from one coordinate to another in degrees.
184
+ ### `truncateText(text, characterLimit)`
185
+
186
+ Truncates text to the character limit, appending `"..."`.
217
187
 
218
188
  **Parameters:**
219
- - `startCoordinate`: `number[] | undefined` - Starting point [longitude, latitude].
220
- - `endCoordinate`: `number[] | undefined` - Ending point [longitude, latitude].
189
+ - `text`: `string` Text to truncate.
190
+ - `characterLimit`: `number` Maximum number of characters.
221
191
 
222
192
  **Example:**
223
193
  ```typescript
224
- const start = [-74.006, 40.7128] // New York
225
- const end = [-118.2437, 34.0522] // Los Angeles
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
- ## TextHelpers
198
+ ---
236
199
 
237
- Utility functions for text manipulation and processing.
200
+ ### `fileNameFromPath(path)`
238
201
 
239
- ### `uuidv4()`
202
+ Extracts the filename from a file path.
240
203
 
241
- Returns a randomly generated UUID v4 string.
204
+ **Parameters:**
205
+ - `path`: `string` — The file path.
242
206
 
243
207
  **Example:**
244
208
  ```typescript
245
- const id = TextHelpers.uuidv4()
246
- console.log(id) // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
209
+ TextHelpers.fileNameFromPath('/uploads/documents/file.pdf') // "file.pdf"
247
210
  ```
248
211
 
249
- ### `formatPosition(position)`
212
+ ---
250
213
 
251
- Returns a string position with appropriate suffix (st, nd, rd, th).
214
+ ### `replaceSpacesWithUnderscore(s?)`
252
215
 
253
- **Parameters:**
254
- - `position`: `number` - The position number.
216
+ Replaces spaces with underscores.
255
217
 
256
218
  **Example:**
257
219
  ```typescript
258
- console.log(TextHelpers.formatPosition(1)) // "1st"
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
- ### `truncateText(text, characterLimit)`
223
+ ---
266
224
 
267
- Returns truncated text with ellipsis if it exceeds the character limit.
225
+ ### `replaceUnderscoreWithSpaces(s?)`
268
226
 
269
- **Parameters:**
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
- const short = TextHelpers.truncateText("Hello World", 5)
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
- ### `fileNameFromPath(path)`
234
+ ---
283
235
 
284
- Extracts the filename from a file path.
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
- - `path`: `string` - The file path.
241
+ - `word`: `string` The word to pluralize.
242
+ - `condition`: `boolean` — Whether to pluralize.
288
243
 
289
244
  **Example:**
290
245
  ```typescript
291
- const filename = TextHelpers.fileNameFromPath('/path/to/file.txt')
292
- console.log(filename) // "file.txt"
293
-
294
- const filename2 = TextHelpers.fileNameFromPath('C:\\Users\\file.pdf')
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
- ### `replaceSpacesWithUnderscore(s?)`
252
+ ---
299
253
 
300
- Replaces spaces with underscores in a string.
254
+ ### `convertSnakeToCamelCase(data)`
301
255
 
302
- **Parameters:**
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
- const result = TextHelpers.replaceSpacesWithUnderscore("hello world test")
308
- console.log(result) // "hello_world_test"
260
+ TextHelpers.convertSnakeToCamelCase("hello_world")
261
+ // "helloWorld"
309
262
 
310
- const result2 = TextHelpers.replaceSpacesWithUnderscore()
311
- console.log(result2) // ""
263
+ TextHelpers.convertSnakeToCamelCase({ first_name: "John", user_info: { phone_number: "123" } })
264
+ // { firstName: "John", userInfo: { phoneNumber: "123" } }
312
265
  ```
313
266
 
314
- ### `replaceUnderscoreWithSpaces(s?)`
267
+ ---
315
268
 
316
- Replaces underscores with spaces in a string.
269
+ ### `convertCamelToSnakeCase(data)`
317
270
 
318
- **Parameters:**
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
- const result = TextHelpers.replaceUnderscoreWithSpaces("hello_world_test")
324
- console.log(result) // "hello world test"
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
- ### `pluralizeOnCondition(word, condition)`
282
+ ---
328
283
 
329
- Returns pluralized version of the word if condition is true.
284
+ ### `convertCamelToKebabCase(word)`
330
285
 
331
- **Parameters:**
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
- const plural = TextHelpers.pluralizeOnCondition("item", true)
338
- console.log(plural) // "items"
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
- ### `convertSnakeToCamelCase(data)`
294
+ ---
351
295
 
352
- Converts snake_case to camelCase for strings, objects, or arrays of objects.
296
+ ### `convertKebabToCamelCase(word)`
353
297
 
354
- **Parameters:**
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
- // String conversion
360
- const camelString = TextHelpers.convertSnakeToCamelCase("hello_world")
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
- ### `convertCamelToSnakeCase(data)`
306
+ ---
382
307
 
383
- Converts camelCase to snake_case for strings, objects, or arrays of objects.
308
+ ### `convertCamelCaseToReadableText(name)`
384
309
 
385
- **Parameters:**
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
- // String conversion
391
- const snakeString = TextHelpers.convertCamelToSnakeCase("helloWorld")
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
- ### `convertCamelToKebabCase(word)`
318
+ ---
413
319
 
414
- Converts camelCase to kebab-case.
320
+ ### `generateAcronym(term)`
415
321
 
416
- **Parameters:**
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
- const kebab = TextHelpers.convertCamelToKebabCase("helloWorld")
422
- console.log(kebab) // "hello-world"
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
- ### `convertKebabToCamelCase(word)`
330
+ ---
429
331
 
430
- Converts kebab-case to camelCase.
332
+ ### `isAcronym(word)`
431
333
 
432
- **Parameters:**
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
- const camel = TextHelpers.convertKebabToCamelCase("hello-world")
438
- console.log(camel) // "HelloWorld"
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
- ### `convertCamelCaseToReadableText(name)`
445
-
446
- Converts camelCase to readable text format with proper capitalization.
342
+ ---
447
343
 
448
- **Parameters:**
344
+ ### `acronymToKebabCase(word)`
449
345
 
450
- - `name`: `string` - The camelCase string to convert.
346
+ Converts an acronym to kebab-case. Throws if input is not an acronym.
451
347
 
452
348
  **Example:**
453
-
454
349
  ```typescript
455
- const readable = TextHelpers.convertCamelCaseToReadableText("helloWorld")
456
- console.log(readable) // "Hello World"
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
- ### `generateAcronym(term)`
355
+ ---
466
356
 
467
- Generates an acronym from a term.
357
+ ### `handleNullDisplay(value, defaultValue?)`
358
+
359
+ Returns the value, or a default string if `null` or `undefined`.
468
360
 
469
361
  **Parameters:**
470
- - `term`: `string` - The term to convert to acronym.
362
+ - `value`: `string | null | undefined`
363
+ - `defaultValue` (optional): `string` — Defaults to `"N/A"`.
471
364
 
472
365
  **Example:**
473
366
  ```typescript
474
- const acronym = TextHelpers.generateAcronym("Hyper Text Markup Language")
475
- console.log(acronym) // "HTML"
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
- ### `isAcronym(word)`
372
+ ---
482
373
 
483
- Validates if a word is an acronym (all uppercase).
374
+ ### `capitalizeText(text?)`
484
375
 
485
- **Parameters:**
486
- - `word`: `string` - The word to validate.
376
+ Capitalizes the first letter, lowercases the rest.
487
377
 
488
378
  **Example:**
489
379
  ```typescript
490
- console.log(TextHelpers.isAcronym("HTML")) // true
491
- console.log(TextHelpers.isAcronym("html")) // false
492
- console.log(TextHelpers.isAcronym("JavaScript")) // false
380
+ TextHelpers.capitalizeText("hello world") // "Hello world"
381
+ TextHelpers.capitalizeText("HELLO") // "Hello"
382
+ TextHelpers.capitalizeText() // ""
493
383
  ```
494
384
 
495
- ### `acronymToKebabCase(word)`
385
+ ---
496
386
 
497
- Converts an acronym to kebab-case.
387
+ ### `enforceCharacterLimit({ text, characterLimit, onCharacterLimit })`
498
388
 
499
- **Parameters:**
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
- const kebab = TextHelpers.acronymToKebabCase("HTML")
505
- console.log(kebab) // "h-t-m-l"
506
-
507
- const kebab2 = TextHelpers.acronymToKebabCase("API")
508
- console.log(kebab2) // "a-p-i"
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
- ### `handleNullDisplay(value, defaultValue?)`
401
+ ---
515
402
 
516
- Returns the value or a default string if the value is null or undefined.
403
+ ### `isValidEmail(email)`
517
404
 
518
- **Parameters:**
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
- console.log(TextHelpers.handleNullDisplay("Hello")) // "Hello"
525
- console.log(TextHelpers.handleNullDisplay(null)) // "N/A"
526
- console.log(TextHelpers.handleNullDisplay(undefined)) // "N/A"
527
- console.log(TextHelpers.handleNullDisplay(null, "No data")) // "No data"
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
- ### `capitalizeText(text?)`
415
+ ---
531
416
 
532
- Capitalizes the first letter of a text.
417
+ ### `generateIDFromWord(text)`
533
418
 
534
- **Parameters:**
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
- console.log(TextHelpers.capitalizeText("hello world")) // "Hello world"
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
- ### `enforceCharacterLimit({text, characterLimit, onCharacterLimit})`
426
+ ---
545
427
 
546
- Enforces a character limit and calls a callback when exceeded.
428
+ ### `generateWordFromId(id, customList?)`
547
429
 
548
- **Parameters:**
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
- const result = TextHelpers.enforceCharacterLimit({
556
- text: "This is a very long text that exceeds the limit",
557
- characterLimit: 10,
558
- onCharacterLimit: () => console.log("Character limit exceeded!")
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
- ### `isValidEmail(email)`
441
+ ---
565
442
 
566
- Validates if an email address is properly formatted.
443
+ ### `generateSlugFromWordsWithID(id, ...words)`
567
444
 
568
- **Parameters:**
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
- console.log(TextHelpers.isValidEmail("user@example.com")) // true
574
- console.log(TextHelpers.isValidEmail("invalid-email")) // false
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
- ### `generateIDFromWord(text)`
453
+ ---
580
454
 
581
- Generates an ID from a word by converting to lowercase and replacing spaces with hyphens.
455
+ ### `extractIDfromSlug(slug)`
582
456
 
583
- **Parameters:**
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
- const id = TextHelpers.generateIDFromWord("Hello World Test")
589
- console.log(id) // "hello-world-test"
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
- ### `generateWordFromId(id, customList?)`
465
+ ---
596
466
 
597
- Converts an ID back to a readable word format.
467
+ ### `abbreviateNumber(number)`
598
468
 
599
- **Parameters:**
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
- const word = TextHelpers.generateWordFromId("hello-world-test")
606
- console.log(word) // "Hello World Test"
607
-
608
- const customWord = TextHelpers.generateWordFromId("api", { "api": "Application Programming Interface" })
609
- console.log(customWord) // "Application Programming Interface"
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
- ### `generateSlugFromWordsWithID(id, ...words)`
480
+ ---
481
+
482
+ ## ObjectHelpers
613
483
 
614
- Generates a URL-safe slug from an ID and additional words.
484
+ ### `isPureObject(object)`
615
485
 
616
- **Parameters:**
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
- const slug = TextHelpers.generateSlugFromWordsWithID("user", "profile", "settings")
623
- console.log(slug) // "profile-settings-user"
624
-
625
- const slug2 = TextHelpers.generateSlugFromWordsWithID("123", "hello world", "test")
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
- ### `extractIDfromSlug(slug)`
496
+ ---
630
497
 
631
- Extracts the ID from a slug (last part after splitting by hyphens).
498
+ ### `parseCookie(str)`
632
499
 
633
- **Parameters:**
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
- const id = TextHelpers.extractIDfromSlug("hello-world-test-123")
639
- console.log(id) // "123"
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
- ### `abbreviateNumber(number)`
508
+ ---
649
509
 
650
- Abbreviates large numbers with K, M, B suffixes.
510
+ ### `filterObjectsByProperty(array, propertyName, propertyValue)`
651
511
 
652
- **Parameters:**
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
- console.log(TextHelpers.abbreviateNumber(500)) // "500"
658
- console.log(TextHelpers.abbreviateNumber(1500)) // "1.5K"
659
- console.log(TextHelpers.abbreviateNumber(1500000)) // "1.5M"
660
- console.log(TextHelpers.abbreviateNumber(1500000000)) // "1.5B"
661
- console.log(TextHelpers.abbreviateNumber(null)) // null
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
- ## ObjectHelpers
522
+ ObjectHelpers.filterObjectsByProperty(users, "role", "admin")
523
+ // [{ id: 1, ... }, { id: 3, ... }]
524
+ ```
665
525
 
666
- Utility functions for object manipulation and processing.
526
+ ---
667
527
 
668
- ### `isPureObject(object)`
528
+ ### `containsSubObject(mainObject, subObject)`
669
529
 
670
- Checks if an object is a pure object (not array, date, or function).
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
- console.log(ObjectHelpers.isPureObject({})) // true
678
- console.log(ObjectHelpers.isPureObject([])) // false
679
- console.log(ObjectHelpers.isPureObject(new Date())) // false
680
- console.log(ObjectHelpers.isPureObject(() => {})) // false
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
- ### `parseCookie(str)`
540
+ ---
685
541
 
686
- Parses a cookie string into an object.
542
+ ### `findObjectBySubObject(array, subObject)`
687
543
 
688
- **Parameters:**
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 cookies = ObjectHelpers.parseCookie("name=John; age=30; city=New York")
694
- console.log(cookies) // { name: "John", age: "30", city: "New York" }
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
- const cookies2 = ObjectHelpers.parseCookie("session=abc123; theme=dark")
697
- console.log(cookies2) // { session: "abc123", theme: "dark" }
556
+ ObjectHelpers.findObjectBySubObject(users, { name: "Alice" })
557
+ // null
698
558
  ```
699
559
 
700
- ### `filterObjectsByProperty(array, propertyName, propertyValue)`
560
+ ---
701
561
 
702
- Filters an array of objects based on a specific property and value.
562
+ ### `filterObjectsBySubObject(array, subObject)`
703
563
 
704
- **Parameters:**
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: "John", age: 35 }
571
+ { id: 3, name: "Bob", age: 30 },
715
572
  ]
716
573
 
717
- const johns = ObjectHelpers.filterObjectsByProperty(users, "name", "John")
718
- console.log(johns) // [{ id: 1, name: "John", age: 30 }, { id: 3, name: "John", age: 35 }]
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
- ### `containsSubObject(mainObject, subObject)`
578
+ ---
725
579
 
726
- Checks if the main object contains all key-value pairs from the sub-object.
580
+ ### `objectPropHasValue({ object, propName, value })`
727
581
 
728
- **Parameters:**
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 mainObj = { id: 1, name: "John", age: 30, city: "New York" }
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
- const subObj2 = { name: "Jane", age: 30 }
740
- console.log(ObjectHelpers.containsSubObject(mainObj, subObj2)) // false
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
- ### `findObjectBySubObject(array, subObject)`
592
+ ---
744
593
 
745
- Finds the first object in an array that contains the specified sub-object.
594
+ ### `findEntry(array, predicate)`
746
595
 
747
- **Parameters:**
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
- const users = [
754
- { id: 1, name: "John", age: 30, city: "New York" },
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
- ### `filterObjectsBySubObject(array, subObject)`
604
+ ---
767
605
 
768
- Filters an array of objects based on containing the specified sub-object.
606
+ ### `convertArrayToMap(arrayData, keyProp)`
769
607
 
770
- **Parameters:**
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", age: 30, city: "New York" },
778
- { id: 2, name: "Jane", age: 25, city: "Boston" },
779
- { id: 3, name: "Bob", age: 30, city: "Chicago" }
613
+ { id: 1, name: "John" },
614
+ { id: 2, name: "Jane" },
780
615
  ]
781
616
 
782
- const results = ObjectHelpers.filterObjectsBySubObject(users, { age: 30 })
783
- console.log(results) // [{ id: 1, name: "John", age: 30, city: "New York" }, { id: 3, name: "Bob", age: 30, city: "Chicago" }]
617
+ ObjectHelpers.convertArrayToMap(users, "id")
618
+ // { "1": { id: 1, name: "John" }, "2": { id: 2, name: "Jane" } }
784
619
  ```
785
620
 
786
- ### `objectPropHasValue({object, propName, value})`
621
+ ---
787
622
 
788
- Checks if an object has a specific property with a specific value.
623
+ ### `convertObjectKeysToKebabCase(obj)`
789
624
 
790
- **Parameters:**
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
- const user = { id: 1, name: "John", age: 30 }
629
+ ObjectHelpers.convertObjectKeysToKebabCase({ firstName: "John", lastName: "Doe" })
630
+ // { "first-name": "John", "last-name": "Doe" }
798
631
 
799
- console.log(ObjectHelpers.objectPropHasValue({ object: user, propName: "name", value: "John" })) // true
800
- console.log(ObjectHelpers.objectPropHasValue({ object: user, propName: "age", value: 25 })) // false
632
+ ObjectHelpers.convertObjectKeysToKebabCase(undefined)
633
+ // undefined
801
634
  ```
802
635
 
803
- ### `findEntry(array, predicate)`
636
+ ---
804
637
 
805
- Finds the first entry in an array that satisfies a predicate function.
638
+ ## MapHelpers
806
639
 
807
- **Parameters:**
808
- - `array`: `EntryType[]` - Array to search.
809
- - `predicate`: `(item: EntryType) => boolean` - Predicate function.
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
- const numbers = [1, 2, 3, 4, 5, 6]
814
-
815
- const even = ObjectHelpers.findEntry(numbers, (n) => n % 2 === 0)
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
- const greaterThan5 = ObjectHelpers.findEntry(numbers, (n) => n > 5)
819
- console.log(greaterThan5) // 6
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
- ### `convertArrayToMap(arrayData, keyProp)`
654
+ ---
826
655
 
827
- Converts an array of objects to a map using a specified key property.
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
- - `arrayData`: `T[]` - Array of objects to convert.
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
- const users = [
836
- { id: 1, name: "John", age: 30 },
837
- { id: 2, name: "Jane", age: 25 },
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
- Converts object keys from camelCase to kebab-case.
670
+ ---
851
671
 
852
- **Parameters:**
672
+ ### `getBearingToCoordinate({ startCoordinate, endCoordinate })`
853
673
 
854
- - `obj`: `T | undefined` - The object to convert.
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
- const camelCaseObj = { firstName: "John", lastName: "Doe", age: 30 }
860
- const result = ObjectHelpers.convertObjectKeysToKebabCase(camelCaseObj)
861
- console.log(result) // { "first-name": "John", "last-name": "Doe", age: 30 }
862
-
863
- // Handles mixed case keys
864
- const mixedObj = { firstName: "John", "last-name": "Doe", userName: "johndoe" }
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
- ## GenericHelpers
686
+ ---
874
687
 
875
- General utility functions for common operations.
688
+ ## GenericHelpers
876
689
 
877
690
  ### `delay(ms)`
878
691
 
879
- Creates a delay (sleep) for the specified number of milliseconds.
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
- // Using with async/await
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
- ### `getPreferredUriScheme(host)`
699
+ ---
900
700
 
901
- Determines the preferred URI scheme (http or https) for a given host.
701
+ ### `getPreferredUriScheme(host)`
902
702
 
903
- **Parameters:**
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
- console.log(GenericHelpers.getPreferredUriScheme("example.com")) // "https"
909
- console.log(GenericHelpers.getPreferredUriScheme("localhost")) // "http"
910
- console.log(GenericHelpers.getPreferredUriScheme("127.0.0.1")) // "http"
911
- console.log(GenericHelpers.getPreferredUriScheme("192.168.1.1")) // "http"
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
- ## FileHelpers
713
+ ---
916
714
 
917
- Utility functions for file operations and validation.
715
+ ## FileHelpers
918
716
 
919
717
  ### `checkFileExtension(filePath, validExtensions)`
920
718
 
921
- Checks if a file path has one of the valid extensions.
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
- console.log(FileHelpers.checkFileExtension("document.pdf", ["pdf", "doc", "docx"])) // true
930
- console.log(FileHelpers.checkFileExtension("image.jpg", ["png", "gif", "svg"])) // false
931
- console.log(FileHelpers.checkFileExtension("data.geojson", ["geojson", "json"])) // true
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
- ### `formatFileSize(bytes)`
937
-
938
- Formats a file size in bytes to a human-readable string with appropriate units.
728
+ ---
939
729
 
940
- **Parameters:**
730
+ ### `formatFileSize(bytes)`
941
731
 
942
- - `bytes`: `number | null` - The file size in bytes.
732
+ Formats a byte count into a human-readable size string.
943
733
 
944
734
  **Example:**
945
-
946
735
  ```typescript
947
- console.log(FileHelpers.formatFileSize(1024)) // "1.0 KB"
948
- console.log(FileHelpers.formatFileSize(1024 * 1024)) // "1.0 MB"
949
- console.log(FileHelpers.formatFileSize(1024 * 1024 * 1024)) // "1.0 GB"
950
- console.log(FileHelpers.formatFileSize(512)) // "512 B"
951
- console.log(FileHelpers.formatFileSize(1536)) // "1.5 KB"
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/) for our semantic release process. **We prefer commit messages to include a scope in parentheses** for better categorization and changelog generation.
761
+ We follow [Conventional Commits](https://www.conventionalcommits.org/). Scope is required.
973
762
 
974
- ### Preferred Format
975
- ```
763
+ ```text
976
764
  type(scope): description
977
-
978
- [optional body]
979
-
980
- [optional footer]
981
765
  ```
982
766
 
983
- ### Examples
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
- ### Common Scopes
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
- ## License
771
+ ## Requirements
1023
772
 
1024
- [MIT](https://github.com/akadenia/AkadeniaHelpers/blob/main/LICENSE)
773
+ - Node.js >= 20
774
+ - Zero runtime dependencies
1025
775
 
1026
- ## Support
776
+ ## License
1027
777
 
1028
- For support, please open an issue on [GitHub](https://github.com/akadenia/AkadeniaHelpers/issues).
778
+ [MIT](LICENSE)