danholibraryjs 1.10.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/dist/Classes/DanhoLogger.d.ts +23 -0
  2. package/dist/Classes/DanhoLogger.js +65 -0
  3. package/dist/Classes/Events/EventEmitter.d.ts +1 -1
  4. package/dist/Classes/Events/EventEmitter.js +1 -1
  5. package/dist/Classes/Time/Date.d.ts +1 -0
  6. package/dist/Classes/Time/Date.js +4 -1
  7. package/dist/Classes/Time/Time.d.ts +5 -4
  8. package/dist/Classes/Time/Time.js +7 -4
  9. package/dist/Classes/index.d.ts +1 -0
  10. package/dist/Classes/index.js +1 -0
  11. package/dist/Classes/store.d.ts +5 -9
  12. package/dist/Extensions/Array/array.extension.d.ts +42 -0
  13. package/dist/Extensions/Array/array.extension.js +57 -0
  14. package/dist/Extensions/Array/crud.extension.d.ts +24 -0
  15. package/dist/Extensions/Array/crud.extension.js +28 -0
  16. package/dist/Extensions/Array/index.d.ts +20 -0
  17. package/dist/Extensions/Array/index.js +40 -0
  18. package/dist/Extensions/Array/loop.extension.d.ts +18 -0
  19. package/dist/Extensions/Array/loop.extension.js +23 -0
  20. package/dist/Extensions/Array/random.extension.d.ts +23 -0
  21. package/dist/Extensions/Array/random.extension.js +35 -0
  22. package/dist/Extensions/Array/sort.extension.d.ts +27 -0
  23. package/dist/Extensions/Array/sort.extension.js +31 -0
  24. package/dist/Extensions/Array/string.extension.d.ts +13 -0
  25. package/dist/Extensions/Array/string.extension.js +14 -0
  26. package/dist/Extensions/Array.d.ts +17 -3
  27. package/dist/Extensions/Array.js +0 -12
  28. package/dist/Extensions/Function.d.ts +17 -2
  29. package/dist/Extensions/Function.js +15 -2
  30. package/dist/Extensions/Number.d.ts +13 -0
  31. package/dist/Extensions/Number.js +40 -0
  32. package/dist/Extensions/Object/arrays.extension.d.ts +17 -0
  33. package/dist/Extensions/Object/arrays.extension.js +13 -0
  34. package/dist/Extensions/Object/booleans.extension.d.ts +18 -0
  35. package/dist/Extensions/Object/booleans.extension.js +37 -0
  36. package/dist/Extensions/Object/extracts.extension.d.ts +38 -0
  37. package/dist/Extensions/Object/extracts.extension.js +72 -0
  38. package/dist/Extensions/Object/index.d.ts +8 -47
  39. package/dist/Extensions/Object/index.js +31 -33
  40. package/dist/Extensions/Object/properties.extension.d.ts +6 -0
  41. package/dist/Extensions/Object/properties.extension.js +4 -0
  42. package/dist/Extensions/Object/properties.js +1 -2
  43. package/dist/Extensions/String/case.extension.d.ts +12 -0
  44. package/dist/Extensions/String/case.extension.js +55 -0
  45. package/dist/Extensions/String/index.d.ts +4 -0
  46. package/dist/Extensions/String/index.js +30 -0
  47. package/dist/Extensions/index.d.ts +1 -12
  48. package/dist/Extensions/index.js +1 -9
  49. package/dist/Types/Able.d.ts +16 -0
  50. package/dist/Types/Able.js +2 -0
  51. package/dist/Types/Array.d.ts +6 -0
  52. package/dist/Types/Array.js +2 -0
  53. package/dist/Types/C#.d.ts +8 -0
  54. package/dist/Types/C#.js +2 -0
  55. package/dist/Types/Date.d.ts +1 -1
  56. package/dist/Types/Events.d.ts +2 -2
  57. package/dist/Types/Function.d.ts +5 -0
  58. package/dist/Types/Function.js +2 -0
  59. package/dist/Types/Object.d.ts +4 -0
  60. package/dist/Types/Object.js +2 -0
  61. package/dist/Types/PropertiesWith.d.ts +21 -0
  62. package/dist/Types/String.d.ts +1 -0
  63. package/dist/Types/String.js +2 -0
  64. package/dist/Types/TransformTypes.d.ts +9 -0
  65. package/dist/Types/index.d.ts +6 -28
  66. package/dist/Types/index.js +6 -0
  67. package/dist/Utils/ApiUtil/ApiTypes.d.ts +15 -0
  68. package/dist/Utils/ApiUtil/ApiTypes.js +15 -0
  69. package/dist/Utils/ApiUtil/RequestUtil.d.ts +19 -0
  70. package/dist/Utils/ApiUtil/RequestUtil.js +73 -0
  71. package/dist/Utils/ApiUtil/index.d.ts +20 -0
  72. package/dist/Utils/ApiUtil/index.js +33 -0
  73. package/dist/Utils/ApiUtils/ApiTypes.d.ts +15 -0
  74. package/dist/Utils/ApiUtils/ApiTypes.js +15 -0
  75. package/dist/Utils/ApiUtils/RequestUtil.d.ts +19 -0
  76. package/dist/Utils/ApiUtils/RequestUtil.js +73 -0
  77. package/dist/Utils/ApiUtils/index.d.ts +20 -0
  78. package/dist/Utils/ApiUtils/index.js +33 -0
  79. package/dist/Utils/ColorUtils.d.ts +11 -0
  80. package/dist/Utils/ColorUtils.js +93 -0
  81. package/dist/Utils/FormUtil.d.ts +6 -0
  82. package/dist/Utils/FormUtil.js +35 -0
  83. package/dist/Utils/FormUtils.d.ts +6 -0
  84. package/dist/Utils/FormUtils.js +35 -0
  85. package/dist/Utils/NumberUtils.d.ts +1 -0
  86. package/dist/Utils/NumberUtils.js +7 -0
  87. package/dist/Utils/PatcherUtils.d.ts +6 -0
  88. package/dist/Utils/PatcherUtils.js +80 -0
  89. package/dist/Utils/StringUtils.d.ts +3 -0
  90. package/dist/Utils/StringUtils.js +47 -0
  91. package/dist/Utils/TimeUtils/debounce.util.d.ts +22 -0
  92. package/dist/Utils/TimeUtils/debounce.util.js +78 -0
  93. package/dist/Utils/TimeUtils/functions.util.d.ts +4 -0
  94. package/dist/Utils/TimeUtils/functions.util.js +21 -0
  95. package/dist/Utils/TimeUtils/index.d.ts +15 -0
  96. package/dist/Utils/TimeUtils/index.js +34 -0
  97. package/dist/Utils/TimeUtils/throttle.util.d.ts +15 -0
  98. package/dist/Utils/TimeUtils/throttle.util.js +43 -0
  99. package/dist/Utils/index.d.ts +7 -0
  100. package/dist/Utils/index.js +23 -0
  101. package/package.json +4 -2
  102. package/src/Classes/DanhoLogger.ts +78 -0
  103. package/src/Classes/Events/Event.ts +96 -96
  104. package/src/Classes/Events/EventCollection.ts +90 -90
  105. package/src/Classes/Events/EventEmitter.ts +68 -68
  106. package/src/Classes/Time/Date.ts +219 -216
  107. package/src/Classes/Time/Time.ts +109 -104
  108. package/src/Classes/Time/TimeSpan.ts +171 -171
  109. package/src/Classes/index.ts +1 -0
  110. package/src/Classes/store.ts +22 -22
  111. package/src/Extensions/Array/array.extension.ts +103 -0
  112. package/src/Extensions/Array/crud.extension.ts +46 -0
  113. package/src/Extensions/Array/index.ts +15 -0
  114. package/src/Extensions/Array/loop.extension.ts +38 -0
  115. package/src/Extensions/Array/random.extension.ts +56 -0
  116. package/src/Extensions/Array/sort.extension.ts +52 -0
  117. package/src/Extensions/Array/string.extension.ts +22 -0
  118. package/src/Extensions/Document.ts +39 -39
  119. package/src/Extensions/Function.ts +37 -10
  120. package/src/Extensions/Map.ts +56 -56
  121. package/src/Extensions/Number.ts +50 -0
  122. package/src/Extensions/Object/arrays.extension.ts +27 -0
  123. package/src/Extensions/Object/booleans.extension.ts +46 -0
  124. package/src/Extensions/Object/extracts.extension.ts +102 -0
  125. package/src/Extensions/Object/index.ts +9 -80
  126. package/src/Extensions/Object/properties.extension.ts +11 -0
  127. package/src/Extensions/Object/properties.ts +35 -36
  128. package/src/Extensions/String/case.extension.ts +95 -0
  129. package/src/Extensions/String/index.ts +5 -0
  130. package/src/Extensions/index.ts +2 -20
  131. package/src/Interfaces/ElementOptions.ts +7 -7
  132. package/src/Interfaces/IReplacement.ts +2 -2
  133. package/src/Types/Able.ts +22 -0
  134. package/src/Types/Array.ts +7 -0
  135. package/src/Types/C#.ts +9 -0
  136. package/src/Types/Date.ts +1 -1
  137. package/src/Types/Events.ts +12 -12
  138. package/src/Types/Function.ts +10 -0
  139. package/src/Types/Object.ts +4 -0
  140. package/src/Types/PropertiesWith.ts +35 -4
  141. package/src/Types/String.ts +1 -0
  142. package/src/Types/TransformTypes.ts +23 -5
  143. package/src/Types/index.ts +7 -41
  144. package/src/Utils/ApiUtils/ApiTypes.ts +43 -0
  145. package/src/Utils/ApiUtils/RequestUtil.ts +87 -0
  146. package/src/Utils/ApiUtils/index.ts +39 -0
  147. package/src/Utils/ColorUtils.ts +102 -0
  148. package/src/Utils/FormUtils.ts +33 -0
  149. package/src/Utils/NumberUtils.ts +3 -0
  150. package/src/Utils/PatcherUtils.ts +111 -0
  151. package/src/Utils/StringUtils.ts +44 -0
  152. package/src/Utils/TimeUtils/debounce.util.ts +85 -0
  153. package/src/Utils/TimeUtils/functions.util.ts +18 -0
  154. package/src/Utils/TimeUtils/index.ts +9 -0
  155. package/src/Utils/TimeUtils/throttle.util.ts +44 -0
  156. package/src/Utils/index.ts +8 -0
  157. package/src/Extensions/Array.ts +0 -95
  158. package/src/Extensions/String.ts +0 -54
@@ -1,24 +1,6 @@
1
-
2
1
  export * from './Array';
3
2
  export * from './Document';
4
3
  export * from './Map';
5
4
  export * from './Object';
6
- export * from './String';
7
-
8
- declare global {
9
- interface BooleanConstructor {
10
- /**
11
- * Parses string to boolean. Will only return true if value === "true" otherwise false
12
- */
13
- parseBoolean(value: string): boolean
14
- }
15
- }
16
-
17
- function parseBoolean(value: string) {
18
- return value === "true";
19
- };
20
- Boolean.parseBoolean = parseBoolean;
21
-
22
- export const BooleanExtensions = {
23
- parseBoolean
24
- };
5
+ export * from './Number';
6
+ export * from './String';
@@ -1,9 +1,9 @@
1
- import { Arrayable, IElement } from "../Types"
1
+ import { Arrayable, IElement } from "../Types";
2
2
 
3
3
  type Events = Record<
4
- `on${Capitalize<keyof HTMLElementEventMap>}`,
5
- (event: Event) => void
6
- >
4
+ `on${Capitalize<keyof HTMLElementEventMap>}`,
5
+ (event: Event) => void
6
+ >;
7
7
 
8
8
  /**
9
9
  * Construction options when creating an HTML element using:
@@ -12,10 +12,10 @@ type Events = Record<
12
12
  * @borrows Arrayable
13
13
  */
14
14
  export type ElementOptions = Partial<
15
- Events & Record<string, any> & {
15
+ Events & Record<string, any> & {
16
16
  id: string,
17
17
  className: Arrayable<string>;
18
18
  children: Arrayable<IElement>;
19
- dataset: Record<string, string>
20
- }>
19
+ dataset: Record<string, string>;
20
+ }>;
21
21
  export default ElementOptions;
@@ -7,7 +7,7 @@ import { StringRegex } from "../Types";
7
7
  * @borrows StringRegex
8
8
  */
9
9
  export interface IReplacement {
10
- replacer?: StringRegex,
11
- replacement?: string
10
+ replacer?: StringRegex,
11
+ replacement?: string;
12
12
  }
13
13
  export default IReplacement;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Item is function or T
3
+ */
4
+ export type Functionable<T, Args extends any[] = []> = T | ((...args: Args) => T);
5
+
6
+ /**
7
+ * Item is Promise<T> or T
8
+ */
9
+ export type Promisable<T> = T | Promise<T>;
10
+
11
+ /**
12
+ * Item is T or null
13
+ */
14
+ export type Nullable<T> = T | null;
15
+
16
+ /**
17
+ * Item cannot be null or undefined
18
+ */
19
+ export type NonNullable<T> =
20
+ T extends null ? never :
21
+ T extends undefined ? never :
22
+ T;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Item is single or multiple
3
+ */
4
+ export type Arrayable<T> = T | Array<T>;
5
+
6
+ export type SingleArrayable<T> = T | [T];
7
+ export type TFromArray<T> = T extends Array<infer U> ? U : never;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * C# Guid representation
3
+ */
4
+ export type Guid = string;
5
+
6
+ /**
7
+ * C# TimeSpan representation from JSON
8
+ */
9
+ export type TimeSpanType = string;
package/src/Types/Date.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type LongMonth = 'Janurary' | 'February' | 'March' | 'April' | 'May' | 'June' | 'July' | 'August' | 'September' | 'October' | 'November' | 'December';
1
+ export type LongMonth = 'January' | 'February' | 'March' | 'April' | 'May' | 'June' | 'July' | 'August' | 'September' | 'October' | 'November' | 'December';
2
2
  export type ShortMonth = 'Jan' | 'Feb' | 'Mar' | 'Apr' | 'May' | 'Jun' | 'Jul' | 'Aug' | 'Sep' | 'Oct' | 'Nov' | 'Dec';
3
3
  export type Month = LongMonth | ShortMonth;
4
4
 
@@ -1,15 +1,15 @@
1
1
  /**
2
- * Default eventhandler mapper. Object with properties that are arrays
2
+ * Default event-handler mapper. Object with properties that are arrays
3
3
  */
4
- export type BaseEvent<Keys extends string, Types extends Array<any>> = Record<Keys, Types>;
4
+ export type BaseEvent<Keys extends string, Types extends Array<any>> = Record<Keys, Types>;
5
5
 
6
- /**
7
- * Eventhandler type for:
8
- * @see EventCollection
9
- * @borrows BaseEvent
10
- */
11
- export type EventHandler<
12
- Events extends BaseEvent<string, Array<any>> = BaseEvent<string, Array<any>>,
13
- Event extends keyof Events = keyof Events,
14
- ReturnType = any
15
- > = (...args: Events[Event]) => ReturnType;
6
+ /**
7
+ * Event-handler type for:
8
+ * @see EventCollection
9
+ * @borrows BaseEvent
10
+ */
11
+ export type EventHandler<
12
+ Events extends BaseEvent<string, Array<any>> = BaseEvent<string, Array<any>>,
13
+ Event extends keyof Events = keyof Events,
14
+ ReturnType = any
15
+ > = (...args: Events[Event]) => ReturnType;
@@ -0,0 +1,10 @@
1
+ export type NewReturnType<
2
+ Function extends (...args: any[]) => any,
3
+ NewReturnType extends any
4
+ > = (...args: Parameters<Function>) => NewReturnType;
5
+
6
+ export type PromisedReturn<
7
+ Function extends (...args: any[]) => any,
8
+ > = NewReturnType<Function, Promise<ReturnType<Function>>>;
9
+
10
+ export type NoFunctions<T> = { [K in keyof T]: T[K] extends Function ? never : T[K]; };
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Return types of T
3
+ */
4
+ export type ValueOf<T> = T[keyof T];
@@ -2,13 +2,44 @@
2
2
  * Filters all properties from From that has the return type of Type
3
3
  */
4
4
  export type PropertiesWith<Type, From> = {
5
- [Key in keyof From as From[Key] extends Type ? Key : never]: From[Key]
6
- }
5
+ [Key in keyof From as From[Key] extends Type ? Key : never]: From[Key]
6
+ };
7
7
  export default PropertiesWith;
8
8
 
9
9
  /**
10
10
  * Fitlers all properties from From that don't have the return type of Type
11
11
  */
12
12
  export type PropertiesWithout<Type, From> = {
13
- [Key in keyof From as From[Key] extends Type ? never : Key]: From[Key]
14
- }
13
+ [Key in keyof From as From[Key] extends Type ? never : Key]: From[Key]
14
+ };
15
+
16
+ /**
17
+ * GetRepeatedKeys<[
18
+ * { username: string, password: string },
19
+ * { username: number, email: string },
20
+ * ]> // { username: string | number }
21
+ */
22
+ export type GetRepeatedKeys<Types extends Array<any>> = (
23
+ Types extends [infer First, infer Second, ...infer Rest]
24
+ ? First extends object
25
+ ? Second extends object
26
+ ? {
27
+ [Key in Extract<keyof First, keyof Second>]: First[Key] | Second[Key]
28
+ } & GetRepeatedKeys<Rest>
29
+ : {}
30
+ : {}
31
+ : {}
32
+ );
33
+
34
+ /**
35
+ * Situation: Model = Character | Artifact | Domain
36
+ * Type must include generic type T, which is the Model type
37
+ * Type must also include generic type TProps, which is the properties of the Model type. Selected properties of TProps must extract the types of Model whose properties has been selected.
38
+ *
39
+ * Example:
40
+ * type Model = Character | Artifact | Domain
41
+ * Properties<Model, 'name' | 'rarity'>
42
+ *
43
+ * Result: Character | Artifact, because only Character and Artifact have 'name' and 'rarity' properties
44
+ */
45
+ export type ModelWithProps<T, TProps extends (keyof T | string)> = T extends Record<TProps, any> ? T : never;
@@ -0,0 +1 @@
1
+ export type Autocomplete<T> = T | (string & {});
@@ -2,17 +2,35 @@
2
2
  * Converts Start types to Switch types in From type
3
3
  */
4
4
  export type TransformType<From, Start, Switch> = {
5
- [Key in keyof From]: From[Key] extends Start ? Switch : From[Key]
6
- }
5
+ [Key in keyof From]: From[Key] extends Start ? Switch : From[Key]
6
+ };
7
7
 
8
8
  /**
9
9
  * Returns object with properties matching BaseType with types of NewType
10
10
  */
11
- export type TransformTypes<From, BaseType, NewType> = Record<keyof {
12
- [Key in keyof From as From[Key] extends BaseType ? Key : never]: Key
13
- }, NewType>
11
+ export type TransformTypes<From, BaseType, NewType> = Record<keyof {
12
+ [Key in keyof From as From[Key] extends BaseType ? Key : never]: Key
13
+ }, NewType>;
14
14
 
15
15
  //Returns From with properties switched from BaseType to NewType
16
16
  // export type TransformTypes<From, BaseType, NewType> = TransformType<From, BaseType[keyof BaseType], NewType>;
17
17
 
18
+ export type Json<T> = {
19
+ [Key in keyof T]: T[Key] extends object
20
+ ? Json<T[Key]>
21
+ : T[Key] extends Array<infer U>
22
+ ? Array<Json<U>>
23
+ : T[Key] extends number | string | boolean | null
24
+ ? T[Key]
25
+ : string
26
+ };
27
+
28
+
29
+ /**
30
+ * Type's properties are ReturnType
31
+ */
32
+ export type AllPropsAre<ReturnType> = {
33
+ [key: string]: ReturnType;
34
+ };
35
+
18
36
  export default TransformTypes;
@@ -1,18 +1,14 @@
1
+ export * from './Able';
2
+ export * from './Array';
1
3
  export * from './BetterTypes';
4
+ export * from './C#';
2
5
  export * from './Date';
3
6
  export * from './Events';
7
+ export * from './Function';
4
8
  export * from './TransformTypes';
9
+ export * from './Object';
5
10
  export * from './PropertiesWith';
6
-
7
- /**
8
- * Item is single or multiple
9
- */
10
- export type Arrayable<T> = T | Array<T>;
11
-
12
- /**
13
- * Item is function or T
14
- */
15
- export type Functionable<T> = T | (() => T);
11
+ export * from './String';
16
12
 
17
13
  /**
18
14
  * Used for HTMLElement.append in ElementOptions, Document.createProperElement.
@@ -23,39 +19,9 @@ export type Functionable<T> = T | (() => T);
23
19
  */
24
20
  export type IElement = HTMLElement | string;
25
21
 
26
- /**
27
- * Return types of T
28
- */
29
- export type ValueOf<T> = T[keyof T];
30
-
31
- /**
32
- * Type's properties are ReturnType
33
- */
34
- export type AllPropsAre<ReturnType> = {
35
- [key: string]: ReturnType
36
- }
37
-
38
22
  /**
39
23
  * string or RegExp.. pretty self-explanatory
40
24
  */
41
25
  export type StringRegex = string | RegExp;
42
26
 
43
- export type If<Boolean extends boolean, True, False> = Boolean extends true ? True : False;
44
-
45
- /**
46
- * GetRepeatedKeys<[
47
- * { username: string, password: string },
48
- * { username: number, email: string },
49
- * ]> // { username: string | number }
50
- */
51
- export type GetRepeatedKeys<Types extends Array<any>> = (
52
- Types extends [infer First, infer Second, ...infer Rest]
53
- ? First extends object
54
- ? Second extends object
55
- ? {
56
- [Key in Extract<keyof First, keyof Second>]: First[Key] | Second[Key]
57
- } & GetRepeatedKeys<Rest>
58
- : {}
59
- : {}
60
- : {}
61
- );
27
+ export type If<Boolean extends boolean, True, False> = Boolean extends true ? True : False;
@@ -0,0 +1,43 @@
1
+ // An ApiEndpoint parameter can be either a string or undefined
2
+ export type TParam = string | undefined;
3
+
4
+ // All possible HTTP methods
5
+ export type HttpMethods =
6
+ | 'GET'
7
+ | 'POST'
8
+ | 'PUT'
9
+ | 'PATCH'
10
+ | 'DELETE';
11
+
12
+ // Options for the Request function
13
+ export type RequestOptions<TBody = any> = Omit<RequestInit, 'method' | 'body'> & {
14
+ method?: HttpMethods;
15
+ body?: TBody;
16
+ noHeaders?: boolean;
17
+ controller?: AbortController;
18
+ query?: Record<string, string | undefined>;
19
+ baseEndpoint?: string;
20
+ };
21
+
22
+ export type ApiUtilOptions = {
23
+ baseEndpointDev: string;
24
+ baseEndpoint?: string;
25
+ log?: boolean;
26
+ }
27
+
28
+ // All possible endpoints for the API. This will generate autocomplete when using the Request function
29
+ // The commented code below is an example from my previous "CitizenTaxi" project to illustrate how this works
30
+
31
+ // export type ApiEndpoints<Param extends TParam = undefined> =
32
+ // | `bookings` // [GET, POST]
33
+ // | `bookings?citizenId=${Param}` // [GET] Guid
34
+ // | `bookings/${Param}` // [GET, PUT, DELETE] Guid bookingId
35
+
36
+ // | `notes` // [GET, POST]
37
+ // | `notes?citizenId=${Param}` // [GET] Guid
38
+ // | `notes/${Param}` // [GET, PUT, DELETE] Guid noteId
39
+
40
+ // | `users` // [GET, POST]
41
+ // | `users?role=${Param}` // [GET] enum Role
42
+ // | `users/${Param}` // [GET, PUT, DELETE] Guid userId
43
+ // | `users/authenticate`; // [POST, DELETE]
@@ -0,0 +1,87 @@
1
+ import { RequestOptions } from "./ApiTypes";
2
+
3
+ /**
4
+ * Makes a request to the API
5
+ * @param path Api endpoint to request
6
+ * @param options Additional options for the request
7
+ * @returns The response from the API
8
+ */
9
+ export async function Request<TData, ApiEndpoints extends string>(
10
+ path: ApiEndpoints,
11
+ // Destructor the options object, if it's undefined then set it to an empty object
12
+ {
13
+ method = 'GET',
14
+ body,
15
+ noHeaders = false,
16
+ controller = new AbortController(),
17
+ query,
18
+ baseEndpoint
19
+ }: RequestOptions | undefined = {},
20
+ log = false
21
+ ) {
22
+ // console.log(`Requesting ${path} with method ${method}`);
23
+
24
+ // Construct the endpoint for the request
25
+ const endpoint = (() => {
26
+ const result = baseEndpoint + ensureSlash(path);
27
+ if (path.includes('?') || !query) return result;
28
+
29
+ // If the query object is defined, then construct a query string from it
30
+ const queryString = Object.entries(query)
31
+ .map(([key, value]) => value ? `${key}=${value}` : '')
32
+ .join('&');
33
+
34
+ return path.includes('?') ? `${result}&${queryString}` : `${result}?${queryString}`;
35
+ })();
36
+
37
+ // Construct the request init object to pass to the fetch function
38
+ const init: RequestInit = {
39
+ method,
40
+ body: body ? !noHeaders ? JSON.stringify(body) : body : undefined,
41
+ headers: !noHeaders ? { 'Content-Type': 'application/json' } : undefined,
42
+ signal: controller.signal,
43
+ credentials: 'include',
44
+ mode: 'cors'
45
+ };
46
+
47
+ // Make the request, log any errors, and throw them again
48
+ const res = await fetch(endpoint, init).catch(err => {
49
+ console.error(`Failed to [${method}] ${path}`, err);
50
+ throw err;
51
+ });
52
+
53
+ if (log) console.log(`[${method}] ${path} responded with ${res.status}`, res);
54
+
55
+ // Clone the response so that it can be converted to JSON and text
56
+ const clone = res.clone();
57
+
58
+ // All successful responses are in the 200s, so check if the status code starts with 2
59
+ const isSuccessful = res.status.toString().startsWith('2');
60
+
61
+ // This try-catch block is used to catch any errors when converting the response to JSON
62
+ // If the response is not jsonable, then the catch will return null for the data
63
+ try {
64
+ return {
65
+ success: isSuccessful,
66
+ status: res.status,
67
+ data: await res.json() as TData,
68
+ text: await clone.text(),
69
+ };
70
+ } catch {
71
+ return {
72
+ success: isSuccessful,
73
+ status: res.status,
74
+ data: null as unknown as TData,
75
+ text: await clone.text(),
76
+ };
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Ensures that the path starts with a /
82
+ * @param path Path string
83
+ * @returns Path that starts with a /
84
+ */
85
+ export function ensureSlash(path: string) {
86
+ return path.startsWith('/') ? path : '/' + path;
87
+ }
@@ -0,0 +1,39 @@
1
+ import { ApiUtilOptions, RequestOptions } from "./ApiTypes";
2
+ import { Request } from "./RequestUtil";
3
+
4
+ export class ApiUtils<ApiEndpoints extends string> {
5
+ protected __baseEndpointDev: string;
6
+ protected __baseEndpoint?: string;
7
+ protected __log: boolean;
8
+
9
+ constructor({ baseEndpointDev, baseEndpoint, log }: ApiUtilOptions) {
10
+ this.__baseEndpointDev = baseEndpointDev;
11
+ this.__baseEndpoint = baseEndpoint;
12
+ this.__log = log ?? false;
13
+ }
14
+
15
+ /**
16
+ * Make a request to the API
17
+ * @param path The path to the endpoint
18
+ * @param options The options for the request
19
+ * @returns The response from the API
20
+ */
21
+ public async request<TData>(
22
+ path: ApiEndpoints,
23
+ options?: RequestOptions
24
+ ) {
25
+ return Request<TData, ApiEndpoints>(path, {
26
+ ...options,
27
+ baseEndpoint: this.baseEndpoint
28
+ }, this.__log);
29
+ }
30
+
31
+ public get baseEndpoint() {
32
+ const processExists = 'process' in globalThis;
33
+
34
+ // @ts-ignore -- process is not defined in the browser
35
+ const isDev = processExists && process.env.NODE_ENV === 'development';
36
+
37
+ return isDev ? this.__baseEndpointDev : this.__baseEndpoint ?? this.__baseEndpointDev;
38
+ }
39
+ }
@@ -0,0 +1,102 @@
1
+ export type RGB = [number, number, number];
2
+ export type Hex = `#${string}`;
3
+ export type ColorType = 'hex' | 'rgb' | 'hsl';
4
+
5
+
6
+ export function convert(value: RGB, to: Exclude<ColorType, 'rgb'>): string;
7
+ export function convert(value: string, from: Exclude<ColorType, 'rgb'>, to: 'rgb'): RGB;
8
+ export function convert(value: string | RGB, fromOrTo: ColorType, to?: ColorType): string | RGB {
9
+ const from = typeof value === 'string' ? fromOrTo : 'rgb';
10
+ const target = typeof value === 'string' ? to : fromOrTo;
11
+
12
+ if (from === target) return value as string;
13
+
14
+ switch (from) {
15
+ case 'hsl': {
16
+ switch (target) {
17
+ case 'hex': return hslToHex(value as string);
18
+ case 'rgb': return hexToRgb(hslToHex(value as string)) as RGB;
19
+ }
20
+ }
21
+ case 'rgb': {
22
+ switch (target) {
23
+ case 'hex': return hslToHex(rgbToHsl(value as RGB))
24
+ case 'hsl': return rgbToHsl(value as RGB);
25
+ }
26
+ }
27
+ case 'hex': {
28
+ switch (target) {
29
+ case 'rgb': return hexToRgb(value as Hex) as RGB;
30
+ case 'hsl': return rgbToHsl(hexToRgb(value as Hex));
31
+ }
32
+ }
33
+ default: return value;
34
+ }
35
+ }
36
+
37
+ export function generateRandomColor(): Hex {
38
+ return `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')}`;
39
+ }
40
+
41
+ export const ColorUtils = {
42
+ convert,
43
+ generateRandomColor
44
+ };
45
+
46
+ export default ColorUtils;
47
+
48
+ function hslToHex(value?: string): Hex {
49
+ if (!value) return "#000000";
50
+
51
+ const match = value.match(/hsl\((\d+), (\d+)%, (\d+)%\)/);
52
+ if (!match) return value as Hex;
53
+
54
+ let [_, h, s, l] = match.map(Number);
55
+ l /= 100;
56
+ const a = s * Math.min(l, 1 - l) / 100;
57
+ const format = (value: number) => {
58
+ const k = (value + h / 30) % 12;
59
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
60
+ return Math.round(255 * color).toString(16).padStart(2, '0');
61
+ };
62
+ return `#${format(0)}${format(8)}${format(4)}`;
63
+ }
64
+
65
+ function hexToRgb(hex: Hex): RGB {
66
+ if (!hex) return [0, 0, 0];
67
+
68
+ const match = hex.match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
69
+ if (!match) return [0, 0, 0];
70
+
71
+ let colorString = match[0];
72
+
73
+ if (match[0].length === 3) colorString = colorString.split('').map(char => char + char).join('');
74
+
75
+ const integer = parseInt(colorString, 16);
76
+ const r = (integer >> 16) & 0xFF;
77
+ const g = (integer >> 8) & 0xFF;
78
+ const b = integer & 0xFF;
79
+
80
+ return [r, g, b];
81
+ }
82
+
83
+ function rgbToHsl(rgb: RGB): string {
84
+ let [r, g, b] = rgb.map(x => x / 255);
85
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
86
+ let h = 0, s = 0, l = (max + min) / 2;
87
+
88
+ if (max !== min) {
89
+ const d = max - min;
90
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
91
+
92
+ switch (max) {
93
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
94
+ case g: h = (b - r) / d + 2; break;
95
+ case b: h = (r - g) / d + 4; break;
96
+ }
97
+
98
+ h /= 6;
99
+ }
100
+
101
+ return `hsl(${Math.round(h * 360)}, ${Math.round(s * 100)}%, ${Math.round(l * 100)}%)`;
102
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Serialize a form into an object
3
+ * @param form The form to serialize
4
+ * @returns An object of type T from the form
5
+ */
6
+ export function serializeForm<T extends object>(form: HTMLFormElement, log = false) {
7
+ const children = Array.from(form.children);
8
+ const formData = children.reduce((acc, child) => {
9
+ // Find inputs and selects
10
+ const elements = Array.from(child.querySelectorAll('input, select') as NodeListOf<HTMLInputElement | HTMLSelectElement>);
11
+ if (['INPUT', 'SELECT'].includes(child.tagName)) elements.push(child as HTMLInputElement | HTMLSelectElement);
12
+
13
+ for (const element of Array.from(elements)) {
14
+ if (element.type === 'submit') continue; // Ignore submit buttons
15
+
16
+ const name = element.getAttribute('name');
17
+ if (!name) {
18
+ console.error('[DanhoLibraryJS] [FormUtil]: name attribute is required', { element });
19
+ throw new Error('name attribute is required');
20
+ }
21
+
22
+ const value = element.value;
23
+ if (value === null) console.warn(`${name}.value returned null`, { element });
24
+
25
+ if (log) console.log(`[DanhoLibraryJS] [FormUtil]`, { name, value });
26
+ acc[name] = /^\d$/.test(value) ? parseInt(value) : value;
27
+ }
28
+
29
+ return acc;
30
+ }, {} as Record<string, any>) as T;
31
+
32
+ return formData;
33
+ }
@@ -0,0 +1,3 @@
1
+ export function between(min: number, max: number): number {
2
+ return Math.floor(Math.random() * (max - min + 1)) + min;
3
+ }