@3dsource/utils 1.0.9 → 1.0.10

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 (140) hide show
  1. package/eslint.config.js +37 -0
  2. package/ng-package.json +7 -0
  3. package/package.json +4 -14
  4. package/{lib/color/CMYKtoRGB.d.ts → src/lib/color/CMYKtoRGB.ts} +11 -1
  5. package/src/lib/color/HEXtoRGB.ts +9 -0
  6. package/src/lib/color/HSVtoRGB.ts +82 -0
  7. package/{lib/color/RGBtoCMYK.d.ts → src/lib/color/RGBtoCMYK.ts} +31 -1
  8. package/src/lib/color/RGBtoHEX.ts +17 -0
  9. package/src/lib/color/RGBtoHSV.ts +53 -0
  10. package/src/lib/color/hsv.ts +14 -0
  11. package/src/lib/color/max.ts +18 -0
  12. package/src/lib/color/min.ts +18 -0
  13. package/src/lib/color/overlay.ts +25 -0
  14. package/{lib/color/rgb.d.ts → src/lib/color/rgb.ts} +3 -1
  15. package/src/lib/color/sub.ts +18 -0
  16. package/src/lib/color/subtract.ts +27 -0
  17. package/src/lib/color/sum.ts +19 -0
  18. package/{lib/color/toRGB.d.ts → src/lib/color/toRGB.ts} +7 -1
  19. package/src/lib/color/toRGBA.ts +8 -0
  20. package/src/lib/constants/color-codes.constant.ts +9 -0
  21. package/src/lib/csv/CSV2Array.ts +66 -0
  22. package/src/lib/csv/CSV2Records.ts +56 -0
  23. package/src/lib/csv/ObjectToCSV.ts +21 -0
  24. package/src/lib/dev/dev3d.ts +1 -0
  25. package/src/lib/dev/logger.ts +94 -0
  26. package/src/lib/dev/timeToString.ts +16 -0
  27. package/src/lib/filenaming/cleanupFileName.ts +18 -0
  28. package/src/lib/filenaming/makePath.ts +5 -0
  29. package/src/lib/filenaming/normalizePath.ts +9 -0
  30. package/src/lib/geom/expandOverRectangle.ts +17 -0
  31. package/src/lib/geom/fitIntoRectangle.ts +43 -0
  32. package/{lib/geom/interfaces/area.interface.d.ts → src/lib/geom/interfaces/area.interface.ts} +2 -1
  33. package/{lib/geom/interfaces/rect.interface.d.ts → src/lib/geom/interfaces/rect.interface.ts} +2 -2
  34. package/src/lib/geom/interfaces/size.interface.ts +4 -0
  35. package/src/lib/geom/interfaces//321/201oords.interface.ts +4 -0
  36. package/src/lib/helpers/BatchLoader.ts +243 -0
  37. package/src/lib/helpers/KeyboardNumericCode.ts +118 -0
  38. package/src/lib/helpers/debounce.ts +10 -0
  39. package/src/lib/helpers/generate-uuid.ts +5 -0
  40. package/{lib/helpers/index.d.ts → src/lib/helpers/index.ts} +1 -0
  41. package/src/lib/helpers/save-to-local-drive.ts +31 -0
  42. package/src/lib/helpers/serialize.ts +11 -0
  43. package/src/lib/helpers/short-hash.ts +20 -0
  44. package/src/lib/helpers/signal.ts +46 -0
  45. package/src/lib/helpers/sleep.ts +3 -0
  46. package/src/lib/helpers/trimLastSlashFromUrl.ts +9 -0
  47. package/src/lib/image/SaveImage.ts +65 -0
  48. package/src/lib/image/getCanvasCached.ts +16 -0
  49. package/src/lib/image/getSnapshot.ts +99 -0
  50. package/src/lib/image/loadImage.ts +13 -0
  51. package/src/lib/interfaces/image-output.ts +8 -0
  52. package/{lib/interfaces/load-args-tmp.interface.d.ts → src/lib/interfaces/load-args-tmp.interface.ts} +2 -1
  53. package/src/lib/interfaces/load-args.interface.ts +15 -0
  54. package/{lib/math/baseSortedIndex.d.ts → src/lib/math/baseSortedIndex.ts} +19 -1
  55. package/{lib/math/calculateMedian.d.ts → src/lib/math/calculateMedian.ts} +17 -1
  56. package/{lib/math/circularIndex.d.ts → src/lib/math/circularIndex.ts} +5 -1
  57. package/src/lib/math/clampf.ts +14 -0
  58. package/src/lib/math/degrees.ts +7 -0
  59. package/{lib/math/floatCompare.d.ts → src/lib/math/floatCompare.ts} +30 -3
  60. package/{lib/math/inverseLerp.d.ts → src/lib/math/inverseLerp.ts} +22 -1
  61. package/src/lib/math/lerp.ts +12 -0
  62. package/{lib/mutex/Mutex.d.ts → src/lib/mutex/Mutex.ts} +15 -8
  63. package/{lib/mutex/Semaphore.d.ts → src/lib/mutex/Semaphore.ts} +27 -7
  64. package/src/lib/mutex/TaskRunner.ts +26 -0
  65. package/src/lib/predicates/operators.ts +75 -0
  66. package/{lib/predicates/textForSearch.d.ts → src/lib/predicates/textForSearch.ts} +17 -1
  67. package/{lib/predicates/where.d.ts → src/lib/predicates/where.ts} +32 -2
  68. package/src/lib/rxjs/leadingTrailingDebounceTime.ts +86 -0
  69. package/{lib/rxjs/smoothTransition.d.ts → src/lib/rxjs/smoothTransition.ts} +19 -1
  70. package/src/lib/rxjs/tapLog.ts +13 -0
  71. package/src/lib/strings/pad.ts +18 -0
  72. package/tsconfig.lib.json +13 -0
  73. package/tsconfig.lib.prod.json +11 -0
  74. package/fesm2022/3dsource-utils.mjs +0 -1886
  75. package/fesm2022/3dsource-utils.mjs.map +0 -1
  76. package/index.d.ts +0 -5
  77. package/lib/color/HEXtoRGB.d.ts +0 -5
  78. package/lib/color/HSVtoRGB.d.ts +0 -21
  79. package/lib/color/RGBtoHEX.d.ts +0 -1
  80. package/lib/color/RGBtoHSV.d.ts +0 -19
  81. package/lib/color/hsv.d.ts +0 -1
  82. package/lib/color/max.d.ts +0 -1
  83. package/lib/color/min.d.ts +0 -1
  84. package/lib/color/overlay.d.ts +0 -1
  85. package/lib/color/sub.d.ts +0 -1
  86. package/lib/color/subtract.d.ts +0 -1
  87. package/lib/color/sum.d.ts +0 -1
  88. package/lib/color/toRGBA.d.ts +0 -1
  89. package/lib/constants/color-codes.constant.d.ts +0 -9
  90. package/lib/csv/CSV2Array.d.ts +0 -1
  91. package/lib/csv/CSV2Records.d.ts +0 -1
  92. package/lib/csv/ObjectToCSV.d.ts +0 -1
  93. package/lib/dev/dev3d.d.ts +0 -1
  94. package/lib/dev/logger.d.ts +0 -11
  95. package/lib/dev/timeToString.d.ts +0 -5
  96. package/lib/filenaming/cleanupFileName.d.ts +0 -1
  97. package/lib/filenaming/makePath.d.ts +0 -1
  98. package/lib/filenaming/normalizePath.d.ts +0 -1
  99. package/lib/geom/expandOverRectangle.d.ts +0 -2
  100. package/lib/geom/fitIntoRectangle.d.ts +0 -2
  101. package/lib/geom/interfaces/size.interface.d.ts +0 -4
  102. package/lib/geom/interfaces//321/201oords.interface.d.ts +0 -4
  103. package/lib/helpers/BatchLoader.d.ts +0 -47
  104. package/lib/helpers/KeyboardNumericCode.d.ts +0 -103
  105. package/lib/helpers/debounce.d.ts +0 -1
  106. package/lib/helpers/generate-uuid.d.ts +0 -1
  107. package/lib/helpers/save-to-local-drive.d.ts +0 -1
  108. package/lib/helpers/serialize.d.ts +0 -1
  109. package/lib/helpers/signal.d.ts +0 -23
  110. package/lib/helpers/sleep.d.ts +0 -1
  111. package/lib/helpers/trimLastSlashFromUrl.d.ts +0 -1
  112. package/lib/image/SaveImage.d.ts +0 -18
  113. package/lib/image/getCanvasCached.d.ts +0 -4
  114. package/lib/image/getSnapshot.d.ts +0 -2
  115. package/lib/image/loadImage.d.ts +0 -1
  116. package/lib/interfaces/image-output.d.ts +0 -7
  117. package/lib/interfaces/load-args.interface.d.ts +0 -15
  118. package/lib/math/clampf.d.ts +0 -8
  119. package/lib/math/degrees.d.ts +0 -2
  120. package/lib/math/lerp.d.ts +0 -7
  121. package/lib/mutex/TaskRunner.d.ts +0 -5
  122. package/lib/predicates/operators.d.ts +0 -32
  123. package/lib/rxjs/leadingTrailingDebounceTime.d.ts +0 -15
  124. package/lib/rxjs/tapLog.d.ts +0 -2
  125. package/lib/strings/pad.d.ts +0 -8
  126. /package/{lib/color/index.d.ts → src/lib/color/index.ts} +0 -0
  127. /package/{lib/constants/index.d.ts → src/lib/constants/index.ts} +0 -0
  128. /package/{lib/csv/index.d.ts → src/lib/csv/index.ts} +0 -0
  129. /package/{lib/dev/index.d.ts → src/lib/dev/index.ts} +0 -0
  130. /package/{lib/filenaming/index.d.ts → src/lib/filenaming/index.ts} +0 -0
  131. /package/{lib/geom/index.d.ts → src/lib/geom/index.ts} +0 -0
  132. /package/{lib/geom/interfaces/index.d.ts → src/lib/geom/interfaces/index.ts} +0 -0
  133. /package/{lib/image/index.d.ts → src/lib/image/index.ts} +0 -0
  134. /package/{lib/interfaces/index.d.ts → src/lib/interfaces/index.ts} +0 -0
  135. /package/{lib/math/index.d.ts → src/lib/math/index.ts} +0 -0
  136. /package/{lib/mutex/index.d.ts → src/lib/mutex/index.ts} +0 -0
  137. /package/{lib/predicates/index.d.ts → src/lib/predicates/index.ts} +0 -0
  138. /package/{lib/rxjs/index.d.ts → src/lib/rxjs/index.ts} +0 -0
  139. /package/{lib/strings/index.d.ts → src/lib/strings/index.ts} +0 -0
  140. /package/{public-api.d.ts → src/public-api.ts} +0 -0
@@ -0,0 +1,46 @@
1
+ import type { Observable } from 'rxjs';
2
+ import { Subject } from 'rxjs';
3
+ import { filter, map } from 'rxjs/operators';
4
+
5
+ interface BroadcastEvent {
6
+ key: any;
7
+ data?: any;
8
+ }
9
+
10
+ /**
11
+ * SingleTone Private class.
12
+ * Event-Driving pattern for sending signals from component to component.
13
+ */
14
+ class SignalClass {
15
+ private static eventBus: Subject<BroadcastEvent>;
16
+
17
+ constructor() {
18
+ if (SignalClass.eventBus) {
19
+ throw new Error(`Check that 'SignalClass' is not instantiated again!`);
20
+ }
21
+ SignalClass.eventBus = new Subject<BroadcastEvent>();
22
+ }
23
+
24
+ /**
25
+ * It is not recommended to use this class directly.
26
+ * use the sendSignal functions instead.
27
+ * those wrappers are more convenient and provide a better type safety.
28
+ */
29
+ broadcast<K, D>(key: K, data?: D) {
30
+ SignalClass.eventBus.next({ key, data });
31
+ }
32
+
33
+ /**
34
+ * It is not recommended to use this class directly.
35
+ * use the fromSignal functions instead.
36
+ * those wrappers are more convenient and provide a better type safety.
37
+ */
38
+ on<K, D = any>(key: K): Observable<D> {
39
+ return SignalClass.eventBus.asObservable().pipe(
40
+ filter((event) => event.key === key),
41
+ map((event) => event.data),
42
+ );
43
+ }
44
+ }
45
+
46
+ export const Signal = new SignalClass();
@@ -0,0 +1,3 @@
1
+ export function sleep(time: number) {
2
+ return new Promise((r) => setTimeout(r, time));
3
+ }
@@ -0,0 +1,9 @@
1
+ export function trimLastSlashFromUrl(baseUrl: string) {
2
+ if (!baseUrl) {
3
+ return null;
4
+ } else if (baseUrl[baseUrl.length - 1] === '/') {
5
+ return baseUrl.substring(0, baseUrl.length - 1);
6
+ }
7
+
8
+ return;
9
+ }
@@ -0,0 +1,65 @@
1
+ import { getSnapshot } from './getSnapshot';
2
+ import type { ImageOutputValues } from '../interfaces';
3
+
4
+ /**
5
+ * USE DownloadImage instead!
6
+ * @deprecated use DownloadImage instead!
7
+ * @param imageSource
8
+ * @param name
9
+ * @param width
10
+ * @param format
11
+ */
12
+ function SaveImage(
13
+ imageSource:
14
+ | HTMLImageElement
15
+ | HTMLCanvasElement
16
+ | HTMLVideoElement
17
+ | ImageBitmap
18
+ | string,
19
+ name: string,
20
+ width?: number,
21
+ format?: string | ImageOutputValues,
22
+ ): any {
23
+ let out;
24
+ const image: any = imageSource;
25
+
26
+ if (typeof image !== 'string') {
27
+ out = getSnapshot(image, width, format as ImageOutputValues);
28
+ } else {
29
+ out = image;
30
+ }
31
+
32
+ if ((navigator as any).msSaveBlob) {
33
+ // IE10+
34
+ try {
35
+ const blob = image.msToBlob();
36
+ return (navigator as any).msSaveBlob(blob, name);
37
+ } catch (e) {
38
+ console.warn(e);
39
+ }
40
+ } else {
41
+ const uri = out;
42
+ const link = document.createElement('a');
43
+ link.download = name;
44
+ link.href = uri as string;
45
+
46
+ document.body.appendChild(link);
47
+ if (link.click) {
48
+ link.click();
49
+ } else {
50
+ const event = document.createEvent('MouseEvents');
51
+ (event as any).initMouseEvent('click', true, true, window);
52
+ link.dispatchEvent(event);
53
+ }
54
+ document.body.removeChild(link);
55
+ }
56
+ }
57
+
58
+ /**
59
+ * @param imageSource
60
+ * @param string name
61
+ * @param number width
62
+ * @param string format
63
+ */
64
+ const DownloadImage = SaveImage;
65
+ export { SaveImage, DownloadImage };
@@ -0,0 +1,16 @@
1
+ const canvasCacheObj: any = {};
2
+
3
+ export function getCanvasCached(id: string): {
4
+ canvas: HTMLCanvasElement;
5
+ ctx: CanvasRenderingContext2D;
6
+ } {
7
+ if (!canvasCacheObj[id]) {
8
+ const canvas = document.createElement('canvas');
9
+ canvasCacheObj[id] = {
10
+ canvas,
11
+ ctx: canvas.getContext('2d'),
12
+ };
13
+ }
14
+
15
+ return canvasCacheObj[id];
16
+ }
@@ -0,0 +1,99 @@
1
+ import { fitIntoRectangle } from '../geom';
2
+ import type { ImageOutputValues } from '../interfaces';
3
+
4
+ function getSnapshot2(
5
+ imageElement:
6
+ | HTMLImageElement
7
+ | HTMLCanvasElement
8
+ | HTMLVideoElement
9
+ | ImageBitmap,
10
+ maxWidth = 1024,
11
+ output: ImageOutputValues = 'image/png',
12
+ quality = 0.9,
13
+ ): HTMLCanvasElement | string {
14
+ const drawableImage = imageElement as any;
15
+ const canvasHelper: HTMLCanvasElement = document.createElement('canvas');
16
+ const drawCTX: CanvasRenderingContext2D = canvasHelper.getContext(
17
+ '2d',
18
+ ) as CanvasRenderingContext2D;
19
+
20
+ const prop = fitIntoRectangle(
21
+ {
22
+ x: 0,
23
+ y: 0,
24
+ w: drawableImage.naturalWidth || drawableImage.width,
25
+ h: drawableImage.naturalHeight || drawableImage.height,
26
+ },
27
+ {
28
+ x: 0,
29
+ y: 0,
30
+ w: maxWidth,
31
+ h: drawableImage.naturalHeight || drawableImage.height,
32
+ },
33
+ );
34
+
35
+ const width = prop.w;
36
+ const height = prop.h;
37
+ canvasHelper.width = width;
38
+ canvasHelper.height = height;
39
+
40
+ drawCTX.save();
41
+ drawCTX.clearRect(0, 0, width, height);
42
+ drawCTX.drawImage(drawableImage, 0, 0, width, height);
43
+ drawCTX.restore();
44
+
45
+ if (output === 'canvas') {
46
+ return canvasHelper;
47
+ }
48
+
49
+ return canvasHelper.toDataURL(output, quality);
50
+ }
51
+
52
+ export function getSnapshot(
53
+ imageElement:
54
+ | HTMLImageElement
55
+ | HTMLCanvasElement
56
+ | HTMLVideoElement
57
+ | ImageBitmap,
58
+ maxWidth = 1024,
59
+ output: ImageOutputValues = 'image/png',
60
+ quality = 0.9,
61
+ ): HTMLCanvasElement | string {
62
+ const drawableImage = imageElement as any;
63
+ const canvasHelper: HTMLCanvasElement = document.createElement('canvas');
64
+ const drawCTX: CanvasRenderingContext2D = canvasHelper.getContext(
65
+ '2d',
66
+ ) as CanvasRenderingContext2D;
67
+
68
+ const prop = fitIntoRectangle(
69
+ {
70
+ x: 0,
71
+ y: 0,
72
+ w: drawableImage.naturalWidth || drawableImage.width,
73
+ h: drawableImage.naturalHeight || drawableImage.height,
74
+ },
75
+ {
76
+ x: 0,
77
+ y: 0,
78
+ w: (drawableImage.naturalWidth || drawableImage.width) / 2,
79
+ h: drawableImage.naturalHeight || drawableImage.height,
80
+ },
81
+ );
82
+
83
+ const width = prop.w;
84
+ const height = prop.h;
85
+ canvasHelper.width = width;
86
+ canvasHelper.height = height;
87
+
88
+ drawCTX.save();
89
+ drawCTX.clearRect(0, 0, width, height);
90
+ drawCTX.drawImage(drawableImage, 0, 0, width, height);
91
+
92
+ drawCTX.restore();
93
+
94
+ if (width > maxWidth * 2) {
95
+ return getSnapshot(canvasHelper, maxWidth, output, quality);
96
+ }
97
+
98
+ return getSnapshot2(drawableImage, maxWidth, output, quality);
99
+ }
@@ -0,0 +1,13 @@
1
+ export function loadImage(url: string): Promise<HTMLImageElement> {
2
+ return new Promise((resolve: any, reject) => {
3
+ const img = new Image();
4
+ img.crossOrigin = 'anonymous';
5
+ img.onload = () => {
6
+ setTimeout(() => resolve(img), 1);
7
+ };
8
+ img.onerror = () => {
9
+ setTimeout(() => reject(null), 1);
10
+ };
11
+ img.src = url;
12
+ });
13
+ }
@@ -0,0 +1,8 @@
1
+ export const ImageOutput = {
2
+ CANVAS: 'canvas',
3
+ PNG: 'image/png',
4
+ WEBP: 'image/webp',
5
+ JPG: 'image/jpeg',
6
+ } as const;
7
+
8
+ export type ImageOutputValues = (typeof ImageOutput)[keyof typeof ImageOutput];
@@ -1,4 +1,5 @@
1
1
  import type { LoadArgs } from './load-args.interface';
2
+
2
3
  export interface LoadArgsTmp extends LoadArgs {
3
- xhr?: XMLHttpRequest;
4
+ xhr?: XMLHttpRequest;
4
5
  }
@@ -0,0 +1,15 @@
1
+ export interface LoadArgs {
2
+ order: number;
3
+ extra: any;
4
+ item?: HTMLImageElement;
5
+ useXhr?: boolean;
6
+ path: string;
7
+ onLoadEnd: (data: LoadArgs) => void;
8
+ onLoadStart: (data: ProgressEvent) => void;
9
+ onProgress: (data: ProgressEvent) => void;
10
+ id?: string;
11
+ img?: HTMLImageElement;
12
+ error?: boolean;
13
+ fallBack?: string;
14
+ resolutionId: number | string | null;
15
+ }
@@ -22,4 +22,22 @@
22
22
  * // returns 1
23
23
  * baseSortedIndex([1, 2, 3], 2);
24
24
  */
25
- export declare function baseSortedIndex(array: number[], value: number): number;
25
+ export function baseSortedIndex(array: number[], value: number): number {
26
+ const MAX_ARRAY_LENGTH = 4294967295;
27
+ const HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
28
+ let low = 0;
29
+ let high = array?.length || low;
30
+
31
+ if (high <= HALF_MAX_ARRAY_LENGTH) {
32
+ while (low < high) {
33
+ const mid = (low + high) >>> 1;
34
+ const computed = array[mid];
35
+ if (computed !== null && computed < value) {
36
+ low = mid + 1;
37
+ } else {
38
+ high = mid;
39
+ }
40
+ }
41
+ }
42
+ return high;
43
+ }
@@ -14,4 +14,20 @@
14
14
  * console.log(median); // Output: 2.5
15
15
  * ```
16
16
  */
17
- export declare function calculateMedian(numbers: number[]): number;
17
+ export function calculateMedian(numbers: number[]): number {
18
+ if (numbers.length === 0) return 0;
19
+
20
+ // Sort the array in ascending order
21
+ const sorted = [...numbers].sort((a, b) => a - b);
22
+
23
+ const length = sorted.length;
24
+ const middle = Math.floor(length / 2);
25
+
26
+ // If the length is even, return the average of the two middle numbers
27
+ if (length % 2 === 0) {
28
+ return (sorted[middle - 1] + sorted[middle]) / 2;
29
+ }
30
+
31
+ // If the length is odd, return the middle number
32
+ return sorted[middle];
33
+ }
@@ -1,3 +1,5 @@
1
+ import { clampf } from './clampf';
2
+
1
3
  /**
2
4
  * Computes a circular index within a given range.
3
5
  *
@@ -32,4 +34,6 @@
32
34
  * const index5 = circularIndex(1, 1);
33
35
  * console.log(index5); // Output: 0
34
36
  */
35
- export declare function circularIndex(index: number, totalItems: number): number;
37
+ export function circularIndex(index: number, totalItems: number): number {
38
+ return clampf(0, totalItems - 1, (totalItems * 2 + index) % totalItems);
39
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Clamps value between min and max;
3
+ * @param min minValue
4
+ * @param max maxValue
5
+ * @param value inputValue
6
+ * @returns number
7
+ */
8
+
9
+ export function clampf(min: number, max: number, value: number): number {
10
+ if (min > max) {
11
+ return min;
12
+ }
13
+ return Math.min(max, Math.max(min, value));
14
+ }
@@ -0,0 +1,7 @@
1
+ export function degreesToRadians(degrees: number): number {
2
+ return degrees * (Math.PI / 180);
3
+ }
4
+
5
+ export function radiansToDegrees(radians: number): number {
6
+ return radians * (180 / Math.PI);
7
+ }
@@ -1,3 +1,11 @@
1
+ /**
2
+ * A small epsilon value used for floating-point comparisons.
3
+ *
4
+ * @remarks
5
+ * The value of `EPSILON` is `0.01`. This can be overridden in the comparison functions if needed.
6
+ */
7
+ const EPSILON = 0.01;
8
+
1
9
  /**
2
10
  * Checks if floating-point number `A` is less than `B` considering a small margin of error.
3
11
  *
@@ -11,7 +19,15 @@
11
19
  * const result = fpIsALessThanB(0.0034, 0.0066); // true
12
20
  * ```
13
21
  */
14
- export declare function fpIsALessThanB(A: number, B: number, Epsilon?: number): boolean;
22
+ export function fpIsALessThanB(
23
+ A: number,
24
+ B: number,
25
+ Epsilon?: number,
26
+ ): boolean {
27
+ Epsilon = Epsilon || EPSILON;
28
+ return A - B < Epsilon && Math.abs(A - B) > Epsilon;
29
+ }
30
+
15
31
  /**
16
32
  * Checks if floating-point number `A` is greater than `B` considering a small margin of error.
17
33
  *
@@ -25,7 +41,15 @@ export declare function fpIsALessThanB(A: number, B: number, Epsilon?: number):
25
41
  * const result = fpIsAGreaterThanB(0.0066, 0.0034); // true
26
42
  * ```
27
43
  */
28
- export declare function fpIsAGreaterThanB(A: number, B: number, Epsilon?: number): boolean;
44
+ export function fpIsAGreaterThanB(
45
+ A: number,
46
+ B: number,
47
+ Epsilon?: number,
48
+ ): boolean {
49
+ Epsilon = Epsilon || EPSILON;
50
+ return A - B > Epsilon && Math.abs(A - B) > Epsilon;
51
+ }
52
+
29
53
  /**
30
54
  * Checks if floating-point number `A` is approximately the same as `B` considering a small margin of error.
31
55
  *
@@ -39,4 +63,7 @@ export declare function fpIsAGreaterThanB(A: number, B: number, Epsilon?: number
39
63
  * const result = fpIsASameAsB(0.005, 0.0051); // true
40
64
  * ```
41
65
  */
42
- export declare function fpIsASameAsB(A: number, B: number, Epsilon?: number): boolean;
66
+ export function fpIsASameAsB(A: number, B: number, Epsilon?: number): boolean {
67
+ Epsilon = Epsilon || EPSILON;
68
+ return Math.abs(A - B) < Epsilon;
69
+ }
@@ -14,4 +14,25 @@
14
14
  * If `clampToNormal` is true, the result is clamped between 0 and 1.
15
15
  * If the difference between `min` and `max` is 0, returns 1 to avoid division by zero.
16
16
  */
17
- export declare function inverseLerp(min: number, max: number, value: number, clampToNormal?: boolean): number;
17
+ export function inverseLerp(
18
+ min: number,
19
+ max: number,
20
+ value: number,
21
+ clampToNormal = false,
22
+ ): number {
23
+ if (clampToNormal) {
24
+ value = Math.min(max, value);
25
+ value = Math.max(min, value);
26
+ }
27
+ const difference = max - min;
28
+
29
+ // Avoid JS division error
30
+ if (difference === 0) {
31
+ return 1;
32
+ }
33
+ const result = (value - min) / difference;
34
+ if (clampToNormal) {
35
+ return Math.min(1, Math.max(0, result));
36
+ }
37
+ return result;
38
+ }
@@ -0,0 +1,12 @@
1
+ import { clampf } from './clampf';
2
+
3
+ /**
4
+ * @param min minimums
5
+ * @param max maximums
6
+ * @param value current float value in 0-1 range
7
+ * @returns clamped value
8
+ */
9
+ export function lerp(min: number, max: number, value: number): number {
10
+ value = clampf(0, 1, value);
11
+ return value * (max - min) + min;
12
+ }
@@ -32,12 +32,19 @@
32
32
  * [LOG]: "Task 4 acquired mutex"
33
33
  * [LOG]: "Task 4 releasing mutex"
34
34
  */
35
- export declare class Mutex {
36
- private mutex;
37
- /**
38
- * Acquires the mutex, returning a promise that resolves when the mutex is acquired.
39
- * The returned promise provides a release function that should be called to release the mutex.
40
- * @returns A promise that resolves with a release function.
41
- */
42
- acquire(): Promise<() => void>;
35
+ export class Mutex {
36
+ private mutex = Promise.resolve();
37
+
38
+ /**
39
+ * Acquires the mutex, returning a promise that resolves when the mutex is acquired.
40
+ * The returned promise provides a release function that should be called to release the mutex.
41
+ * @returns A promise that resolves with a release function.
42
+ */
43
+ async acquire(): Promise<() => void> {
44
+ let release: () => void;
45
+ const previous = this.mutex;
46
+ this.mutex = new Promise<void>((resolve) => (release = resolve));
47
+ await previous;
48
+ return release!;
49
+ }
43
50
  }
@@ -32,11 +32,31 @@
32
32
  * [LOG]: "Task 4 releasing semaphore"
33
33
  * [LOG]: "Task 3 releasing semaphore"
34
34
  */
35
- export declare class Semaphore {
36
- private readonly maxConcurrency;
37
- private tasks;
38
- private currentCount;
39
- constructor(maxConcurrency: number);
40
- acquire(): Promise<void>;
41
- release(): void;
35
+ export class Semaphore {
36
+ private tasks: (() => void)[] = [];
37
+ private currentCount = 0;
38
+
39
+ constructor(private readonly maxConcurrency: number) {}
40
+
41
+ public acquire(): Promise<void> {
42
+ return new Promise((resolve) => {
43
+ if (this.currentCount < this.maxConcurrency) {
44
+ this.currentCount++;
45
+ resolve();
46
+ } else {
47
+ this.tasks.push(resolve);
48
+ }
49
+ });
50
+ }
51
+
52
+ public release(): void {
53
+ if (this.tasks.length > 0) {
54
+ const nextTask = this.tasks.shift();
55
+ if (nextTask) {
56
+ nextTask();
57
+ }
58
+ } else if (this.currentCount > 0) {
59
+ this.currentCount--;
60
+ }
61
+ }
42
62
  }
@@ -0,0 +1,26 @@
1
+ import type { Observable } from 'rxjs';
2
+ import { finalize, from, switchMap } from 'rxjs';
3
+ import { Logger } from '../dev';
4
+ import { Mutex } from './Mutex';
5
+
6
+ export class TaskRunner {
7
+ private mutex = new Mutex();
8
+
9
+ runTask(name: string, task: () => Observable<string | null>) {
10
+ // Log that the task is waiting to acquire the mutex
11
+ Logger.log(`${name} waiting to acquire mutex`);
12
+
13
+ return from(this.mutex.acquire()).pipe(
14
+ switchMap((release) => {
15
+ // Log that the mutex has been acquired
16
+ Logger.log(`${name} acquired mutex`);
17
+ return task().pipe(
18
+ finalize(() => {
19
+ Logger.log(`${name} releasing mutex`);
20
+ release();
21
+ }),
22
+ );
23
+ }),
24
+ );
25
+ }
26
+ }
@@ -0,0 +1,75 @@
1
+ type TruthyTypesOf<T> = T extends false | '' | 0 | null | undefined ? never : T;
2
+ type FalsyTypesOf<T> = T extends false | '' | 0 | null | undefined ? T : never;
3
+ type EmptyTypesOf<T> = T extends undefined | null | object | '' ? T : never;
4
+ type NonEmptyTypesOf<T> = T extends undefined | null | object | '' ? never : T;
5
+ /**
6
+ * The Boolean object represents a truth value: true or false.
7
+ * @param value
8
+ * @constructor
9
+ * Returns:boolean
10
+ */
11
+ export const Truthy: <T>(value: T) => value is TruthyTypesOf<T> = <T>(
12
+ value?: T,
13
+ ): value is TruthyTypesOf<T> =>
14
+ !!value && value !== 'false' && value !== 'undefined' && value !== 'null';
15
+
16
+ /**
17
+ * The Boolean object represents an INVERSE truth value: true or false.
18
+ * @param value
19
+ * @constructor
20
+ * Returns:boolean
21
+ */
22
+ export const Falsy: <T>(value: T) => value is FalsyTypesOf<T> = <T>(
23
+ value?: T,
24
+ ): value is FalsyTypesOf<T> => !Truthy(value);
25
+
26
+ /**
27
+ * Checks if a value is empty.
28
+ *
29
+ * @param {any} value - The value to check.
30
+ * @return {boolean} Returns true if the value is empty, otherwise false.
31
+ */
32
+ export const IsEmpty: <T>(value: T) => value is EmptyTypesOf<T> = <T>(
33
+ value: T,
34
+ ): value is EmptyTypesOf<T> => {
35
+ return (
36
+ value === undefined ||
37
+ value === null ||
38
+ (typeof value === 'object' && Object.keys(value).length === 0) ||
39
+ (typeof value === 'string' && value.trim().length === 0)
40
+ );
41
+ };
42
+
43
+ export const NotEmpty: <T>(value: T) => value is NonEmptyTypesOf<T> = <T>(
44
+ value: T,
45
+ ): value is NonEmptyTypesOf<T> => {
46
+ return !IsEmpty(value);
47
+ };
48
+ export const isDefined = <T>(arg: T | null | undefined): arg is T =>
49
+ arg !== null && arg !== undefined;
50
+
51
+ export const isNotDefined = <T>(
52
+ arg: T | null | undefined,
53
+ ): arg is null | undefined => arg === null || arg === undefined;
54
+
55
+ export const isJSON = (str: string): boolean => {
56
+ try {
57
+ JSON.parse(str);
58
+ } catch (e) {
59
+ console.warn(e);
60
+
61
+ return false;
62
+ }
63
+
64
+ return true;
65
+ };
66
+
67
+ export const isEmpty = (value: any) =>
68
+ value === undefined ||
69
+ value === null ||
70
+ (typeof value === 'object' && Object.keys(value).length === 0) ||
71
+ (typeof value === 'string' && value.trim().length === 0);
72
+
73
+ export function isAllValuesTruthy<T extends string, K>(value: Record<T, K>) {
74
+ return Object.values(value).every(Truthy);
75
+ }
@@ -1,3 +1,5 @@
1
+ const cache: Record<string, unknown> = {};
2
+
1
3
  /**
2
4
  * Converts a given value to a string suitable for search comparisons.
3
5
  * The resulting string is in lowercase, with consecutive spaces replaced by underscores.
@@ -15,4 +17,18 @@
15
17
  * retrieved from the cache or freshly computed and then cached.
16
18
  *
17
19
  */
18
- export declare function textForSearch(value: unknown, caseSensitive?: boolean): string;
20
+ export function textForSearch(value: unknown, caseSensitive = false): string {
21
+ const key = `${value}_${caseSensitive}`;
22
+ return (cache[key] ||
23
+ (() => {
24
+ let result = String(value).trim().replace(/ +/gi, '_');
25
+
26
+ if (!caseSensitive) {
27
+ result = result.toLowerCase();
28
+ }
29
+
30
+ cache[key] = result;
31
+
32
+ return result;
33
+ })()) as string;
34
+ }