@real1ty-obsidian-plugins/utils 2.28.0 → 2.30.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 (236) hide show
  1. package/package.json +1 -1
  2. package/src/core/history.ts +45 -0
  3. package/src/core/index.ts +1 -0
  4. package/src/settings/settings-ui-builder.ts +0 -1
  5. package/dist/async/async.d.ts +0 -69
  6. package/dist/async/async.d.ts.map +0 -1
  7. package/dist/async/async.js +0 -108
  8. package/dist/async/async.js.map +0 -1
  9. package/dist/async/batch-operations.d.ts +0 -21
  10. package/dist/async/batch-operations.d.ts.map +0 -1
  11. package/dist/async/batch-operations.js +0 -60
  12. package/dist/async/batch-operations.js.map +0 -1
  13. package/dist/async/change-notifier.d.ts +0 -13
  14. package/dist/async/change-notifier.d.ts.map +0 -1
  15. package/dist/async/change-notifier.js +0 -26
  16. package/dist/async/change-notifier.js.map +0 -1
  17. package/dist/async/debounced-notifier.d.ts +0 -26
  18. package/dist/async/debounced-notifier.d.ts.map +0 -1
  19. package/dist/async/debounced-notifier.js +0 -50
  20. package/dist/async/debounced-notifier.js.map +0 -1
  21. package/dist/async/index.d.ts +0 -5
  22. package/dist/async/index.d.ts.map +0 -1
  23. package/dist/async/index.js +0 -5
  24. package/dist/async/index.js.map +0 -1
  25. package/dist/components/frontmatter-propagation-modal.d.ts +0 -17
  26. package/dist/components/frontmatter-propagation-modal.d.ts.map +0 -1
  27. package/dist/components/frontmatter-propagation-modal.js +0 -85
  28. package/dist/components/frontmatter-propagation-modal.js.map +0 -1
  29. package/dist/components/index.d.ts +0 -5
  30. package/dist/components/index.d.ts.map +0 -1
  31. package/dist/components/index.js +0 -5
  32. package/dist/components/index.js.map +0 -1
  33. package/dist/components/input-managers/base.d.ts +0 -30
  34. package/dist/components/input-managers/base.d.ts.map +0 -1
  35. package/dist/components/input-managers/base.js +0 -115
  36. package/dist/components/input-managers/base.js.map +0 -1
  37. package/dist/components/input-managers/expression.d.ts +0 -12
  38. package/dist/components/input-managers/expression.d.ts.map +0 -1
  39. package/dist/components/input-managers/expression.js +0 -56
  40. package/dist/components/input-managers/expression.js.map +0 -1
  41. package/dist/components/input-managers/index.d.ts +0 -4
  42. package/dist/components/input-managers/index.d.ts.map +0 -1
  43. package/dist/components/input-managers/index.js +0 -4
  44. package/dist/components/input-managers/index.js.map +0 -1
  45. package/dist/components/input-managers/search.d.ts +0 -6
  46. package/dist/components/input-managers/search.d.ts.map +0 -1
  47. package/dist/components/input-managers/search.js +0 -16
  48. package/dist/components/input-managers/search.js.map +0 -1
  49. package/dist/components/registered-events-component.d.ts +0 -30
  50. package/dist/components/registered-events-component.d.ts.map +0 -1
  51. package/dist/components/registered-events-component.js +0 -43
  52. package/dist/components/registered-events-component.js.map +0 -1
  53. package/dist/components/whats-new-modal.d.ts +0 -64
  54. package/dist/components/whats-new-modal.d.ts.map +0 -1
  55. package/dist/components/whats-new-modal.js +0 -139
  56. package/dist/components/whats-new-modal.js.map +0 -1
  57. package/dist/core/color-utils.d.ts +0 -17
  58. package/dist/core/color-utils.d.ts.map +0 -1
  59. package/dist/core/color-utils.js +0 -29
  60. package/dist/core/color-utils.js.map +0 -1
  61. package/dist/core/css-utils.d.ts +0 -39
  62. package/dist/core/css-utils.d.ts.map +0 -1
  63. package/dist/core/css-utils.js +0 -60
  64. package/dist/core/css-utils.js.map +0 -1
  65. package/dist/core/evaluator/base.d.ts +0 -22
  66. package/dist/core/evaluator/base.d.ts.map +0 -1
  67. package/dist/core/evaluator/base.js +0 -67
  68. package/dist/core/evaluator/base.js.map +0 -1
  69. package/dist/core/evaluator/color.d.ts +0 -19
  70. package/dist/core/evaluator/color.d.ts.map +0 -1
  71. package/dist/core/evaluator/color.js +0 -25
  72. package/dist/core/evaluator/color.js.map +0 -1
  73. package/dist/core/evaluator/excluded.d.ts +0 -32
  74. package/dist/core/evaluator/excluded.d.ts.map +0 -1
  75. package/dist/core/evaluator/excluded.js +0 -41
  76. package/dist/core/evaluator/excluded.js.map +0 -1
  77. package/dist/core/evaluator/filter.d.ts +0 -15
  78. package/dist/core/evaluator/filter.d.ts.map +0 -1
  79. package/dist/core/evaluator/filter.js +0 -27
  80. package/dist/core/evaluator/filter.js.map +0 -1
  81. package/dist/core/evaluator/included.d.ts +0 -36
  82. package/dist/core/evaluator/included.d.ts.map +0 -1
  83. package/dist/core/evaluator/included.js +0 -51
  84. package/dist/core/evaluator/included.js.map +0 -1
  85. package/dist/core/evaluator/index.d.ts +0 -6
  86. package/dist/core/evaluator/index.d.ts.map +0 -1
  87. package/dist/core/evaluator/index.js +0 -6
  88. package/dist/core/evaluator/index.js.map +0 -1
  89. package/dist/core/expression-utils.d.ts +0 -17
  90. package/dist/core/expression-utils.d.ts.map +0 -1
  91. package/dist/core/expression-utils.js +0 -40
  92. package/dist/core/expression-utils.js.map +0 -1
  93. package/dist/core/frontmatter-value.d.ts +0 -157
  94. package/dist/core/frontmatter-value.d.ts.map +0 -1
  95. package/dist/core/frontmatter-value.js +0 -417
  96. package/dist/core/frontmatter-value.js.map +0 -1
  97. package/dist/core/generate.d.ts +0 -7
  98. package/dist/core/generate.d.ts.map +0 -1
  99. package/dist/core/generate.js +0 -13
  100. package/dist/core/generate.js.map +0 -1
  101. package/dist/core/index.d.ts +0 -10
  102. package/dist/core/index.d.ts.map +0 -1
  103. package/dist/core/index.js +0 -10
  104. package/dist/core/index.js.map +0 -1
  105. package/dist/core/indexer.d.ts +0 -109
  106. package/dist/core/indexer.d.ts.map +0 -1
  107. package/dist/core/indexer.js +0 -185
  108. package/dist/core/indexer.js.map +0 -1
  109. package/dist/core/property-renderer.d.ts +0 -9
  110. package/dist/core/property-renderer.d.ts.map +0 -1
  111. package/dist/core/property-renderer.js +0 -42
  112. package/dist/core/property-renderer.js.map +0 -1
  113. package/dist/core/validation.d.ts +0 -13
  114. package/dist/core/validation.d.ts.map +0 -1
  115. package/dist/core/validation.js +0 -27
  116. package/dist/core/validation.js.map +0 -1
  117. package/dist/date/date-recurrence.d.ts +0 -30
  118. package/dist/date/date-recurrence.d.ts.map +0 -1
  119. package/dist/date/date-recurrence.js +0 -188
  120. package/dist/date/date-recurrence.js.map +0 -1
  121. package/dist/date/date.d.ts +0 -21
  122. package/dist/date/date.d.ts.map +0 -1
  123. package/dist/date/date.js +0 -105
  124. package/dist/date/date.js.map +0 -1
  125. package/dist/date/index.d.ts +0 -3
  126. package/dist/date/index.d.ts.map +0 -1
  127. package/dist/date/index.js +0 -3
  128. package/dist/date/index.js.map +0 -1
  129. package/dist/file/child-reference.d.ts +0 -9
  130. package/dist/file/child-reference.d.ts.map +0 -1
  131. package/dist/file/child-reference.js +0 -57
  132. package/dist/file/child-reference.js.map +0 -1
  133. package/dist/file/file-operations.d.ts +0 -31
  134. package/dist/file/file-operations.d.ts.map +0 -1
  135. package/dist/file/file-operations.js +0 -160
  136. package/dist/file/file-operations.js.map +0 -1
  137. package/dist/file/file-utils.d.ts +0 -33
  138. package/dist/file/file-utils.d.ts.map +0 -1
  139. package/dist/file/file-utils.js +0 -76
  140. package/dist/file/file-utils.js.map +0 -1
  141. package/dist/file/file.d.ts +0 -332
  142. package/dist/file/file.d.ts.map +0 -1
  143. package/dist/file/file.js +0 -559
  144. package/dist/file/file.js.map +0 -1
  145. package/dist/file/frontmatter-diff.d.ts +0 -38
  146. package/dist/file/frontmatter-diff.d.ts.map +0 -1
  147. package/dist/file/frontmatter-diff.js +0 -162
  148. package/dist/file/frontmatter-diff.js.map +0 -1
  149. package/dist/file/frontmatter-propagation.d.ts +0 -4
  150. package/dist/file/frontmatter-propagation.d.ts.map +0 -1
  151. package/dist/file/frontmatter-propagation.js +0 -28
  152. package/dist/file/frontmatter-propagation.js.map +0 -1
  153. package/dist/file/frontmatter-serialization.d.ts +0 -21
  154. package/dist/file/frontmatter-serialization.d.ts.map +0 -1
  155. package/dist/file/frontmatter-serialization.js +0 -57
  156. package/dist/file/frontmatter-serialization.js.map +0 -1
  157. package/dist/file/frontmatter.d.ts +0 -15
  158. package/dist/file/frontmatter.d.ts.map +0 -1
  159. package/dist/file/frontmatter.js +0 -68
  160. package/dist/file/frontmatter.js.map +0 -1
  161. package/dist/file/index.d.ts +0 -13
  162. package/dist/file/index.d.ts.map +0 -1
  163. package/dist/file/index.js +0 -13
  164. package/dist/file/index.js.map +0 -1
  165. package/dist/file/link-parser.d.ts +0 -63
  166. package/dist/file/link-parser.d.ts.map +0 -1
  167. package/dist/file/link-parser.js +0 -137
  168. package/dist/file/link-parser.js.map +0 -1
  169. package/dist/file/property-utils.d.ts +0 -55
  170. package/dist/file/property-utils.d.ts.map +0 -1
  171. package/dist/file/property-utils.js +0 -90
  172. package/dist/file/property-utils.js.map +0 -1
  173. package/dist/file/templater-service.d.ts +0 -16
  174. package/dist/file/templater-service.d.ts.map +0 -1
  175. package/dist/file/templater-service.js +0 -37
  176. package/dist/file/templater-service.js.map +0 -1
  177. package/dist/file/templater.d.ts +0 -28
  178. package/dist/file/templater.d.ts.map +0 -1
  179. package/dist/file/templater.js +0 -126
  180. package/dist/file/templater.js.map +0 -1
  181. package/dist/index.d.ts +0 -9
  182. package/dist/index.d.ts.map +0 -1
  183. package/dist/index.js +0 -17
  184. package/dist/index.js.map +0 -1
  185. package/dist/inputs/index.d.ts +0 -2
  186. package/dist/inputs/index.d.ts.map +0 -1
  187. package/dist/inputs/index.js +0 -2
  188. package/dist/inputs/index.js.map +0 -1
  189. package/dist/inputs/input-filter-manager.d.ts +0 -72
  190. package/dist/inputs/input-filter-manager.d.ts.map +0 -1
  191. package/dist/inputs/input-filter-manager.js +0 -140
  192. package/dist/inputs/input-filter-manager.js.map +0 -1
  193. package/dist/settings/index.d.ts +0 -3
  194. package/dist/settings/index.d.ts.map +0 -1
  195. package/dist/settings/index.js +0 -3
  196. package/dist/settings/index.js.map +0 -1
  197. package/dist/settings/settings-store.d.ts +0 -20
  198. package/dist/settings/settings-store.d.ts.map +0 -1
  199. package/dist/settings/settings-store.js +0 -82
  200. package/dist/settings/settings-store.js.map +0 -1
  201. package/dist/settings/settings-ui-builder.d.ts +0 -74
  202. package/dist/settings/settings-ui-builder.d.ts.map +0 -1
  203. package/dist/settings/settings-ui-builder.js +0 -437
  204. package/dist/settings/settings-ui-builder.js.map +0 -1
  205. package/dist/string/changelog-parser.d.ts +0 -17
  206. package/dist/string/changelog-parser.d.ts.map +0 -1
  207. package/dist/string/changelog-parser.js +0 -77
  208. package/dist/string/changelog-parser.js.map +0 -1
  209. package/dist/string/filename-utils.d.ts +0 -46
  210. package/dist/string/filename-utils.d.ts.map +0 -1
  211. package/dist/string/filename-utils.js +0 -65
  212. package/dist/string/filename-utils.js.map +0 -1
  213. package/dist/string/index.d.ts +0 -4
  214. package/dist/string/index.d.ts.map +0 -1
  215. package/dist/string/index.js +0 -4
  216. package/dist/string/index.js.map +0 -1
  217. package/dist/string/string.d.ts +0 -5
  218. package/dist/string/string.d.ts.map +0 -1
  219. package/dist/string/string.js +0 -25
  220. package/dist/string/string.js.map +0 -1
  221. package/dist/testing/index.d.ts +0 -5
  222. package/dist/testing/index.d.ts.map +0 -1
  223. package/dist/testing/index.js +0 -6
  224. package/dist/testing/index.js.map +0 -1
  225. package/dist/testing/mocks/obsidian.d.ts +0 -150
  226. package/dist/testing/mocks/obsidian.d.ts.map +0 -1
  227. package/dist/testing/mocks/obsidian.js +0 -226
  228. package/dist/testing/mocks/obsidian.js.map +0 -1
  229. package/dist/testing/mocks/utils.d.ts +0 -14
  230. package/dist/testing/mocks/utils.d.ts.map +0 -1
  231. package/dist/testing/mocks/utils.js +0 -85
  232. package/dist/testing/mocks/utils.js.map +0 -1
  233. package/dist/testing/setup.d.ts +0 -2
  234. package/dist/testing/setup.d.ts.map +0 -1
  235. package/dist/testing/setup.js +0 -18
  236. package/dist/testing/setup.js.map +0 -1
@@ -1,185 +0,0 @@
1
- import { __awaiter } from "tslib";
2
- import { TFile } from "obsidian";
3
- import { from, fromEventPattern, lastValueFrom, merge, of, BehaviorSubject as RxBehaviorSubject, Subject, } from "rxjs";
4
- import { debounceTime, filter, groupBy, map, mergeMap, switchMap, toArray } from "rxjs/operators";
5
- import { compareFrontmatter } from "../file/frontmatter-diff";
6
- /**
7
- * Generic indexer that listens to Obsidian vault events and emits
8
- * RxJS observables with frontmatter diffs and metadata.
9
- *
10
- * This indexer is framework-agnostic and can be used by any plugin
11
- * that needs to track file changes with frontmatter.
12
- */
13
- export class Indexer {
14
- constructor(app, configStore) {
15
- this.fileSub = null;
16
- this.configSubscription = null;
17
- this.scanEventsSubject = new Subject();
18
- this.indexingCompleteSubject = new RxBehaviorSubject(false);
19
- this.frontmatterCache = new Map();
20
- this.vault = app.vault;
21
- this.metadataCache = app.metadataCache;
22
- this.config = this.normalizeConfig(configStore.value);
23
- this.configSubscription = configStore.subscribe((newConfig) => {
24
- const includeFileChanged = this.config.includeFile !== this.normalizeConfig(newConfig).includeFile;
25
- this.config = this.normalizeConfig(newConfig);
26
- if (includeFileChanged) {
27
- this.indexingCompleteSubject.next(false);
28
- void this.scanAllFiles();
29
- }
30
- });
31
- this.events$ = this.scanEventsSubject.asObservable();
32
- this.indexingComplete$ = this.indexingCompleteSubject.asObservable();
33
- }
34
- normalizeConfig(config) {
35
- return {
36
- includeFile: config.includeFile || (() => true),
37
- excludedDiffProps: config.excludedDiffProps || new Set(),
38
- scanConcurrency: config.scanConcurrency || 10,
39
- debounceMs: config.debounceMs || 100,
40
- };
41
- }
42
- start() {
43
- return __awaiter(this, void 0, void 0, function* () {
44
- this.indexingCompleteSubject.next(false);
45
- const fileSystemEvents$ = this.buildFileSystemEvents$();
46
- this.fileSub = fileSystemEvents$.subscribe((event) => {
47
- this.scanEventsSubject.next(event);
48
- });
49
- yield this.scanAllFiles();
50
- });
51
- }
52
- stop() {
53
- var _a, _b;
54
- (_a = this.fileSub) === null || _a === void 0 ? void 0 : _a.unsubscribe();
55
- this.fileSub = null;
56
- (_b = this.configSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
57
- this.configSubscription = null;
58
- this.indexingCompleteSubject.complete();
59
- }
60
- resync() {
61
- this.frontmatterCache.clear();
62
- this.indexingCompleteSubject.next(false);
63
- void this.scanAllFiles();
64
- }
65
- /**
66
- * Scan all markdown files in the configured directory
67
- */
68
- scanAllFiles() {
69
- return __awaiter(this, void 0, void 0, function* () {
70
- const allFiles = this.vault.getMarkdownFiles();
71
- const relevantFiles = allFiles.filter((file) => this.config.includeFile(file.path));
72
- const events$ = from(relevantFiles).pipe(mergeMap((file) => __awaiter(this, void 0, void 0, function* () {
73
- try {
74
- return yield this.buildEvent(file);
75
- }
76
- catch (error) {
77
- console.error(`Error processing file ${file.path}:`, error);
78
- return null;
79
- }
80
- }), this.config.scanConcurrency), filter((event) => event !== null), toArray());
81
- try {
82
- const allEvents = yield lastValueFrom(events$);
83
- for (const event of allEvents) {
84
- this.scanEventsSubject.next(event);
85
- }
86
- this.indexingCompleteSubject.next(true);
87
- }
88
- catch (error) {
89
- console.error("❌ Error during file scanning:", error);
90
- this.indexingCompleteSubject.next(true);
91
- }
92
- });
93
- }
94
- /**
95
- * Create an observable from a vault event
96
- */
97
- fromVaultEvent(eventName) {
98
- if (eventName === "create") {
99
- return fromEventPattern((handler) => this.vault.on("create", handler), (handler) => this.vault.off("create", handler));
100
- }
101
- if (eventName === "modify") {
102
- return fromEventPattern((handler) => this.vault.on("modify", handler), (handler) => this.vault.off("modify", handler));
103
- }
104
- if (eventName === "delete") {
105
- return fromEventPattern((handler) => this.vault.on("delete", handler), (handler) => this.vault.off("delete", handler));
106
- }
107
- // eventName === "rename"
108
- return fromEventPattern((handler) => this.vault.on("rename", handler), (handler) => this.vault.off("rename", handler)).pipe(map(([file]) => file));
109
- }
110
- static isMarkdownFile(f) {
111
- return f instanceof TFile && f.extension === "md";
112
- }
113
- /**
114
- * Filter to only relevant markdown files in configured directory
115
- */
116
- toRelevantFiles() {
117
- return (source) => source.pipe(filter((f) => Indexer.isMarkdownFile(f)), filter((f) => this.config.includeFile(f.path)));
118
- }
119
- /**
120
- * Debounce events by file path
121
- */
122
- debounceByPath(ms, key) {
123
- return (source) => source.pipe(groupBy(key), mergeMap((g$) => g$.pipe(debounceTime(ms))));
124
- }
125
- /**
126
- * Build the file system events observable stream
127
- */
128
- buildFileSystemEvents$() {
129
- const created$ = this.fromVaultEvent("create").pipe(this.toRelevantFiles());
130
- const modified$ = this.fromVaultEvent("modify").pipe(this.toRelevantFiles());
131
- const deleted$ = this.fromVaultEvent("delete").pipe(this.toRelevantFiles());
132
- const renamed$ = fromEventPattern((handler) => this.vault.on("rename", handler), (handler) => this.vault.off("rename", handler));
133
- const changedIntents$ = merge(created$, modified$).pipe(this.debounceByPath(this.config.debounceMs, (f) => f.path), map((file) => ({ kind: "changed", file, path: file.path })));
134
- const deletedIntents$ = deleted$.pipe(map((file) => ({ kind: "deleted", path: file.path })));
135
- const renamedIntents$ = renamed$.pipe(map(([f, oldPath]) => [f, oldPath]), filter(([f]) => Indexer.isMarkdownFile(f) && this.config.includeFile(f.path)), mergeMap(([f, oldPath]) => [
136
- { kind: "deleted", path: oldPath, isRename: true },
137
- { kind: "changed", file: f, path: f.path, oldPath },
138
- ]));
139
- const intents$ = merge(changedIntents$, deletedIntents$, renamedIntents$);
140
- return intents$.pipe(switchMap((intent) => {
141
- if (intent.kind === "deleted") {
142
- this.frontmatterCache.delete(intent.path);
143
- return of({
144
- type: "file-deleted",
145
- filePath: intent.path,
146
- isRename: intent.isRename,
147
- });
148
- }
149
- return from(this.buildEvent(intent.file, intent.oldPath)).pipe(filter((e) => e !== null));
150
- }));
151
- }
152
- /**
153
- * Build an indexer event from a file
154
- */
155
- buildEvent(file, oldPath) {
156
- return __awaiter(this, void 0, void 0, function* () {
157
- var _a;
158
- const cache = this.metadataCache.getFileCache(file);
159
- if (!cache || !cache.frontmatter)
160
- return null;
161
- const { frontmatter } = cache;
162
- const oldFrontmatter = this.frontmatterCache.get(file.path);
163
- const source = {
164
- filePath: file.path,
165
- mtime: file.stat.mtime,
166
- frontmatter,
167
- folder: ((_a = file.parent) === null || _a === void 0 ? void 0 : _a.path) || "",
168
- };
169
- const event = {
170
- type: "file-changed",
171
- filePath: file.path,
172
- oldPath,
173
- source,
174
- oldFrontmatter,
175
- frontmatterDiff: oldFrontmatter
176
- ? compareFrontmatter(oldFrontmatter, frontmatter, this.config.excludedDiffProps)
177
- : undefined,
178
- };
179
- // Update cache
180
- this.frontmatterCache.set(file.path, Object.assign({}, frontmatter));
181
- return event;
182
- });
183
- }
184
- }
185
- //# sourceMappingURL=indexer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"indexer.js","sourceRoot":"","sources":["../../src/core/indexer.ts"],"names":[],"mappings":"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","sourcesContent":["import { type App, type MetadataCache, type TAbstractFile, TFile, type Vault } from \"obsidian\";\nimport {\n\ttype BehaviorSubject,\n\tfrom,\n\tfromEventPattern,\n\tlastValueFrom,\n\tmerge,\n\ttype Observable,\n\tof,\n\tBehaviorSubject as RxBehaviorSubject,\n\tSubject,\n\ttype Subscription,\n} from \"rxjs\";\nimport { debounceTime, filter, groupBy, map, mergeMap, switchMap, toArray } from \"rxjs/operators\";\nimport { compareFrontmatter, type FrontmatterDiff } from \"../file/frontmatter-diff\";\n\n/**\n * Generic frontmatter object type for indexer\n */\nexport type IndexerFrontmatter = Record<string, unknown>;\n\n/**\n * Configuration for the generic indexer\n */\nexport interface IndexerConfig {\n\t/**\n\t * Function that determines whether a file should be included in the indexer.\n\t * Returns true if the file should be indexed, false otherwise.\n\t * If not provided, all files are included.\n\t */\n\tincludeFile?: (path: string) => boolean;\n\n\t/**\n\t * Properties to exclude when comparing frontmatter diffs\n\t */\n\texcludedDiffProps?: Set<string>;\n\n\t/**\n\t * Concurrency limit for file scanning operations\n\t */\n\tscanConcurrency?: number;\n\n\t/**\n\t * Debounce time in milliseconds for file change events\n\t */\n\tdebounceMs?: number;\n}\n\n/**\n * Raw file source with frontmatter and metadata\n */\nexport interface FileSource {\n\tfilePath: string;\n\tmtime: number;\n\tfrontmatter: IndexerFrontmatter;\n\tfolder: string;\n}\n\n/**\n * Types of indexer events\n */\nexport type IndexerEventType = \"file-changed\" | \"file-deleted\";\n\n/**\n * Generic indexer event\n */\nexport interface IndexerEvent {\n\ttype: IndexerEventType;\n\tfilePath: string;\n\toldPath?: string;\n\tsource?: FileSource;\n\toldFrontmatter?: IndexerFrontmatter;\n\tfrontmatterDiff?: FrontmatterDiff;\n\t/**\n\t * True if this deletion event is part of a rename operation.\n\t * Only present on \"file-deleted\" events.\n\t */\n\tisRename?: boolean;\n}\n\ntype VaultEvent = \"create\" | \"modify\" | \"delete\" | \"rename\";\n\ntype FileIntent =\n\t| { kind: \"changed\"; file: TFile; path: string; oldPath?: string }\n\t| { kind: \"deleted\"; path: string; isRename?: boolean };\n\n/**\n * Generic indexer that listens to Obsidian vault events and emits\n * RxJS observables with frontmatter diffs and metadata.\n *\n * This indexer is framework-agnostic and can be used by any plugin\n * that needs to track file changes with frontmatter.\n */\nexport class Indexer {\n\tprivate config: Required<IndexerConfig>;\n\tprivate fileSub: Subscription | null = null;\n\tprivate configSubscription: Subscription | null = null;\n\tprivate vault: Vault;\n\tprivate metadataCache: MetadataCache;\n\tprivate scanEventsSubject = new Subject<IndexerEvent>();\n\tprivate indexingCompleteSubject = new RxBehaviorSubject<boolean>(false);\n\tprivate frontmatterCache: Map<string, IndexerFrontmatter> = new Map();\n\n\tpublic readonly events$: Observable<IndexerEvent>;\n\tpublic readonly indexingComplete$: Observable<boolean>;\n\n\tconstructor(app: App, configStore: BehaviorSubject<IndexerConfig>) {\n\t\tthis.vault = app.vault;\n\t\tthis.metadataCache = app.metadataCache;\n\t\tthis.config = this.normalizeConfig(configStore.value);\n\n\t\tthis.configSubscription = configStore.subscribe((newConfig) => {\n\t\t\tconst includeFileChanged =\n\t\t\t\tthis.config.includeFile !== this.normalizeConfig(newConfig).includeFile;\n\t\t\tthis.config = this.normalizeConfig(newConfig);\n\n\t\t\tif (includeFileChanged) {\n\t\t\t\tthis.indexingCompleteSubject.next(false);\n\t\t\t\tvoid this.scanAllFiles();\n\t\t\t}\n\t\t});\n\n\t\tthis.events$ = this.scanEventsSubject.asObservable();\n\t\tthis.indexingComplete$ = this.indexingCompleteSubject.asObservable();\n\t}\n\n\tprivate normalizeConfig(config: IndexerConfig): Required<IndexerConfig> {\n\t\treturn {\n\t\t\tincludeFile: config.includeFile || (() => true),\n\t\t\texcludedDiffProps: config.excludedDiffProps || new Set(),\n\t\t\tscanConcurrency: config.scanConcurrency || 10,\n\t\t\tdebounceMs: config.debounceMs || 100,\n\t\t};\n\t}\n\n\tasync start(): Promise<void> {\n\t\tthis.indexingCompleteSubject.next(false);\n\n\t\tconst fileSystemEvents$ = this.buildFileSystemEvents$();\n\n\t\tthis.fileSub = fileSystemEvents$.subscribe((event) => {\n\t\t\tthis.scanEventsSubject.next(event);\n\t\t});\n\n\t\tawait this.scanAllFiles();\n\t}\n\n\tstop(): void {\n\t\tthis.fileSub?.unsubscribe();\n\t\tthis.fileSub = null;\n\t\tthis.configSubscription?.unsubscribe();\n\t\tthis.configSubscription = null;\n\t\tthis.indexingCompleteSubject.complete();\n\t}\n\n\tresync(): void {\n\t\tthis.frontmatterCache.clear();\n\t\tthis.indexingCompleteSubject.next(false);\n\t\tvoid this.scanAllFiles();\n\t}\n\n\t/**\n\t * Scan all markdown files in the configured directory\n\t */\n\tprivate async scanAllFiles(): Promise<void> {\n\t\tconst allFiles = this.vault.getMarkdownFiles();\n\t\tconst relevantFiles = allFiles.filter((file) => this.config.includeFile(file.path));\n\n\t\tconst events$ = from(relevantFiles).pipe(\n\t\t\tmergeMap(async (file) => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await this.buildEvent(file);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(`Error processing file ${file.path}:`, error);\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}, this.config.scanConcurrency),\n\t\t\tfilter((event): event is IndexerEvent => event !== null),\n\t\t\ttoArray()\n\t\t);\n\n\t\ttry {\n\t\t\tconst allEvents = await lastValueFrom(events$);\n\n\t\t\tfor (const event of allEvents) {\n\t\t\t\tthis.scanEventsSubject.next(event);\n\t\t\t}\n\n\t\t\tthis.indexingCompleteSubject.next(true);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"❌ Error during file scanning:\", error);\n\t\t\tthis.indexingCompleteSubject.next(true);\n\t\t}\n\t}\n\n\t/**\n\t * Create an observable from a vault event\n\t */\n\tprivate fromVaultEvent(eventName: VaultEvent): Observable<TAbstractFile> {\n\t\tif (eventName === \"create\") {\n\t\t\treturn fromEventPattern<TAbstractFile>(\n\t\t\t\t(handler) => this.vault.on(\"create\", handler),\n\t\t\t\t(handler) => this.vault.off(\"create\", handler)\n\t\t\t);\n\t\t}\n\n\t\tif (eventName === \"modify\") {\n\t\t\treturn fromEventPattern<TAbstractFile>(\n\t\t\t\t(handler) => this.vault.on(\"modify\", handler),\n\t\t\t\t(handler) => this.vault.off(\"modify\", handler)\n\t\t\t);\n\t\t}\n\n\t\tif (eventName === \"delete\") {\n\t\t\treturn fromEventPattern<TAbstractFile>(\n\t\t\t\t(handler) => this.vault.on(\"delete\", handler),\n\t\t\t\t(handler) => this.vault.off(\"delete\", handler)\n\t\t\t);\n\t\t}\n\n\t\t// eventName === \"rename\"\n\t\treturn fromEventPattern<[TAbstractFile, string]>(\n\t\t\t(handler) => this.vault.on(\"rename\", handler),\n\t\t\t(handler) => this.vault.off(\"rename\", handler)\n\t\t).pipe(map(([file]) => file));\n\t}\n\n\tprivate static isMarkdownFile(f: TAbstractFile): f is TFile {\n\t\treturn f instanceof TFile && f.extension === \"md\";\n\t}\n\n\t/**\n\t * Filter to only relevant markdown files in configured directory\n\t */\n\tprivate toRelevantFiles<T extends TAbstractFile>() {\n\t\treturn (source: Observable<T>) =>\n\t\t\tsource.pipe(\n\t\t\t\tfilter((f: TAbstractFile): f is TFile => Indexer.isMarkdownFile(f)),\n\t\t\t\tfilter((f) => this.config.includeFile(f.path))\n\t\t\t);\n\t}\n\n\t/**\n\t * Debounce events by file path\n\t */\n\tprivate debounceByPath<T>(ms: number, key: (x: T) => string) {\n\t\treturn (source: Observable<T>) =>\n\t\t\tsource.pipe(\n\t\t\t\tgroupBy(key),\n\t\t\t\tmergeMap((g$) => g$.pipe(debounceTime(ms)))\n\t\t\t);\n\t}\n\n\t/**\n\t * Build the file system events observable stream\n\t */\n\tprivate buildFileSystemEvents$(): Observable<IndexerEvent> {\n\t\tconst created$ = this.fromVaultEvent(\"create\").pipe(this.toRelevantFiles());\n\t\tconst modified$ = this.fromVaultEvent(\"modify\").pipe(this.toRelevantFiles());\n\t\tconst deleted$ = this.fromVaultEvent(\"delete\").pipe(this.toRelevantFiles());\n\n\t\tconst renamed$ = fromEventPattern<[TAbstractFile, string]>(\n\t\t\t(handler) => this.vault.on(\"rename\", handler),\n\t\t\t(handler) => this.vault.off(\"rename\", handler)\n\t\t);\n\n\t\tconst changedIntents$ = merge(created$, modified$).pipe(\n\t\t\tthis.debounceByPath(this.config.debounceMs, (f) => f.path),\n\t\t\tmap((file): FileIntent => ({ kind: \"changed\", file, path: file.path }))\n\t\t);\n\n\t\tconst deletedIntents$ = deleted$.pipe(\n\t\t\tmap((file): FileIntent => ({ kind: \"deleted\", path: file.path }))\n\t\t);\n\n\t\tconst renamedIntents$ = renamed$.pipe(\n\t\t\tmap(([f, oldPath]) => [f, oldPath] as const),\n\t\t\tfilter(([f]) => Indexer.isMarkdownFile(f) && this.config.includeFile(f.path)),\n\t\t\tmergeMap(([f, oldPath]) => [\n\t\t\t\t{ kind: \"deleted\", path: oldPath, isRename: true } as FileIntent,\n\t\t\t\t{ kind: \"changed\", file: f, path: f.path, oldPath } as FileIntent,\n\t\t\t])\n\t\t);\n\n\t\tconst intents$ = merge(changedIntents$, deletedIntents$, renamedIntents$);\n\n\t\treturn intents$.pipe(\n\t\t\tswitchMap((intent) => {\n\t\t\t\tif (intent.kind === \"deleted\") {\n\t\t\t\t\tthis.frontmatterCache.delete(intent.path);\n\t\t\t\t\treturn of<IndexerEvent>({\n\t\t\t\t\t\ttype: \"file-deleted\",\n\t\t\t\t\t\tfilePath: intent.path,\n\t\t\t\t\t\tisRename: intent.isRename,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn from(this.buildEvent(intent.file, intent.oldPath)).pipe(\n\t\t\t\t\tfilter((e): e is IndexerEvent => e !== null)\n\t\t\t\t);\n\t\t\t})\n\t\t);\n\t}\n\n\t/**\n\t * Build an indexer event from a file\n\t */\n\tprivate async buildEvent(file: TFile, oldPath?: string): Promise<IndexerEvent | null> {\n\t\tconst cache = this.metadataCache.getFileCache(file);\n\t\tif (!cache || !cache.frontmatter) return null;\n\n\t\tconst { frontmatter } = cache;\n\t\tconst oldFrontmatter = this.frontmatterCache.get(file.path);\n\n\t\tconst source: FileSource = {\n\t\t\tfilePath: file.path,\n\t\t\tmtime: file.stat.mtime,\n\t\t\tfrontmatter,\n\t\t\tfolder: file.parent?.path || \"\",\n\t\t};\n\n\t\tconst event: IndexerEvent = {\n\t\t\ttype: \"file-changed\",\n\t\t\tfilePath: file.path,\n\t\t\toldPath,\n\t\t\tsource,\n\t\t\toldFrontmatter,\n\t\t\tfrontmatterDiff: oldFrontmatter\n\t\t\t\t? compareFrontmatter(oldFrontmatter, frontmatter, this.config.excludedDiffProps)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\t// Update cache\n\t\tthis.frontmatterCache.set(file.path, { ...frontmatter });\n\n\t\treturn event;\n\t}\n}\n"]}
@@ -1,9 +0,0 @@
1
- export interface PropertyRendererConfig {
2
- createLink: (text: string, path: string, isObsidianLink: boolean) => HTMLElement;
3
- createText: (text: string) => HTMLElement | Text;
4
- createSeparator?: () => HTMLElement | Text;
5
- }
6
- export declare function renderPropertyValue(container: HTMLElement, value: any, config: PropertyRendererConfig): void;
7
- export declare function createTextNode(text: string): Text;
8
- export declare function createDefaultSeparator(): Text;
9
- //# sourceMappingURL=property-renderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"property-renderer.d.ts","sourceRoot":"","sources":["../../src/core/property-renderer.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACtC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,KAAK,WAAW,CAAC;IACjF,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,GAAG,IAAI,CAAC;IACjD,eAAe,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;CAC3C;AAED,wBAAgB,mBAAmB,CAClC,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE,GAAG,EACV,MAAM,EAAE,sBAAsB,GAC5B,IAAI,CAqBN;AAsBD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}
@@ -1,42 +0,0 @@
1
- import { getObsidianLinkAlias, getObsidianLinkPath, isObsidianLink } from "../file/link-parser";
2
- export function renderPropertyValue(container, value, config) {
3
- // Handle arrays - render each item separately
4
- if (Array.isArray(value)) {
5
- const hasClickableLinks = value.some(isObsidianLink);
6
- if (hasClickableLinks) {
7
- for (let index = 0; index < value.length; index++) {
8
- if (index > 0 && config.createSeparator) {
9
- container.appendChild(config.createSeparator());
10
- }
11
- renderSingleValue(container, value[index], config);
12
- }
13
- }
14
- else {
15
- // Plain array - just join with commas
16
- const textNode = config.createText(value.join(", "));
17
- container.appendChild(textNode);
18
- }
19
- return;
20
- }
21
- renderSingleValue(container, value, config);
22
- }
23
- function renderSingleValue(container, value, config) {
24
- const stringValue = String(value).trim();
25
- if (isObsidianLink(stringValue)) {
26
- const displayText = getObsidianLinkAlias(stringValue);
27
- const linkPath = getObsidianLinkPath(stringValue);
28
- const link = config.createLink(displayText, linkPath, true);
29
- container.appendChild(link);
30
- return;
31
- }
32
- // Regular text
33
- const textNode = config.createText(stringValue);
34
- container.appendChild(textNode);
35
- }
36
- export function createTextNode(text) {
37
- return document.createTextNode(text);
38
- }
39
- export function createDefaultSeparator() {
40
- return document.createTextNode(", ");
41
- }
42
- //# sourceMappingURL=property-renderer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"property-renderer.js","sourceRoot":"","sources":["../../src/core/property-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAQhG,MAAM,UAAU,mBAAmB,CAClC,SAAsB,EACtB,KAAU,EACV,MAA8B;IAE9B,8CAA8C;IAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAErD,IAAI,iBAAiB,EAAE,CAAC;YACvB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;gBACnD,IAAI,KAAK,GAAG,CAAC,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;oBACzC,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;gBACjD,CAAC;gBACD,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;YACpD,CAAC;QACF,CAAC;aAAM,CAAC;YACP,sCAAsC;YACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACrD,SAAS,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QACD,OAAO;IACR,CAAC;IAED,iBAAiB,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,iBAAiB,CACzB,SAAsB,EACtB,KAAU,EACV,MAA8B;IAE9B,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IAEzC,IAAI,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;QACjC,MAAM,WAAW,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC5D,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC5B,OAAO;IACR,CAAC;IAED,eAAe;IACf,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChD,SAAS,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IAC1C,OAAO,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,sBAAsB;IACrC,OAAO,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC","sourcesContent":["import { getObsidianLinkAlias, getObsidianLinkPath, isObsidianLink } from \"../file/link-parser\";\n\nexport interface PropertyRendererConfig {\n\tcreateLink: (text: string, path: string, isObsidianLink: boolean) => HTMLElement;\n\tcreateText: (text: string) => HTMLElement | Text;\n\tcreateSeparator?: () => HTMLElement | Text;\n}\n\nexport function renderPropertyValue(\n\tcontainer: HTMLElement,\n\tvalue: any,\n\tconfig: PropertyRendererConfig\n): void {\n\t// Handle arrays - render each item separately\n\tif (Array.isArray(value)) {\n\t\tconst hasClickableLinks = value.some(isObsidianLink);\n\n\t\tif (hasClickableLinks) {\n\t\t\tfor (let index = 0; index < value.length; index++) {\n\t\t\t\tif (index > 0 && config.createSeparator) {\n\t\t\t\t\tcontainer.appendChild(config.createSeparator());\n\t\t\t\t}\n\t\t\t\trenderSingleValue(container, value[index], config);\n\t\t\t}\n\t\t} else {\n\t\t\t// Plain array - just join with commas\n\t\t\tconst textNode = config.createText(value.join(\", \"));\n\t\t\tcontainer.appendChild(textNode);\n\t\t}\n\t\treturn;\n\t}\n\n\trenderSingleValue(container, value, config);\n}\n\nfunction renderSingleValue(\n\tcontainer: HTMLElement,\n\tvalue: any,\n\tconfig: PropertyRendererConfig\n): void {\n\tconst stringValue = String(value).trim();\n\n\tif (isObsidianLink(stringValue)) {\n\t\tconst displayText = getObsidianLinkAlias(stringValue);\n\t\tconst linkPath = getObsidianLinkPath(stringValue);\n\t\tconst link = config.createLink(displayText, linkPath, true);\n\t\tcontainer.appendChild(link);\n\t\treturn;\n\t}\n\n\t// Regular text\n\tconst textNode = config.createText(stringValue);\n\tcontainer.appendChild(textNode);\n}\n\nexport function createTextNode(text: string): Text {\n\treturn document.createTextNode(text);\n}\n\nexport function createDefaultSeparator(): Text {\n\treturn document.createTextNode(\", \");\n}\n"]}
@@ -1,13 +0,0 @@
1
- /**
2
- * Checks if a value is not empty.
3
- * Returns false for: undefined, null, empty string, or empty arrays.
4
- * Returns true for all other values.
5
- */
6
- export declare function isNotEmpty(value: unknown): boolean;
7
- /**
8
- * Parses a value to a positive integer.
9
- * Handles both number and string types from frontmatter.
10
- * Returns the parsed integer if valid and positive, otherwise returns the fallback value.
11
- */
12
- export declare function parsePositiveInt(value: unknown, fallback: number): number;
13
- //# sourceMappingURL=validation.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/core/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAQlD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMzE"}
@@ -1,27 +0,0 @@
1
- /**
2
- * Checks if a value is not empty.
3
- * Returns false for: undefined, null, empty string, or empty arrays.
4
- * Returns true for all other values.
5
- */
6
- export function isNotEmpty(value) {
7
- if (value === undefined || value === null || value === "") {
8
- return false;
9
- }
10
- if (Array.isArray(value) && value.length === 0) {
11
- return false;
12
- }
13
- return true;
14
- }
15
- /**
16
- * Parses a value to a positive integer.
17
- * Handles both number and string types from frontmatter.
18
- * Returns the parsed integer if valid and positive, otherwise returns the fallback value.
19
- */
20
- export function parsePositiveInt(value, fallback) {
21
- if (value === undefined || value === null) {
22
- return fallback;
23
- }
24
- const parsed = typeof value === "number" ? Math.floor(value) : Number.parseInt(String(value), 10);
25
- return !Number.isNaN(parsed) && parsed > 0 ? parsed : fallback;
26
- }
27
- //# sourceMappingURL=validation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/core/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc;IACxC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QAC3D,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc,EAAE,QAAgB;IAChE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC3C,OAAO,QAAQ,CAAC;IACjB,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;IAClG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAChE,CAAC","sourcesContent":["/**\n * Checks if a value is not empty.\n * Returns false for: undefined, null, empty string, or empty arrays.\n * Returns true for all other values.\n */\nexport function isNotEmpty(value: unknown): boolean {\n\tif (value === undefined || value === null || value === \"\") {\n\t\treturn false;\n\t}\n\tif (Array.isArray(value) && value.length === 0) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n/**\n * Parses a value to a positive integer.\n * Handles both number and string types from frontmatter.\n * Returns the parsed integer if valid and positive, otherwise returns the fallback value.\n */\nexport function parsePositiveInt(value: unknown, fallback: number): number {\n\tif (value === undefined || value === null) {\n\t\treturn fallback;\n\t}\n\tconst parsed = typeof value === \"number\" ? Math.floor(value) : Number.parseInt(String(value), 10);\n\treturn !Number.isNaN(parsed) && parsed > 0 ? parsed : fallback;\n}\n"]}
@@ -1,30 +0,0 @@
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
- export declare function iterateOccurrencesInRange(startDate: DateTime, rrules: {
22
- type: RecurrenceType;
23
- weekdays?: Weekday[];
24
- }, rangeStart: DateTime, rangeEnd: DateTime): Generator<DateTime, void, unknown>;
25
- /**
26
- * Calculates a DateTime for a specific date with optional time
27
- */
28
- export declare function calculateInstanceDateTime(instanceDate: DateTime, timeString?: string): DateTime;
29
- export declare function calculateRecurringInstanceDateTime(nextInstanceDateTime: DateTime, nodeRecuringEventDateTime: DateTime, recurrenceType: RecurrenceType, allDay?: boolean): DateTime;
30
- //# sourceMappingURL=date-recurrence.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"date-recurrence.d.ts","sourceRoot":"","sources":["../../src/date/date-recurrence.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,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,CA+DpC;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,CAO/F;AAED,wBAAgB,kCAAkC,CACjD,oBAAoB,EAAE,QAAQ,EAC9B,yBAAyB,EAAE,QAAQ,EACnC,cAAc,EAAE,cAAc,EAC9B,MAAM,CAAC,EAAE,OAAO,GACd,QAAQ,CA0DV"}
@@ -1,188 +0,0 @@
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
- export function* iterateOccurrencesInRange(startDate, rrules, rangeStart, rangeEnd) {
75
- // Normalize to start of day for comparison
76
- const normalizedStart = startDate.startOf("day");
77
- const normalizedRangeStart = rangeStart.startOf("day");
78
- const normalizedRangeEnd = rangeEnd.startOf("day");
79
- // Start from the later of startDate or rangeStart
80
- let currentDate = normalizedStart >= normalizedRangeStart ? normalizedStart : normalizedRangeStart;
81
- // For weekly/bi-weekly with weekdays, we need to track which week we're in
82
- if ((rrules.type === "weekly" || rrules.type === "bi-weekly") &&
83
- rrules.weekdays &&
84
- rrules.weekdays.length > 0) {
85
- // Calculate week offset from start date
86
- const weeksFromStart = Math.floor(currentDate.diff(normalizedStart, "weeks").weeks);
87
- // For bi-weekly, we only want even weeks (0, 2, 4...) from the start date
88
- const weekInterval = rrules.type === "bi-weekly" ? 2 : 1;
89
- // Adjust to the correct week if we're in an off-week
90
- const weekOffset = weeksFromStart % weekInterval;
91
- if (weekOffset !== 0) {
92
- currentDate = currentDate.plus({ weeks: weekInterval - weekOffset });
93
- }
94
- // Now iterate through weeks, checking each day
95
- while (currentDate <= normalizedRangeEnd) {
96
- // Check all 7 days of the current week
97
- for (let dayOffset = 0; dayOffset < 7; dayOffset++) {
98
- const checkDate = currentDate.plus({ days: dayOffset });
99
- // Only yield if within range and matches a target weekday
100
- if (checkDate >= normalizedRangeStart &&
101
- checkDate <= normalizedRangeEnd &&
102
- isDateOnWeekdays(checkDate, rrules.weekdays)) {
103
- yield checkDate;
104
- }
105
- }
106
- // Move to next occurrence week (1 week for weekly, 2 weeks for bi-weekly)
107
- currentDate = currentDate.plus({ weeks: weekInterval });
108
- }
109
- }
110
- else {
111
- // For other recurrence types (daily, monthly, yearly, or weekly without weekdays)
112
- while (currentDate <= normalizedRangeEnd) {
113
- if (currentDate >= normalizedRangeStart) {
114
- yield currentDate;
115
- }
116
- const nextDate = getNextOccurrence(currentDate, rrules.type, rrules.weekdays);
117
- if (nextDate <= normalizedRangeEnd) {
118
- currentDate = nextDate;
119
- }
120
- else {
121
- break;
122
- }
123
- }
124
- }
125
- }
126
- /**
127
- * Calculates a DateTime for a specific date with optional time
128
- */
129
- export function calculateInstanceDateTime(instanceDate, timeString) {
130
- if (!timeString) {
131
- return instanceDate.startOf("day");
132
- }
133
- const [hours, minutes] = timeString.split(":").map(Number);
134
- return instanceDate.set({ hour: hours, minute: minutes, second: 0, millisecond: 0 });
135
- }
136
- export function calculateRecurringInstanceDateTime(nextInstanceDateTime, nodeRecuringEventDateTime, recurrenceType, allDay) {
137
- // Convert the original event time to the target timezone once to preserve local time
138
- const originalInTargetZone = nodeRecuringEventDateTime.setZone(nextInstanceDateTime.zone);
139
- switch (recurrenceType) {
140
- case "daily":
141
- case "weekly":
142
- case "bi-weekly": {
143
- if (allDay) {
144
- return nextInstanceDateTime.startOf("day");
145
- }
146
- return nextInstanceDateTime.set({
147
- hour: originalInTargetZone.hour,
148
- minute: originalInTargetZone.minute,
149
- second: 0,
150
- millisecond: 0,
151
- });
152
- }
153
- case "monthly":
154
- case "bi-monthly": {
155
- if (allDay) {
156
- return nextInstanceDateTime.set({ day: originalInTargetZone.day }).startOf("day");
157
- }
158
- return nextInstanceDateTime.set({
159
- day: originalInTargetZone.day,
160
- hour: originalInTargetZone.hour,
161
- minute: originalInTargetZone.minute,
162
- second: 0,
163
- millisecond: 0,
164
- });
165
- }
166
- case "yearly": {
167
- if (allDay) {
168
- return nextInstanceDateTime
169
- .set({
170
- month: originalInTargetZone.month,
171
- day: originalInTargetZone.day,
172
- })
173
- .startOf("day");
174
- }
175
- return nextInstanceDateTime.set({
176
- month: originalInTargetZone.month,
177
- day: originalInTargetZone.day,
178
- hour: originalInTargetZone.hour,
179
- minute: originalInTargetZone.minute,
180
- second: 0,
181
- millisecond: 0,
182
- });
183
- }
184
- default:
185
- return nextInstanceDateTime.startOf("day");
186
- }
187
- }
188
- //# sourceMappingURL=date-recurrence.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"date-recurrence.js","sourceRoot":"","sources":["../../src/date/date-recurrence.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DateTime } from \"luxon\";\n\nexport type RecurrenceType = \"daily\" | \"weekly\" | \"bi-weekly\" | \"monthly\" | \"bi-monthly\" | \"yearly\";\n\nexport type Weekday =\n\t| \"sunday\"\n\t| \"monday\"\n\t| \"tuesday\"\n\t| \"wednesday\"\n\t| \"thursday\"\n\t| \"friday\"\n\t| \"saturday\";\n\nexport const WEEKDAY_TO_NUMBER: Record<Weekday, number> = {\n\tsunday: 0,\n\tmonday: 1,\n\ttuesday: 2,\n\twednesday: 3,\n\tthursday: 4,\n\tfriday: 5,\n\tsaturday: 6,\n};\n\n/**\n * Calculates the next occurrence date based on recurrence type and optional weekdays\n */\nexport function getNextOccurrence(\n\tcurrentDate: DateTime,\n\trecurrenceType: RecurrenceType,\n\tweekdays?: Weekday[]\n): DateTime {\n\tswitch (recurrenceType) {\n\t\tcase \"daily\":\n\t\t\treturn currentDate.plus({ days: 1 });\n\t\tcase \"weekly\":\n\t\t\tif (weekdays && weekdays.length > 0) {\n\t\t\t\treturn getNextWeekdayOccurrence(currentDate, weekdays);\n\t\t\t}\n\t\t\treturn currentDate.plus({ weeks: 1 });\n\t\tcase \"bi-weekly\":\n\t\t\tif (weekdays && weekdays.length > 0) {\n\t\t\t\treturn getNextBiWeeklyOccurrence(currentDate, weekdays);\n\t\t\t}\n\t\t\treturn currentDate.plus({ weeks: 2 });\n\t\tcase \"monthly\":\n\t\t\treturn currentDate.plus({ months: 1 });\n\t\tcase \"bi-monthly\":\n\t\t\treturn currentDate.plus({ months: 2 });\n\t\tcase \"yearly\":\n\t\t\treturn currentDate.plus({ years: 1 });\n\t\tdefault:\n\t\t\treturn currentDate.plus({ days: 1 });\n\t}\n}\n\n/**\n * Checks if a given date matches any of the specified weekdays\n */\nexport function isDateOnWeekdays(date: DateTime, weekdays: Weekday[]): boolean {\n\tconst dateWeekday = date.weekday;\n\tconst luxonWeekdays = weekdays.map((day) => {\n\t\tconst dayNumber = WEEKDAY_TO_NUMBER[day];\n\t\treturn dayNumber === 0 ? 7 : dayNumber; // Convert Sunday from 0 to 7 for Luxon\n\t});\n\n\treturn luxonWeekdays.includes(dateWeekday);\n}\n\n/**\n * Finds the next occurrence on specified weekdays\n */\nexport function getNextWeekdayOccurrence(currentDate: DateTime, weekdays: Weekday[]): DateTime {\n\tconst currentWeekday = currentDate.weekday;\n\tconst luxonWeekdays = weekdays.map((day) => {\n\t\tconst dayNumber = WEEKDAY_TO_NUMBER[day];\n\t\treturn dayNumber === 0 ? 7 : dayNumber; // Convert Sunday from 0 to 7 for Luxon\n\t});\n\n\t// Find next weekday in the current week (after today)\n\tconst nextWeekday = luxonWeekdays.find((day) => day > currentWeekday);\n\tif (nextWeekday) {\n\t\treturn currentDate.set({ weekday: nextWeekday as 1 | 2 | 3 | 4 | 5 | 6 | 7 });\n\t}\n\n\t// No more weekdays this week, go to first weekday of next week\n\tconst firstWeekday = Math.min(...luxonWeekdays);\n\treturn currentDate.plus({ weeks: 1 }).set({ weekday: firstWeekday as 1 | 2 | 3 | 4 | 5 | 6 | 7 });\n}\n\n/**\n * Finds the next bi-weekly occurrence on specified weekdays\n */\nexport function getNextBiWeeklyOccurrence(currentDate: DateTime, weekdays: Weekday[]): DateTime {\n\tconst nextWeekly = getNextWeekdayOccurrence(currentDate, weekdays);\n\t// Add one more week to make it bi-weekly\n\treturn nextWeekly.plus({ weeks: 1 });\n}\n\nexport function* iterateOccurrencesInRange(\n\tstartDate: DateTime,\n\trrules: { type: RecurrenceType; weekdays?: Weekday[] },\n\trangeStart: DateTime,\n\trangeEnd: DateTime\n): Generator<DateTime, void, unknown> {\n\t// Normalize to start of day for comparison\n\tconst normalizedStart = startDate.startOf(\"day\");\n\tconst normalizedRangeStart = rangeStart.startOf(\"day\");\n\tconst normalizedRangeEnd = rangeEnd.startOf(\"day\");\n\n\t// Start from the later of startDate or rangeStart\n\tlet currentDate =\n\t\tnormalizedStart >= normalizedRangeStart ? normalizedStart : normalizedRangeStart;\n\n\t// For weekly/bi-weekly with weekdays, we need to track which week we're in\n\tif (\n\t\t(rrules.type === \"weekly\" || rrules.type === \"bi-weekly\") &&\n\t\trrules.weekdays &&\n\t\trrules.weekdays.length > 0\n\t) {\n\t\t// Calculate week offset from start date\n\t\tconst weeksFromStart = Math.floor(currentDate.diff(normalizedStart, \"weeks\").weeks);\n\n\t\t// For bi-weekly, we only want even weeks (0, 2, 4...) from the start date\n\t\tconst weekInterval = rrules.type === \"bi-weekly\" ? 2 : 1;\n\n\t\t// Adjust to the correct week if we're in an off-week\n\t\tconst weekOffset = weeksFromStart % weekInterval;\n\t\tif (weekOffset !== 0) {\n\t\t\tcurrentDate = currentDate.plus({ weeks: weekInterval - weekOffset });\n\t\t}\n\n\t\t// Now iterate through weeks, checking each day\n\t\twhile (currentDate <= normalizedRangeEnd) {\n\t\t\t// Check all 7 days of the current week\n\t\t\tfor (let dayOffset = 0; dayOffset < 7; dayOffset++) {\n\t\t\t\tconst checkDate = currentDate.plus({ days: dayOffset });\n\n\t\t\t\t// Only yield if within range and matches a target weekday\n\t\t\t\tif (\n\t\t\t\t\tcheckDate >= normalizedRangeStart &&\n\t\t\t\t\tcheckDate <= normalizedRangeEnd &&\n\t\t\t\t\tisDateOnWeekdays(checkDate, rrules.weekdays)\n\t\t\t\t) {\n\t\t\t\t\tyield checkDate;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Move to next occurrence week (1 week for weekly, 2 weeks for bi-weekly)\n\t\t\tcurrentDate = currentDate.plus({ weeks: weekInterval });\n\t\t}\n\t} else {\n\t\t// For other recurrence types (daily, monthly, yearly, or weekly without weekdays)\n\t\twhile (currentDate <= normalizedRangeEnd) {\n\t\t\tif (currentDate >= normalizedRangeStart) {\n\t\t\t\tyield currentDate;\n\t\t\t}\n\n\t\t\tconst nextDate = getNextOccurrence(currentDate, rrules.type, rrules.weekdays);\n\n\t\t\tif (nextDate <= normalizedRangeEnd) {\n\t\t\t\tcurrentDate = nextDate;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Calculates a DateTime for a specific date with optional time\n */\nexport function calculateInstanceDateTime(instanceDate: DateTime, timeString?: string): DateTime {\n\tif (!timeString) {\n\t\treturn instanceDate.startOf(\"day\");\n\t}\n\n\tconst [hours, minutes] = timeString.split(\":\").map(Number);\n\treturn instanceDate.set({ hour: hours, minute: minutes, second: 0, millisecond: 0 });\n}\n\nexport function calculateRecurringInstanceDateTime(\n\tnextInstanceDateTime: DateTime,\n\tnodeRecuringEventDateTime: DateTime,\n\trecurrenceType: RecurrenceType,\n\tallDay?: boolean\n): DateTime {\n\t// Convert the original event time to the target timezone once to preserve local time\n\tconst originalInTargetZone = nodeRecuringEventDateTime.setZone(nextInstanceDateTime.zone);\n\n\tswitch (recurrenceType) {\n\t\tcase \"daily\":\n\t\tcase \"weekly\":\n\t\tcase \"bi-weekly\": {\n\t\t\tif (allDay) {\n\t\t\t\treturn nextInstanceDateTime.startOf(\"day\");\n\t\t\t}\n\n\t\t\treturn nextInstanceDateTime.set({\n\t\t\t\thour: originalInTargetZone.hour,\n\t\t\t\tminute: originalInTargetZone.minute,\n\t\t\t\tsecond: 0,\n\t\t\t\tmillisecond: 0,\n\t\t\t});\n\t\t}\n\n\t\tcase \"monthly\":\n\t\tcase \"bi-monthly\": {\n\t\t\tif (allDay) {\n\t\t\t\treturn nextInstanceDateTime.set({ day: originalInTargetZone.day }).startOf(\"day\");\n\t\t\t}\n\n\t\t\treturn nextInstanceDateTime.set({\n\t\t\t\tday: originalInTargetZone.day,\n\t\t\t\thour: originalInTargetZone.hour,\n\t\t\t\tminute: originalInTargetZone.minute,\n\t\t\t\tsecond: 0,\n\t\t\t\tmillisecond: 0,\n\t\t\t});\n\t\t}\n\n\t\tcase \"yearly\": {\n\t\t\tif (allDay) {\n\t\t\t\treturn nextInstanceDateTime\n\t\t\t\t\t.set({\n\t\t\t\t\t\tmonth: originalInTargetZone.month,\n\t\t\t\t\t\tday: originalInTargetZone.day,\n\t\t\t\t\t})\n\t\t\t\t\t.startOf(\"day\");\n\t\t\t}\n\n\t\t\treturn nextInstanceDateTime.set({\n\t\t\t\tmonth: originalInTargetZone.month,\n\t\t\t\tday: originalInTargetZone.day,\n\t\t\t\thour: originalInTargetZone.hour,\n\t\t\t\tminute: originalInTargetZone.minute,\n\t\t\t\tsecond: 0,\n\t\t\t\tmillisecond: 0,\n\t\t\t});\n\t\t}\n\n\t\tdefault:\n\t\t\treturn nextInstanceDateTime.startOf(\"day\");\n\t}\n}\n"]}
@@ -1,21 +0,0 @@
1
- import { DateTime } from "luxon";
2
- export declare const formatDateTimeForInput: (dateString: string) => string;
3
- export declare const formatDateForInput: (dateString: string) => string;
4
- /**
5
- * Converts input value to ISO string, handling edge cases where
6
- * browser datetime-local inputs behave differently across platforms.
7
- * Returns null for invalid dates to prevent silent failures.
8
- */
9
- export declare const inputValueToISOString: (inputValue: string) => string | null;
10
- export declare const formatDuration: (minutes: number) => string;
11
- /**
12
- * Parse time string from datetime value - returns DateTime object
13
- * Rejects plain HH:mm format, requires full datetime
14
- */
15
- export declare const parseTimeString: (value: string | null) => DateTime | undefined;
16
- /**
17
- * Parse and validate datetime strings for event parsing
18
- * Supports multiple formats including date-only and datetime formats
19
- */
20
- export declare const parseDateTimeString: (value: string | null) => DateTime | undefined;
21
- //# sourceMappingURL=date.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../src/date/date.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjC,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,QAAQ,GAAG,SAgBjE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,MAAM,GAAG,IAAI,KAAG,QAAQ,GAAG,SA8BrE,CAAC"}