@real1ty-obsidian-plugins/utils 1.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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -0
  3. package/dist/async-utils.d.ts +69 -0
  4. package/dist/async-utils.d.ts.map +1 -0
  5. package/dist/async-utils.js +108 -0
  6. package/dist/batch-operations.d.ts +11 -0
  7. package/dist/batch-operations.d.ts.map +1 -0
  8. package/dist/batch-operations.js +31 -0
  9. package/dist/child-reference-utils.d.ts +9 -0
  10. package/dist/child-reference-utils.d.ts.map +1 -0
  11. package/dist/child-reference-utils.js +57 -0
  12. package/dist/date-recurrence-utils.d.ts +32 -0
  13. package/dist/date-recurrence-utils.d.ts.map +1 -0
  14. package/dist/date-recurrence-utils.js +117 -0
  15. package/dist/date-utils.d.ts +20 -0
  16. package/dist/date-utils.d.ts.map +1 -0
  17. package/dist/date-utils.js +105 -0
  18. package/dist/evaluator-base.d.ts +52 -0
  19. package/dist/evaluator-base.d.ts.map +1 -0
  20. package/dist/evaluator-base.js +84 -0
  21. package/dist/file-operations.d.ts +31 -0
  22. package/dist/file-operations.d.ts.map +1 -0
  23. package/dist/file-operations.js +160 -0
  24. package/dist/file-utils.d.ts +6 -0
  25. package/dist/file-utils.d.ts.map +1 -0
  26. package/dist/file-utils.js +25 -0
  27. package/dist/generate.d.ts +7 -0
  28. package/dist/generate.d.ts.map +1 -0
  29. package/dist/generate.js +13 -0
  30. package/dist/index.d.ts +14 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +14 -0
  33. package/dist/link-parser.d.ts +9 -0
  34. package/dist/link-parser.d.ts.map +1 -0
  35. package/dist/link-parser.js +19 -0
  36. package/dist/settings-store.d.ts +19 -0
  37. package/dist/settings-store.d.ts.map +1 -0
  38. package/dist/settings-store.js +79 -0
  39. package/dist/string-utils.d.ts +5 -0
  40. package/dist/string-utils.d.ts.map +1 -0
  41. package/dist/string-utils.js +25 -0
  42. package/dist/templater-utils.d.ts +4 -0
  43. package/dist/templater-utils.d.ts.map +1 -0
  44. package/dist/templater-utils.js +51 -0
  45. package/dist/testing/index.d.ts +5 -0
  46. package/dist/testing/index.d.ts.map +1 -0
  47. package/dist/testing/index.js +6 -0
  48. package/dist/testing/mocks/obsidian.d.ts +149 -0
  49. package/dist/testing/mocks/obsidian.d.ts.map +1 -0
  50. package/dist/testing/mocks/obsidian.js +220 -0
  51. package/dist/testing/mocks/utils.d.ts +14 -0
  52. package/dist/testing/mocks/utils.d.ts.map +1 -0
  53. package/dist/testing/mocks/utils.js +85 -0
  54. package/dist/testing/setup.d.ts +2 -0
  55. package/dist/testing/setup.d.ts.map +1 -0
  56. package/dist/testing/setup.js +18 -0
  57. package/package.json +112 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020-2025 Dynalist Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # @real1ty-obsidian-plugins/utils
2
+
3
+ Shared utilities for Obsidian plugins - a comprehensive collection of reusable functions and helpers to streamline Obsidian plugin development.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @real1ty-obsidian-plugins/utils
9
+ # or
10
+ pnpm add @real1ty-obsidian-plugins/utils
11
+ # or
12
+ yarn add @real1ty-obsidian-plugins/utils
13
+ ```
14
+
15
+ ## Features
16
+
17
+ - **Date & Time Utilities**: Recurrence handling, date formatting, and time operations
18
+ - **File Operations**: File system helpers, path utilities, and content manipulation
19
+ - **String Utilities**: Text processing, sanitization, and formatting functions
20
+ - **Async Utilities**: Promise helpers and async operation management
21
+ - **Batch Operations**: Efficient bulk processing utilities
22
+ - **Settings Store**: Reactive settings management with RxJS
23
+ - **Testing Utilities**: Mock factories and test helpers for Obsidian plugins
24
+ - **Link Parser**: Markdown link parsing and manipulation
25
+ - **Child Reference Utils**: Hierarchical content reference management
26
+
27
+ ## Usage
28
+
29
+ ```typescript
30
+ import {
31
+ formatDateTimeForInput,
32
+ generateUniqueFilePath,
33
+ SettingsStore
34
+ } from '@real1ty-obsidian-plugins/utils';
35
+
36
+ // Date utilities
37
+ const formattedDate = formatDateTimeForInput('2023-12-25T10:30:00');
38
+
39
+ // File operations
40
+ const uniquePath = await generateUniqueFilePath(app, folder, 'my-file');
41
+
42
+ // Settings management
43
+ const settingsStore = new SettingsStore(defaultSettings);
44
+ settingsStore.settings$.subscribe(settings => {
45
+ // React to settings changes
46
+ });
47
+ ```
48
+
49
+ ### Testing Utilities
50
+
51
+ For testing your Obsidian plugins:
52
+
53
+ ```typescript
54
+ import {
55
+ createMockApp,
56
+ createMockFile,
57
+ setupTestEnvironment
58
+ } from '@real1ty-obsidian-plugins/utils/testing';
59
+
60
+ // Set up test environment
61
+ setupTestEnvironment();
62
+
63
+ // Create mock Obsidian instances
64
+ const mockApp = createMockApp();
65
+ const mockFile = createMockFile('test.md');
66
+ ```
67
+
68
+ ## API Reference
69
+
70
+ ### Available Modules
71
+
72
+ - `async-utils` - Promise utilities and async helpers
73
+ - `batch-operations` - Bulk processing functions
74
+ - `child-reference-utils` - Hierarchical reference management
75
+ - `date-recurrence-utils` - Recurrence pattern handling
76
+ - `date-utils` - Date/time formatting and manipulation
77
+ - `file-operations` - File system operations
78
+ - `file-utils` - File path and content utilities
79
+ - `settings-store` - Reactive settings management
80
+ - `string-utils` - String processing functions
81
+ - `templater-utils` - Template processing utilities
82
+ - `testing` - Testing mocks and utilities
83
+
84
+ ## TypeScript Support
85
+
86
+ This package is written in TypeScript and includes full type definitions. All utilities are properly typed for the best development experience.
87
+
88
+ ## License
89
+
90
+ MIT
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Creates a function that ensures an async operation runs only once,
3
+ * returning the same promise for concurrent calls.
4
+ *
5
+ * Useful for initialization patterns where you want to ensure
6
+ * expensive async operations (like indexing, API calls, etc.)
7
+ * only happen once even if called multiple times.
8
+ *
9
+ * @param fn The async function to memoize
10
+ * @returns A function that returns the same promise on subsequent calls
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const initializeOnce = onceAsync(async () => {
15
+ * await heavyInitialization();
16
+ * console.log("Initialized!");
17
+ * });
18
+ *
19
+ * // All these calls will share the same promise
20
+ * await initializeOnce();
21
+ * await initializeOnce(); // Won't run again
22
+ * await initializeOnce(); // Won't run again
23
+ * ```
24
+ */
25
+ export declare function onceAsync<T>(fn: () => Promise<T>): () => Promise<T>;
26
+ /**
27
+ * Creates a function that ensures an async operation runs only once per key,
28
+ * useful for caching expensive operations with different parameters.
29
+ *
30
+ * @param fn The async function to memoize
31
+ * @returns A function that memoizes results by key
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const fetchUserOnce = onceAsyncKeyed(async (userId: string) => {
36
+ * return await api.getUser(userId);
37
+ * });
38
+ *
39
+ * // Each unique userId will only be fetched once
40
+ * await fetchUserOnce("user1");
41
+ * await fetchUserOnce("user1"); // Returns cached promise
42
+ * await fetchUserOnce("user2"); // New fetch for different key
43
+ * ```
44
+ */
45
+ export declare function onceAsyncKeyed<TArgs extends readonly unknown[], TReturn>(fn: (...args: TArgs) => Promise<TReturn>): (...args: TArgs) => Promise<TReturn>;
46
+ /**
47
+ * Creates a resettable version of onceAsync that can be cleared and re-run.
48
+ *
49
+ * @param fn The async function to memoize
50
+ * @returns Object with execute and reset methods
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const { execute: initialize, reset } = onceAsyncResettable(async () => {
55
+ * await heavyInitialization();
56
+ * });
57
+ *
58
+ * await initialize(); // Runs
59
+ * await initialize(); // Cached
60
+ *
61
+ * reset(); // Clear cache
62
+ * await initialize(); // Runs again
63
+ * ```
64
+ */
65
+ export declare function onceAsyncResettable<T>(fn: () => Promise<T>): {
66
+ execute: () => Promise<T>;
67
+ reset: () => void;
68
+ };
69
+ //# sourceMappingURL=async-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-utils.d.ts","sourceRoot":"","sources":["../src/async-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,CAcnE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,EAAE,OAAO,EACvE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,GACtC,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAYtC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG;IAC7D,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,IAAI,CAAC;CAClB,CAmBA"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Creates a function that ensures an async operation runs only once,
3
+ * returning the same promise for concurrent calls.
4
+ *
5
+ * Useful for initialization patterns where you want to ensure
6
+ * expensive async operations (like indexing, API calls, etc.)
7
+ * only happen once even if called multiple times.
8
+ *
9
+ * @param fn The async function to memoize
10
+ * @returns A function that returns the same promise on subsequent calls
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const initializeOnce = onceAsync(async () => {
15
+ * await heavyInitialization();
16
+ * console.log("Initialized!");
17
+ * });
18
+ *
19
+ * // All these calls will share the same promise
20
+ * await initializeOnce();
21
+ * await initializeOnce(); // Won't run again
22
+ * await initializeOnce(); // Won't run again
23
+ * ```
24
+ */
25
+ export function onceAsync(fn) {
26
+ let promise = null;
27
+ return () => {
28
+ if (!promise) {
29
+ try {
30
+ promise = fn();
31
+ }
32
+ catch (error) {
33
+ // Convert synchronous errors to rejected promises
34
+ promise = Promise.reject(error);
35
+ }
36
+ }
37
+ return promise;
38
+ };
39
+ }
40
+ /**
41
+ * Creates a function that ensures an async operation runs only once per key,
42
+ * useful for caching expensive operations with different parameters.
43
+ *
44
+ * @param fn The async function to memoize
45
+ * @returns A function that memoizes results by key
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * const fetchUserOnce = onceAsyncKeyed(async (userId: string) => {
50
+ * return await api.getUser(userId);
51
+ * });
52
+ *
53
+ * // Each unique userId will only be fetched once
54
+ * await fetchUserOnce("user1");
55
+ * await fetchUserOnce("user1"); // Returns cached promise
56
+ * await fetchUserOnce("user2"); // New fetch for different key
57
+ * ```
58
+ */
59
+ export function onceAsyncKeyed(fn) {
60
+ const cache = new Map();
61
+ return (...args) => {
62
+ const key = JSON.stringify(args);
63
+ if (!cache.has(key)) {
64
+ cache.set(key, fn(...args));
65
+ }
66
+ return cache.get(key);
67
+ };
68
+ }
69
+ /**
70
+ * Creates a resettable version of onceAsync that can be cleared and re-run.
71
+ *
72
+ * @param fn The async function to memoize
73
+ * @returns Object with execute and reset methods
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * const { execute: initialize, reset } = onceAsyncResettable(async () => {
78
+ * await heavyInitialization();
79
+ * });
80
+ *
81
+ * await initialize(); // Runs
82
+ * await initialize(); // Cached
83
+ *
84
+ * reset(); // Clear cache
85
+ * await initialize(); // Runs again
86
+ * ```
87
+ */
88
+ export function onceAsyncResettable(fn) {
89
+ let promise = null;
90
+ return {
91
+ execute: () => {
92
+ if (!promise) {
93
+ try {
94
+ promise = fn();
95
+ }
96
+ catch (error) {
97
+ // Convert synchronous errors to rejected promises
98
+ promise = Promise.reject(error);
99
+ }
100
+ }
101
+ return promise;
102
+ },
103
+ reset: () => {
104
+ promise = null;
105
+ },
106
+ };
107
+ }
108
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXN5bmMtdXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYXN5bmMtdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBdUJHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBSSxFQUFvQjtJQUNoRCxJQUFJLE9BQU8sR0FBc0IsSUFBSSxDQUFDO0lBRXRDLE9BQU8sR0FBRyxFQUFFO1FBQ1gsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2QsSUFBSSxDQUFDO2dCQUNKLE9BQU8sR0FBRyxFQUFFLEVBQUUsQ0FBQztZQUNoQixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDaEIsa0RBQWtEO2dCQUNsRCxPQUFPLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNqQyxDQUFDO1FBQ0YsQ0FBQztRQUNELE9BQU8sT0FBTyxDQUFDO0lBQ2hCLENBQUMsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FDN0IsRUFBd0M7SUFFeEMsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQTRCLENBQUM7SUFFbEQsT0FBTyxDQUFDLEdBQUcsSUFBVyxFQUFFLEVBQUU7UUFDekIsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVqQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3JCLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDN0IsQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUUsQ0FBQztJQUN4QixDQUFDLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FBSSxFQUFvQjtJQUkxRCxJQUFJLE9BQU8sR0FBc0IsSUFBSSxDQUFDO0lBRXRDLE9BQU87UUFDTixPQUFPLEVBQUUsR0FBRyxFQUFFO1lBQ2IsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNkLElBQUksQ0FBQztvQkFDSixPQUFPLEdBQUcsRUFBRSxFQUFFLENBQUM7Z0JBQ2hCLENBQUM7Z0JBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztvQkFDaEIsa0RBQWtEO29CQUNsRCxPQUFPLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDakMsQ0FBQztZQUNGLENBQUM7WUFDRCxPQUFPLE9BQU8sQ0FBQztRQUNoQixDQUFDO1FBQ0QsS0FBSyxFQUFFLEdBQUcsRUFBRTtZQUNYLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFDaEIsQ0FBQztLQUNELENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCBlbnN1cmVzIGFuIGFzeW5jIG9wZXJhdGlvbiBydW5zIG9ubHkgb25jZSxcbiAqIHJldHVybmluZyB0aGUgc2FtZSBwcm9taXNlIGZvciBjb25jdXJyZW50IGNhbGxzLlxuICpcbiAqIFVzZWZ1bCBmb3IgaW5pdGlhbGl6YXRpb24gcGF0dGVybnMgd2hlcmUgeW91IHdhbnQgdG8gZW5zdXJlXG4gKiBleHBlbnNpdmUgYXN5bmMgb3BlcmF0aW9ucyAobGlrZSBpbmRleGluZywgQVBJIGNhbGxzLCBldGMuKVxuICogb25seSBoYXBwZW4gb25jZSBldmVuIGlmIGNhbGxlZCBtdWx0aXBsZSB0aW1lcy5cbiAqXG4gKiBAcGFyYW0gZm4gVGhlIGFzeW5jIGZ1bmN0aW9uIHRvIG1lbW9pemVcbiAqIEByZXR1cm5zIEEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZSBzYW1lIHByb21pc2Ugb24gc3Vic2VxdWVudCBjYWxsc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBpbml0aWFsaXplT25jZSA9IG9uY2VBc3luYyhhc3luYyAoKSA9PiB7XG4gKiAgIGF3YWl0IGhlYXZ5SW5pdGlhbGl6YXRpb24oKTtcbiAqICAgY29uc29sZS5sb2coXCJJbml0aWFsaXplZCFcIik7XG4gKiB9KTtcbiAqXG4gKiAvLyBBbGwgdGhlc2UgY2FsbHMgd2lsbCBzaGFyZSB0aGUgc2FtZSBwcm9taXNlXG4gKiBhd2FpdCBpbml0aWFsaXplT25jZSgpO1xuICogYXdhaXQgaW5pdGlhbGl6ZU9uY2UoKTsgLy8gV29uJ3QgcnVuIGFnYWluXG4gKiBhd2FpdCBpbml0aWFsaXplT25jZSgpOyAvLyBXb24ndCBydW4gYWdhaW5cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gb25jZUFzeW5jPFQ+KGZuOiAoKSA9PiBQcm9taXNlPFQ+KTogKCkgPT4gUHJvbWlzZTxUPiB7XG5cdGxldCBwcm9taXNlOiBQcm9taXNlPFQ+IHwgbnVsbCA9IG51bGw7XG5cblx0cmV0dXJuICgpID0+IHtcblx0XHRpZiAoIXByb21pc2UpIHtcblx0XHRcdHRyeSB7XG5cdFx0XHRcdHByb21pc2UgPSBmbigpO1xuXHRcdFx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHRcdFx0Ly8gQ29udmVydCBzeW5jaHJvbm91cyBlcnJvcnMgdG8gcmVqZWN0ZWQgcHJvbWlzZXNcblx0XHRcdFx0cHJvbWlzZSA9IFByb21pc2UucmVqZWN0KGVycm9yKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIHByb21pc2U7XG5cdH07XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQgZW5zdXJlcyBhbiBhc3luYyBvcGVyYXRpb24gcnVucyBvbmx5IG9uY2UgcGVyIGtleSxcbiAqIHVzZWZ1bCBmb3IgY2FjaGluZyBleHBlbnNpdmUgb3BlcmF0aW9ucyB3aXRoIGRpZmZlcmVudCBwYXJhbWV0ZXJzLlxuICpcbiAqIEBwYXJhbSBmbiBUaGUgYXN5bmMgZnVuY3Rpb24gdG8gbWVtb2l6ZVxuICogQHJldHVybnMgQSBmdW5jdGlvbiB0aGF0IG1lbW9pemVzIHJlc3VsdHMgYnkga2V5XG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGZldGNoVXNlck9uY2UgPSBvbmNlQXN5bmNLZXllZChhc3luYyAodXNlcklkOiBzdHJpbmcpID0+IHtcbiAqICAgcmV0dXJuIGF3YWl0IGFwaS5nZXRVc2VyKHVzZXJJZCk7XG4gKiB9KTtcbiAqXG4gKiAvLyBFYWNoIHVuaXF1ZSB1c2VySWQgd2lsbCBvbmx5IGJlIGZldGNoZWQgb25jZVxuICogYXdhaXQgZmV0Y2hVc2VyT25jZShcInVzZXIxXCIpO1xuICogYXdhaXQgZmV0Y2hVc2VyT25jZShcInVzZXIxXCIpOyAvLyBSZXR1cm5zIGNhY2hlZCBwcm9taXNlXG4gKiBhd2FpdCBmZXRjaFVzZXJPbmNlKFwidXNlcjJcIik7IC8vIE5ldyBmZXRjaCBmb3IgZGlmZmVyZW50IGtleVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBvbmNlQXN5bmNLZXllZDxUQXJncyBleHRlbmRzIHJlYWRvbmx5IHVua25vd25bXSwgVFJldHVybj4oXG5cdGZuOiAoLi4uYXJnczogVEFyZ3MpID0+IFByb21pc2U8VFJldHVybj5cbik6ICguLi5hcmdzOiBUQXJncykgPT4gUHJvbWlzZTxUUmV0dXJuPiB7XG5cdGNvbnN0IGNhY2hlID0gbmV3IE1hcDxzdHJpbmcsIFByb21pc2U8VFJldHVybj4+KCk7XG5cblx0cmV0dXJuICguLi5hcmdzOiBUQXJncykgPT4ge1xuXHRcdGNvbnN0IGtleSA9IEpTT04uc3RyaW5naWZ5KGFyZ3MpO1xuXG5cdFx0aWYgKCFjYWNoZS5oYXMoa2V5KSkge1xuXHRcdFx0Y2FjaGUuc2V0KGtleSwgZm4oLi4uYXJncykpO1xuXHRcdH1cblxuXHRcdHJldHVybiBjYWNoZS5nZXQoa2V5KSE7XG5cdH07XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHJlc2V0dGFibGUgdmVyc2lvbiBvZiBvbmNlQXN5bmMgdGhhdCBjYW4gYmUgY2xlYXJlZCBhbmQgcmUtcnVuLlxuICpcbiAqIEBwYXJhbSBmbiBUaGUgYXN5bmMgZnVuY3Rpb24gdG8gbWVtb2l6ZVxuICogQHJldHVybnMgT2JqZWN0IHdpdGggZXhlY3V0ZSBhbmQgcmVzZXQgbWV0aG9kc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCB7IGV4ZWN1dGU6IGluaXRpYWxpemUsIHJlc2V0IH0gPSBvbmNlQXN5bmNSZXNldHRhYmxlKGFzeW5jICgpID0+IHtcbiAqICAgYXdhaXQgaGVhdnlJbml0aWFsaXphdGlvbigpO1xuICogfSk7XG4gKlxuICogYXdhaXQgaW5pdGlhbGl6ZSgpOyAvLyBSdW5zXG4gKiBhd2FpdCBpbml0aWFsaXplKCk7IC8vIENhY2hlZFxuICpcbiAqIHJlc2V0KCk7IC8vIENsZWFyIGNhY2hlXG4gKiBhd2FpdCBpbml0aWFsaXplKCk7IC8vIFJ1bnMgYWdhaW5cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gb25jZUFzeW5jUmVzZXR0YWJsZTxUPihmbjogKCkgPT4gUHJvbWlzZTxUPik6IHtcblx0ZXhlY3V0ZTogKCkgPT4gUHJvbWlzZTxUPjtcblx0cmVzZXQ6ICgpID0+IHZvaWQ7XG59IHtcblx0bGV0IHByb21pc2U6IFByb21pc2U8VD4gfCBudWxsID0gbnVsbDtcblxuXHRyZXR1cm4ge1xuXHRcdGV4ZWN1dGU6ICgpID0+IHtcblx0XHRcdGlmICghcHJvbWlzZSkge1xuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdHByb21pc2UgPSBmbigpO1xuXHRcdFx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0XHRcdC8vIENvbnZlcnQgc3luY2hyb25vdXMgZXJyb3JzIHRvIHJlamVjdGVkIHByb21pc2VzXG5cdFx0XHRcdFx0cHJvbWlzZSA9IFByb21pc2UucmVqZWN0KGVycm9yKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHByb21pc2U7XG5cdFx0fSxcblx0XHRyZXNldDogKCkgPT4ge1xuXHRcdFx0cHJvbWlzZSA9IG51bGw7XG5cdFx0fSxcblx0fTtcbn1cbiJdfQ==
@@ -0,0 +1,11 @@
1
+ export interface BatchOperationOptions {
2
+ closeAfter?: boolean;
3
+ callOnComplete?: boolean;
4
+ }
5
+ export interface BatchOperationResult {
6
+ successCount: number;
7
+ errorCount: number;
8
+ }
9
+ export declare function runBatchOperation<T>(items: T[], operationLabel: string, handler: (item: T) => Promise<void>, showResult?: boolean): Promise<BatchOperationResult>;
10
+ export declare function showBatchOperationResult(operation: string, successCount: number, errorCount: number): void;
11
+ //# sourceMappingURL=batch-operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-operations.d.ts","sourceRoot":"","sources":["../src/batch-operations.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,iBAAiB,CAAC,CAAC,EACxC,KAAK,EAAE,CAAC,EAAE,EACV,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,EACnC,UAAU,GAAE,OAAc,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAmB/B;AAED,wBAAgB,wBAAwB,CACvC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GAChB,IAAI,CAUN"}
@@ -0,0 +1,31 @@
1
+ import { __awaiter } from "tslib";
2
+ import { Notice } from "obsidian";
3
+ export function runBatchOperation(items_1, operationLabel_1, handler_1) {
4
+ return __awaiter(this, arguments, void 0, function* (items, operationLabel, handler, showResult = true) {
5
+ let successCount = 0;
6
+ let errorCount = 0;
7
+ for (const item of items) {
8
+ try {
9
+ yield handler(item);
10
+ successCount++;
11
+ }
12
+ catch (error) {
13
+ console.error(`${operationLabel}: error processing item:`, error);
14
+ errorCount++;
15
+ }
16
+ }
17
+ if (showResult) {
18
+ showBatchOperationResult(operationLabel, successCount, errorCount);
19
+ }
20
+ return { successCount, errorCount };
21
+ });
22
+ }
23
+ export function showBatchOperationResult(operation, successCount, errorCount) {
24
+ if (errorCount === 0) {
25
+ new Notice(`${operation}: ${successCount} item${successCount === 1 ? "" : "s"} processed successfully`);
26
+ }
27
+ else {
28
+ new Notice(`${operation}: ${successCount} succeeded, ${errorCount} failed. Check console for details.`);
29
+ }
30
+ }
31
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmF0Y2gtb3BlcmF0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9iYXRjaC1vcGVyYXRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBWWxDLE1BQU0sVUFBZ0IsaUJBQWlCO3lEQUN0QyxLQUFVLEVBQ1YsY0FBc0IsRUFDdEIsT0FBbUMsRUFDbkMsYUFBc0IsSUFBSTtRQUUxQixJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7UUFDckIsSUFBSSxVQUFVLEdBQUcsQ0FBQyxDQUFDO1FBRW5CLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7WUFDMUIsSUFBSSxDQUFDO2dCQUNKLE1BQU0sT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNwQixZQUFZLEVBQUUsQ0FBQztZQUNoQixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDaEIsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLGNBQWMsMEJBQTBCLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQ2xFLFVBQVUsRUFBRSxDQUFDO1lBQ2QsQ0FBQztRQUNGLENBQUM7UUFFRCxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ2hCLHdCQUF3QixDQUFDLGNBQWMsRUFBRSxZQUFZLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDcEUsQ0FBQztRQUVELE9BQU8sRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLENBQUM7SUFDckMsQ0FBQztDQUFBO0FBRUQsTUFBTSxVQUFVLHdCQUF3QixDQUN2QyxTQUFpQixFQUNqQixZQUFvQixFQUNwQixVQUFrQjtJQUVsQixJQUFJLFVBQVUsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN0QixJQUFJLE1BQU0sQ0FDVCxHQUFHLFNBQVMsS0FBSyxZQUFZLFFBQVEsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLHlCQUF5QixDQUMzRixDQUFDO0lBQ0gsQ0FBQztTQUFNLENBQUM7UUFDUCxJQUFJLE1BQU0sQ0FDVCxHQUFHLFNBQVMsS0FBSyxZQUFZLGVBQWUsVUFBVSxxQ0FBcUMsQ0FDM0YsQ0FBQztJQUNILENBQUM7QUFDRixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTm90aWNlIH0gZnJvbSBcIm9ic2lkaWFuXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmF0Y2hPcGVyYXRpb25PcHRpb25zIHtcblx0Y2xvc2VBZnRlcj86IGJvb2xlYW47XG5cdGNhbGxPbkNvbXBsZXRlPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBCYXRjaE9wZXJhdGlvblJlc3VsdCB7XG5cdHN1Y2Nlc3NDb3VudDogbnVtYmVyO1xuXHRlcnJvckNvdW50OiBudW1iZXI7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBydW5CYXRjaE9wZXJhdGlvbjxUPihcblx0aXRlbXM6IFRbXSxcblx0b3BlcmF0aW9uTGFiZWw6IHN0cmluZyxcblx0aGFuZGxlcjogKGl0ZW06IFQpID0+IFByb21pc2U8dm9pZD4sXG5cdHNob3dSZXN1bHQ6IGJvb2xlYW4gPSB0cnVlXG4pOiBQcm9taXNlPEJhdGNoT3BlcmF0aW9uUmVzdWx0PiB7XG5cdGxldCBzdWNjZXNzQ291bnQgPSAwO1xuXHRsZXQgZXJyb3JDb3VudCA9IDA7XG5cblx0Zm9yIChjb25zdCBpdGVtIG9mIGl0ZW1zKSB7XG5cdFx0dHJ5IHtcblx0XHRcdGF3YWl0IGhhbmRsZXIoaXRlbSk7XG5cdFx0XHRzdWNjZXNzQ291bnQrKztcblx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0Y29uc29sZS5lcnJvcihgJHtvcGVyYXRpb25MYWJlbH06IGVycm9yIHByb2Nlc3NpbmcgaXRlbTpgLCBlcnJvcik7XG5cdFx0XHRlcnJvckNvdW50Kys7XG5cdFx0fVxuXHR9XG5cblx0aWYgKHNob3dSZXN1bHQpIHtcblx0XHRzaG93QmF0Y2hPcGVyYXRpb25SZXN1bHQob3BlcmF0aW9uTGFiZWwsIHN1Y2Nlc3NDb3VudCwgZXJyb3JDb3VudCk7XG5cdH1cblxuXHRyZXR1cm4geyBzdWNjZXNzQ291bnQsIGVycm9yQ291bnQgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNob3dCYXRjaE9wZXJhdGlvblJlc3VsdChcblx0b3BlcmF0aW9uOiBzdHJpbmcsXG5cdHN1Y2Nlc3NDb3VudDogbnVtYmVyLFxuXHRlcnJvckNvdW50OiBudW1iZXJcbik6IHZvaWQge1xuXHRpZiAoZXJyb3JDb3VudCA9PT0gMCkge1xuXHRcdG5ldyBOb3RpY2UoXG5cdFx0XHRgJHtvcGVyYXRpb259OiAke3N1Y2Nlc3NDb3VudH0gaXRlbSR7c3VjY2Vzc0NvdW50ID09PSAxID8gXCJcIiA6IFwic1wifSBwcm9jZXNzZWQgc3VjY2Vzc2Z1bGx5YFxuXHRcdCk7XG5cdH0gZWxzZSB7XG5cdFx0bmV3IE5vdGljZShcblx0XHRcdGAke29wZXJhdGlvbn06ICR7c3VjY2Vzc0NvdW50fSBzdWNjZWVkZWQsICR7ZXJyb3JDb3VudH0gZmFpbGVkLiBDaGVjayBjb25zb2xlIGZvciBkZXRhaWxzLmBcblx0XHQpO1xuXHR9XG59XG4iXX0=
@@ -0,0 +1,9 @@
1
+ import { TFile } from "obsidian";
2
+ export interface VaultAdapter {
3
+ getAbstractFileByPath(path: string): TFile | null;
4
+ }
5
+ export declare function extractDirectoryPath(filePath: string): string;
6
+ export declare function isRelativeChildReference(childRef: string): boolean;
7
+ export declare function normalizeChildReference(childRef: string, vault: VaultAdapter, currentFileDirectory?: string): string;
8
+ export declare function normalizeChildReferences(childRefs: string[], vault: VaultAdapter, currentFileDirectory?: string): string[];
9
+ //# sourceMappingURL=child-reference-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-reference-utils.d.ts","sourceRoot":"","sources":["../src/child-reference-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAIjC,MAAM,WAAW,YAAY;IAC5B,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC;CAClD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM7D;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAMlE;AAED,wBAAgB,uBAAuB,CACtC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,YAAY,EACnB,oBAAoB,CAAC,EAAE,MAAM,GAC3B,MAAM,CAqCR;AAED,wBAAgB,wBAAwB,CACvC,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAE,YAAY,EACnB,oBAAoB,CAAC,EAAE,MAAM,GAC3B,MAAM,EAAE,CAIV"}
@@ -0,0 +1,57 @@
1
+ import { TFile } from "obsidian";
2
+ import { createFileLink } from "./file-operations";
3
+ import { extractFilePathFromLink } from "./link-parser";
4
+ export function extractDirectoryPath(filePath) {
5
+ const lastSlashIndex = filePath.lastIndexOf("/");
6
+ if (lastSlashIndex === -1) {
7
+ return "";
8
+ }
9
+ return filePath.substring(0, lastSlashIndex);
10
+ }
11
+ export function isRelativeChildReference(childRef) {
12
+ const filePath = extractFilePathFromLink(childRef);
13
+ if (!filePath) {
14
+ return !childRef.includes("/");
15
+ }
16
+ return !filePath.includes("/");
17
+ }
18
+ export function normalizeChildReference(childRef, vault, currentFileDirectory) {
19
+ const filePath = extractFilePathFromLink(childRef);
20
+ // Handle plain text references (not wrapped in [[]])
21
+ if (!filePath) {
22
+ // If it's not a link format, check if it should be converted to a link
23
+ if (!childRef.includes("/") && currentFileDirectory !== undefined) {
24
+ // This is a plain text reference that might need to be converted to a link
25
+ const potentialPath = currentFileDirectory
26
+ ? `${currentFileDirectory}/${childRef.endsWith(".md") ? childRef : `${childRef}.md`}`
27
+ : childRef.endsWith(".md")
28
+ ? childRef
29
+ : `${childRef}.md`;
30
+ const file = vault.getAbstractFileByPath(potentialPath);
31
+ if (file instanceof TFile) {
32
+ return createFileLink(file);
33
+ }
34
+ }
35
+ return childRef;
36
+ }
37
+ // Handle relative references by making them absolute
38
+ if (isRelativeChildReference(childRef) && currentFileDirectory) {
39
+ const absolutePath = `${currentFileDirectory}/${filePath}`;
40
+ const file = vault.getAbstractFileByPath(absolutePath);
41
+ if (file instanceof TFile) {
42
+ return createFileLink(file);
43
+ }
44
+ }
45
+ // For absolute references or when no directory context, try to find the file as-is
46
+ const file = vault.getAbstractFileByPath(filePath);
47
+ if (file instanceof TFile) {
48
+ return createFileLink(file);
49
+ }
50
+ return childRef;
51
+ }
52
+ export function normalizeChildReferences(childRefs, vault, currentFileDirectory) {
53
+ return childRefs.map((childRef) => {
54
+ return normalizeChildReference(childRef, vault, currentFileDirectory);
55
+ });
56
+ }
57
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hpbGQtcmVmZXJlbmNlLXV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NoaWxkLXJlZmVyZW5jZS11dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ2pDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFNeEQsTUFBTSxVQUFVLG9CQUFvQixDQUFDLFFBQWdCO0lBQ3BELE1BQU0sY0FBYyxHQUFHLFFBQVEsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDakQsSUFBSSxjQUFjLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUMzQixPQUFPLEVBQUUsQ0FBQztJQUNYLENBQUM7SUFDRCxPQUFPLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLGNBQWMsQ0FBQyxDQUFDO0FBQzlDLENBQUM7QUFFRCxNQUFNLFVBQVUsd0JBQXdCLENBQUMsUUFBZ0I7SUFDeEQsTUFBTSxRQUFRLEdBQUcsdUJBQXVCLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDbkQsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2YsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUNELE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ2hDLENBQUM7QUFFRCxNQUFNLFVBQVUsdUJBQXVCLENBQ3RDLFFBQWdCLEVBQ2hCLEtBQW1CLEVBQ25CLG9CQUE2QjtJQUU3QixNQUFNLFFBQVEsR0FBRyx1QkFBdUIsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUVuRCxxREFBcUQ7SUFDckQsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2YsdUVBQXVFO1FBQ3ZFLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLG9CQUFvQixLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ25FLDJFQUEyRTtZQUMzRSxNQUFNLGFBQWEsR0FBRyxvQkFBb0I7Z0JBQ3pDLENBQUMsQ0FBQyxHQUFHLG9CQUFvQixJQUFJLFFBQVEsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRyxRQUFRLEtBQUssRUFBRTtnQkFDckYsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDO29CQUN6QixDQUFDLENBQUMsUUFBUTtvQkFDVixDQUFDLENBQUMsR0FBRyxRQUFRLEtBQUssQ0FBQztZQUNyQixNQUFNLElBQUksR0FBRyxLQUFLLENBQUMscUJBQXFCLENBQUMsYUFBYSxDQUFDLENBQUM7WUFDeEQsSUFBSSxJQUFJLFlBQVksS0FBSyxFQUFFLENBQUM7Z0JBQzNCLE9BQU8sY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzdCLENBQUM7UUFDRixDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUM7SUFDakIsQ0FBQztJQUVELHFEQUFxRDtJQUNyRCxJQUFJLHdCQUF3QixDQUFDLFFBQVEsQ0FBQyxJQUFJLG9CQUFvQixFQUFFLENBQUM7UUFDaEUsTUFBTSxZQUFZLEdBQUcsR0FBRyxvQkFBb0IsSUFBSSxRQUFRLEVBQUUsQ0FBQztRQUMzRCxNQUFNLElBQUksR0FBRyxLQUFLLENBQUMscUJBQXFCLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDdkQsSUFBSSxJQUFJLFlBQVksS0FBSyxFQUFFLENBQUM7WUFDM0IsT0FBTyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDN0IsQ0FBQztJQUNGLENBQUM7SUFFRCxtRkFBbUY7SUFDbkYsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLHFCQUFxQixDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ25ELElBQUksSUFBSSxZQUFZLEtBQUssRUFBRSxDQUFDO1FBQzNCLE9BQU8sY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzdCLENBQUM7SUFFRCxPQUFPLFFBQVEsQ0FBQztBQUNqQixDQUFDO0FBRUQsTUFBTSxVQUFVLHdCQUF3QixDQUN2QyxTQUFtQixFQUNuQixLQUFtQixFQUNuQixvQkFBNkI7SUFFN0IsT0FBTyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUU7UUFDakMsT0FBTyx1QkFBdUIsQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLG9CQUFvQixDQUFDLENBQUM7SUFDdkUsQ0FBQyxDQUFDLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgVEZpbGUgfSBmcm9tIFwib2JzaWRpYW5cIjtcbmltcG9ydCB7IGNyZWF0ZUZpbGVMaW5rIH0gZnJvbSBcIi4vZmlsZS1vcGVyYXRpb25zXCI7XG5pbXBvcnQgeyBleHRyYWN0RmlsZVBhdGhGcm9tTGluayB9IGZyb20gXCIuL2xpbmstcGFyc2VyXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmF1bHRBZGFwdGVyIHtcblx0Z2V0QWJzdHJhY3RGaWxlQnlQYXRoKHBhdGg6IHN0cmluZyk6IFRGaWxlIHwgbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3REaXJlY3RvcnlQYXRoKGZpbGVQYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRjb25zdCBsYXN0U2xhc2hJbmRleCA9IGZpbGVQYXRoLmxhc3RJbmRleE9mKFwiL1wiKTtcblx0aWYgKGxhc3RTbGFzaEluZGV4ID09PSAtMSkge1xuXHRcdHJldHVybiBcIlwiO1xuXHR9XG5cdHJldHVybiBmaWxlUGF0aC5zdWJzdHJpbmcoMCwgbGFzdFNsYXNoSW5kZXgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNSZWxhdGl2ZUNoaWxkUmVmZXJlbmNlKGNoaWxkUmVmOiBzdHJpbmcpOiBib29sZWFuIHtcblx0Y29uc3QgZmlsZVBhdGggPSBleHRyYWN0RmlsZVBhdGhGcm9tTGluayhjaGlsZFJlZik7XG5cdGlmICghZmlsZVBhdGgpIHtcblx0XHRyZXR1cm4gIWNoaWxkUmVmLmluY2x1ZGVzKFwiL1wiKTtcblx0fVxuXHRyZXR1cm4gIWZpbGVQYXRoLmluY2x1ZGVzKFwiL1wiKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZUNoaWxkUmVmZXJlbmNlKFxuXHRjaGlsZFJlZjogc3RyaW5nLFxuXHR2YXVsdDogVmF1bHRBZGFwdGVyLFxuXHRjdXJyZW50RmlsZURpcmVjdG9yeT86IHN0cmluZ1xuKTogc3RyaW5nIHtcblx0Y29uc3QgZmlsZVBhdGggPSBleHRyYWN0RmlsZVBhdGhGcm9tTGluayhjaGlsZFJlZik7XG5cblx0Ly8gSGFuZGxlIHBsYWluIHRleHQgcmVmZXJlbmNlcyAobm90IHdyYXBwZWQgaW4gW1tdXSlcblx0aWYgKCFmaWxlUGF0aCkge1xuXHRcdC8vIElmIGl0J3Mgbm90IGEgbGluayBmb3JtYXQsIGNoZWNrIGlmIGl0IHNob3VsZCBiZSBjb252ZXJ0ZWQgdG8gYSBsaW5rXG5cdFx0aWYgKCFjaGlsZFJlZi5pbmNsdWRlcyhcIi9cIikgJiYgY3VycmVudEZpbGVEaXJlY3RvcnkgIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0Ly8gVGhpcyBpcyBhIHBsYWluIHRleHQgcmVmZXJlbmNlIHRoYXQgbWlnaHQgbmVlZCB0byBiZSBjb252ZXJ0ZWQgdG8gYSBsaW5rXG5cdFx0XHRjb25zdCBwb3RlbnRpYWxQYXRoID0gY3VycmVudEZpbGVEaXJlY3Rvcnlcblx0XHRcdFx0PyBgJHtjdXJyZW50RmlsZURpcmVjdG9yeX0vJHtjaGlsZFJlZi5lbmRzV2l0aChcIi5tZFwiKSA/IGNoaWxkUmVmIDogYCR7Y2hpbGRSZWZ9Lm1kYH1gXG5cdFx0XHRcdDogY2hpbGRSZWYuZW5kc1dpdGgoXCIubWRcIilcblx0XHRcdFx0XHQ/IGNoaWxkUmVmXG5cdFx0XHRcdFx0OiBgJHtjaGlsZFJlZn0ubWRgO1xuXHRcdFx0Y29uc3QgZmlsZSA9IHZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aChwb3RlbnRpYWxQYXRoKTtcblx0XHRcdGlmIChmaWxlIGluc3RhbmNlb2YgVEZpbGUpIHtcblx0XHRcdFx0cmV0dXJuIGNyZWF0ZUZpbGVMaW5rKGZpbGUpO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gY2hpbGRSZWY7XG5cdH1cblxuXHQvLyBIYW5kbGUgcmVsYXRpdmUgcmVmZXJlbmNlcyBieSBtYWtpbmcgdGhlbSBhYnNvbHV0ZVxuXHRpZiAoaXNSZWxhdGl2ZUNoaWxkUmVmZXJlbmNlKGNoaWxkUmVmKSAmJiBjdXJyZW50RmlsZURpcmVjdG9yeSkge1xuXHRcdGNvbnN0IGFic29sdXRlUGF0aCA9IGAke2N1cnJlbnRGaWxlRGlyZWN0b3J5fS8ke2ZpbGVQYXRofWA7XG5cdFx0Y29uc3QgZmlsZSA9IHZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aChhYnNvbHV0ZVBhdGgpO1xuXHRcdGlmIChmaWxlIGluc3RhbmNlb2YgVEZpbGUpIHtcblx0XHRcdHJldHVybiBjcmVhdGVGaWxlTGluayhmaWxlKTtcblx0XHR9XG5cdH1cblxuXHQvLyBGb3IgYWJzb2x1dGUgcmVmZXJlbmNlcyBvciB3aGVuIG5vIGRpcmVjdG9yeSBjb250ZXh0LCB0cnkgdG8gZmluZCB0aGUgZmlsZSBhcy1pc1xuXHRjb25zdCBmaWxlID0gdmF1bHQuZ2V0QWJzdHJhY3RGaWxlQnlQYXRoKGZpbGVQYXRoKTtcblx0aWYgKGZpbGUgaW5zdGFuY2VvZiBURmlsZSkge1xuXHRcdHJldHVybiBjcmVhdGVGaWxlTGluayhmaWxlKTtcblx0fVxuXG5cdHJldHVybiBjaGlsZFJlZjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZUNoaWxkUmVmZXJlbmNlcyhcblx0Y2hpbGRSZWZzOiBzdHJpbmdbXSxcblx0dmF1bHQ6IFZhdWx0QWRhcHRlcixcblx0Y3VycmVudEZpbGVEaXJlY3Rvcnk/OiBzdHJpbmdcbik6IHN0cmluZ1tdIHtcblx0cmV0dXJuIGNoaWxkUmVmcy5tYXAoKGNoaWxkUmVmKSA9PiB7XG5cdFx0cmV0dXJuIG5vcm1hbGl6ZUNoaWxkUmVmZXJlbmNlKGNoaWxkUmVmLCB2YXVsdCwgY3VycmVudEZpbGVEaXJlY3RvcnkpO1xuXHR9KTtcbn1cbiJdfQ==
@@ -0,0 +1,32 @@
1
+ import type { DateTime } from "luxon";
2
+ export type RecurrenceType = "daily" | "weekly" | "bi-weekly" | "monthly" | "bi-monthly" | "yearly";
3
+ export type Weekday = "sunday" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday";
4
+ export declare const WEEKDAY_TO_NUMBER: Record<Weekday, number>;
5
+ /**
6
+ * Calculates the next occurrence date based on recurrence type and optional weekdays
7
+ */
8
+ export declare function getNextOccurrence(currentDate: DateTime, recurrenceType: RecurrenceType, weekdays?: Weekday[]): DateTime;
9
+ /**
10
+ * Checks if a given date matches any of the specified weekdays
11
+ */
12
+ export declare function isDateOnWeekdays(date: DateTime, weekdays: Weekday[]): boolean;
13
+ /**
14
+ * Finds the next occurrence on specified weekdays
15
+ */
16
+ export declare function getNextWeekdayOccurrence(currentDate: DateTime, weekdays: Weekday[]): DateTime;
17
+ /**
18
+ * Finds the next bi-weekly occurrence on specified weekdays
19
+ */
20
+ export declare function getNextBiWeeklyOccurrence(currentDate: DateTime, weekdays: Weekday[]): DateTime;
21
+ /**
22
+ * Iterates through all occurrence dates in a given range based on recurrence rules
23
+ */
24
+ export declare function iterateOccurrencesInRange(startDate: DateTime, rrules: {
25
+ type: RecurrenceType;
26
+ weekdays?: Weekday[];
27
+ }, rangeStart: DateTime, rangeEnd: DateTime): Generator<DateTime, void, unknown>;
28
+ /**
29
+ * Calculates a DateTime for a specific date with optional time
30
+ */
31
+ export declare function calculateInstanceDateTime(instanceDate: DateTime, timeString?: string): DateTime;
32
+ //# sourceMappingURL=date-recurrence-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-recurrence-utils.d.ts","sourceRoot":"","sources":["../src/date-recurrence-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;AAEpG,MAAM,MAAM,OAAO,GAChB,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,WAAW,GACX,UAAU,GACV,QAAQ,GACR,UAAU,CAAC;AAEd,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAQrD,CAAC;AAEF;;GAEG;AACH,wBAAgB,iBAAiB,CAChC,WAAW,EAAE,QAAQ,EACrB,cAAc,EAAE,cAAc,EAC9B,QAAQ,CAAC,EAAE,OAAO,EAAE,GAClB,QAAQ,CAuBV;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAQ7E;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,CAgB7F;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,CAI9F;AAED;;GAEG;AACH,wBAAiB,yBAAyB,CACzC,SAAS,EAAE,QAAQ,EACnB,MAAM,EAAE;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,EACtD,UAAU,EAAE,QAAQ,EACpB,QAAQ,EAAE,QAAQ,GAChB,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAgCpC;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,CAO/F"}
@@ -0,0 +1,117 @@
1
+ export const WEEKDAY_TO_NUMBER = {
2
+ sunday: 0,
3
+ monday: 1,
4
+ tuesday: 2,
5
+ wednesday: 3,
6
+ thursday: 4,
7
+ friday: 5,
8
+ saturday: 6,
9
+ };
10
+ /**
11
+ * Calculates the next occurrence date based on recurrence type and optional weekdays
12
+ */
13
+ export function getNextOccurrence(currentDate, recurrenceType, weekdays) {
14
+ switch (recurrenceType) {
15
+ case "daily":
16
+ return currentDate.plus({ days: 1 });
17
+ case "weekly":
18
+ if (weekdays && weekdays.length > 0) {
19
+ return getNextWeekdayOccurrence(currentDate, weekdays);
20
+ }
21
+ return currentDate.plus({ weeks: 1 });
22
+ case "bi-weekly":
23
+ if (weekdays && weekdays.length > 0) {
24
+ return getNextBiWeeklyOccurrence(currentDate, weekdays);
25
+ }
26
+ return currentDate.plus({ weeks: 2 });
27
+ case "monthly":
28
+ return currentDate.plus({ months: 1 });
29
+ case "bi-monthly":
30
+ return currentDate.plus({ months: 2 });
31
+ case "yearly":
32
+ return currentDate.plus({ years: 1 });
33
+ default:
34
+ return currentDate.plus({ days: 1 });
35
+ }
36
+ }
37
+ /**
38
+ * Checks if a given date matches any of the specified weekdays
39
+ */
40
+ export function isDateOnWeekdays(date, weekdays) {
41
+ const dateWeekday = date.weekday;
42
+ const luxonWeekdays = weekdays.map((day) => {
43
+ const dayNumber = WEEKDAY_TO_NUMBER[day];
44
+ return dayNumber === 0 ? 7 : dayNumber; // Convert Sunday from 0 to 7 for Luxon
45
+ });
46
+ return luxonWeekdays.includes(dateWeekday);
47
+ }
48
+ /**
49
+ * Finds the next occurrence on specified weekdays
50
+ */
51
+ export function getNextWeekdayOccurrence(currentDate, weekdays) {
52
+ const currentWeekday = currentDate.weekday;
53
+ const luxonWeekdays = weekdays.map((day) => {
54
+ const dayNumber = WEEKDAY_TO_NUMBER[day];
55
+ return dayNumber === 0 ? 7 : dayNumber; // Convert Sunday from 0 to 7 for Luxon
56
+ });
57
+ // Find next weekday in the current week (after today)
58
+ const nextWeekday = luxonWeekdays.find((day) => day > currentWeekday);
59
+ if (nextWeekday) {
60
+ return currentDate.set({ weekday: nextWeekday });
61
+ }
62
+ // No more weekdays this week, go to first weekday of next week
63
+ const firstWeekday = Math.min(...luxonWeekdays);
64
+ return currentDate.plus({ weeks: 1 }).set({ weekday: firstWeekday });
65
+ }
66
+ /**
67
+ * Finds the next bi-weekly occurrence on specified weekdays
68
+ */
69
+ export function getNextBiWeeklyOccurrence(currentDate, weekdays) {
70
+ const nextWeekly = getNextWeekdayOccurrence(currentDate, weekdays);
71
+ // Add one more week to make it bi-weekly
72
+ return nextWeekly.plus({ weeks: 1 });
73
+ }
74
+ /**
75
+ * Iterates through all occurrence dates in a given range based on recurrence rules
76
+ */
77
+ export function* iterateOccurrencesInRange(startDate, rrules, rangeStart, rangeEnd) {
78
+ let currentDate = startDate > rangeStart ? startDate : rangeStart;
79
+ while (currentDate <= rangeEnd) {
80
+ // Check if current date should have an event
81
+ let shouldAddEvent = false;
82
+ if (rrules.type === "daily") {
83
+ shouldAddEvent = true;
84
+ }
85
+ else if (rrules.type === "weekly" || rrules.type === "bi-weekly") {
86
+ if (rrules.weekdays && rrules.weekdays.length > 0) {
87
+ shouldAddEvent = isDateOnWeekdays(currentDate, rrules.weekdays);
88
+ }
89
+ else {
90
+ shouldAddEvent = true;
91
+ }
92
+ }
93
+ else {
94
+ shouldAddEvent = true;
95
+ }
96
+ if (shouldAddEvent) {
97
+ yield currentDate;
98
+ }
99
+ // Calculate next occurrence
100
+ const nextDate = getNextOccurrence(currentDate, rrules.type, rrules.weekdays);
101
+ if (nextDate > rangeEnd) {
102
+ break;
103
+ }
104
+ currentDate = nextDate;
105
+ }
106
+ }
107
+ /**
108
+ * Calculates a DateTime for a specific date with optional time
109
+ */
110
+ export function calculateInstanceDateTime(instanceDate, timeString) {
111
+ if (!timeString) {
112
+ return instanceDate.startOf("day");
113
+ }
114
+ const [hours, minutes] = timeString.split(":").map(Number);
115
+ return instanceDate.set({ hour: hours, minute: minutes, second: 0, millisecond: 0 });
116
+ }
117
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZS1yZWN1cnJlbmNlLXV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2RhdGUtcmVjdXJyZW5jZS11dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFhQSxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBNEI7SUFDekQsTUFBTSxFQUFFLENBQUM7SUFDVCxNQUFNLEVBQUUsQ0FBQztJQUNULE9BQU8sRUFBRSxDQUFDO0lBQ1YsU0FBUyxFQUFFLENBQUM7SUFDWixRQUFRLEVBQUUsQ0FBQztJQUNYLE1BQU0sRUFBRSxDQUFDO0lBQ1QsUUFBUSxFQUFFLENBQUM7Q0FDWCxDQUFDO0FBRUY7O0dBRUc7QUFDSCxNQUFNLFVBQVUsaUJBQWlCLENBQ2hDLFdBQXFCLEVBQ3JCLGNBQThCLEVBQzlCLFFBQW9CO0lBRXBCLFFBQVEsY0FBYyxFQUFFLENBQUM7UUFDeEIsS0FBSyxPQUFPO1lBQ1gsT0FBTyxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDdEMsS0FBSyxRQUFRO1lBQ1osSUFBSSxRQUFRLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDckMsT0FBTyx3QkFBd0IsQ0FBQyxXQUFXLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFDeEQsQ0FBQztZQUNELE9BQU8sV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZDLEtBQUssV0FBVztZQUNmLElBQUksUUFBUSxJQUFJLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3JDLE9BQU8seUJBQXlCLENBQUMsV0FBVyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQ3pELENBQUM7WUFDRCxPQUFPLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN2QyxLQUFLLFNBQVM7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QyxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzNELE9BQU8sWUFBWSxDQUFDLEdBQUcsQ0FBQyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQ3RGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IERhdGVUaW1lIH0gZnJvbSBcImx1eG9uXCI7XG5cbmV4cG9ydCB0eXBlIFJlY3VycmVuY2VUeXBlID0gXCJkYWlseVwiIHwgXCJ3ZWVrbHlcIiB8IFwiYmktd2Vla2x5XCIgfCBcIm1vbnRobHlcIiB8IFwiYmktbW9udGhseVwiIHwgXCJ5ZWFybHlcIjtcblxuZXhwb3J0IHR5cGUgV2Vla2RheSA9XG5cdHwgXCJzdW5kYXlcIlxuXHR8IFwibW9uZGF5XCJcblx0fCBcInR1ZXNkYXlcIlxuXHR8IFwid2VkbmVzZGF5XCJcblx0fCBcInRodXJzZGF5XCJcblx0fCBcImZyaWRheVwiXG5cdHwgXCJzYXR1cmRheVwiO1xuXG5leHBvcnQgY29uc3QgV0VFS0RBWV9UT19OVU1CRVI6IFJlY29yZDxXZWVrZGF5LCBudW1iZXI+ID0ge1xuXHRzdW5kYXk6IDAsXG5cdG1vbmRheTogMSxcblx0dHVlc2RheTogMixcblx0d2VkbmVzZGF5OiAzLFxuXHR0aHVyc2RheTogNCxcblx0ZnJpZGF5OiA1LFxuXHRzYXR1cmRheTogNixcbn07XG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgbmV4dCBvY2N1cnJlbmNlIGRhdGUgYmFzZWQgb24gcmVjdXJyZW5jZSB0eXBlIGFuZCBvcHRpb25hbCB3ZWVrZGF5c1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV4dE9jY3VycmVuY2UoXG5cdGN1cnJlbnREYXRlOiBEYXRlVGltZSxcblx0cmVjdXJyZW5jZVR5cGU6IFJlY3VycmVuY2VUeXBlLFxuXHR3ZWVrZGF5cz86IFdlZWtkYXlbXVxuKTogRGF0ZVRpbWUge1xuXHRzd2l0Y2ggKHJlY3VycmVuY2VUeXBlKSB7XG5cdFx0Y2FzZSBcImRhaWx5XCI6XG5cdFx0XHRyZXR1cm4gY3VycmVudERhdGUucGx1cyh7IGRheXM6IDEgfSk7XG5cdFx0Y2FzZSBcIndlZWtseVwiOlxuXHRcdFx0aWYgKHdlZWtkYXlzICYmIHdlZWtkYXlzLmxlbmd0aCA+IDApIHtcblx0XHRcdFx0cmV0dXJuIGdldE5leHRXZWVrZGF5T2NjdXJyZW5jZShjdXJyZW50RGF0ZSwgd2Vla2RheXMpO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGN1cnJlbnREYXRlLnBsdXMoeyB3ZWVrczogMSB9KTtcblx0XHRjYXNlIFwiYmktd2Vla2x5XCI6XG5cdFx0XHRpZiAod2Vla2RheXMgJiYgd2Vla2RheXMubGVuZ3RoID4gMCkge1xuXHRcdFx0XHRyZXR1cm4gZ2V0TmV4dEJpV2Vla2x5T2NjdXJyZW5jZShjdXJyZW50RGF0ZSwgd2Vla2RheXMpO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGN1cnJlbnREYXRlLnBsdXMoeyB3ZWVrczogMiB9KTtcblx0XHRjYXNlIFwibW9udGhseVwiOlxuXHRcdFx0cmV0dXJuIGN1cnJlbnREYXRlLnBsdXMoeyBtb250aHM6IDEgfSk7XG5cdFx0Y2FzZSBcImJpLW1vbnRobHlcIjpcblx0XHRcdHJldHVybiBjdXJyZW50RGF0ZS5wbHVzKHsgbW9udGhzOiAyIH0pO1xuXHRcdGNhc2UgXCJ5ZWFybHlcIjpcblx0XHRcdHJldHVybiBjdXJyZW50RGF0ZS5wbHVzKHsgeWVhcnM6IDEgfSk7XG5cdFx0ZGVmYXVsdDpcblx0XHRcdHJldHVybiBjdXJyZW50RGF0ZS5wbHVzKHsgZGF5czogMSB9KTtcblx0fVxufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIGdpdmVuIGRhdGUgbWF0Y2hlcyBhbnkgb2YgdGhlIHNwZWNpZmllZCB3ZWVrZGF5c1xuICovXG5leHBvcnQgZnVuY3Rpb24gaXNEYXRlT25XZWVrZGF5cyhkYXRlOiBEYXRlVGltZSwgd2Vla2RheXM6IFdlZWtkYXlbXSk6IGJvb2xlYW4ge1xuXHRjb25zdCBkYXRlV2Vla2RheSA9IGRhdGUud2Vla2RheTtcblx0Y29uc3QgbHV4b25XZWVrZGF5cyA9IHdlZWtkYXlzLm1hcCgoZGF5KSA9PiB7XG5cdFx0Y29uc3QgZGF5TnVtYmVyID0gV0VFS0RBWV9UT19OVU1CRVJbZGF5XTtcblx0XHRyZXR1cm4gZGF5TnVtYmVyID09PSAwID8gNyA6IGRheU51bWJlcjsgLy8gQ29udmVydCBTdW5kYXkgZnJvbSAwIHRvIDcgZm9yIEx1eG9uXG5cdH0pO1xuXG5cdHJldHVybiBsdXhvbldlZWtkYXlzLmluY2x1ZGVzKGRhdGVXZWVrZGF5KTtcbn1cblxuLyoqXG4gKiBGaW5kcyB0aGUgbmV4dCBvY2N1cnJlbmNlIG9uIHNwZWNpZmllZCB3ZWVrZGF5c1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV4dFdlZWtkYXlPY2N1cnJlbmNlKGN1cnJlbnREYXRlOiBEYXRlVGltZSwgd2Vla2RheXM6IFdlZWtkYXlbXSk6IERhdGVUaW1lIHtcblx0Y29uc3QgY3VycmVudFdlZWtkYXkgPSBjdXJyZW50RGF0ZS53ZWVrZGF5O1xuXHRjb25zdCBsdXhvbldlZWtkYXlzID0gd2Vla2RheXMubWFwKChkYXkpID0+IHtcblx0XHRjb25zdCBkYXlOdW1iZXIgPSBXRUVLREFZX1RPX05VTUJFUltkYXldO1xuXHRcdHJldHVybiBkYXlOdW1iZXIgPT09IDAgPyA3IDogZGF5TnVtYmVyOyAvLyBDb252ZXJ0IFN1bmRheSBmcm9tIDAgdG8gNyBmb3IgTHV4b25cblx0fSk7XG5cblx0Ly8gRmluZCBuZXh0IHdlZWtkYXkgaW4gdGhlIGN1cnJlbnQgd2VlayAoYWZ0ZXIgdG9kYXkpXG5cdGNvbnN0IG5leHRXZWVrZGF5ID0gbHV4b25XZWVrZGF5cy5maW5kKChkYXkpID0+IGRheSA+IGN1cnJlbnRXZWVrZGF5KTtcblx0aWYgKG5leHRXZWVrZGF5KSB7XG5cdFx0cmV0dXJuIGN1cnJlbnREYXRlLnNldCh7IHdlZWtkYXk6IG5leHRXZWVrZGF5IGFzIDEgfCAyIHwgMyB8IDQgfCA1IHwgNiB8IDcgfSk7XG5cdH1cblxuXHQvLyBObyBtb3JlIHdlZWtkYXlzIHRoaXMgd2VlaywgZ28gdG8gZmlyc3Qgd2Vla2RheSBvZiBuZXh0IHdlZWtcblx0Y29uc3QgZmlyc3RXZWVrZGF5ID0gTWF0aC5taW4oLi4ubHV4b25XZWVrZGF5cyk7XG5cdHJldHVybiBjdXJyZW50RGF0ZS5wbHVzKHsgd2Vla3M6IDEgfSkuc2V0KHsgd2Vla2RheTogZmlyc3RXZWVrZGF5IGFzIDEgfCAyIHwgMyB8IDQgfCA1IHwgNiB8IDcgfSk7XG59XG5cbi8qKlxuICogRmluZHMgdGhlIG5leHQgYmktd2Vla2x5IG9jY3VycmVuY2Ugb24gc3BlY2lmaWVkIHdlZWtkYXlzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXROZXh0QmlXZWVrbHlPY2N1cnJlbmNlKGN1cnJlbnREYXRlOiBEYXRlVGltZSwgd2Vla2RheXM6IFdlZWtkYXlbXSk6IERhdGVUaW1lIHtcblx0Y29uc3QgbmV4dFdlZWtseSA9IGdldE5leHRXZWVrZGF5T2NjdXJyZW5jZShjdXJyZW50RGF0ZSwgd2Vla2RheXMpO1xuXHQvLyBBZGQgb25lIG1vcmUgd2VlayB0byBtYWtlIGl0IGJpLXdlZWtseVxuXHRyZXR1cm4gbmV4dFdlZWtseS5wbHVzKHsgd2Vla3M6IDEgfSk7XG59XG5cbi8qKlxuICogSXRlcmF0ZXMgdGhyb3VnaCBhbGwgb2NjdXJyZW5jZSBkYXRlcyBpbiBhIGdpdmVuIHJhbmdlIGJhc2VkIG9uIHJlY3VycmVuY2UgcnVsZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uKiBpdGVyYXRlT2NjdXJyZW5jZXNJblJhbmdlKFxuXHRzdGFydERhdGU6IERhdGVUaW1lLFxuXHRycnVsZXM6IHsgdHlwZTogUmVjdXJyZW5jZVR5cGU7IHdlZWtkYXlzPzogV2Vla2RheVtdIH0sXG5cdHJhbmdlU3RhcnQ6IERhdGVUaW1lLFxuXHRyYW5nZUVuZDogRGF0ZVRpbWVcbik6IEdlbmVyYXRvcjxEYXRlVGltZSwgdm9pZCwgdW5rbm93bj4ge1xuXHRsZXQgY3VycmVudERhdGUgPSBzdGFydERhdGUgPiByYW5nZVN0YXJ0ID8gc3RhcnREYXRlIDogcmFuZ2VTdGFydDtcblxuXHR3aGlsZSAoY3VycmVudERhdGUgPD0gcmFuZ2VFbmQpIHtcblx0XHQvLyBDaGVjayBpZiBjdXJyZW50IGRhdGUgc2hvdWxkIGhhdmUgYW4gZXZlbnRcblx0XHRsZXQgc2hvdWxkQWRkRXZlbnQgPSBmYWxzZTtcblxuXHRcdGlmIChycnVsZXMudHlwZSA9PT0gXCJkYWlseVwiKSB7XG5cdFx0XHRzaG91bGRBZGRFdmVudCA9IHRydWU7XG5cdFx0fSBlbHNlIGlmIChycnVsZXMudHlwZSA9PT0gXCJ3ZWVrbHlcIiB8fCBycnVsZXMudHlwZSA9PT0gXCJiaS13ZWVrbHlcIikge1xuXHRcdFx0aWYgKHJydWxlcy53ZWVrZGF5cyAmJiBycnVsZXMud2Vla2RheXMubGVuZ3RoID4gMCkge1xuXHRcdFx0XHRzaG91bGRBZGRFdmVudCA9IGlzRGF0ZU9uV2Vla2RheXMoY3VycmVudERhdGUsIHJydWxlcy53ZWVrZGF5cyk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRzaG91bGRBZGRFdmVudCA9IHRydWU7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdHNob3VsZEFkZEV2ZW50ID0gdHJ1ZTtcblx0XHR9XG5cblx0XHRpZiAoc2hvdWxkQWRkRXZlbnQpIHtcblx0XHRcdHlpZWxkIGN1cnJlbnREYXRlO1xuXHRcdH1cblxuXHRcdC8vIENhbGN1bGF0ZSBuZXh0IG9jY3VycmVuY2Vcblx0XHRjb25zdCBuZXh0RGF0ZSA9IGdldE5leHRPY2N1cnJlbmNlKGN1cnJlbnREYXRlLCBycnVsZXMudHlwZSwgcnJ1bGVzLndlZWtkYXlzKTtcblxuXHRcdGlmIChuZXh0RGF0ZSA+IHJhbmdlRW5kKSB7XG5cdFx0XHRicmVhaztcblx0XHR9XG5cblx0XHRjdXJyZW50RGF0ZSA9IG5leHREYXRlO1xuXHR9XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlcyBhIERhdGVUaW1lIGZvciBhIHNwZWNpZmljIGRhdGUgd2l0aCBvcHRpb25hbCB0aW1lXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjYWxjdWxhdGVJbnN0YW5jZURhdGVUaW1lKGluc3RhbmNlRGF0ZTogRGF0ZVRpbWUsIHRpbWVTdHJpbmc/OiBzdHJpbmcpOiBEYXRlVGltZSB7XG5cdGlmICghdGltZVN0cmluZykge1xuXHRcdHJldHVybiBpbnN0YW5jZURhdGUuc3RhcnRPZihcImRheVwiKTtcblx0fVxuXG5cdGNvbnN0IFtob3VycywgbWludXRlc10gPSB0aW1lU3RyaW5nLnNwbGl0KFwiOlwiKS5tYXAoTnVtYmVyKTtcblx0cmV0dXJuIGluc3RhbmNlRGF0ZS5zZXQoeyBob3VyOiBob3VycywgbWludXRlOiBtaW51dGVzLCBzZWNvbmQ6IDAsIG1pbGxpc2Vjb25kOiAwIH0pO1xufVxuIl19
@@ -0,0 +1,20 @@
1
+ export declare const formatDateTimeForInput: (dateString: string) => string;
2
+ export declare const formatDateForInput: (dateString: string) => string;
3
+ /**
4
+ * Converts input value to ISO string, handling edge cases where
5
+ * browser datetime-local inputs behave differently across platforms.
6
+ * Returns null for invalid dates to prevent silent failures.
7
+ */
8
+ export declare const inputValueToISOString: (inputValue: string) => string | null;
9
+ export declare const formatDuration: (minutes: number) => string;
10
+ /**
11
+ * Parse time string from datetime value - extracts HH:mm format
12
+ * Rejects plain HH:mm format, requires full datetime
13
+ */
14
+ export declare const parseTimeString: (value: string | null) => string | undefined;
15
+ /**
16
+ * Parse and validate datetime strings for event parsing
17
+ * Supports multiple formats including date-only and datetime formats
18
+ */
19
+ export declare const parseDateTimeString: (value: string | null) => string | undefined;
20
+ //# sourceMappingURL=date-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-utils.d.ts","sourceRoot":"","sources":["../src/date-utils.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,sBAAsB,GAAI,YAAY,MAAM,KAAG,MAgB3D,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,YAAY,MAAM,KAAG,MAavD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,YAAY,MAAM,KAAG,MAAM,GAAG,IAMnE,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,MAIhD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,GAAG,IAAI,KAAG,MAAM,GAAG,SAgB/D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,MAAM,GAAG,IAAI,KAAG,MAAM,GAAG,SA8BnE,CAAC"}