danholibraryjs 2.0.1 → 2.0.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 (44) hide show
  1. package/README.md +1 -0
  2. package/dist/Extensions/Array/random.extension.d.ts +1 -2
  3. package/dist/Extensions/Array/random.extension.js +1 -22
  4. package/dist/Extensions/Array/string.extension.d.ts +3 -4
  5. package/dist/Extensions/Number.d.ts +2 -2
  6. package/dist/Extensions/Number.js +1 -1
  7. package/dist/Extensions/Object/arrays.extension.d.ts +14 -0
  8. package/dist/Extensions/Object/arrays.extension.js +7 -2
  9. package/dist/Extensions/Object/extracts.extension.d.ts +6 -6
  10. package/dist/Extensions/Object/extracts.extension.js +10 -7
  11. package/dist/Extensions/String/index.d.ts +1 -0
  12. package/dist/Extensions/String/index.js +1 -0
  13. package/dist/Extensions/String/string.extension.d.ts +6 -0
  14. package/dist/Extensions/String/string.extension.js +10 -0
  15. package/dist/Types/Able.d.ts +1 -1
  16. package/dist/Utils/NumberUtils.d.ts +5 -0
  17. package/dist/Utils/NumberUtils.js +25 -1
  18. package/dist/Utils/StringUtils.d.ts +5 -0
  19. package/dist/Utils/StringUtils.js +6 -1
  20. package/dist/Utils/TimeUtils/index.d.ts +3 -0
  21. package/dist/Utils/TimeUtils/index.js +2 -0
  22. package/dist/Utils/TimeUtils/string.util.d.ts +3 -0
  23. package/dist/Utils/TimeUtils/string.util.js +19 -0
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.js +1 -0
  26. package/docs/Extensions.md +48 -15
  27. package/docs/Types.md +1 -1
  28. package/docs/Utils.md +335 -0
  29. package/docs/index.md +1 -0
  30. package/package.json +1 -1
  31. package/src/Extensions/Array/random.extension.ts +2 -25
  32. package/src/Extensions/Array/string.extension.ts +3 -4
  33. package/src/Extensions/Number.ts +3 -3
  34. package/src/Extensions/Object/arrays.extension.ts +23 -2
  35. package/src/Extensions/Object/extracts.extension.ts +18 -13
  36. package/src/Extensions/String/index.ts +2 -1
  37. package/src/Extensions/String/string.extension.ts +11 -0
  38. package/src/Types/Able.ts +1 -1
  39. package/src/Utils/NumberUtils.ts +27 -0
  40. package/src/Utils/StringUtils.ts +7 -1
  41. package/src/Utils/TimeUtils/index.ts +2 -0
  42. package/src/Utils/TimeUtils/string.util.ts +13 -0
  43. package/src/index.ts +2 -1
  44. package/src/Extensions/Object/properties.ts +0 -51
package/README.md CHANGED
@@ -26,3 +26,4 @@ import { ... } from 'DanhoLibraryJS';
26
26
  * [Extensions](/docs/Extensions.md)
27
27
  * [Interfaces](/docs/Interfaces.md)
28
28
  * [Types](/docs/Types.md)
29
+ * [Utils](/docs/Utils.md)
@@ -15,9 +15,8 @@ declare global {
15
15
  * @param items An array of tuples where each tuple contains an item and its corresponding weight.
16
16
  * @returns A randomly selected item based on the provided weights.
17
17
  */
18
- randomWithPercentages(items: [item: T, weight: number][]): T;
18
+ randomWithPercentages(items: Array<[item: T, weight: number]>): T;
19
19
  }
20
20
  }
21
21
  export declare function random<T>(this: Array<T>): T;
22
22
  export declare function shuffle<T>(this: Array<T>): Array<T>;
23
- export declare function randomWithPercentages<T>(items: [item: T, weight: number][]): T;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.randomWithPercentages = exports.shuffle = exports.random = void 0;
3
+ exports.shuffle = exports.random = void 0;
4
4
  function random() {
5
5
  const randomIndex = Math.floor(Math.random() * this.length);
6
6
  return this[randomIndex];
@@ -12,24 +12,3 @@ function shuffle() {
12
12
  }
13
13
  exports.shuffle = shuffle;
14
14
  Array.prototype.shuffle = shuffle;
15
- function randomWithPercentages(items) {
16
- if (items.length === 0)
17
- throw new Error('Items array cannot be empty');
18
- // Calculate total weight in case weights don't sum to 100
19
- const totalWeight = items.reduce((sum, [, weight]) => sum + weight, 0);
20
- if (totalWeight === 0)
21
- throw new Error('Total weight must be greater than zero');
22
- // Generate random number between 0 and totalWeight
23
- const random = Math.random() * totalWeight;
24
- // Find the item that corresponds to this random value
25
- let currentWeight = 0;
26
- for (const [item, weight] of items) {
27
- currentWeight += weight;
28
- if (random <= currentWeight) {
29
- return item;
30
- }
31
- }
32
- throw new Error('Unable to select an item based on weights');
33
- }
34
- exports.randomWithPercentages = randomWithPercentages;
35
- Array.prototype.randomWithPercentages = randomWithPercentages;
@@ -2,12 +2,11 @@ declare global {
2
2
  interface Array<T> {
3
3
  /**
4
4
  * Joins the elements of the array into a string, with optional custom separators.
5
- * @param args An array of strings or undefined values to be used as separators between elements.
6
- * @param separator The default separator to use between elements if args is not provided or undefined.
7
- * @param endSeparator The separator to use before the last element.
5
+ * @param separator The default separator to use between elements. Defaults to ','.
6
+ * @param endSeparator The separator to use before the last element. Default is '&'.
8
7
  * @returns A string with the joined elements.
9
8
  */
10
- join(args?: Array<string | undefined>, separator?: string, endSeparator?: string): string;
9
+ join(separator?: string, endSeparator?: string): string;
11
10
  }
12
11
  }
13
12
  export declare function join<T>(this: Array<T>, separator?: string, endSeparator?: string): string;
@@ -4,10 +4,10 @@ type Separators = {
4
4
  };
5
5
  declare global {
6
6
  interface Number {
7
- toSeparationString(separators: Partial<Separators>): string;
7
+ toSeparationString(separators?: Partial<Separators>): string;
8
8
  toRomanNumeral(): string;
9
9
  }
10
10
  }
11
- export declare function toSeparationString(this: number, separators: Partial<Separators>): string;
11
+ export declare function toSeparationString(this: number, separators?: Partial<Separators>): string;
12
12
  export declare function toRomanNumeral(this: number): string;
13
13
  export {};
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toRomanNumeral = exports.toSeparationString = void 0;
4
4
  function toSeparationString(separators) {
5
- const { thousand = '.', decimal = '.' } = separators;
5
+ const { thousand = '.', decimal = '.' } = separators || {};
6
6
  const [integerPart, decimalPart] = this.toString().split('.');
7
7
  const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, thousand);
8
8
  return decimalPart ? `${formattedInteger}${decimal}${decimalPart}` : formattedInteger;
@@ -6,6 +6,18 @@ declare global {
6
6
  * @param from Object to destruct
7
7
  */
8
8
  array<From extends {} = {}>(from: From): Array<[keyof From, ValueOf<From>]>;
9
+ /**
10
+ * Destructures object into array of property keys or values depending on selector
11
+ * @param from Object to destruct
12
+ * @param selector Selects whether to return keys or values
13
+ */
14
+ array<From extends {} = {}>(from: From, selector: 'keys'): Array<keyof From>;
15
+ /**
16
+ * Destructures object into array of property keys or values depending on selector
17
+ * @param from Object to destruct
18
+ * @param selector Selects whether to return keys or values
19
+ */
20
+ array<From extends {} = {}>(from: From, selector: 'values'): Array<ValueOf<From>>;
9
21
  /**
10
22
  * Destructures object into array of property keys
11
23
  * @param from Object to destruct
@@ -14,4 +26,6 @@ declare global {
14
26
  }
15
27
  }
16
28
  export declare function array<From extends {} = {}>(this: object, from: From): Array<[keyof From, ValueOf<From>]>;
29
+ export declare function array<From extends {} = {}>(this: object, from: From, selector: 'keys'): Array<keyof From>;
30
+ export declare function array<From extends {} = {}>(this: object, from: From, selector: 'values'): Array<ValueOf<From>>;
17
31
  export declare function keysOf<From extends {} = {}>(this: object, from: From): Array<keyof From>;
@@ -1,8 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.keysOf = exports.array = void 0;
4
- function array(from) {
5
- return Object.entries(from);
4
+ function array(from, selector) {
5
+ const entries = Object.entries(from);
6
+ switch (selector) {
7
+ case 'keys': return entries.map(([key]) => key);
8
+ case 'values': return entries.map(([, value]) => value);
9
+ default: return entries;
10
+ }
6
11
  }
7
12
  exports.array = array;
8
13
  Object.array = array;
@@ -13,24 +13,24 @@ declare global {
13
13
  */
14
14
  pick<From extends {}, Props extends keyof From>(from: From, ...props: Array<Props | Partial<From>>): Pick<From, Props>;
15
15
  /**
16
- * Receive an object with properties that are not in union of source and target objects
16
+ * Returns the difference between two objects (properties where values differ)
17
17
  * @param source Source object
18
18
  * @param target Target object
19
- * @param exclude Properties to exclude from difference
20
- * @returns Object with properties that are not in union of source and target objects, excluding specified properties
19
+ * @param exclude Properties to exclude from comparison
20
+ * @returns Object with properties where values differ between source and target, excluding specified properties
21
21
  */
22
- difference<T extends object>(source: T, target: T, ...exclude: Array<keyof T>): Omit<T, keyof T>;
22
+ difference<T extends object>(source: T, target: T, ...exclude: Array<keyof T>): Partial<T>;
23
23
  /**
24
24
  * Deeply combines objects, with later objects in parameters taking precedence over earlier ones. Does not combine arrays.
25
25
  * @param objects Objects to combine
26
26
  * @returns Combined object
27
27
  */
28
- combine<T extends Record<string, any | undefined>>(...objects: Array<Partial<T> | undefined>): T;
28
+ combine<T extends Record<string, any | undefined>>(...objects: Array<Combinable<T> | undefined>): T;
29
29
  }
30
30
  }
31
31
  export declare function omit<From extends {}, Props extends keyof From>(from: From, ...props: Array<Props | Partial<From>>): Omit<From, Props>;
32
32
  export declare function pick<From extends {}, Props extends keyof From>(from: From, ...props: Array<Props | Partial<From>>): Pick<From, Props>;
33
- export declare function difference<T extends object>(source: T, target: T, ...exclude: Array<keyof T>): Omit<T, keyof T>;
33
+ export declare function difference<T extends object>(source: T, target: T, ...exclude: Array<keyof T>): Partial<T>;
34
34
  type Combinable<T extends Record<string, any>> = {
35
35
  [key in keyof T]?: T[key] extends Record<string, any> ? Combinable<T[key]> : T[key];
36
36
  };
@@ -30,13 +30,16 @@ function pick(from, ...props) {
30
30
  exports.pick = pick;
31
31
  Object.pick = pick;
32
32
  function difference(source, target, ...exclude) {
33
- const diffKeys = new Set([...Object.keysOf(source), ...Object.keysOf(target)]);
34
- exclude?.forEach(key => diffKeys.delete(key));
35
- return [...diffKeys.values()].reduce((acc, key, i, arr) => {
36
- const sourceValue = JSON.stringify(source[key]);
37
- const targetValue = JSON.stringify(target[key]);
38
- if (sourceValue !== targetValue)
39
- acc[key] = target[key];
33
+ const excludeSet = new Set(exclude);
34
+ const allKeys = new Set([...Object.keysOf(source), ...Object.keysOf(target)]);
35
+ return [...allKeys].reduce((acc, key) => {
36
+ if (excludeSet.has(key))
37
+ return acc;
38
+ const sourceValue = source[key];
39
+ const targetValue = target[key];
40
+ if (JSON.stringify(sourceValue) !== JSON.stringify(targetValue)) {
41
+ acc[key] = targetValue;
42
+ }
40
43
  return acc;
41
44
  }, {});
42
45
  }
@@ -1 +1,2 @@
1
1
  export * from './case.extension';
2
+ export * from './string.extension';
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./case.extension"), exports);
18
+ __exportStar(require("./string.extension"), exports);
@@ -0,0 +1,6 @@
1
+ declare global {
2
+ interface String {
3
+ truncate(length: number, ellipsis?: string): string;
4
+ }
5
+ }
6
+ export declare function truncate(this: string, length: number, ellipsis?: string): string;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.truncate = void 0;
4
+ function truncate(length, ellipsis = "...") {
5
+ if (this.length <= length)
6
+ return this;
7
+ return this.slice(0, length - ellipsis.length) + ellipsis;
8
+ }
9
+ exports.truncate = truncate;
10
+ String.prototype.truncate = truncate;
@@ -5,7 +5,7 @@ export type Functionable<T, Args extends any[] = []> = T | ((...args: Args) => T
5
5
  /**
6
6
  * Item is Promise<T> or T
7
7
  */
8
- export type Promisable<T> = T | Promise<T>;
8
+ export type Promiseable<T> = T | Promise<T>;
9
9
  /**
10
10
  * Item is T or null
11
11
  */
@@ -1 +1,6 @@
1
1
  export declare function between(min: number, max: number): number;
2
+ export declare function randomWithPercentages<T>(items: [item: T, weight: number][]): T;
3
+ export declare const NumberUtils: {
4
+ between: typeof between;
5
+ randomWithPercentages: typeof randomWithPercentages;
6
+ };
@@ -1,7 +1,31 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.between = void 0;
3
+ exports.NumberUtils = exports.randomWithPercentages = exports.between = void 0;
4
4
  function between(min, max) {
5
5
  return Math.floor(Math.random() * (max - min + 1)) + min;
6
6
  }
7
7
  exports.between = between;
8
+ function randomWithPercentages(items) {
9
+ if (items.length === 0)
10
+ throw new Error('Items array cannot be empty');
11
+ // Calculate total weight in case weights don't sum to 100
12
+ const totalWeight = items.reduce((sum, [, weight]) => sum + weight, 0);
13
+ if (totalWeight === 0)
14
+ throw new Error('Total weight must be greater than zero');
15
+ // Generate random number between 0 and totalWeight
16
+ const random = Math.random() * totalWeight;
17
+ // Find the item that corresponds to this random value
18
+ let currentWeight = 0;
19
+ for (const [item, weight] of items) {
20
+ currentWeight += weight;
21
+ if (random <= currentWeight) {
22
+ return item;
23
+ }
24
+ }
25
+ throw new Error('Unable to select an item based on weights');
26
+ }
27
+ exports.randomWithPercentages = randomWithPercentages;
28
+ exports.NumberUtils = {
29
+ between,
30
+ randomWithPercentages,
31
+ };
@@ -1,3 +1,8 @@
1
1
  export declare function classNames(...args: Array<any>): string;
2
2
  export declare function randomId(length?: number): string;
3
3
  export declare function pluralize(countable: number | ArrayLike<any> | Map<any, any>, singular: string, plural?: string): string;
4
+ export declare const StringUtils: {
5
+ classNames: typeof classNames;
6
+ randomId: typeof randomId;
7
+ pluralize: typeof pluralize;
8
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.pluralize = exports.randomId = exports.classNames = void 0;
3
+ exports.StringUtils = exports.pluralize = exports.randomId = exports.classNames = void 0;
4
4
  function classNames(...args) {
5
5
  return args.reduce((acc, arg) => {
6
6
  if (!arg)
@@ -45,3 +45,8 @@ function pluralize(countable, singular, plural) {
45
45
  return `${singular}s`;
46
46
  }
47
47
  exports.pluralize = pluralize;
48
+ exports.StringUtils = {
49
+ classNames,
50
+ randomId,
51
+ pluralize
52
+ };
@@ -1,4 +1,7 @@
1
1
  export declare const TimeUtils: {
2
+ ensureStartZero(num: number): string;
3
+ get12HourFormat(hour: number): string;
4
+ get24HourFormat(hour: number): string;
2
5
  throttle<T>(throttleId: string, callback: () => T, cooldown: number): T;
3
6
  wrapInThrottle<T_1>(callback: (...args: T_1[]) => void, cooldown: number): (...args: T_1[]) => void;
4
7
  isThrottleOnCooldown(throttleId: string): boolean;
@@ -27,8 +27,10 @@ exports.TimeUtils = void 0;
27
27
  const Debounce = __importStar(require("./debounce.util"));
28
28
  const Functions = __importStar(require("./functions.util"));
29
29
  const Throttle = __importStar(require("./throttle.util"));
30
+ const StringUtils = __importStar(require("./string.util"));
30
31
  exports.TimeUtils = {
31
32
  ...Functions,
32
33
  ...Debounce,
33
34
  ...Throttle,
35
+ ...StringUtils,
34
36
  };
@@ -0,0 +1,3 @@
1
+ export declare function ensureStartZero(num: number): string;
2
+ export declare function get12HourFormat(hour: number): string;
3
+ export declare function get24HourFormat(hour: number): string;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.get24HourFormat = exports.get12HourFormat = exports.ensureStartZero = void 0;
4
+ function ensureStartZero(num) {
5
+ return num < 10 ? `0${num}` : num.toString();
6
+ }
7
+ exports.ensureStartZero = ensureStartZero;
8
+ function get12HourFormat(hour) {
9
+ if (hour === 0)
10
+ return '12am';
11
+ if (hour > 12)
12
+ return `${hour - 12}pm`;
13
+ return `${hour}am`;
14
+ }
15
+ exports.get12HourFormat = get12HourFormat;
16
+ function get24HourFormat(hour) {
17
+ return ensureStartZero(hour);
18
+ }
19
+ exports.get24HourFormat = get24HourFormat;
package/dist/index.d.ts CHANGED
@@ -2,3 +2,4 @@ export * from './Classes';
2
2
  export * from './Extensions';
3
3
  export * from './Interfaces';
4
4
  export * from './Types';
5
+ export * from './Utils';
package/dist/index.js CHANGED
@@ -18,3 +18,4 @@ __exportStar(require("./Classes"), exports);
18
18
  __exportStar(require("./Extensions"), exports);
19
19
  __exportStar(require("./Interfaces"), exports);
20
20
  __exportStar(require("./Types"), exports);
21
+ __exportStar(require("./Utils"), exports);
@@ -108,16 +108,6 @@ interface ArrayConstructor {
108
108
  }
109
109
  ```
110
110
 
111
- #### Standalone Functions
112
-
113
- ```ts
114
- /**
115
- * Selects random item from weighted items
116
- * @param items Array of [item, weight] tuples where weight is probability
117
- */
118
- function randomWithPercentages<T>(items: [item: T, weight: number][]): T;
119
- ```
120
-
121
111
  ### Function
122
112
 
123
113
  ```ts
@@ -192,9 +182,9 @@ interface Map<K, V> {
192
182
  interface Number {
193
183
  /**
194
184
  * Formats number with thousand and decimal separators
195
- * @param separators Custom separators for thousand and decimal
185
+ * @param separators Custom separators for thousand and decimal (optional)
196
186
  */
197
- toSeparationString(separators: Partial<{ thousand: string; decimal: string }>): string;
187
+ toSeparationString(separators?: Partial<{ thousand: string; decimal: string }>): string;
198
188
 
199
189
  /**
200
190
  * Converts number to Roman numeral (1-3999)
@@ -210,16 +200,52 @@ interface Number {
210
200
  ```ts
211
201
  interface ObjectConstructor {
212
202
  /**
213
- * Converts object to array of [key, value] tuples
214
- * @param from Object to convert
203
+ * Destructures object into array of [property, value]
204
+ * @param from Object to destruct
205
+ */
206
+ array<From extends {} = {}>(from: From): Array<[keyof From, ValueOf<From>]>;
207
+ /**
208
+ * Destructures object into array of property keys or values depending on selector
209
+ * @param from Object to destruct
210
+ * @param selector Selects whether to return keys or values
215
211
  */
216
- array<From = {}>(from: From): Array<[keyof From, ValueOf<From>]>;
212
+ array<From extends {} = {}>(from: From, selector: 'keys'): Array<keyof From>;
213
+ /**
214
+ * Destructures object into array of property keys or values depending on selector
215
+ * @param from Object to destruct
216
+ * @param selector Selects whether to return keys or values
217
+ */
218
+ array<From extends {} = {}>(from: From, selector: 'values'): Array<ValueOf<From>>;
217
219
 
218
220
  /**
219
221
  * Returns array of object keys with proper typing
220
222
  * @param from Object to get keys from
221
223
  */
222
224
  keysOf<From = {}>(from: From): Array<keyof From>;
225
+
226
+ /**
227
+ * Object with property filter methods by type
228
+ * Methods: getStrings, getNumbers, getBooleans, getUndefineds, getNulls,
229
+ * getObjects, getFunctions, getAnys, getDates, getRegExps,
230
+ * getPromises, getArrays, getMaps, getSets
231
+ * @example Object.properties.getStrings(obj) // Returns object with only string properties
232
+ */
233
+ properties: {
234
+ getStrings<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
235
+ getNumbers<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
236
+ getBooleans<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
237
+ getUndefineds<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
238
+ getNulls<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
239
+ getObjects<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
240
+ getFunctions<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
241
+ getAnys<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
242
+ getDates<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
243
+ getRegExps<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
244
+ getPromises<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
245
+ getArrays<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
246
+ getMaps<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
247
+ getSets<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions): Partial<Source>;
248
+ };
223
249
  }
224
250
  ```
225
251
 
@@ -278,6 +304,13 @@ interface String {
278
304
  * @param to Cases to convert to, can chain multiple conversions
279
305
  */
280
306
  convertCase(from: Case, ...to: Array<Case>): string;
307
+
308
+ /**
309
+ * Truncates string to specified length with optional ellipsis
310
+ * @param length Maximum length of string
311
+ * @param ellipsis String to append if truncated (default: '...')
312
+ */
313
+ truncate(length: number, ellipsis?: string): string;
281
314
  }
282
315
  ```
283
316
 
package/docs/Types.md CHANGED
@@ -38,7 +38,7 @@ type Functionable<T, Args extends any[] = []> = T | ((...args: Args) => T);
38
38
  /**
39
39
  * Value can be either T or a Promise that resolves to T
40
40
  */
41
- type Promisable<T> = T | Promise<T>;
41
+ type Promiseable<T> = T | Promise<T>;
42
42
 
43
43
  /**
44
44
  * Value can be T or null
package/docs/Utils.md ADDED
@@ -0,0 +1,335 @@
1
+ # [DanhoLibraryJS](../README.md)
2
+
3
+ ## Utils
4
+
5
+ Utility functions and classes for common tasks.
6
+
7
+ ### ApiUtils
8
+
9
+ ```ts
10
+ /**
11
+ * API utility class for making HTTP requests
12
+ */
13
+ class ApiUtils<ApiEndpoints extends string> {
14
+ /**
15
+ * @param options Configuration options
16
+ * @param options.baseEndpointDev Base URL for development environment
17
+ * @param options.baseEndpoint Base URL for production environment (optional)
18
+ * @param options.log Enable request logging (default: false)
19
+ */
20
+ constructor(options: {
21
+ baseEndpointDev: string;
22
+ baseEndpoint?: string;
23
+ log?: boolean;
24
+ });
25
+
26
+ /**
27
+ * Make a request to the API
28
+ * @param path The path to the endpoint
29
+ * @param options Request options (method, body, headers, etc.)
30
+ * @returns The response from the API
31
+ */
32
+ public async request<TData>(
33
+ path: ApiEndpoints,
34
+ options?: RequestOptions
35
+ ): Promise<TData>;
36
+
37
+ /**
38
+ * Get the base endpoint URL based on environment
39
+ */
40
+ public get baseEndpoint(): string;
41
+ }
42
+
43
+ /**
44
+ * Request options type
45
+ */
46
+ type RequestOptions<TBody = any> = Omit<RequestInit, 'method' | 'body'> & {
47
+ method?: HttpMethods;
48
+ body?: TBody;
49
+ params?: Record<string, string | number | boolean>;
50
+ };
51
+
52
+ /**
53
+ * HTTP methods
54
+ */
55
+ type HttpMethods =
56
+ | 'GET'
57
+ | 'POST'
58
+ | 'PUT'
59
+ | 'PATCH'
60
+ | 'DELETE'
61
+ | 'HEAD'
62
+ | 'OPTIONS';
63
+ ```
64
+
65
+ ### ColorUtils
66
+
67
+ ```ts
68
+ /**
69
+ * RGB color as tuple
70
+ */
71
+ type RGB = [number, number, number];
72
+
73
+ /**
74
+ * Hex color string
75
+ */
76
+ type Hex = `#${string}`;
77
+
78
+ /**
79
+ * Color type identifier
80
+ */
81
+ type ColorType = 'hex' | 'rgb' | 'hsl';
82
+
83
+ /**
84
+ * Convert colors between different formats
85
+ * @param value Color value to convert
86
+ * @param fromOrTo Source format (for strings) or target format (for RGB)
87
+ * @param to Target format (when converting from string)
88
+ */
89
+ function convert(value: RGB, to: Exclude<ColorType, 'rgb'>): string;
90
+ function convert(value: string, from: Exclude<ColorType, 'rgb'>, to: 'rgb'): RGB;
91
+ function convert(value: string | RGB, fromOrTo: ColorType, to?: ColorType): string | RGB;
92
+
93
+ /**
94
+ * Generate a random hex color
95
+ * @returns Random hex color string
96
+ */
97
+ function generateRandomColor(): Hex;
98
+
99
+ /**
100
+ * Color utilities object
101
+ */
102
+ const ColorUtils = {
103
+ convert,
104
+ generateRandomColor
105
+ };
106
+ ```
107
+
108
+ ### FormUtils
109
+
110
+ ```ts
111
+ /**
112
+ * Serialize a form into an object
113
+ * @param form The form element to serialize
114
+ * @param log Whether to log the serialization process (default: false)
115
+ * @returns An object containing the form data
116
+ */
117
+ function serializeForm<T extends object>(form: HTMLFormElement, log?: boolean): T;
118
+ ```
119
+
120
+ ### NumberUtils
121
+
122
+ ```ts
123
+ /**
124
+ * Generate a random number between min and max (inclusive)
125
+ * @param min Minimum value
126
+ * @param max Maximum value
127
+ * @returns Random number between min and max
128
+ */
129
+ function between(min: number, max: number): number;
130
+
131
+ /**
132
+ * Select a random item from weighted items
133
+ * @param items Array of [item, weight] tuples where weight determines probability
134
+ * @returns Randomly selected item based on weights
135
+ * @throws Error if items array is empty or total weight is zero
136
+ */
137
+ function randomWithPercentages<T>(items: [item: T, weight: number][]): T;
138
+
139
+ /**
140
+ * Number utilities object
141
+ */
142
+ const NumberUtils = {
143
+ between,
144
+ randomWithPercentages,
145
+ };
146
+ ```
147
+
148
+ ### PatcherUtils
149
+
150
+ ```ts
151
+ /**
152
+ * Patch event type
153
+ */
154
+ type PatchEvent = 'before' | 'instead' | 'after';
155
+
156
+ /**
157
+ * Monkey patch a property or method on an object
158
+ * @param target Object to patch
159
+ * @param property Property or method name to patch
160
+ * @param event When to run the patch ('before', 'instead', or 'after')
161
+ * @param replacement Replacement function or value handler
162
+ * @returns Function to unpatch
163
+ */
164
+ function patch<
165
+ TTarget extends object,
166
+ TProperty extends keyof TTarget,
167
+ TPatchEvent extends PatchEvent,
168
+ TPatchReplacement extends PatcherReplacement<TTarget, TProperty, TPatchEvent>
169
+ >(
170
+ target: TTarget,
171
+ property: TProperty,
172
+ event: TPatchEvent,
173
+ replacement: TPatchReplacement
174
+ ): (() => void) | undefined;
175
+
176
+ /**
177
+ * Remove all patches from a specific property
178
+ * @param target Object with patches
179
+ * @param property Property to unpatch
180
+ */
181
+ function unpatch<TTarget extends object, TProperty extends keyof TTarget>(
182
+ target: TTarget,
183
+ property: TProperty
184
+ ): void;
185
+
186
+ /**
187
+ * Remove all patches from all objects
188
+ */
189
+ function unpatchAll(): void;
190
+ ```
191
+
192
+ ### StringUtils
193
+
194
+ ```ts
195
+ /**
196
+ * Combines class names from various input types
197
+ * Supports strings, objects (key-value where truthy values include the key),
198
+ * arrays, and nested structures
199
+ * @param args Class name arguments
200
+ * @returns Combined class name string
201
+ */
202
+ function classNames(...args: Array<any>): string;
203
+
204
+ /**
205
+ * Generate a random ID string
206
+ * @param length Length of the ID (default: 16)
207
+ * @returns Random alphanumeric string
208
+ */
209
+ function randomId(length?: number): string;
210
+
211
+ /**
212
+ * Pluralize a word based on count
213
+ * @param countable Number, array-like object, or Map to count
214
+ * @param singular Singular form of the word
215
+ * @param plural Optional custom plural form (default: adds 's' to singular)
216
+ * @returns Singular or plural form based on count
217
+ */
218
+ function pluralize(
219
+ countable: number | ArrayLike<any> | Map<any, any>,
220
+ singular: string,
221
+ plural?: string
222
+ ): string;
223
+ ```
224
+
225
+ ### TimeUtils
226
+
227
+ ```ts
228
+ /**
229
+ * Wait for a specified amount of time or execute a callback after a delay
230
+ * @param time Milliseconds to wait
231
+ */
232
+ function wait<T>(time: number): Promise<void>;
233
+ function wait<T>(callback: (...args: any[]) => T, time: number): Promise<T>;
234
+
235
+ /**
236
+ * Get Unix timestamp from various date formats
237
+ * @param date Date object or date string
238
+ */
239
+ function getUnixTime(date: Date | string): number;
240
+ function getUnixTime(timestamp: number): number;
241
+
242
+ /**
243
+ * Debounce a function call
244
+ * @param debounceId Unique identifier for this debounce
245
+ * @param callback Function to debounce
246
+ * @param delay Delay in milliseconds
247
+ * @param signal Optional AbortSignal to cancel the debounce
248
+ * @returns Promise that resolves with callback result or rejects if cancelled
249
+ */
250
+ function debounce<T>(
251
+ debounceId: string,
252
+ callback: () => T,
253
+ delay: number,
254
+ signal?: AbortSignal
255
+ ): Promise<T>;
256
+
257
+ /**
258
+ * Wrap a function in a debounce
259
+ * @param callback Function to wrap
260
+ * @param delay Delay in milliseconds
261
+ * @returns Debounced function
262
+ */
263
+ function wrapInDebounce<T>(
264
+ callback: (...args: T[]) => void,
265
+ delay: number
266
+ ): (...args: T[]) => void;
267
+
268
+ /**
269
+ * Throttle a function call
270
+ * @param throttleId Unique identifier for this throttle
271
+ * @param callback Function to throttle
272
+ * @param cooldown Cooldown period in milliseconds
273
+ * @returns Callback result or undefined if on cooldown
274
+ */
275
+ function throttle<T>(
276
+ throttleId: string,
277
+ callback: () => T,
278
+ cooldown: number
279
+ ): T | undefined;
280
+
281
+ /**
282
+ * Wrap a function in a throttle
283
+ * @param callback Function to wrap
284
+ * @param cooldown Cooldown period in milliseconds
285
+ * @returns Throttled function
286
+ */
287
+ function wrapInThrottle<T>(
288
+ callback: (...args: T[]) => void,
289
+ cooldown: number
290
+ ): (...args: T[]) => void;
291
+
292
+ /**
293
+ * Check if a throttle is currently on cooldown
294
+ * @param throttleId Throttle identifier to check
295
+ * @returns True if on cooldown, false otherwise
296
+ */
297
+ function isThrottleOnCooldown(throttleId: string): boolean;
298
+
299
+ /**
300
+ * Ensure a number is formatted with a leading zero if less than 10
301
+ * @param num Number to format
302
+ * @returns String with leading zero if needed
303
+ */
304
+ function ensureStartZero(num: number): string;
305
+
306
+ /**
307
+ * Convert 24-hour format to 12-hour format with am/pm
308
+ * @param hour Hour in 24-hour format (0-23)
309
+ * @returns Hour in 12-hour format with am/pm suffix
310
+ */
311
+ function get12HourFormat(hour: number): string;
312
+
313
+ /**
314
+ * Format hour in 24-hour format with leading zero
315
+ * @param hour Hour to format
316
+ * @returns Hour as two-digit string
317
+ */
318
+ function get24HourFormat(hour: number): string;
319
+
320
+ /**
321
+ * Time utilities object containing all time-related functions
322
+ */
323
+ const TimeUtils = {
324
+ wait,
325
+ getUnixTime,
326
+ debounce,
327
+ wrapInDebounce,
328
+ throttle,
329
+ wrapInThrottle,
330
+ isThrottleOnCooldown,
331
+ ensureStartZero,
332
+ get12HourFormat,
333
+ get24HourFormat
334
+ };
335
+ ```
package/docs/index.md CHANGED
@@ -26,3 +26,4 @@ import { ... } from 'DanhoLibraryJS';
26
26
  * [Extensions](./Extensions.md)
27
27
  * [Interfaces](./Interfaces.md)
28
28
  * [Types](./Types.md)
29
+ * [Utils](./Utils.md)
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "registry": "https://registry.npmjs.org/"
5
5
  },
6
- "version": "2.0.1",
6
+ "version": "2.0.2",
7
7
  "description": "Library for Javascript.",
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
@@ -17,7 +17,7 @@ declare global {
17
17
  * @param items An array of tuples where each tuple contains an item and its corresponding weight.
18
18
  * @returns A randomly selected item based on the provided weights.
19
19
  */
20
- randomWithPercentages(items: [item: T, weight: number][]): T;
20
+ randomWithPercentages(items: Array<[item: T, weight: number]>): T;
21
21
  }
22
22
  }
23
23
 
@@ -30,27 +30,4 @@ Array.prototype.random = random;
30
30
  export function shuffle<T>(this: Array<T>): Array<T> {
31
31
  return this.sort(() => Math.random() - 0.5);
32
32
  }
33
- Array.prototype.shuffle = shuffle;
34
-
35
- export function randomWithPercentages<T>(items: [item: T, weight: number][]): T {
36
- if (items.length === 0) throw new Error('Items array cannot be empty');
37
-
38
- // Calculate total weight in case weights don't sum to 100
39
- const totalWeight = items.reduce((sum, [, weight]) => sum + weight, 0);
40
- if (totalWeight === 0) throw new Error('Total weight must be greater than zero');
41
-
42
- // Generate random number between 0 and totalWeight
43
- const random = Math.random() * totalWeight;
44
-
45
- // Find the item that corresponds to this random value
46
- let currentWeight = 0;
47
- for (const [item, weight] of items) {
48
- currentWeight += weight;
49
- if (random <= currentWeight) {
50
- return item;
51
- }
52
- }
53
-
54
- throw new Error('Unable to select an item based on weights');
55
- }
56
- Array.prototype.randomWithPercentages = randomWithPercentages;
33
+ Array.prototype.shuffle = shuffle;
@@ -2,12 +2,11 @@ declare global {
2
2
  interface Array<T> {
3
3
  /**
4
4
  * Joins the elements of the array into a string, with optional custom separators.
5
- * @param args An array of strings or undefined values to be used as separators between elements.
6
- * @param separator The default separator to use between elements if args is not provided or undefined.
7
- * @param endSeparator The separator to use before the last element.
5
+ * @param separator The default separator to use between elements. Defaults to ','.
6
+ * @param endSeparator The separator to use before the last element. Default is '&'.
8
7
  * @returns A string with the joined elements.
9
8
  */
10
- join(args?: Array<string | undefined>, separator?: string, endSeparator?: string): string;
9
+ join(separator?: string, endSeparator?: string): string;
11
10
  }
12
11
  }
13
12
 
@@ -5,13 +5,13 @@ type Separators = {
5
5
 
6
6
  declare global {
7
7
  interface Number {
8
- toSeparationString(separators: Partial<Separators>): string;
8
+ toSeparationString(separators?: Partial<Separators>): string;
9
9
  toRomanNumeral(): string;
10
10
  }
11
11
  }
12
12
 
13
- export function toSeparationString(this: number, separators: Partial<Separators>): string {
14
- const { thousand = '.', decimal = '.' } = separators;
13
+ export function toSeparationString(this: number, separators?: Partial<Separators>): string {
14
+ const { thousand = '.', decimal = '.' } = separators || {};
15
15
  const [integerPart, decimalPart] = this.toString().split('.');
16
16
  const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, thousand);
17
17
  return decimalPart ? `${formattedInteger}${decimal}${decimalPart}` : formattedInteger;
@@ -7,6 +7,18 @@ declare global {
7
7
  * @param from Object to destruct
8
8
  */
9
9
  array<From extends {} = {}>(from: From): Array<[keyof From, ValueOf<From>]>;
10
+ /**
11
+ * Destructures object into array of property keys or values depending on selector
12
+ * @param from Object to destruct
13
+ * @param selector Selects whether to return keys or values
14
+ */
15
+ array<From extends {} = {}>(from: From, selector: 'keys'): Array<keyof From>;
16
+ /**
17
+ * Destructures object into array of property keys or values depending on selector
18
+ * @param from Object to destruct
19
+ * @param selector Selects whether to return keys or values
20
+ */
21
+ array<From extends {} = {}>(from: From, selector: 'values'): Array<ValueOf<From>>;
10
22
 
11
23
  /**
12
24
  * Destructures object into array of property keys
@@ -16,8 +28,17 @@ declare global {
16
28
  }
17
29
  }
18
30
 
19
- export function array<From extends {} = {}>(this: object, from: From): Array<[keyof From, ValueOf<From>]> {
20
- return Object.entries(from) as Array<[keyof From, ValueOf<From>]>;
31
+ export function array<From extends {} = {}>(this: object, from: From): Array<[keyof From, ValueOf<From>]>;
32
+ export function array<From extends {} = {}>(this: object, from: From, selector: 'keys'): Array<keyof From>;
33
+ export function array<From extends {} = {}>(this: object, from: From, selector: 'values'): Array<ValueOf<From>>;
34
+ export function array<From extends {} = {}>(this: object, from: From, selector?: 'keys' | 'values') {
35
+ const entries = Object.entries(from) as Array<[keyof From, ValueOf<From>]>;
36
+
37
+ switch (selector) {
38
+ case 'keys': return entries.map(([key]) => key);
39
+ case 'values': return entries.map(([, value]) => value);
40
+ default: return entries;
41
+ }
21
42
  }
22
43
  Object.array = array;
23
44
 
@@ -15,20 +15,20 @@ declare global {
15
15
  pick<From extends {}, Props extends keyof From>(from: From, ...props: Array<Props | Partial<From>>): Pick<From, Props>;
16
16
 
17
17
  /**
18
- * Receive an object with properties that are not in union of source and target objects
18
+ * Returns the difference between two objects (properties where values differ)
19
19
  * @param source Source object
20
20
  * @param target Target object
21
- * @param exclude Properties to exclude from difference
22
- * @returns Object with properties that are not in union of source and target objects, excluding specified properties
21
+ * @param exclude Properties to exclude from comparison
22
+ * @returns Object with properties where values differ between source and target, excluding specified properties
23
23
  */
24
- difference<T extends object>(source: T, target: T, ...exclude: Array<keyof T>): Omit<T, keyof T>;
24
+ difference<T extends object>(source: T, target: T, ...exclude: Array<keyof T>): Partial<T>;
25
25
 
26
26
  /**
27
27
  * Deeply combines objects, with later objects in parameters taking precedence over earlier ones. Does not combine arrays.
28
28
  * @param objects Objects to combine
29
29
  * @returns Combined object
30
30
  */
31
- combine<T extends Record<string, any | undefined>>(...objects: Array<Partial<T> | undefined>): T;
31
+ combine<T extends Record<string, any | undefined>>(...objects: Array<Combinable<T> | undefined>): T;
32
32
  }
33
33
  }
34
34
 
@@ -60,16 +60,21 @@ export function pick<From extends {}, Props extends keyof From>(from: From, ...p
60
60
  }
61
61
  Object.pick = pick;
62
62
 
63
- export function difference<T extends object>(source: T, target: T, ...exclude: Array<keyof T>): Omit<T, keyof T> {
64
- const diffKeys = new Set([...Object.keysOf(source), ...Object.keysOf(target)]);
65
- exclude?.forEach(key => diffKeys.delete(key));
63
+ export function difference<T extends object>(source: T, target: T, ...exclude: Array<keyof T>): Partial<T> {
64
+ const excludeSet = new Set(exclude);
65
+ const allKeys = new Set([...Object.keysOf(source), ...Object.keysOf(target)]);
66
66
 
67
- return [...diffKeys.values()].reduce((acc, key, i, arr) => {
68
- const sourceValue = JSON.stringify(source[key]);
69
- const targetValue = JSON.stringify(target[key]);
70
- if (sourceValue !== targetValue) acc[key] = target[key];
67
+ return [...allKeys].reduce((acc, key) => {
68
+ if (excludeSet.has(key)) return acc;
69
+
70
+ const sourceValue = (source as any)[key];
71
+ const targetValue = (target as any)[key];
72
+
73
+ if (JSON.stringify(sourceValue) !== JSON.stringify(targetValue)) {
74
+ acc[key] = targetValue;
75
+ }
71
76
  return acc;
72
- }, {} as T);
77
+ }, {} as any) as Partial<T>;
73
78
  }
74
79
  Object.difference = difference;
75
80
 
@@ -1 +1,2 @@
1
- export * from './case.extension';
1
+ export * from './case.extension';
2
+ export * from './string.extension';
@@ -0,0 +1,11 @@
1
+ declare global {
2
+ interface String {
3
+ truncate(length: number, ellipsis?: string): string;
4
+ }
5
+ }
6
+
7
+ export function truncate(this: string, length: number, ellipsis: string = "..."): string {
8
+ if (this.length <= length) return this;
9
+ return this.slice(0, length - ellipsis.length) + ellipsis;
10
+ }
11
+ String.prototype.truncate = truncate;
package/src/Types/Able.ts CHANGED
@@ -6,7 +6,7 @@ export type Functionable<T, Args extends any[] = []> = T | ((...args: Args) => T
6
6
  /**
7
7
  * Item is Promise<T> or T
8
8
  */
9
- export type Promisable<T> = T | Promise<T>;
9
+ export type Promiseable<T> = T | Promise<T>;
10
10
 
11
11
  /**
12
12
  * Item is T or null
@@ -1,3 +1,30 @@
1
1
  export function between(min: number, max: number): number {
2
2
  return Math.floor(Math.random() * (max - min + 1)) + min;
3
+ }
4
+
5
+ export function randomWithPercentages<T>(items: [item: T, weight: number][]): T {
6
+ if (items.length === 0) throw new Error('Items array cannot be empty');
7
+
8
+ // Calculate total weight in case weights don't sum to 100
9
+ const totalWeight = items.reduce((sum, [, weight]) => sum + weight, 0);
10
+ if (totalWeight === 0) throw new Error('Total weight must be greater than zero');
11
+
12
+ // Generate random number between 0 and totalWeight
13
+ const random = Math.random() * totalWeight;
14
+
15
+ // Find the item that corresponds to this random value
16
+ let currentWeight = 0;
17
+ for (const [item, weight] of items) {
18
+ currentWeight += weight;
19
+ if (random <= currentWeight) {
20
+ return item;
21
+ }
22
+ }
23
+
24
+ throw new Error('Unable to select an item based on weights');
25
+ }
26
+
27
+ export const NumberUtils = {
28
+ between,
29
+ randomWithPercentages,
3
30
  }
@@ -41,4 +41,10 @@ export function pluralize(countable: number | ArrayLike<any> | Map<any, any>, si
41
41
  if (count === 1) return singular;
42
42
  if (plural) return plural;
43
43
  return `${singular}s`;
44
- }
44
+ }
45
+
46
+ export const StringUtils = {
47
+ classNames,
48
+ randomId,
49
+ pluralize
50
+ };
@@ -1,9 +1,11 @@
1
1
  import * as Debounce from './debounce.util';
2
2
  import * as Functions from './functions.util';
3
3
  import * as Throttle from './throttle.util';
4
+ import * as StringUtils from './string.util';
4
5
 
5
6
  export const TimeUtils = {
6
7
  ...Functions,
7
8
  ...Debounce,
8
9
  ...Throttle,
10
+ ...StringUtils,
9
11
  };
@@ -0,0 +1,13 @@
1
+ export function ensureStartZero(num: number): string {
2
+ return num < 10 ? `0${num}` : num.toString();
3
+ }
4
+
5
+ export function get12HourFormat(hour: number): string {
6
+ if (hour === 0) return '12am';
7
+ if (hour > 12) return `${hour - 12}pm`;
8
+ return `${hour}am`;
9
+ }
10
+
11
+ export function get24HourFormat(hour: number): string {
12
+ return ensureStartZero(hour);
13
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './Classes';
2
2
  export * from './Extensions';
3
3
  export * from './Interfaces';
4
- export * from './Types';
4
+ export * from './Types';
5
+ export * from './Utils';
@@ -1,51 +0,0 @@
1
- import { PropertiesWith, If } from '../../Types';
2
- import { convertCase } from '../String/case.extension';
3
-
4
- type PrimitiveMap = {
5
- string: string;
6
- number: number;
7
- boolean: boolean;
8
- undefined: undefined;
9
- null: null;
10
- object: object;
11
- function: Function;
12
- any: any;
13
- Date: Date;
14
- RegExp: RegExp;
15
- Promise: Promise<any>;
16
- Array: Array<any>;
17
- Map: Map<any, any>;
18
- Set: Set<any>;
19
- };
20
-
21
- /**
22
- * Object with getPrimitiveTypes<Source, AllowFunctions extends boolean>(
23
- * source: Source,
24
- * allowFunctions: AllowFunctions = false
25
- * ): Object with properties from source that matches primitive type
26
- */
27
- export type Properties = {
28
- [Key in keyof PrimitiveMap as `get${Capitalize<Key>}s`]:
29
- <Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions) =>
30
- If<AllowFunctions,
31
- PropertiesWith<PrimitiveMap[Key] | ((...args: any[]) => PrimitiveMap[Key]), Source>,
32
- PropertiesWith<PrimitiveMap[Key], Source>
33
- >
34
- };
35
-
36
- export const properties: Properties = [
37
- 'string', 'number', 'boolean', 'undefined', 'null',
38
- 'object', 'function', 'any',
39
- 'Date', 'RegExp', 'Promise', 'Array', 'Map', 'Set'
40
- ].reduce((result, primitive) => {
41
- result[`get${convertCase('camel', 'pascal')}s` as keyof Properties] = function <Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions: AllowFunctions = false as AllowFunctions) {
42
- return Object.keysOf<Source>(source).reduce((result, key) => {
43
- if ((source[key] as any).constructor.name === primitive ||
44
- (withFunctions && typeof source[key] === 'function' && source[key] as any).constructor.name === primitive) {
45
- result[key] = source[key];
46
- }
47
- return result;
48
- }, {} as any);
49
- };
50
- return result;
51
- }, {} as Properties);