@resq-sw/helpers 0.1.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 (46) hide show
  1. package/README.md +218 -0
  2. package/lib/browser/html-entities.d.ts +34 -0
  3. package/lib/browser/html-entities.d.ts.map +1 -0
  4. package/lib/browser/html-entities.js +63 -0
  5. package/lib/browser/html-entities.js.map +1 -0
  6. package/lib/browser/index.d.ts +3 -0
  7. package/lib/browser/index.js +3 -0
  8. package/lib/browser/platform.d.ts +252 -0
  9. package/lib/browser/platform.d.ts.map +1 -0
  10. package/lib/browser/platform.js +272 -0
  11. package/lib/browser/platform.js.map +1 -0
  12. package/lib/formatting/date.d.ts +80 -0
  13. package/lib/formatting/date.d.ts.map +1 -0
  14. package/lib/formatting/date.js +135 -0
  15. package/lib/formatting/date.js.map +1 -0
  16. package/lib/formatting/date.types.d.ts +35 -0
  17. package/lib/formatting/date.types.d.ts.map +1 -0
  18. package/lib/formatting/date.types.js +0 -0
  19. package/lib/formatting/index.d.ts +5 -0
  20. package/lib/formatting/index.js +4 -0
  21. package/lib/formatting/number.d.ts +22 -0
  22. package/lib/formatting/number.d.ts.map +1 -0
  23. package/lib/formatting/number.js +39 -0
  24. package/lib/formatting/number.js.map +1 -0
  25. package/lib/formatting/string.d.ts +22 -0
  26. package/lib/formatting/string.d.ts.map +1 -0
  27. package/lib/formatting/string.js +30 -0
  28. package/lib/formatting/string.js.map +1 -0
  29. package/lib/helpers.d.ts +142 -0
  30. package/lib/helpers.d.ts.map +1 -0
  31. package/lib/helpers.js +159 -0
  32. package/lib/helpers.js.map +1 -0
  33. package/lib/index.d.ts +11 -0
  34. package/lib/index.js +9 -0
  35. package/lib/parse-code-path.d.ts +85 -0
  36. package/lib/parse-code-path.d.ts.map +1 -0
  37. package/lib/parse-code-path.js +160 -0
  38. package/lib/parse-code-path.js.map +1 -0
  39. package/lib/task-exec.d.ts +26 -0
  40. package/lib/task-exec.d.ts.map +1 -0
  41. package/lib/task-exec.js +45 -0
  42. package/lib/task-exec.js.map +1 -0
  43. package/lib/task-exec.types.d.ts +23 -0
  44. package/lib/task-exec.types.d.ts.map +1 -0
  45. package/lib/task-exec.types.js +0 -0
  46. package/package.json +55 -0
@@ -0,0 +1,22 @@
1
+ //#region src/formatting/string.d.ts
2
+ /**
3
+ * Copyright 2026 ResQ
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ declare function capitalize(str: string): string;
18
+ declare function truncate(str: string, length: number): string;
19
+ declare function slugify(str: string): string;
20
+ //#endregion
21
+ export { capitalize, slugify, truncate };
22
+ //# sourceMappingURL=string.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string.d.ts","names":[],"sources":["../../src/formatting/string.ts"],"mappings":";;AAgBA;;;;;AAIA;;;;;AAKA;;;;iBATgB,UAAA,CAAW,GAAA;AAAA,iBAIX,QAAA,CAAS,GAAA,UAAa,MAAA;AAAA,iBAKtB,OAAA,CAAQ,GAAA"}
@@ -0,0 +1,30 @@
1
+ //#region src/formatting/string.ts
2
+ /**
3
+ * Copyright 2026 ResQ
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ function capitalize(str) {
18
+ return str.charAt(0).toUpperCase() + str.slice(1);
19
+ }
20
+ function truncate(str, length) {
21
+ if (str.length <= length) return str;
22
+ return str.slice(0, length) + "...";
23
+ }
24
+ function slugify(str) {
25
+ return str.toLowerCase().replaceAll(/[^\w ]+/g, "").replaceAll(/ +/g, "-");
26
+ }
27
+ //#endregion
28
+ export { capitalize, slugify, truncate };
29
+
30
+ //# sourceMappingURL=string.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string.js","names":[],"sources":["../../src/formatting/string.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\nexport function truncate(str: string, length: number): string {\n if (str.length <= length) return str\n return str.slice(0, length) + '...'\n}\n\nexport function slugify(str: string): string {\n return str\n .toLowerCase()\n .replaceAll(/[^\\w ]+/g, '')\n .replaceAll(/ +/g, '-')\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,SAAgB,WAAW,KAAqB;AAC9C,QAAO,IAAI,OAAO,EAAE,CAAC,aAAa,GAAG,IAAI,MAAM,EAAE;;AAGnD,SAAgB,SAAS,KAAa,QAAwB;AAC5D,KAAI,IAAI,UAAU,OAAQ,QAAO;AACjC,QAAO,IAAI,MAAM,GAAG,OAAO,GAAG;;AAGhC,SAAgB,QAAQ,KAAqB;AAC3C,QAAO,IACJ,aAAa,CACb,WAAW,YAAY,GAAG,CAC1B,WAAW,OAAO,IAAI"}
@@ -0,0 +1,142 @@
1
+ //#region src/helpers.d.ts
2
+ /**
3
+ * Copyright 2026 ResQ
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Converts an object to a formatted JSON string with proper indentation.
19
+ *
20
+ * @param {object} obj - The object to convert to a JSON string
21
+ * @returns {string} A properly formatted JSON string representation of the input object with 2-space indentation
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const obj = { name: "John", age: 30 };
26
+ * const jsonString = Stringify(obj);
27
+ * // Returns:
28
+ * // {
29
+ * // "name": "John",
30
+ * // "age": 30
31
+ * // }
32
+ * ```
33
+ *
34
+ * @remarks
35
+ * - Uses JSON.stringify() internally with null replacer and 2-space indent
36
+ * - Handles circular references by throwing an error
37
+ * - Preserves object structure and nesting
38
+ * - Useful for debugging, logging, and data serialization
39
+ * - Safe with primitives, arrays, objects, null and undefined
40
+ */
41
+ declare const Stringify: (obj: object) => string;
42
+ /**
43
+ * Constructs a fully qualified URL based on the current globalThis's location,
44
+ * with an optional path.
45
+ *
46
+ * @param {string} [path=''] - Optional path to append to the base URL
47
+ * @returns {string} Complete URL with proper formatting and protocol
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * // Assuming current page is "http://localhost:5173/dashboard"
52
+ * getURL("api/users") // Returns "http://localhost:5173/api/users"
53
+ * getURL() // Returns "http://localhost:5173"
54
+ *
55
+ * // Assuming current page is "[https://example.com/products](https://example.com/products)"
56
+ * getURL("test") // Returns "[https://example.com/test](https://example.com/test)"
57
+ * ```
58
+ *
59
+ * @remarks
60
+ * - Uses globalThis.location.origin as the base URL.
61
+ * - Removes trailing slashes from base URL.
62
+ * - Removes leading slashes from path.
63
+ * - Handles empty/undefined path gracefully.
64
+ * - Suitable for client-side contexts where the API/resource is on the same origin.
65
+ * - NOT recommended for defining a fixed API base URL across environments or for server-side use.
66
+ */
67
+ declare const getURL: (path?: string) => string;
68
+ type Success<T> = {
69
+ readonly success: true;
70
+ readonly value: T;
71
+ };
72
+ type Failure<E> = {
73
+ readonly success: false;
74
+ readonly error: E;
75
+ };
76
+ type Result<T, E> = Success<T> | Failure<E>;
77
+ /**
78
+ * Creates a successful result
79
+ * @param value The value to wrap in a success result
80
+ */
81
+ declare const success: <T>(value: T) => Success<T>;
82
+ /**
83
+ * Creates a failed result
84
+ * @param error The error to wrap in a failure result
85
+ */
86
+ declare const failure: <E>(error: E) => Failure<E>;
87
+ type ExtractAsyncArgs<Args extends Array<unknown>> = Args extends Array<infer PotentialArgTypes> ? [PotentialArgTypes] : [];
88
+ declare const catchError: <Args extends Array<unknown>, ReturnType>(asyncFunction: (...args: ExtractAsyncArgs<Args>) => Promise<ReturnType>, ...args: ExtractAsyncArgs<Args>) => Promise<Result<ReturnType, Error>>;
89
+ /**
90
+ * Maps a successful result to a new value
91
+ * @param fn Mapping function to apply to the successful value
92
+ */
93
+ declare const map: <T, U, E>(fn: (value: T) => U) => ((result: Result<T, E>) => Result<U, E>);
94
+ /**
95
+ * Chains a result-returning function after a successful result
96
+ * @param fn Function that returns a new result
97
+ */
98
+ declare const bindResult: <T, U, E>(fn: (value: T) => Result<U, E>) => ((result: Result<T, E>) => Result<U, E>);
99
+ /**
100
+ * Applies a series of functions to an input value, short-circuiting on the first failure
101
+ * @param input Initial input value
102
+ * @param functions Array of functions to apply sequentially
103
+ * @returns Final result after applying all functions or first encountered failure
104
+ */
105
+ declare function railway<TInput, T1, E>(input: TInput, fn1: (input: TInput) => Result<T1, E>): Result<T1, E>;
106
+ declare function railway<TInput, T1, T2, E>(input: TInput, fn1: (input: TInput) => Result<T1, E>, fn2: (input: T1) => Result<T2, E>): Result<T2, E>;
107
+ declare function railway<TInput, T1, T2, T3, E>(input: TInput, fn1: (input: TInput) => Result<T1, E>, fn2: (input: T1) => Result<T2, E>, fn3: (input: T2) => Result<T3, E>): Result<T3, E>;
108
+ declare function railway<TInput, T1, T2, T3, T4, E>(input: TInput, fn1: (input: TInput) => Result<T1, E>, fn2: (input: T1) => Result<T2, E>, fn3: (input: T2) => Result<T3, E>, fn4: (input: T3) => Result<T4, E>): Result<T4, E>;
109
+ declare function railway<TInput, T1, T2, T3, T4, T5, E>(input: TInput, fn1: (input: TInput) => Result<T1, E>, fn2: (input: T1) => Result<T2, E>, fn3: (input: T2) => Result<T3, E>, fn4: (input: T3) => Result<T4, E>, fn5: (input: T4) => Result<T5, E>): Result<T5, E>;
110
+ /**
111
+ * Recovers from a failure by applying a function to the error
112
+ * @param fn Function to handle the error and return a new result
113
+ */
114
+ declare const recover: <T, E1, E2>(fn: (error: E1) => Result<T, E2>) => ((result: Result<T, E1>) => Result<T, E2>);
115
+ /**
116
+ * Taps into a result chain for side effects without modifying the value
117
+ * @param fn Side effect function to execute on success
118
+ */
119
+ declare const tap: <T, E>(fn: (value: T) => void) => ((result: Result<T, E>) => Result<T, E>);
120
+ /**
121
+ * Checks if a value is a number
122
+ * @param value The value to check
123
+ */
124
+ declare const isNumber: (value: unknown) => value is number;
125
+ /**
126
+ * Checks if a value is a string
127
+ * @param value The value to check
128
+ */
129
+ declare const isString: (value: unknown) => value is string;
130
+ /**
131
+ * Checks if a value is a function
132
+ * @param value The value to check
133
+ */
134
+ declare const isFunction: (value: unknown) => value is Function;
135
+ /**
136
+ * Checks if a value is a promise
137
+ * @param value The value to check
138
+ */
139
+ declare const isPromise: (value: unknown) => value is Promise<unknown>;
140
+ //#endregion
141
+ export { Stringify, bindResult, catchError, failure, getURL, isFunction, isNumber, isPromise, isString, map, railway, recover, success, tap };
142
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","names":[],"sources":["../src/helpers.ts"],"mappings":"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"}
package/lib/helpers.js ADDED
@@ -0,0 +1,159 @@
1
+ import { Logger } from "@resq-sw/logger";
2
+ //#region src/helpers.ts
3
+ /**
4
+ * Copyright 2026 ResQ
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+ const logger = Logger.getLogger("[helpers]");
19
+ /**
20
+ * Converts an object to a formatted JSON string with proper indentation.
21
+ *
22
+ * @param {object} obj - The object to convert to a JSON string
23
+ * @returns {string} A properly formatted JSON string representation of the input object with 2-space indentation
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const obj = { name: "John", age: 30 };
28
+ * const jsonString = Stringify(obj);
29
+ * // Returns:
30
+ * // {
31
+ * // "name": "John",
32
+ * // "age": 30
33
+ * // }
34
+ * ```
35
+ *
36
+ * @remarks
37
+ * - Uses JSON.stringify() internally with null replacer and 2-space indent
38
+ * - Handles circular references by throwing an error
39
+ * - Preserves object structure and nesting
40
+ * - Useful for debugging, logging, and data serialization
41
+ * - Safe with primitives, arrays, objects, null and undefined
42
+ */
43
+ const Stringify = (obj) => {
44
+ return JSON.stringify(obj, null, 2);
45
+ };
46
+ /**
47
+ * Constructs a fully qualified URL based on the current globalThis's location,
48
+ * with an optional path.
49
+ *
50
+ * @param {string} [path=''] - Optional path to append to the base URL
51
+ * @returns {string} Complete URL with proper formatting and protocol
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * // Assuming current page is "http://localhost:5173/dashboard"
56
+ * getURL("api/users") // Returns "http://localhost:5173/api/users"
57
+ * getURL() // Returns "http://localhost:5173"
58
+ *
59
+ * // Assuming current page is "[https://example.com/products](https://example.com/products)"
60
+ * getURL("test") // Returns "[https://example.com/test](https://example.com/test)"
61
+ * ```
62
+ *
63
+ * @remarks
64
+ * - Uses globalThis.location.origin as the base URL.
65
+ * - Removes trailing slashes from base URL.
66
+ * - Removes leading slashes from path.
67
+ * - Handles empty/undefined path gracefully.
68
+ * - Suitable for client-side contexts where the API/resource is on the same origin.
69
+ * - NOT recommended for defining a fixed API base URL across environments or for server-side use.
70
+ */
71
+ const getURL = (path = "") => {
72
+ let url = "";
73
+ if (typeof globalThis !== "undefined" && globalThis.location?.origin) url = globalThis.location.origin;
74
+ else {
75
+ const envBaseUrl = process?.env?.["VITE_BASE_URL"] || process?.env?.["NEXT_PUBLIC_BASE_URL"] || process?.env?.["BASE_URL"];
76
+ if (envBaseUrl && typeof envBaseUrl === "string") url = envBaseUrl;
77
+ else {
78
+ logger.warn("getURL: 'globalThis' is not defined and no environment base URL found. This function relies on client-side context. Returning empty string.");
79
+ return "";
80
+ }
81
+ }
82
+ url = url.replace(/\/+$/, "");
83
+ const sanitizedPath = path.replace(/^\/+/, "");
84
+ return sanitizedPath ? `${url}/${sanitizedPath}` : url;
85
+ };
86
+ /**
87
+ * Creates a successful result
88
+ * @param value The value to wrap in a success result
89
+ */
90
+ const success = (value) => Object.freeze({
91
+ success: true,
92
+ value
93
+ });
94
+ /**
95
+ * Creates a failed result
96
+ * @param error The error to wrap in a failure result
97
+ */
98
+ const failure = (error) => Object.freeze({
99
+ success: false,
100
+ error
101
+ });
102
+ const catchError = async (asyncFunction, ...args) => {
103
+ try {
104
+ return success(await asyncFunction(...args));
105
+ } catch (error) {
106
+ logger.error("catchError", error);
107
+ return failure(error instanceof Error ? error : new Error(String(error)));
108
+ }
109
+ };
110
+ /**
111
+ * Maps a successful result to a new value
112
+ * @param fn Mapping function to apply to the successful value
113
+ */
114
+ const map = (fn) => (result) => result.success ? success(fn(result.value)) : result;
115
+ /**
116
+ * Chains a result-returning function after a successful result
117
+ * @param fn Function that returns a new result
118
+ */
119
+ const bindResult = (fn) => (result) => result.success ? fn(result.value) : result;
120
+ function railway(input, ...functions) {
121
+ return functions.reduce((result, fn) => result.success ? fn(result.value) : result, success(input));
122
+ }
123
+ /**
124
+ * Recovers from a failure by applying a function to the error
125
+ * @param fn Function to handle the error and return a new result
126
+ */
127
+ const recover = (fn) => (result) => result.success ? result : fn(result.error);
128
+ /**
129
+ * Taps into a result chain for side effects without modifying the value
130
+ * @param fn Side effect function to execute on success
131
+ */
132
+ const tap = (fn) => (result) => {
133
+ if (result.success) fn(result.value);
134
+ return result;
135
+ };
136
+ /**
137
+ * Checks if a value is a number
138
+ * @param value The value to check
139
+ */
140
+ const isNumber = (value) => typeof value === "number";
141
+ /**
142
+ * Checks if a value is a string
143
+ * @param value The value to check
144
+ */
145
+ const isString = (value) => typeof value === "string";
146
+ /**
147
+ * Checks if a value is a function
148
+ * @param value The value to check
149
+ */
150
+ const isFunction = (value) => typeof value === "function";
151
+ /**
152
+ * Checks if a value is a promise
153
+ * @param value The value to check
154
+ */
155
+ const isPromise = (value) => !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
156
+ //#endregion
157
+ export { Stringify, bindResult, catchError, failure, getURL, isFunction, isNumber, isPromise, isString, map, railway, recover, success, tap };
158
+
159
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","names":[],"sources":["../src/helpers.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from '@resq-sw/logger';\n\nconst logger = Logger.getLogger('[helpers]');\n\n/**\n * Converts an object to a formatted JSON string with proper indentation.\n *\n * @param {object} obj - The object to convert to a JSON string\n * @returns {string} A properly formatted JSON string representation of the input object with 2-space indentation\n *\n * @example\n * ```ts\n * const obj = { name: \"John\", age: 30 };\n * const jsonString = Stringify(obj);\n * // Returns:\n * // {\n * // \"name\": \"John\",\n * // \"age\": 30\n * // }\n * ```\n *\n * @remarks\n * - Uses JSON.stringify() internally with null replacer and 2-space indent\n * - Handles circular references by throwing an error\n * - Preserves object structure and nesting\n * - Useful for debugging, logging, and data serialization\n * - Safe with primitives, arrays, objects, null and undefined\n */\nexport const Stringify = (obj: object): string => {\n return JSON.stringify(obj, null, 2);\n};\n\n/**\n * Constructs a fully qualified URL based on the current globalThis's location,\n * with an optional path.\n *\n * @param {string} [path=''] - Optional path to append to the base URL\n * @returns {string} Complete URL with proper formatting and protocol\n *\n * @example\n * ```ts\n * // Assuming current page is \"http://localhost:5173/dashboard\"\n * getURL(\"api/users\") // Returns \"http://localhost:5173/api/users\"\n * getURL() // Returns \"http://localhost:5173\"\n *\n * // Assuming current page is \"[https://example.com/products](https://example.com/products)\"\n * getURL(\"test\") // Returns \"[https://example.com/test](https://example.com/test)\"\n * ```\n *\n * @remarks\n * - Uses globalThis.location.origin as the base URL.\n * - Removes trailing slashes from base URL.\n * - Removes leading slashes from path.\n * - Handles empty/undefined path gracefully.\n * - Suitable for client-side contexts where the API/resource is on the same origin.\n * - NOT recommended for defining a fixed API base URL across environments or for server-side use.\n */\nexport const getURL = (path = ''): string => {\n let url = '';\n\n // Use the current globalThis's origin as the base URL if available.\n // globalThis.location.origin includes the protocol, hostname, and port (e.g., \"https://example.com:8080\")\n if (typeof globalThis !== 'undefined' && globalThis.location?.origin) {\n url = globalThis.location.origin;\n } else {\n // This function will not work correctly in a non-browser environment (e.g., during SSR or build processes)\n // where `globalThis` is not defined. We'll attempt to use environment variables for a more reliable default.\n const envBaseUrl =\n process?.env?.['VITE_BASE_URL'] ||\n process?.env?.['NEXT_PUBLIC_BASE_URL'] ||\n process?.env?.['BASE_URL'];\n\n if (envBaseUrl && typeof envBaseUrl === 'string') {\n url = envBaseUrl;\n } else {\n logger.warn(\n \"getURL: 'globalThis' is not defined and no environment base URL found. This function relies on client-side context. Returning empty string.\",\n );\n return '';\n }\n }\n\n // Remove any trailing slashes from the base URL (globalThis.location.origin typically doesn't have one, but for consistency)\n url = url.replace(/\\/+$/, '');\n\n // Remove any leading slashes from the path\n const sanitizedPath = path.replace(/^\\/+/, '');\n\n // Combine the URL and path, ensuring a single slash in between if a path exists\n return sanitizedPath ? `${url}/${sanitizedPath}` : url;\n};\n\ntype Success<T> = {\n readonly success: true;\n readonly value: T;\n};\n\ntype Failure<E> = {\n readonly success: false;\n readonly error: E;\n};\n\ntype Result<T, E> = Success<T> | Failure<E>;\n\n/**\n * Creates a successful result\n * @param value The value to wrap in a success result\n */\nexport const success = <T>(value: T): Success<T> => Object.freeze({ success: true, value });\n\n/**\n * Creates a failed result\n * @param error The error to wrap in a failure result\n */\nexport const failure = <E>(error: E): Failure<E> => Object.freeze({ success: false, error });\n\ntype ExtractAsyncArgs<Args extends Array<unknown>> =\n Args extends Array<infer PotentialArgTypes> ? [PotentialArgTypes] : [];\n\nexport const catchError = async <Args extends Array<unknown>, ReturnType>(\n asyncFunction: (...args: ExtractAsyncArgs<Args>) => Promise<ReturnType>,\n ...args: ExtractAsyncArgs<Args>\n): Promise<Result<ReturnType, Error>> => {\n try {\n const result = await asyncFunction(...args);\n return success(result);\n } catch (error) {\n logger.error('catchError', error);\n return failure(error instanceof Error ? error : new Error(String(error)));\n }\n};\n\n/**\n * Maps a successful result to a new value\n * @param fn Mapping function to apply to the successful value\n */\nexport const map =\n <T, U, E>(fn: (value: T) => U): ((result: Result<T, E>) => Result<U, E>) =>\n (result) =>\n result.success ? success(fn(result.value)) : result;\n\n/**\n * Chains a result-returning function after a successful result\n * @param fn Function that returns a new result\n */\nexport const bindResult =\n <T, U, E>(fn: (value: T) => Result<U, E>): ((result: Result<T, E>) => Result<U, E>) =>\n (result) =>\n result.success ? fn(result.value) : result;\n\n/**\n * Applies a series of functions to an input value, short-circuiting on the first failure\n * @param input Initial input value\n * @param functions Array of functions to apply sequentially\n * @returns Final result after applying all functions or first encountered failure\n */\nexport function railway<TInput, T1, E>(\n input: TInput,\n fn1: (input: TInput) => Result<T1, E>,\n): Result<T1, E>;\nexport function railway<TInput, T1, T2, E>(\n input: TInput,\n fn1: (input: TInput) => Result<T1, E>,\n fn2: (input: T1) => Result<T2, E>,\n): Result<T2, E>;\nexport function railway<TInput, T1, T2, T3, E>(\n input: TInput,\n fn1: (input: TInput) => Result<T1, E>,\n fn2: (input: T1) => Result<T2, E>,\n fn3: (input: T2) => Result<T3, E>,\n): Result<T3, E>;\nexport function railway<TInput, T1, T2, T3, T4, E>(\n input: TInput,\n fn1: (input: TInput) => Result<T1, E>,\n fn2: (input: T1) => Result<T2, E>,\n fn3: (input: T2) => Result<T3, E>,\n fn4: (input: T3) => Result<T4, E>,\n): Result<T4, E>;\nexport function railway<TInput, T1, T2, T3, T4, T5, E>(\n input: TInput,\n fn1: (input: TInput) => Result<T1, E>,\n fn2: (input: T1) => Result<T2, E>,\n fn3: (input: T2) => Result<T3, E>,\n fn4: (input: T3) => Result<T4, E>,\n fn5: (input: T4) => Result<T5, E>,\n): Result<T5, E>;\nexport function railway<TInput, TOutput, E>(\n input: TInput,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ...functions: Array<(input: any) => Result<any, E>>\n): Result<TOutput, E> {\n return functions.reduce<Result<any, E>>(\n (result, fn) => (result.success ? fn(result.value) : result),\n success(input),\n ) as Result<TOutput, E>;\n}\n\n/**\n * Recovers from a failure by applying a function to the error\n * @param fn Function to handle the error and return a new result\n */\nexport const recover =\n <T, E1, E2>(fn: (error: E1) => Result<T, E2>): ((result: Result<T, E1>) => Result<T, E2>) =>\n (result) =>\n result.success ? result : fn(result.error);\n\n/**\n * Taps into a result chain for side effects without modifying the value\n * @param fn Side effect function to execute on success\n */\nexport const tap =\n <T, E>(fn: (value: T) => void): ((result: Result<T, E>) => Result<T, E>) =>\n (result) => {\n if (result.success) {\n fn(result.value);\n }\n return result;\n };\n\n/**\n * Checks if a value is a number\n * @param value The value to check\n */\nexport const isNumber = (value: unknown): value is number => typeof value === 'number';\n\n/**\n * Checks if a value is a string\n * @param value The value to check\n */\nexport const isString = (value: unknown): value is string => typeof value === 'string';\n\n/**\n * Checks if a value is a function\n * @param value The value to check\n */\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport const isFunction = (value: unknown): value is Function => typeof value === 'function';\n\n/**\n * Checks if a value is a promise\n * @param value The value to check\n */\nexport const isPromise = (value: unknown): value is Promise<unknown> =>\n !!value &&\n (typeof value === 'object' || typeof value === 'function') &&\n typeof (value as Promise<unknown>).then === 'function';\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,MAAM,SAAS,OAAO,UAAU,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;AA0B5C,MAAa,aAAa,QAAwB;AAChD,QAAO,KAAK,UAAU,KAAK,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BrC,MAAa,UAAU,OAAO,OAAe;CAC3C,IAAI,MAAM;AAIV,KAAI,OAAO,eAAe,eAAe,WAAW,UAAU,OAC5D,OAAM,WAAW,SAAS;MACrB;EAGL,MAAM,aACJ,SAAS,MAAM,oBACf,SAAS,MAAM,2BACf,SAAS,MAAM;AAEjB,MAAI,cAAc,OAAO,eAAe,SACtC,OAAM;OACD;AACL,UAAO,KACL,8IACD;AACD,UAAO;;;AAKX,OAAM,IAAI,QAAQ,QAAQ,GAAG;CAG7B,MAAM,gBAAgB,KAAK,QAAQ,QAAQ,GAAG;AAG9C,QAAO,gBAAgB,GAAG,IAAI,GAAG,kBAAkB;;;;;;AAmBrD,MAAa,WAAc,UAAyB,OAAO,OAAO;CAAE,SAAS;CAAM;CAAO,CAAC;;;;;AAM3F,MAAa,WAAc,UAAyB,OAAO,OAAO;CAAE,SAAS;CAAO;CAAO,CAAC;AAK5F,MAAa,aAAa,OACxB,eACA,GAAG,SACoC;AACvC,KAAI;AAEF,SAAO,QADQ,MAAM,cAAc,GAAG,KAAK,CACrB;UACf,OAAO;AACd,SAAO,MAAM,cAAc,MAAM;AACjC,SAAO,QAAQ,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC;;;;;;;AAQ7E,MAAa,OACD,QACT,WACC,OAAO,UAAU,QAAQ,GAAG,OAAO,MAAM,CAAC,GAAG;;;;;AAMjD,MAAa,cACD,QACT,WACC,OAAO,UAAU,GAAG,OAAO,MAAM,GAAG;AAsCxC,SAAgB,QACd,OAEA,GAAG,WACiB;AACpB,QAAO,UAAU,QACd,QAAQ,OAAQ,OAAO,UAAU,GAAG,OAAO,MAAM,GAAG,QACrD,QAAQ,MAAM,CACf;;;;;;AAOH,MAAa,WACC,QACX,WACC,OAAO,UAAU,SAAS,GAAG,OAAO,MAAM;;;;;AAM9C,MAAa,OACJ,QACN,WAAW;AACV,KAAI,OAAO,QACT,IAAG,OAAO,MAAM;AAElB,QAAO;;;;;;AAOX,MAAa,YAAY,UAAoC,OAAO,UAAU;;;;;AAM9E,MAAa,YAAY,UAAoC,OAAO,UAAU;;;;;AAO9E,MAAa,cAAc,UAAsC,OAAO,UAAU;;;;;AAMlF,MAAa,aAAa,UACxB,CAAC,CAAC,UACD,OAAO,UAAU,YAAY,OAAO,UAAU,eAC/C,OAAQ,MAA2B,SAAS"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { obfuscateLink } from "./browser/html-entities.js";
2
+ import { getBrowser, getPlatform, isAndroid, isAndroidChrome, isAndroidEdge, isAndroidFirefox, isAndroidOpera, isChrome, isChromeOS, isEdge, isFirefox, isIOS, isIOSChrome, isIOSEdge, isIOSFirefox, isIOSOpera, isIOSSafari, isMacOS, isMacOSChrome, isMacOSEdge, isOpera, isSafari, isTouchScreen, isWindows, isWindowsChrome, isWindowsEdge } from "./browser/platform.js";
3
+ import { DateFormatOptions } from "./formatting/date.types.js";
4
+ import { formatDate, formatDateOnly, formatDatePeriod, formatDateTime, formatMonthYear, formatRelativeTime } from "./formatting/date.js";
5
+ import { formatBytes, formatNumber, formatPercent } from "./formatting/number.js";
6
+ import { capitalize, slugify, truncate } from "./formatting/string.js";
7
+ import { Stringify, bindResult, catchError, failure, getURL, isFunction, isNumber, isPromise, isString, map, railway, recover, success, tap } from "./helpers.js";
8
+ import { parseCodePath, parseCodePathDetailed } from "./parse-code-path.js";
9
+ import { TaskExec } from "./task-exec.js";
10
+ import { TimedTask } from "./task-exec.types.js";
11
+ export { DateFormatOptions, Stringify, TaskExec, TimedTask, bindResult, capitalize, catchError, failure, formatBytes, formatDate, formatDateOnly, formatDatePeriod, formatDateTime, formatMonthYear, formatNumber, formatPercent, formatRelativeTime, getBrowser, getPlatform, getURL, isAndroid, isAndroidChrome, isAndroidEdge, isAndroidFirefox, isAndroidOpera, isChrome, isChromeOS, isEdge, isFirefox, isFunction, isIOS, isIOSChrome, isIOSEdge, isIOSFirefox, isIOSOpera, isIOSSafari, isMacOS, isMacOSChrome, isMacOSEdge, isNumber, isOpera, isPromise, isSafari, isString, isTouchScreen, isWindows, isWindowsChrome, isWindowsEdge, map, obfuscateLink, parseCodePath, parseCodePathDetailed, railway, recover, slugify, success, tap, truncate };
package/lib/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import { Stringify, bindResult, catchError, failure, getURL, isFunction, isNumber, isPromise, isString, map, railway, recover, success, tap } from "./helpers.js";
2
+ import { parseCodePath, parseCodePathDetailed } from "./parse-code-path.js";
3
+ import { TaskExec } from "./task-exec.js";
4
+ import { formatDate, formatDateOnly, formatDatePeriod, formatDateTime, formatMonthYear, formatRelativeTime } from "./formatting/date.js";
5
+ import { formatBytes, formatNumber, formatPercent } from "./formatting/number.js";
6
+ import { capitalize, slugify, truncate } from "./formatting/string.js";
7
+ import { getBrowser, getPlatform, isAndroid, isAndroidChrome, isAndroidEdge, isAndroidFirefox, isAndroidOpera, isChrome, isChromeOS, isEdge, isFirefox, isIOS, isIOSChrome, isIOSEdge, isIOSFirefox, isIOSOpera, isIOSSafari, isMacOS, isMacOSChrome, isMacOSEdge, isOpera, isSafari, isTouchScreen, isWindows, isWindowsChrome, isWindowsEdge } from "./browser/platform.js";
8
+ import { obfuscateLink } from "./browser/html-entities.js";
9
+ export { Stringify, TaskExec, bindResult, capitalize, catchError, failure, formatBytes, formatDate, formatDateOnly, formatDatePeriod, formatDateTime, formatMonthYear, formatNumber, formatPercent, formatRelativeTime, getBrowser, getPlatform, getURL, isAndroid, isAndroidChrome, isAndroidEdge, isAndroidFirefox, isAndroidOpera, isChrome, isChromeOS, isEdge, isFirefox, isFunction, isIOS, isIOSChrome, isIOSEdge, isIOSFirefox, isIOSOpera, isIOSSafari, isMacOS, isMacOSChrome, isMacOSEdge, isNumber, isOpera, isPromise, isSafari, isString, isTouchScreen, isWindows, isWindowsChrome, isWindowsEdge, map, obfuscateLink, parseCodePath, parseCodePathDetailed, railway, recover, slugify, success, tap, truncate };
@@ -0,0 +1,85 @@
1
+ //#region src/parse-code-path.d.ts
2
+ /**
3
+ * Copyright 2026 ResQ
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Parses and constructs a formatted string representing the code location, including the file path,
19
+ * associated entity name (such as a function, class, component, or decorator), and human context.
20
+ *
21
+ * The result is useful for debugging, developer logging, and traceability—matching the entity (function, class, etc.)
22
+ * and the context in source code references.
23
+ *
24
+ * @template C The type of the context value.
25
+ * @template T The type of the entity parameter.
26
+ * @param {C} context - A description, situation, or custom value relevant to this code path.
27
+ * @param {T} entity - The entity whose name is included; may be a function, class, object, component, decorator, or their name.
28
+ * @returns {string} A formatted string: "location: <path> @<entity>: <context>".
29
+ * @throws {Error} This function does not throw directly, but see {@link getFilePath}, which may throw in rare stack-trace parsing errors.
30
+ * @example
31
+ * // Function usage
32
+ * function myFunction() {}
33
+ * parseCodePath('initialization', myFunction);
34
+ * // => "location: /current/dir/file.js @myFunction: initialization"
35
+ *
36
+ * // Class usage
37
+ * class MyClass {}
38
+ * parseCodePath('instantiating MyClass', MyClass);
39
+ * // => "location: ... @MyClass: instantiating MyClass"
40
+ *
41
+ * // String as entity
42
+ * parseCodePath('some context', 'EntityAsString');
43
+ * // => "location: ... @EntityAsString: some context"
44
+ *
45
+
46
+ * @see parseCodePathDetailed
47
+
48
+ * @readonly
49
+ * @public
50
+ * @version 1.0.0
51
+ */
52
+ declare const parseCodePath: <C, T>(context: C, entity: T) => string;
53
+ /**
54
+ * Parses and constructs a detailed formatted location string, including file path, entity, and context,
55
+ * with optional line number, ISO timestamp, and custom prefix control. Useful for enhanced debugging or audit logs.
56
+ *
57
+ * @template C The type of the context parameter.
58
+ * @template T The type of entity (function, class, etc.).
59
+ * @param {C} context - Context description of the operation or location.
60
+ * @param {T} entity - The entity whose name is included.
61
+ * @param {object} [options] - Optional configuration for output.
62
+ * @param {boolean} [options.includeLineNumber] - If true, appends the call site line number.
63
+ * @param {boolean} [options.includeTimestamp] - If true, appends an ISO 8601 timestamp.
64
+ * @param {string} [options.customPrefix] - Custom prefix instead of default "location".
65
+ * @returns {string} Detailed formatted location string.
66
+ * @throws {Error} Does not throw directly but relies on internal getFilePath logic.
67
+ * @example
68
+ * parseCodePathDetailed('init', MyClass, {includeLineNumber: true, includeTimestamp: true});
69
+ * // => "location: ...:42 [2024-06-01T08:00:00.000Z] @MyClass: init"
70
+ *
71
+
72
+ * @see parseCodePath
73
+
74
+ * @readonly
75
+ * @public
76
+ * @version 1.0.0
77
+ */
78
+ declare const parseCodePathDetailed: <C, T>(context: C, entity: T, options?: {
79
+ includeLineNumber?: boolean;
80
+ includeTimestamp?: boolean;
81
+ customPrefix?: string;
82
+ }) => string;
83
+ //#endregion
84
+ export { parseCodePath, parseCodePathDetailed };
85
+ //# sourceMappingURL=parse-code-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-code-path.d.ts","names":[],"sources":["../src/parse-code-path.ts"],"mappings":";;AAmDA;;;;;;;;;;;;AAkHA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAlHa,aAAA,SAAuB,OAAA,EAAS,CAAA,EAAG,MAAA,EAAQ,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;cAkH3C,qBAAA,SACX,OAAA,EAAS,CAAA,EACT,MAAA,EAAQ,CAAA,EACR,OAAA;EACE,iBAAA;EACA,gBAAA;EACA,YAAA;AAAA"}