@3dsource/utils 0.0.1

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 (94) hide show
  1. package/README.md +64 -0
  2. package/eslint.config.js +37 -0
  3. package/ng-package.json +7 -0
  4. package/package.json +11 -0
  5. package/src/lib/color/CMYKtoRGB.ts +20 -0
  6. package/src/lib/color/HEXtoRGB.ts +9 -0
  7. package/src/lib/color/HSVtoRGB.ts +82 -0
  8. package/src/lib/color/RGBtoCMYK.ts +50 -0
  9. package/src/lib/color/RGBtoHEX.ts +17 -0
  10. package/src/lib/color/RGBtoHSV.ts +53 -0
  11. package/src/lib/color/hsv.ts +14 -0
  12. package/src/lib/color/index.ts +16 -0
  13. package/src/lib/color/max.ts +18 -0
  14. package/src/lib/color/min.ts +18 -0
  15. package/src/lib/color/overlay.ts +25 -0
  16. package/src/lib/color/rgb.ts +10 -0
  17. package/src/lib/color/sub.ts +18 -0
  18. package/src/lib/color/subtract.ts +27 -0
  19. package/src/lib/color/sum.ts +19 -0
  20. package/src/lib/color/toRGB.ts +14 -0
  21. package/src/lib/color/toRGBA.ts +8 -0
  22. package/src/lib/constants/color-codes.constant.ts +9 -0
  23. package/src/lib/constants/index.ts +1 -0
  24. package/src/lib/csv/CSV2Array.ts +66 -0
  25. package/src/lib/csv/CSV2Records.ts +56 -0
  26. package/src/lib/csv/ObjectToCSV.ts +21 -0
  27. package/src/lib/csv/index.ts +3 -0
  28. package/src/lib/csv/test/Csv.spec.ts +51 -0
  29. package/src/lib/dev/dev3d.ts +1 -0
  30. package/src/lib/dev/index.ts +3 -0
  31. package/src/lib/dev/logger.ts +94 -0
  32. package/src/lib/dev/timeToString.ts +16 -0
  33. package/src/lib/filenaming/cleanupFileName.ts +18 -0
  34. package/src/lib/filenaming/index.ts +3 -0
  35. package/src/lib/filenaming/makePath.ts +5 -0
  36. package/src/lib/filenaming/normalizePath.ts +9 -0
  37. package/src/lib/filenaming/test/cleanupFileName.spec.ts +9 -0
  38. package/src/lib/filenaming/test/makePath.spec.ts +7 -0
  39. package/src/lib/filenaming/test/normalizePath.spec.ts +9 -0
  40. package/src/lib/geom/expandOverRectangle.ts +17 -0
  41. package/src/lib/geom/fitIntoRectangle.ts +43 -0
  42. package/src/lib/geom/index.ts +3 -0
  43. package/src/lib/geom/interfaces/area.interface.ts +5 -0
  44. package/src/lib/geom/interfaces/index.ts +4 -0
  45. package/src/lib/geom/interfaces/rect.interface.ts +4 -0
  46. package/src/lib/geom/interfaces/size.interface.ts +4 -0
  47. package/src/lib/geom/interfaces//321/201oords.interface.ts +4 -0
  48. package/src/lib/geom/test/fitRectangle.spec.ts +54 -0
  49. package/src/lib/helpers/BatchLoader.ts +243 -0
  50. package/src/lib/helpers/KeyboardNumericCode.ts +118 -0
  51. package/src/lib/helpers/index.ts +6 -0
  52. package/src/lib/helpers/serialize.ts +11 -0
  53. package/src/lib/helpers/sleep.ts +3 -0
  54. package/src/lib/helpers/test/sleep.spec.ts +11 -0
  55. package/src/lib/helpers/trimLastSlashFromUrl.ts +9 -0
  56. package/src/lib/image/SaveImage.ts +65 -0
  57. package/src/lib/image/getCanvasCached.ts +16 -0
  58. package/src/lib/image/getSnapshot.ts +99 -0
  59. package/src/lib/image/index.ts +4 -0
  60. package/src/lib/image/loadImage.ts +13 -0
  61. package/src/lib/interfaces/image-output.ts +8 -0
  62. package/src/lib/interfaces/index.ts +3 -0
  63. package/src/lib/interfaces/load-args-tmp.interface.ts +5 -0
  64. package/src/lib/interfaces/load-args.interface.ts +15 -0
  65. package/src/lib/math/baseSortedIndex.ts +43 -0
  66. package/src/lib/math/calculateMedian.ts +33 -0
  67. package/src/lib/math/circularIndex.ts +39 -0
  68. package/src/lib/math/clampf.ts +14 -0
  69. package/src/lib/math/degrees.ts +7 -0
  70. package/src/lib/math/floatCompare.ts +69 -0
  71. package/src/lib/math/index.ts +8 -0
  72. package/src/lib/math/inverseLerp.ts +38 -0
  73. package/src/lib/math/lerp.ts +12 -0
  74. package/src/lib/math/test/baseSortedIndex.spec.ts +43 -0
  75. package/src/lib/math/test/circularIndex.spec.ts +38 -0
  76. package/src/lib/mutex/Mutex.ts +50 -0
  77. package/src/lib/mutex/Semaphore.ts +62 -0
  78. package/src/lib/mutex/TaskRunner.ts +26 -0
  79. package/src/lib/mutex/index.ts +3 -0
  80. package/src/lib/predicates/BooleanPredictors.ts +47 -0
  81. package/src/lib/predicates/index.ts +3 -0
  82. package/src/lib/predicates/test/BooleanPredictors.spec.ts +71 -0
  83. package/src/lib/predicates/test/where.spec.ts +94 -0
  84. package/src/lib/predicates/textForSearch.ts +34 -0
  85. package/src/lib/predicates/where.ts +76 -0
  86. package/src/lib/rxjs/index.ts +3 -0
  87. package/src/lib/rxjs/leadingTrailingDebounceTime.ts +86 -0
  88. package/src/lib/rxjs/smoothTransition.ts +29 -0
  89. package/src/lib/rxjs/tapLog.ts +13 -0
  90. package/src/lib/strings/index.ts +1 -0
  91. package/src/lib/strings/pad.ts +18 -0
  92. package/src/public-api.ts +14 -0
  93. package/tsconfig.lib.json +13 -0
  94. package/tsconfig.lib.prod.json +11 -0
@@ -0,0 +1,34 @@
1
+ const cache: Record<string, unknown> = {};
2
+
3
+ /**
4
+ * Converts a given value to a string suitable for search comparisons.
5
+ * The resulting string is in lowercase, with consecutive spaces replaced by underscores.
6
+ * The function uses a cache to improve performance by storing and reusing the results of previous conversions.
7
+ *
8
+ * @param {any} value - The value to be converted to a search-friendly string.
9
+ * It can be of any type, but it will be coerced to a string if not already one.
10
+ *
11
+ * @param {boolean} caseSensitive - A flag indicating whether the comparison should be case-sensitive.
12
+ * If set to true, the function will perform case-sensitive comparisons, preserving the original casing of input strings.
13
+ * If set to false (default), the function will convert the input strings to lowercase for case-insensitive comparisons
14
+ *
15
+ * @returns {string} The processed string, which is trimmed, converted to lowercase (unless caseSensitive is true),
16
+ * and has all sequences of spaces replaced with underscores. This string is either
17
+ * retrieved from the cache or freshly computed and then cached.
18
+ *
19
+ */
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
+ }
@@ -0,0 +1,76 @@
1
+ import { textForSearch } from './textForSearch';
2
+ import type { TruthyTypesOf } from 'rxjs';
3
+
4
+ /**
5
+ * Creates a predicate function to filter records from a collection based on specified criteria.
6
+ *
7
+ * The `where` function accepts a criteria object with key-value pairs, indicating the fields
8
+ * and their expected values for filtering. It returns a predicate function that filters a collection
9
+ * of records. This predicate checks if records match the criteria using a case-insensitive comparison,
10
+ * making it particularly useful in conjunction with the `textForSearch` function, which standardizes
11
+ * strings for such comparisons.
12
+ *
13
+ * Each criterion value is first processed with `textForSearch` to normalize spacing and case,
14
+ * ensuring consistent and predictable filtering. The comparison between each record's field value
15
+ * and the criterion value is thus case-insensitive and ignores extra spaces.
16
+ *
17
+ * @param {Partial<Record<K, T[K]>>} criteria - An object representing the filtering criteria.
18
+ * Keys correspond to the record's fields to be filtered, and values are the expected values for those fields,
19
+ * processed in a case-insensitive manner. Undefined values are ignored.
20
+ *
21
+ * @param {boolean} caseSensitive - A flag indicating whether the comparison should be case-sensitive.
22
+ * If set to true, the function will perform case-sensitive comparisons, preserving the original casing of input strings.
23
+ * If set to false (default), the function will convert the input strings to lowercase for case-insensitive comparisons
24
+ *
25
+ * @returns {(record: T) => boolean} A predicate function that takes a record of type `T`
26
+ * and returns `true` if the record's field values match all criteria, otherwise `false`.
27
+ *
28
+ * @example
29
+ * // Define a collection of items
30
+ * const items = [
31
+ * { name: "Apple", category: "Fruit" },
32
+ * { name: "Carrot", category: "Vegetable" },
33
+ * { name: "Banana", category: "Fruit" }
34
+ * ];
35
+ *
36
+ * // Create a predicate to find fruits, using a case-insensitive comparison
37
+ * const isFruit = where({ category: "fruit" }); // 'fruit' will match 'Fruit' in items
38
+ *
39
+ * // Filter the collection with the predicate
40
+ * const fruits = items.filter(isFruit);
41
+ * // Output: [{ name: "Apple", category: "Fruit" }, { name: "Banana", category: "Fruit" }]
42
+ *
43
+ * @typeparam T - Specifies the type of records in the collection to be filtered. It extends `object`,
44
+ * ensuring the function is only used with object types. This generic approach allows for flexible usage
45
+ * with various record structures.
46
+ */
47
+
48
+ export function where<T extends object>(
49
+ criteria: Partial<TruthyTypesOf<T>>,
50
+ caseSensitive = false,
51
+ ): (record: T) => boolean {
52
+ const preComputedEntries = Object.entries(criteria)
53
+ .filter(([, value]) => value !== undefined)
54
+ .map(([key, value]) => [key, textForSearch(value, caseSensitive)] as const);
55
+
56
+ return (record: T): boolean => {
57
+ return (
58
+ preComputedEntries.length > 0 &&
59
+ preComputedEntries.every(([key, criterionValue]) => {
60
+ return (
61
+ textForSearch(record[key as keyof T] ?? '', caseSensitive) ===
62
+ criterionValue
63
+ );
64
+ })
65
+ );
66
+ };
67
+ }
68
+ export function whereNot<T extends object>(
69
+ criteria: Partial<TruthyTypesOf<T>>,
70
+ caseSensitive = false,
71
+ ): (record: T) => boolean {
72
+ const whereFunc = where(criteria, caseSensitive);
73
+ return (record: T) => {
74
+ return !whereFunc(record);
75
+ };
76
+ }
@@ -0,0 +1,3 @@
1
+ export * from './leadingTrailingDebounceTime';
2
+ export * from './smoothTransition';
3
+ export * from './tapLog';
@@ -0,0 +1,86 @@
1
+ import type { SchedulerLike, Subscriber, Subscription } from 'rxjs';
2
+ import { asyncScheduler, Observable, timer } from 'rxjs';
3
+
4
+ /**
5
+ * Emits the most recent value emitted by the source Observable after a
6
+ * specified time span has passed without another source emission.
7
+ *
8
+ * This is a combination of `debounceTime` and `auditTime` operators.
9
+ *
10
+ * The leading value is emitted immediately, and trailing values are debounced.
11
+ *
12
+ * @param dueTime The time to wait before emitting the last value.
13
+ * @param scheduler The scheduler to use for the timeout.
14
+ * @returns A function that returns an Observable that mirrors the source Observable, but applies the specified debouncing.
15
+ */
16
+ export function leadingTrailingDebounceTime<T>(
17
+ dueTime: number,
18
+ scheduler: SchedulerLike = asyncScheduler,
19
+ ): (source: Observable<T>) => Observable<T> {
20
+ return (source: Observable<T>) =>
21
+ new Observable<T>((subscriber: Subscriber<T>) => {
22
+ let hasValue = false;
23
+ let lastValue: T | null = null;
24
+ let timerSubscription: Subscription | null = null;
25
+ let leading = true; // Controls whether we emit immediately.
26
+
27
+ const clearTimer = () => {
28
+ if (timerSubscription) {
29
+ timerSubscription.unsubscribe();
30
+ timerSubscription = null;
31
+ }
32
+ };
33
+
34
+ const resetValues = () => {
35
+ hasValue = false;
36
+ lastValue = null;
37
+ leading = true; // Reset so the next new value is immediate.
38
+ };
39
+
40
+ const emitLastValue = () => {
41
+ if (hasValue && lastValue !== null) {
42
+ subscriber.next(lastValue);
43
+ resetValues();
44
+ }
45
+ };
46
+
47
+ const sourceSubscription = source.subscribe({
48
+ next: (value) => {
49
+ // If we are "leading", emit immediately and switch leading off
50
+ if (leading) {
51
+ subscriber.next(value);
52
+ leading = false;
53
+ timerSubscription = timer(dueTime, scheduler).subscribe(() => {
54
+ resetValues();
55
+ clearTimer();
56
+ });
57
+ return;
58
+ }
59
+
60
+ // Otherwise, save the value and start (or restart) timer
61
+ hasValue = true;
62
+ lastValue = value;
63
+ clearTimer();
64
+ timerSubscription = timer(dueTime, scheduler).subscribe(() => {
65
+ emitLastValue();
66
+ });
67
+ },
68
+ error: (err: unknown) => {
69
+ clearTimer();
70
+ subscriber.error(err);
71
+ },
72
+ complete: () => {
73
+ // If there is a pending emission, emit it before completing
74
+ clearTimer();
75
+ emitLastValue();
76
+ subscriber.complete();
77
+ },
78
+ });
79
+
80
+ // Cleanup logic
81
+ return () => {
82
+ clearTimer();
83
+ sourceSubscription.unsubscribe();
84
+ };
85
+ });
86
+ }
@@ -0,0 +1,29 @@
1
+ import type { Observable } from 'rxjs';
2
+ import { animationFrameScheduler, interval } from 'rxjs';
3
+ import { distinctUntilChanged, map } from 'rxjs/operators';
4
+ import { clampf, lerp } from '../math';
5
+
6
+ /**
7
+ * Creates an observable that emits values transitioning smoothly from the start value to the end value over a specified duration.
8
+ * The transition is performed using linear interpolation (lerp) and clamped to the range [0, 1].
9
+ *
10
+ * @param {number} start - The starting value of the transition.
11
+ * @param {number} end - The ending value of the transition.
12
+ * @param {number} duration - The duration of the transition in milliseconds.
13
+ * @returns {Observable<number>} An observable that emits the interpolated values from start to end over the specified duration.
14
+ */
15
+ export const smoothTransition = (
16
+ start: number,
17
+ end: number,
18
+ duration: number,
19
+ ): Observable<number> => {
20
+ const startTime = animationFrameScheduler.now();
21
+ return interval(0, animationFrameScheduler).pipe(
22
+ map(() => {
23
+ const elapsed = (animationFrameScheduler.now() - startTime) / duration;
24
+ return clampf(0, 1, elapsed);
25
+ }),
26
+ distinctUntilChanged(),
27
+ map((fraction) => lerp(start, end, fraction)),
28
+ );
29
+ };
@@ -0,0 +1,13 @@
1
+ import { tap } from 'rxjs/operators';
2
+ import type { Observable } from 'rxjs';
3
+ import { Logger } from '../dev';
4
+ import { COLOR_CODES } from '../constants';
5
+
6
+ export const tapLog =
7
+ <T>(text: string, ...args: any): ((source: Observable<T>) => Observable<T>) =>
8
+ (source: Observable<T>) =>
9
+ source.pipe(
10
+ tap((data) => {
11
+ Logger.colored(...COLOR_CODES.TAP_LOG, text, data, ...args);
12
+ }),
13
+ );
@@ -0,0 +1 @@
1
+ export * from './pad';
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Adds required number of symbols before input
3
+ * @param input input string
4
+ * @param size amount of total symbols
5
+ * @param symbol filler
6
+ * @returns string
7
+ */
8
+ export function pad(
9
+ input: number | string,
10
+ size: number,
11
+ symbol = '0',
12
+ ): string {
13
+ let s = input + '';
14
+ while (s.length < size) {
15
+ s = symbol + s;
16
+ }
17
+ return s.slice(-size);
18
+ }
@@ -0,0 +1,14 @@
1
+ export * from './lib/color';
2
+ export * from './lib/constants';
3
+ export * from './lib/csv';
4
+ export * from './lib/dev';
5
+ export * from './lib/filenaming';
6
+ export * from './lib/geom';
7
+ export * from './lib/helpers';
8
+ export * from './lib/image';
9
+ export * from './lib/interfaces';
10
+ export * from './lib/math';
11
+ export * from './lib/mutex';
12
+ export * from './lib/predicates';
13
+ export * from './lib/rxjs';
14
+ export * from './lib/strings';
@@ -0,0 +1,13 @@
1
+ /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
2
+ /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
3
+ {
4
+ "extends": "../../../tsconfig.json",
5
+ "compilerOptions": {
6
+ "outDir": "../../../out-tsc/lib",
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "inlineSources": true,
10
+ "types": []
11
+ },
12
+ "exclude": ["**/*.spec.ts"]
13
+ }
@@ -0,0 +1,11 @@
1
+ /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
2
+ /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
3
+ {
4
+ "extends": "./tsconfig.lib.json",
5
+ "compilerOptions": {
6
+ "declarationMap": false
7
+ },
8
+ "angularCompilerOptions": {
9
+ "compilationMode": "partial"
10
+ }
11
+ }