@real1ty-obsidian-plugins/utils 2.30.0 → 2.31.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 (238) hide show
  1. package/dist/async/async.d.ts +69 -0
  2. package/dist/async/async.d.ts.map +1 -0
  3. package/dist/async/async.js +108 -0
  4. package/dist/async/async.js.map +1 -0
  5. package/dist/async/batch-operations.d.ts +21 -0
  6. package/dist/async/batch-operations.d.ts.map +1 -0
  7. package/dist/async/batch-operations.js +60 -0
  8. package/dist/async/batch-operations.js.map +1 -0
  9. package/dist/async/change-notifier.d.ts +13 -0
  10. package/dist/async/change-notifier.d.ts.map +1 -0
  11. package/dist/async/change-notifier.js +26 -0
  12. package/dist/async/change-notifier.js.map +1 -0
  13. package/dist/async/debounced-notifier.d.ts +26 -0
  14. package/dist/async/debounced-notifier.d.ts.map +1 -0
  15. package/dist/async/debounced-notifier.js +50 -0
  16. package/dist/async/debounced-notifier.js.map +1 -0
  17. package/dist/async/index.d.ts +5 -0
  18. package/dist/async/index.d.ts.map +1 -0
  19. package/dist/async/index.js +5 -0
  20. package/dist/async/index.js.map +1 -0
  21. package/dist/components/frontmatter-propagation-modal.d.ts +17 -0
  22. package/dist/components/frontmatter-propagation-modal.d.ts.map +1 -0
  23. package/dist/components/frontmatter-propagation-modal.js +85 -0
  24. package/dist/components/frontmatter-propagation-modal.js.map +1 -0
  25. package/dist/components/index.d.ts +5 -0
  26. package/dist/components/index.d.ts.map +1 -0
  27. package/dist/components/index.js +5 -0
  28. package/dist/components/index.js.map +1 -0
  29. package/dist/components/input-managers/base.d.ts +30 -0
  30. package/dist/components/input-managers/base.d.ts.map +1 -0
  31. package/dist/components/input-managers/base.js +115 -0
  32. package/dist/components/input-managers/base.js.map +1 -0
  33. package/dist/components/input-managers/expression.d.ts +12 -0
  34. package/dist/components/input-managers/expression.d.ts.map +1 -0
  35. package/dist/components/input-managers/expression.js +56 -0
  36. package/dist/components/input-managers/expression.js.map +1 -0
  37. package/dist/components/input-managers/index.d.ts +4 -0
  38. package/dist/components/input-managers/index.d.ts.map +1 -0
  39. package/dist/components/input-managers/index.js +4 -0
  40. package/dist/components/input-managers/index.js.map +1 -0
  41. package/dist/components/input-managers/search.d.ts +6 -0
  42. package/dist/components/input-managers/search.d.ts.map +1 -0
  43. package/dist/components/input-managers/search.js +16 -0
  44. package/dist/components/input-managers/search.js.map +1 -0
  45. package/dist/components/registered-events-component.d.ts +30 -0
  46. package/dist/components/registered-events-component.d.ts.map +1 -0
  47. package/dist/components/registered-events-component.js +43 -0
  48. package/dist/components/registered-events-component.js.map +1 -0
  49. package/dist/components/whats-new-modal.d.ts +89 -0
  50. package/dist/components/whats-new-modal.d.ts.map +1 -0
  51. package/dist/components/whats-new-modal.js +196 -0
  52. package/dist/components/whats-new-modal.js.map +1 -0
  53. package/dist/core/color-utils.d.ts +17 -0
  54. package/dist/core/color-utils.d.ts.map +1 -0
  55. package/dist/core/color-utils.js +29 -0
  56. package/dist/core/color-utils.js.map +1 -0
  57. package/dist/core/css-utils.d.ts +39 -0
  58. package/dist/core/css-utils.d.ts.map +1 -0
  59. package/dist/core/css-utils.js +60 -0
  60. package/dist/core/css-utils.js.map +1 -0
  61. package/dist/core/evaluator/base.d.ts +22 -0
  62. package/dist/core/evaluator/base.d.ts.map +1 -0
  63. package/dist/core/evaluator/base.js +67 -0
  64. package/dist/core/evaluator/base.js.map +1 -0
  65. package/dist/core/evaluator/color.d.ts +19 -0
  66. package/dist/core/evaluator/color.d.ts.map +1 -0
  67. package/dist/core/evaluator/color.js +25 -0
  68. package/dist/core/evaluator/color.js.map +1 -0
  69. package/dist/core/evaluator/excluded.d.ts +32 -0
  70. package/dist/core/evaluator/excluded.d.ts.map +1 -0
  71. package/dist/core/evaluator/excluded.js +41 -0
  72. package/dist/core/evaluator/excluded.js.map +1 -0
  73. package/dist/core/evaluator/filter.d.ts +15 -0
  74. package/dist/core/evaluator/filter.d.ts.map +1 -0
  75. package/dist/core/evaluator/filter.js +27 -0
  76. package/dist/core/evaluator/filter.js.map +1 -0
  77. package/dist/core/evaluator/included.d.ts +36 -0
  78. package/dist/core/evaluator/included.d.ts.map +1 -0
  79. package/dist/core/evaluator/included.js +51 -0
  80. package/dist/core/evaluator/included.js.map +1 -0
  81. package/dist/core/evaluator/index.d.ts +6 -0
  82. package/dist/core/evaluator/index.d.ts.map +1 -0
  83. package/dist/core/evaluator/index.js +6 -0
  84. package/dist/core/evaluator/index.js.map +1 -0
  85. package/dist/core/expression-utils.d.ts +17 -0
  86. package/dist/core/expression-utils.d.ts.map +1 -0
  87. package/dist/core/expression-utils.js +40 -0
  88. package/dist/core/expression-utils.js.map +1 -0
  89. package/dist/core/frontmatter-value.d.ts +157 -0
  90. package/dist/core/frontmatter-value.d.ts.map +1 -0
  91. package/dist/core/frontmatter-value.js +417 -0
  92. package/dist/core/frontmatter-value.js.map +1 -0
  93. package/dist/core/generate.d.ts +7 -0
  94. package/dist/core/generate.d.ts.map +1 -0
  95. package/dist/core/generate.js +13 -0
  96. package/dist/core/generate.js.map +1 -0
  97. package/dist/core/history.d.ts +12 -0
  98. package/dist/core/history.d.ts.map +1 -0
  99. package/dist/core/history.js +39 -0
  100. package/dist/core/history.js.map +1 -0
  101. package/dist/core/index.d.ts +11 -0
  102. package/dist/core/index.d.ts.map +1 -0
  103. package/dist/core/index.js +11 -0
  104. package/dist/core/index.js.map +1 -0
  105. package/dist/core/indexer.d.ts +109 -0
  106. package/dist/core/indexer.d.ts.map +1 -0
  107. package/dist/core/indexer.js +185 -0
  108. package/dist/core/indexer.js.map +1 -0
  109. package/dist/core/property-renderer.d.ts +9 -0
  110. package/dist/core/property-renderer.d.ts.map +1 -0
  111. package/dist/core/property-renderer.js +42 -0
  112. package/dist/core/property-renderer.js.map +1 -0
  113. package/dist/core/validation.d.ts +13 -0
  114. package/dist/core/validation.d.ts.map +1 -0
  115. package/dist/core/validation.js +27 -0
  116. package/dist/core/validation.js.map +1 -0
  117. package/dist/date/date-recurrence.d.ts +30 -0
  118. package/dist/date/date-recurrence.d.ts.map +1 -0
  119. package/dist/date/date-recurrence.js +188 -0
  120. package/dist/date/date-recurrence.js.map +1 -0
  121. package/dist/date/date.d.ts +21 -0
  122. package/dist/date/date.d.ts.map +1 -0
  123. package/dist/date/date.js +105 -0
  124. package/dist/date/date.js.map +1 -0
  125. package/dist/date/index.d.ts +3 -0
  126. package/dist/date/index.d.ts.map +1 -0
  127. package/dist/date/index.js +3 -0
  128. package/dist/date/index.js.map +1 -0
  129. package/dist/file/child-reference.d.ts +9 -0
  130. package/dist/file/child-reference.d.ts.map +1 -0
  131. package/dist/file/child-reference.js +57 -0
  132. package/dist/file/child-reference.js.map +1 -0
  133. package/dist/file/file-operations.d.ts +31 -0
  134. package/dist/file/file-operations.d.ts.map +1 -0
  135. package/dist/file/file-operations.js +160 -0
  136. package/dist/file/file-operations.js.map +1 -0
  137. package/dist/file/file-utils.d.ts +33 -0
  138. package/dist/file/file-utils.d.ts.map +1 -0
  139. package/dist/file/file-utils.js +76 -0
  140. package/dist/file/file-utils.js.map +1 -0
  141. package/dist/file/file.d.ts +332 -0
  142. package/dist/file/file.d.ts.map +1 -0
  143. package/dist/file/file.js +559 -0
  144. package/dist/file/file.js.map +1 -0
  145. package/dist/file/frontmatter-diff.d.ts +38 -0
  146. package/dist/file/frontmatter-diff.d.ts.map +1 -0
  147. package/dist/file/frontmatter-diff.js +162 -0
  148. package/dist/file/frontmatter-diff.js.map +1 -0
  149. package/dist/file/frontmatter-propagation.d.ts +4 -0
  150. package/dist/file/frontmatter-propagation.d.ts.map +1 -0
  151. package/dist/file/frontmatter-propagation.js +28 -0
  152. package/dist/file/frontmatter-propagation.js.map +1 -0
  153. package/dist/file/frontmatter-serialization.d.ts +21 -0
  154. package/dist/file/frontmatter-serialization.d.ts.map +1 -0
  155. package/dist/file/frontmatter-serialization.js +57 -0
  156. package/dist/file/frontmatter-serialization.js.map +1 -0
  157. package/dist/file/frontmatter.d.ts +15 -0
  158. package/dist/file/frontmatter.d.ts.map +1 -0
  159. package/dist/file/frontmatter.js +68 -0
  160. package/dist/file/frontmatter.js.map +1 -0
  161. package/dist/file/index.d.ts +13 -0
  162. package/dist/file/index.d.ts.map +1 -0
  163. package/dist/file/index.js +13 -0
  164. package/dist/file/index.js.map +1 -0
  165. package/dist/file/link-parser.d.ts +63 -0
  166. package/dist/file/link-parser.d.ts.map +1 -0
  167. package/dist/file/link-parser.js +137 -0
  168. package/dist/file/link-parser.js.map +1 -0
  169. package/dist/file/property-utils.d.ts +55 -0
  170. package/dist/file/property-utils.d.ts.map +1 -0
  171. package/dist/file/property-utils.js +90 -0
  172. package/dist/file/property-utils.js.map +1 -0
  173. package/dist/file/templater-service.d.ts +16 -0
  174. package/dist/file/templater-service.d.ts.map +1 -0
  175. package/dist/file/templater-service.js +37 -0
  176. package/dist/file/templater-service.js.map +1 -0
  177. package/dist/file/templater.d.ts +28 -0
  178. package/dist/file/templater.d.ts.map +1 -0
  179. package/dist/file/templater.js +126 -0
  180. package/dist/file/templater.js.map +1 -0
  181. package/dist/index.d.ts +9 -0
  182. package/dist/index.d.ts.map +1 -0
  183. package/dist/index.js +17 -0
  184. package/dist/index.js.map +1 -0
  185. package/dist/inputs/index.d.ts +2 -0
  186. package/dist/inputs/index.d.ts.map +1 -0
  187. package/dist/inputs/index.js +2 -0
  188. package/dist/inputs/index.js.map +1 -0
  189. package/dist/inputs/input-filter-manager.d.ts +72 -0
  190. package/dist/inputs/input-filter-manager.d.ts.map +1 -0
  191. package/dist/inputs/input-filter-manager.js +140 -0
  192. package/dist/inputs/input-filter-manager.js.map +1 -0
  193. package/dist/settings/index.d.ts +3 -0
  194. package/dist/settings/index.d.ts.map +1 -0
  195. package/dist/settings/index.js +3 -0
  196. package/dist/settings/index.js.map +1 -0
  197. package/dist/settings/settings-store.d.ts +20 -0
  198. package/dist/settings/settings-store.d.ts.map +1 -0
  199. package/dist/settings/settings-store.js +82 -0
  200. package/dist/settings/settings-store.js.map +1 -0
  201. package/dist/settings/settings-ui-builder.d.ts +74 -0
  202. package/dist/settings/settings-ui-builder.d.ts.map +1 -0
  203. package/dist/settings/settings-ui-builder.js +436 -0
  204. package/dist/settings/settings-ui-builder.js.map +1 -0
  205. package/dist/string/changelog-parser.d.ts +17 -0
  206. package/dist/string/changelog-parser.d.ts.map +1 -0
  207. package/dist/string/changelog-parser.js +77 -0
  208. package/dist/string/changelog-parser.js.map +1 -0
  209. package/dist/string/filename-utils.d.ts +46 -0
  210. package/dist/string/filename-utils.d.ts.map +1 -0
  211. package/dist/string/filename-utils.js +65 -0
  212. package/dist/string/filename-utils.js.map +1 -0
  213. package/dist/string/index.d.ts +4 -0
  214. package/dist/string/index.d.ts.map +1 -0
  215. package/dist/string/index.js +4 -0
  216. package/dist/string/index.js.map +1 -0
  217. package/dist/string/string.d.ts +5 -0
  218. package/dist/string/string.d.ts.map +1 -0
  219. package/dist/string/string.js +25 -0
  220. package/dist/string/string.js.map +1 -0
  221. package/dist/testing/index.d.ts +5 -0
  222. package/dist/testing/index.d.ts.map +1 -0
  223. package/dist/testing/index.js +6 -0
  224. package/dist/testing/index.js.map +1 -0
  225. package/dist/testing/mocks/obsidian.d.ts +150 -0
  226. package/dist/testing/mocks/obsidian.d.ts.map +1 -0
  227. package/dist/testing/mocks/obsidian.js +226 -0
  228. package/dist/testing/mocks/obsidian.js.map +1 -0
  229. package/dist/testing/mocks/utils.d.ts +14 -0
  230. package/dist/testing/mocks/utils.d.ts.map +1 -0
  231. package/dist/testing/mocks/utils.js +85 -0
  232. package/dist/testing/mocks/utils.js.map +1 -0
  233. package/dist/testing/setup.d.ts +2 -0
  234. package/dist/testing/setup.d.ts.map +1 -0
  235. package/dist/testing/setup.js +18 -0
  236. package/dist/testing/setup.js.map +1 -0
  237. package/package.json +1 -1
  238. package/src/components/whats-new-modal.ts +74 -0
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Handles different link formats and edge cases:
3
+ * [[FileName]] -> FileName.md
4
+ * [[Folder/FileName]] -> Folder/FileName.md
5
+ * [[Folder/FileName|DisplayName]] -> Folder/FileName.md
6
+ * Normalizes paths and handles malformed links gracefully.
7
+ */
8
+ export const extractFilePathFromLink = (link) => {
9
+ const match = link.match(/\[\[([^|\]]+?)(?:\|.*?)?\]\]/);
10
+ if (!match)
11
+ return null;
12
+ const filePath = match[1].trim();
13
+ if (!filePath)
14
+ return null;
15
+ if (filePath.includes("[[") || filePath.includes("]]"))
16
+ return null;
17
+ return filePath.endsWith(".md") ? filePath : `${filePath}.md`;
18
+ };
19
+ /**
20
+ * Parses an Obsidian wiki link to extract the file path.
21
+ * Handles formats like:
22
+ * - [[path/to/file]]
23
+ * - [[path/to/file|Display Name]]
24
+ *
25
+ * @param link - The wiki link string
26
+ * @returns The file path without the [[ ]] brackets, or null if invalid
27
+ */
28
+ export function parseWikiLink(link) {
29
+ if (!link || typeof link !== "string") {
30
+ return null;
31
+ }
32
+ const trimmed = link.trim();
33
+ // Match [[path/to/file]] or [[path/to/file|Display Name]]
34
+ const match = trimmed.match(/^\[\[([^\]|]+)(?:\|[^\]]+)?\]\]$/);
35
+ if (!match) {
36
+ return null;
37
+ }
38
+ return match[1].trim();
39
+ }
40
+ /**
41
+ * Parses a property value that can be a single link or an array of links.
42
+ * Extracts file paths from all valid wiki links.
43
+ *
44
+ * @param value - The property value (string, string[], or undefined)
45
+ * @returns Array of file paths, empty if no valid links found
46
+ */
47
+ export function parsePropertyLinks(value) {
48
+ if (!value) {
49
+ return [];
50
+ }
51
+ const links = Array.isArray(value) ? value : [value];
52
+ return links.map((link) => parseWikiLink(link)).filter((path) => path !== null);
53
+ }
54
+ /**
55
+ * Formats a file path as an Obsidian wiki link with display name.
56
+ * Example: "Projects/MyProject" -> "[[Projects/MyProject|MyProject]]"
57
+ *
58
+ * @param filePath - The file path to format
59
+ * @returns The formatted wiki link with display name alias
60
+ */
61
+ export function formatWikiLink(filePath) {
62
+ if (!filePath || typeof filePath !== "string") {
63
+ return "";
64
+ }
65
+ const trimmed = filePath.trim();
66
+ if (!trimmed) {
67
+ return "";
68
+ }
69
+ // Extract the filename (last segment after the last /)
70
+ const segments = trimmed.split("/");
71
+ const displayName = segments[segments.length - 1];
72
+ // If there's no path separator, just return simple link
73
+ if (segments.length === 1) {
74
+ return `[[${trimmed}]]`;
75
+ }
76
+ return `[[${trimmed}|${displayName}]]`;
77
+ }
78
+ /**
79
+ * Checks if a value is an Obsidian internal link in the format [[...]]
80
+ */
81
+ export function isObsidianLink(value) {
82
+ if (typeof value !== "string")
83
+ return false;
84
+ const trimmed = value.trim();
85
+ return /^\[\[.+\]\]$/.test(trimmed);
86
+ }
87
+ /**
88
+ * Parses an Obsidian internal link and extracts its components
89
+ *
90
+ * Supports both formats:
91
+ * - Simple: [[Page Name]]
92
+ * - With alias: [[Path/To/Page|Display Name]]
93
+ */
94
+ export function parseObsidianLink(linkString) {
95
+ var _a;
96
+ if (!isObsidianLink(linkString))
97
+ return null;
98
+ const trimmed = linkString.trim();
99
+ const linkContent = (_a = trimmed.match(/^\[\[(.+?)\]\]$/)) === null || _a === void 0 ? void 0 : _a[1];
100
+ if (!linkContent)
101
+ return null;
102
+ // Handle pipe syntax: [[path|display]]
103
+ if (linkContent.includes("|")) {
104
+ const parts = linkContent.split("|");
105
+ const path = parts[0].trim();
106
+ const alias = parts.slice(1).join("|").trim(); // Handle multiple pipes
107
+ return {
108
+ raw: trimmed,
109
+ path,
110
+ alias,
111
+ };
112
+ }
113
+ // Simple format: [[path]]
114
+ const path = linkContent.trim();
115
+ return {
116
+ raw: trimmed,
117
+ path,
118
+ alias: path,
119
+ };
120
+ }
121
+ /**
122
+ * Gets the display alias from an Obsidian link
123
+ */
124
+ export function getObsidianLinkAlias(linkString) {
125
+ var _a;
126
+ const parsed = parseObsidianLink(linkString);
127
+ return (_a = parsed === null || parsed === void 0 ? void 0 : parsed.alias) !== null && _a !== void 0 ? _a : linkString;
128
+ }
129
+ /**
130
+ * Gets the file path from an Obsidian link
131
+ */
132
+ export function getObsidianLinkPath(linkString) {
133
+ var _a;
134
+ const parsed = parseObsidianLink(linkString);
135
+ return (_a = parsed === null || parsed === void 0 ? void 0 : parsed.path) !== null && _a !== void 0 ? _a : linkString;
136
+ }
137
+ //# sourceMappingURL=link-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-parser.js","sourceRoot":"","sources":["../../src/file/link-parser.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Handles different link formats and edge cases:\n * [[FileName]] -> FileName.md\n * [[Folder/FileName]] -> Folder/FileName.md\n * [[Folder/FileName|DisplayName]] -> Folder/FileName.md\n * Normalizes paths and handles malformed links gracefully.\n */\nexport const extractFilePathFromLink = (link: string): string | null => {\n\tconst match = link.match(/\\[\\[([^|\\]]+?)(?:\\|.*?)?\\]\\]/);\n\tif (!match) return null;\n\n\tconst filePath = match[1].trim();\n\tif (!filePath) return null;\n\n\tif (filePath.includes(\"[[\") || filePath.includes(\"]]\")) return null;\n\n\treturn filePath.endsWith(\".md\") ? filePath : `${filePath}.md`;\n};\n\n/**\n * Parses an Obsidian wiki link to extract the file path.\n * Handles formats like:\n * - [[path/to/file]]\n * - [[path/to/file|Display Name]]\n *\n * @param link - The wiki link string\n * @returns The file path without the [[ ]] brackets, or null if invalid\n */\nexport function parseWikiLink(link: string): string | null {\n\tif (!link || typeof link !== \"string\") {\n\t\treturn null;\n\t}\n\n\tconst trimmed = link.trim();\n\n\t// Match [[path/to/file]] or [[path/to/file|Display Name]]\n\tconst match = trimmed.match(/^\\[\\[([^\\]|]+)(?:\\|[^\\]]+)?\\]\\]$/);\n\n\tif (!match) {\n\t\treturn null;\n\t}\n\n\treturn match[1].trim();\n}\n\n/**\n * Parses a property value that can be a single link or an array of links.\n * Extracts file paths from all valid wiki links.\n *\n * @param value - The property value (string, string[], or undefined)\n * @returns Array of file paths, empty if no valid links found\n */\nexport function parsePropertyLinks(value: string | string[] | undefined): string[] {\n\tif (!value) {\n\t\treturn [];\n\t}\n\n\tconst links = Array.isArray(value) ? value : [value];\n\n\treturn links.map((link) => parseWikiLink(link)).filter((path): path is string => path !== null);\n}\n\n/**\n * Formats a file path as an Obsidian wiki link with display name.\n * Example: \"Projects/MyProject\" -> \"[[Projects/MyProject|MyProject]]\"\n *\n * @param filePath - The file path to format\n * @returns The formatted wiki link with display name alias\n */\nexport function formatWikiLink(filePath: string): string {\n\tif (!filePath || typeof filePath !== \"string\") {\n\t\treturn \"\";\n\t}\n\n\tconst trimmed = filePath.trim();\n\n\tif (!trimmed) {\n\t\treturn \"\";\n\t}\n\n\t// Extract the filename (last segment after the last /)\n\tconst segments = trimmed.split(\"/\");\n\tconst displayName = segments[segments.length - 1];\n\n\t// If there's no path separator, just return simple link\n\tif (segments.length === 1) {\n\t\treturn `[[${trimmed}]]`;\n\t}\n\n\treturn `[[${trimmed}|${displayName}]]`;\n}\n\n/**\n * Represents a parsed Obsidian link with its components\n */\nexport interface ObsidianLink {\n\traw: string;\n\tpath: string;\n\talias: string;\n}\n\n/**\n * Checks if a value is an Obsidian internal link in the format [[...]]\n */\nexport function isObsidianLink(value: unknown): boolean {\n\tif (typeof value !== \"string\") return false;\n\tconst trimmed = value.trim();\n\treturn /^\\[\\[.+\\]\\]$/.test(trimmed);\n}\n\n/**\n * Parses an Obsidian internal link and extracts its components\n *\n * Supports both formats:\n * - Simple: [[Page Name]]\n * - With alias: [[Path/To/Page|Display Name]]\n */\nexport function parseObsidianLink(linkString: string): ObsidianLink | null {\n\tif (!isObsidianLink(linkString)) return null;\n\n\tconst trimmed = linkString.trim();\n\tconst linkContent = trimmed.match(/^\\[\\[(.+?)\\]\\]$/)?.[1];\n\n\tif (!linkContent) return null;\n\n\t// Handle pipe syntax: [[path|display]]\n\tif (linkContent.includes(\"|\")) {\n\t\tconst parts = linkContent.split(\"|\");\n\t\tconst path = parts[0].trim();\n\t\tconst alias = parts.slice(1).join(\"|\").trim(); // Handle multiple pipes\n\n\t\treturn {\n\t\t\traw: trimmed,\n\t\t\tpath,\n\t\t\talias,\n\t\t};\n\t}\n\n\t// Simple format: [[path]]\n\tconst path = linkContent.trim();\n\treturn {\n\t\traw: trimmed,\n\t\tpath,\n\t\talias: path,\n\t};\n}\n\n/**\n * Gets the display alias from an Obsidian link\n */\nexport function getObsidianLinkAlias(linkString: string): string {\n\tconst parsed = parseObsidianLink(linkString);\n\treturn parsed?.alias ?? linkString;\n}\n\n/**\n * Gets the file path from an Obsidian link\n */\nexport function getObsidianLinkPath(linkString: string): string {\n\tconst parsed = parseObsidianLink(linkString);\n\treturn parsed?.path ?? linkString;\n}\n"]}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Adds a link to a property, avoiding duplicates using normalized path comparison.
3
+ * Prevents cycles and duplicate relationships by comparing normalized paths.
4
+ *
5
+ * **Important**: linkPath should be WITHOUT .md extension (wikilink format).
6
+ *
7
+ * @param currentValue - The current property value (can be string, string[], or undefined)
8
+ * @param linkPath - The file path to add (without .md extension, e.g., "folder/file")
9
+ * @returns New array with link added, or same array if link already exists
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * addLinkToProperty(undefined, "MyNote") // ["[[MyNote]]"]
14
+ * addLinkToProperty("[[Note1]]", "Note2") // ["[[Note1]]", "[[Note2]]"]
15
+ * addLinkToProperty(["[[Note1]]"], "Note2") // ["[[Note1]]", "[[Note2]]"]
16
+ * addLinkToProperty(["[[Note1]]"], "Note1") // ["[[Note1]]"] (no change - duplicate prevented)
17
+ * addLinkToProperty(["[[Folder/Note]]"], "folder/note") // ["[[Folder/Note]]", "[[folder/note|note]]"] (case-sensitive, different entry)
18
+ * ```
19
+ */
20
+ export declare function addLinkToProperty(currentValue: string | string[] | undefined, linkPath: string): string[];
21
+ /**
22
+ * Removes a link from a property using normalized path comparison.
23
+ *
24
+ * @param currentValue - The current property value (can be string, string[], or undefined)
25
+ * @param linkPath - The file path to remove (without .md extension)
26
+ * @returns New array with link removed (can be empty)
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * removeLinkFromProperty(["[[Note1]]", "[[Note2]]"], "Note1") // ["[[Note2]]"]
31
+ * removeLinkFromProperty(["[[Note1]]"], "Note1") // []
32
+ * removeLinkFromProperty("[[Note1]]", "Note1") // []
33
+ * removeLinkFromProperty(undefined, "Note1") // []
34
+ * removeLinkFromProperty(["[[Folder/Note]]"], "Folder/Note") // [] (case-sensitive removal)
35
+ * ```
36
+ */
37
+ export declare function removeLinkFromProperty(currentValue: string | string[] | undefined, linkPath: string): string[];
38
+ /**
39
+ * Checks if a link exists in a property using normalized path comparison.
40
+ *
41
+ * @param currentValue - The current property value (can be string, string[], or undefined)
42
+ * @param linkPath - The file path to check (without .md extension)
43
+ * @returns True if the link exists
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * hasLinkInProperty(["[[Note1]]", "[[Note2]]"], "Note1") // true
48
+ * hasLinkInProperty("[[Note1]]", "Note1") // true
49
+ * hasLinkInProperty([], "Note1") // false
50
+ * hasLinkInProperty(undefined, "Note1") // false
51
+ * hasLinkInProperty(["[[Folder/Note]]"], "Folder/Note") // true (case-sensitive match)
52
+ * ```
53
+ */
54
+ export declare function hasLinkInProperty(currentValue: string | string[] | undefined, linkPath: string): boolean;
55
+ //# sourceMappingURL=property-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property-utils.d.ts","sourceRoot":"","sources":["../../src/file/property-utils.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAChC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAC3C,QAAQ,EAAE,MAAM,GACd,MAAM,EAAE,CAsBV;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CACrC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAC3C,QAAQ,EAAE,MAAM,GACd,MAAM,EAAE,CAiBV;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAChC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAC3C,QAAQ,EAAE,MAAM,GACd,OAAO,CAMT"}
@@ -0,0 +1,90 @@
1
+ import { normalizePath } from "obsidian";
2
+ import { formatWikiLink, parsePropertyLinks } from "./link-parser";
3
+ /**
4
+ * Adds a link to a property, avoiding duplicates using normalized path comparison.
5
+ * Prevents cycles and duplicate relationships by comparing normalized paths.
6
+ *
7
+ * **Important**: linkPath should be WITHOUT .md extension (wikilink format).
8
+ *
9
+ * @param currentValue - The current property value (can be string, string[], or undefined)
10
+ * @param linkPath - The file path to add (without .md extension, e.g., "folder/file")
11
+ * @returns New array with link added, or same array if link already exists
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * addLinkToProperty(undefined, "MyNote") // ["[[MyNote]]"]
16
+ * addLinkToProperty("[[Note1]]", "Note2") // ["[[Note1]]", "[[Note2]]"]
17
+ * addLinkToProperty(["[[Note1]]"], "Note2") // ["[[Note1]]", "[[Note2]]"]
18
+ * addLinkToProperty(["[[Note1]]"], "Note1") // ["[[Note1]]"] (no change - duplicate prevented)
19
+ * addLinkToProperty(["[[Folder/Note]]"], "folder/note") // ["[[Folder/Note]]", "[[folder/note|note]]"] (case-sensitive, different entry)
20
+ * ```
21
+ */
22
+ export function addLinkToProperty(currentValue, linkPath) {
23
+ // Handle undefined or null
24
+ if (currentValue === undefined || currentValue === null) {
25
+ return [formatWikiLink(linkPath)];
26
+ }
27
+ // Normalize to array
28
+ const currentArray = Array.isArray(currentValue) ? currentValue : [currentValue];
29
+ const existingPaths = parsePropertyLinks(currentArray);
30
+ // Normalize paths for comparison to prevent duplicates with different casing or separators
31
+ const normalizedLinkPath = normalizePath(linkPath);
32
+ const normalizedExistingPaths = existingPaths.map((p) => normalizePath(p));
33
+ // Only add if not already present (using normalized path comparison)
34
+ if (!normalizedExistingPaths.includes(normalizedLinkPath)) {
35
+ return [...currentArray, formatWikiLink(linkPath)];
36
+ }
37
+ return currentArray;
38
+ }
39
+ /**
40
+ * Removes a link from a property using normalized path comparison.
41
+ *
42
+ * @param currentValue - The current property value (can be string, string[], or undefined)
43
+ * @param linkPath - The file path to remove (without .md extension)
44
+ * @returns New array with link removed (can be empty)
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * removeLinkFromProperty(["[[Note1]]", "[[Note2]]"], "Note1") // ["[[Note2]]"]
49
+ * removeLinkFromProperty(["[[Note1]]"], "Note1") // []
50
+ * removeLinkFromProperty("[[Note1]]", "Note1") // []
51
+ * removeLinkFromProperty(undefined, "Note1") // []
52
+ * removeLinkFromProperty(["[[Folder/Note]]"], "Folder/Note") // [] (case-sensitive removal)
53
+ * ```
54
+ */
55
+ export function removeLinkFromProperty(currentValue, linkPath) {
56
+ if (currentValue === undefined || currentValue === null) {
57
+ return [];
58
+ }
59
+ // Normalize to array
60
+ const currentArray = Array.isArray(currentValue) ? currentValue : [currentValue];
61
+ const normalizedLinkPath = normalizePath(linkPath);
62
+ return currentArray.filter((item) => {
63
+ const parsed = parsePropertyLinks([item])[0];
64
+ if (!parsed)
65
+ return true; // Keep invalid entries
66
+ return normalizePath(parsed) !== normalizedLinkPath;
67
+ });
68
+ }
69
+ /**
70
+ * Checks if a link exists in a property using normalized path comparison.
71
+ *
72
+ * @param currentValue - The current property value (can be string, string[], or undefined)
73
+ * @param linkPath - The file path to check (without .md extension)
74
+ * @returns True if the link exists
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * hasLinkInProperty(["[[Note1]]", "[[Note2]]"], "Note1") // true
79
+ * hasLinkInProperty("[[Note1]]", "Note1") // true
80
+ * hasLinkInProperty([], "Note1") // false
81
+ * hasLinkInProperty(undefined, "Note1") // false
82
+ * hasLinkInProperty(["[[Folder/Note]]"], "Folder/Note") // true (case-sensitive match)
83
+ * ```
84
+ */
85
+ export function hasLinkInProperty(currentValue, linkPath) {
86
+ const existingPaths = parsePropertyLinks(currentValue);
87
+ const normalizedLinkPath = normalizePath(linkPath);
88
+ return existingPaths.some((path) => normalizePath(path) === normalizedLinkPath);
89
+ }
90
+ //# sourceMappingURL=property-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property-utils.js","sourceRoot":"","sources":["../../src/file/property-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,iBAAiB,CAChC,YAA2C,EAC3C,QAAgB;IAEhB,2BAA2B;IAC3B,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QACzD,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,qBAAqB;IACrB,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAEjF,MAAM,aAAa,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAEvD,2FAA2F;IAC3F,MAAM,kBAAkB,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAEnD,MAAM,uBAAuB,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3E,qEAAqE;IACrE,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC3D,OAAO,CAAC,GAAG,YAAY,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,YAAY,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB,CACrC,YAA2C,EAC3C,QAAgB;IAEhB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QACzD,OAAO,EAAE,CAAC;IACX,CAAC;IAED,qBAAqB;IACrB,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAEjF,MAAM,kBAAkB,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAEnD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACnC,MAAM,MAAM,GAAG,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7C,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,CAAC,uBAAuB;QAEjD,OAAO,aAAa,CAAC,MAAM,CAAC,KAAK,kBAAkB,CAAC;IACrD,CAAC,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,iBAAiB,CAChC,YAA2C,EAC3C,QAAgB;IAEhB,MAAM,aAAa,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAEvD,MAAM,kBAAkB,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAEnD,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,kBAAkB,CAAC,CAAC;AACjF,CAAC","sourcesContent":["import { normalizePath } from \"obsidian\";\n\nimport { formatWikiLink, parsePropertyLinks } from \"./link-parser\";\n\n/**\n * Adds a link to a property, avoiding duplicates using normalized path comparison.\n * Prevents cycles and duplicate relationships by comparing normalized paths.\n *\n * **Important**: linkPath should be WITHOUT .md extension (wikilink format).\n *\n * @param currentValue - The current property value (can be string, string[], or undefined)\n * @param linkPath - The file path to add (without .md extension, e.g., \"folder/file\")\n * @returns New array with link added, or same array if link already exists\n *\n * @example\n * ```ts\n * addLinkToProperty(undefined, \"MyNote\") // [\"[[MyNote]]\"]\n * addLinkToProperty(\"[[Note1]]\", \"Note2\") // [\"[[Note1]]\", \"[[Note2]]\"]\n * addLinkToProperty([\"[[Note1]]\"], \"Note2\") // [\"[[Note1]]\", \"[[Note2]]\"]\n * addLinkToProperty([\"[[Note1]]\"], \"Note1\") // [\"[[Note1]]\"] (no change - duplicate prevented)\n * addLinkToProperty([\"[[Folder/Note]]\"], \"folder/note\") // [\"[[Folder/Note]]\", \"[[folder/note|note]]\"] (case-sensitive, different entry)\n * ```\n */\nexport function addLinkToProperty(\n\tcurrentValue: string | string[] | undefined,\n\tlinkPath: string\n): string[] {\n\t// Handle undefined or null\n\tif (currentValue === undefined || currentValue === null) {\n\t\treturn [formatWikiLink(linkPath)];\n\t}\n\n\t// Normalize to array\n\tconst currentArray = Array.isArray(currentValue) ? currentValue : [currentValue];\n\n\tconst existingPaths = parsePropertyLinks(currentArray);\n\n\t// Normalize paths for comparison to prevent duplicates with different casing or separators\n\tconst normalizedLinkPath = normalizePath(linkPath);\n\n\tconst normalizedExistingPaths = existingPaths.map((p) => normalizePath(p));\n\n\t// Only add if not already present (using normalized path comparison)\n\tif (!normalizedExistingPaths.includes(normalizedLinkPath)) {\n\t\treturn [...currentArray, formatWikiLink(linkPath)];\n\t}\n\n\treturn currentArray;\n}\n\n/**\n * Removes a link from a property using normalized path comparison.\n *\n * @param currentValue - The current property value (can be string, string[], or undefined)\n * @param linkPath - The file path to remove (without .md extension)\n * @returns New array with link removed (can be empty)\n *\n * @example\n * ```ts\n * removeLinkFromProperty([\"[[Note1]]\", \"[[Note2]]\"], \"Note1\") // [\"[[Note2]]\"]\n * removeLinkFromProperty([\"[[Note1]]\"], \"Note1\") // []\n * removeLinkFromProperty(\"[[Note1]]\", \"Note1\") // []\n * removeLinkFromProperty(undefined, \"Note1\") // []\n * removeLinkFromProperty([\"[[Folder/Note]]\"], \"Folder/Note\") // [] (case-sensitive removal)\n * ```\n */\nexport function removeLinkFromProperty(\n\tcurrentValue: string | string[] | undefined,\n\tlinkPath: string\n): string[] {\n\tif (currentValue === undefined || currentValue === null) {\n\t\treturn [];\n\t}\n\n\t// Normalize to array\n\tconst currentArray = Array.isArray(currentValue) ? currentValue : [currentValue];\n\n\tconst normalizedLinkPath = normalizePath(linkPath);\n\n\treturn currentArray.filter((item) => {\n\t\tconst parsed = parsePropertyLinks([item])[0];\n\n\t\tif (!parsed) return true; // Keep invalid entries\n\n\t\treturn normalizePath(parsed) !== normalizedLinkPath;\n\t});\n}\n\n/**\n * Checks if a link exists in a property using normalized path comparison.\n *\n * @param currentValue - The current property value (can be string, string[], or undefined)\n * @param linkPath - The file path to check (without .md extension)\n * @returns True if the link exists\n *\n * @example\n * ```ts\n * hasLinkInProperty([\"[[Note1]]\", \"[[Note2]]\"], \"Note1\") // true\n * hasLinkInProperty(\"[[Note1]]\", \"Note1\") // true\n * hasLinkInProperty([], \"Note1\") // false\n * hasLinkInProperty(undefined, \"Note1\") // false\n * hasLinkInProperty([\"[[Folder/Note]]\"], \"Folder/Note\") // true (case-sensitive match)\n * ```\n */\nexport function hasLinkInProperty(\n\tcurrentValue: string | string[] | undefined,\n\tlinkPath: string\n): boolean {\n\tconst existingPaths = parsePropertyLinks(currentValue);\n\n\tconst normalizedLinkPath = normalizePath(linkPath);\n\n\treturn existingPaths.some((path) => normalizePath(path) === normalizedLinkPath);\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import type { App, TFile } from "obsidian";
2
+ import type { FileCreationOptions } from "./templater";
3
+ export type { FileCreationOptions };
4
+ export declare class TemplaterService {
5
+ private app;
6
+ constructor(app: App);
7
+ /**
8
+ * Checks if Templater plugin is installed and enabled.
9
+ */
10
+ isAvailable(): boolean;
11
+ /**
12
+ * Creates a file using Templater or falls back to manual creation.
13
+ */
14
+ createFile(options: FileCreationOptions): Promise<TFile>;
15
+ }
16
+ //# sourceMappingURL=templater-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templater-service.d.ts","sourceRoot":"","sources":["../../src/file/templater-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAQvD,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAMpC,qBAAa,gBAAgB;IAChB,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,GAAG;IAE5B;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,KAAK,CAAC;CA2B9D"}
@@ -0,0 +1,37 @@
1
+ import { __awaiter } from "tslib";
2
+ import { createFileManually, createFromTemplate, isTemplaterAvailable, shouldUseTemplate, } from "./templater";
3
+ // ============================================================================
4
+ // Templater Service (Class-based wrapper)
5
+ // ============================================================================
6
+ export class TemplaterService {
7
+ constructor(app) {
8
+ this.app = app;
9
+ }
10
+ /**
11
+ * Checks if Templater plugin is installed and enabled.
12
+ */
13
+ isAvailable() {
14
+ return isTemplaterAvailable(this.app);
15
+ }
16
+ /**
17
+ * Creates a file using Templater or falls back to manual creation.
18
+ */
19
+ createFile(options) {
20
+ return __awaiter(this, void 0, void 0, function* () {
21
+ const { title, targetDirectory, filename, content, frontmatter, templatePath, useTemplater } = options;
22
+ const finalFilename = filename || title;
23
+ if (content) {
24
+ return createFileManually(this.app, targetDirectory, finalFilename, content, frontmatter);
25
+ }
26
+ if (useTemplater && shouldUseTemplate(this.app, templatePath)) {
27
+ const templateFile = yield createFromTemplate(this.app, templatePath, targetDirectory, finalFilename, false, frontmatter);
28
+ if (templateFile) {
29
+ return templateFile;
30
+ }
31
+ }
32
+ // Fallback to manual creation
33
+ return createFileManually(this.app, targetDirectory, finalFilename, content, frontmatter);
34
+ });
35
+ }
36
+ }
37
+ //# sourceMappingURL=templater-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templater-service.js","sourceRoot":"","sources":["../../src/file/templater-service.ts"],"names":[],"mappings":";AAEA,OAAO,EACN,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,GACjB,MAAM,aAAa,CAAC;AAIrB,+EAA+E;AAC/E,0CAA0C;AAC1C,+EAA+E;AAE/E,MAAM,OAAO,gBAAgB;IAC5B,YAAoB,GAAQ;QAAR,QAAG,GAAH,GAAG,CAAK;IAAG,CAAC;IAEhC;;OAEG;IACH,WAAW;QACV,OAAO,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACG,UAAU,CAAC,OAA4B;;YAC5C,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,GAC3F,OAAO,CAAC;YAET,MAAM,aAAa,GAAG,QAAQ,IAAI,KAAK,CAAC;YAExC,IAAI,OAAO,EAAE,CAAC;gBACb,OAAO,kBAAkB,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;YAC3F,CAAC;YAED,IAAI,YAAY,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,CAAC;gBAC/D,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAC5C,IAAI,CAAC,GAAG,EACR,YAAa,EACb,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,CACX,CAAC;gBAEF,IAAI,YAAY,EAAE,CAAC;oBAClB,OAAO,YAAY,CAAC;gBACrB,CAAC;YACF,CAAC;YACD,8BAA8B;YAC9B,OAAO,kBAAkB,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QAC3F,CAAC;KAAA;CACD","sourcesContent":["import type { App, TFile } from \"obsidian\";\nimport type { FileCreationOptions } from \"./templater\";\nimport {\n\tcreateFileManually,\n\tcreateFromTemplate,\n\tisTemplaterAvailable,\n\tshouldUseTemplate,\n} from \"./templater\";\n\nexport type { FileCreationOptions };\n\n// ============================================================================\n// Templater Service (Class-based wrapper)\n// ============================================================================\n\nexport class TemplaterService {\n\tconstructor(private app: App) {}\n\n\t/**\n\t * Checks if Templater plugin is installed and enabled.\n\t */\n\tisAvailable(): boolean {\n\t\treturn isTemplaterAvailable(this.app);\n\t}\n\n\t/**\n\t * Creates a file using Templater or falls back to manual creation.\n\t */\n\tasync createFile(options: FileCreationOptions): Promise<TFile> {\n\t\tconst { title, targetDirectory, filename, content, frontmatter, templatePath, useTemplater } =\n\t\t\toptions;\n\n\t\tconst finalFilename = filename || title;\n\n\t\tif (content) {\n\t\t\treturn createFileManually(this.app, targetDirectory, finalFilename, content, frontmatter);\n\t\t}\n\n\t\tif (useTemplater && shouldUseTemplate(this.app, templatePath)) {\n\t\t\tconst templateFile = await createFromTemplate(\n\t\t\t\tthis.app,\n\t\t\t\ttemplatePath!,\n\t\t\t\ttargetDirectory,\n\t\t\t\tfinalFilename,\n\t\t\t\tfalse,\n\t\t\t\tfrontmatter\n\t\t\t);\n\n\t\t\tif (templateFile) {\n\t\t\t\treturn templateFile;\n\t\t\t}\n\t\t}\n\t\t// Fallback to manual creation\n\t\treturn createFileManually(this.app, targetDirectory, finalFilename, content, frontmatter);\n\t}\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import { type App, TFile } from "obsidian";
2
+ export interface FileCreationOptions {
3
+ title: string;
4
+ targetDirectory: string;
5
+ filename?: string;
6
+ content?: string;
7
+ frontmatter?: Record<string, unknown>;
8
+ templatePath?: string;
9
+ useTemplater?: boolean;
10
+ }
11
+ export declare function isTemplaterAvailable(app: App): boolean;
12
+ /**
13
+ * Checks if a template should be used based on availability and file existence.
14
+ */
15
+ export declare function shouldUseTemplate(app: App, templatePath: string | undefined): boolean;
16
+ /**
17
+ * Creates a file at the specified full path with optional frontmatter and content.
18
+ * Returns existing file if it already exists.
19
+ */
20
+ export declare function createFileAtPath(app: App, filePath: string, content?: string, frontmatter?: Record<string, unknown>): Promise<TFile>;
21
+ /**
22
+ * Creates a file manually with optional frontmatter and content.
23
+ * Returns existing file if it already exists.
24
+ */
25
+ export declare function createFileManually(app: App, targetDirectory: string, filename: string, content?: string, frontmatter?: Record<string, unknown>): Promise<TFile>;
26
+ export declare function createFromTemplate(app: App, templatePath: string, targetFolder?: string, filename?: string, openNewNote?: boolean, frontmatter?: Record<string, unknown>): Promise<TFile | null>;
27
+ export declare function createFileWithTemplate(app: App, options: FileCreationOptions): Promise<TFile>;
28
+ //# sourceMappingURL=templater.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templater.d.ts","sourceRoot":"","sources":["../../src/file/templater.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAyB,KAAK,EAAE,MAAM,UAAU,CAAC;AAiBlE,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB;AAmBD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAGtD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAOrF;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACrC,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,OAAO,CAAC,KAAK,CAAC,CAkBhB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACvC,GAAG,EAAE,GAAG,EACR,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,OAAO,CAAC,KAAK,CAAC,CAKhB;AAED,wBAAsB,kBAAkB,CACvC,GAAG,EAAE,GAAG,EACR,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,UAAQ,EACnB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CA8CvB;AAED,wBAAsB,sBAAsB,CAC3C,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,mBAAmB,GAC1B,OAAO,CAAC,KAAK,CAAC,CA4BhB"}
@@ -0,0 +1,126 @@
1
+ import { __awaiter } from "tslib";
2
+ import { Notice, normalizePath, TFile } from "obsidian";
3
+ import { waitForFileReady } from "./file-utils";
4
+ import { createFileContentWithFrontmatter } from "./frontmatter-serialization";
5
+ const TEMPLATER_ID = "templater-obsidian";
6
+ function waitForTemplater(app_1) {
7
+ return __awaiter(this, arguments, void 0, function* (app, timeoutMs = 8000) {
8
+ var _a, _b, _c, _d;
9
+ yield new Promise((resolve) => app.workspace.onLayoutReady(resolve));
10
+ const started = Date.now();
11
+ while (Date.now() - started < timeoutMs) {
12
+ const plug = (_b = (_a = app.plugins) === null || _a === void 0 ? void 0 : _a.getPlugin) === null || _b === void 0 ? void 0 : _b.call(_a, TEMPLATER_ID);
13
+ const api = (_c = plug === null || plug === void 0 ? void 0 : plug.templater) !== null && _c !== void 0 ? _c : null;
14
+ const createFn = (_d = api === null || api === void 0 ? void 0 : api.create_new_note_from_template) === null || _d === void 0 ? void 0 : _d.bind(api);
15
+ if (typeof createFn === "function") {
16
+ return { create_new_note_from_template: createFn };
17
+ }
18
+ yield new Promise((r) => setTimeout(r, 150));
19
+ }
20
+ return null;
21
+ });
22
+ }
23
+ export function isTemplaterAvailable(app) {
24
+ var _a, _b;
25
+ const instance = (_b = (_a = app.plugins) === null || _a === void 0 ? void 0 : _a.getPlugin) === null || _b === void 0 ? void 0 : _b.call(_a, TEMPLATER_ID);
26
+ return !!instance;
27
+ }
28
+ /**
29
+ * Checks if a template should be used based on availability and file existence.
30
+ */
31
+ export function shouldUseTemplate(app, templatePath) {
32
+ return !!(templatePath &&
33
+ templatePath.trim() !== "" &&
34
+ isTemplaterAvailable(app) &&
35
+ app.vault.getFileByPath(templatePath));
36
+ }
37
+ /**
38
+ * Creates a file at the specified full path with optional frontmatter and content.
39
+ * Returns existing file if it already exists.
40
+ */
41
+ export function createFileAtPath(app, filePath, content, frontmatter) {
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ // Check if file already exists
44
+ const existingFile = app.vault.getAbstractFileByPath(filePath);
45
+ if (existingFile instanceof TFile) {
46
+ return existingFile;
47
+ }
48
+ const bodyContent = content || "";
49
+ let fileContent;
50
+ if (frontmatter && Object.keys(frontmatter).length > 0) {
51
+ fileContent = createFileContentWithFrontmatter(frontmatter, bodyContent);
52
+ }
53
+ else {
54
+ fileContent = bodyContent;
55
+ }
56
+ const file = yield app.vault.create(filePath, fileContent);
57
+ return file;
58
+ });
59
+ }
60
+ /**
61
+ * Creates a file manually with optional frontmatter and content.
62
+ * Returns existing file if it already exists.
63
+ */
64
+ export function createFileManually(app, targetDirectory, filename, content, frontmatter) {
65
+ return __awaiter(this, void 0, void 0, function* () {
66
+ const baseName = filename.replace(/\.md$/, "");
67
+ const filePath = `${targetDirectory}/${baseName}.md`;
68
+ return createFileAtPath(app, filePath, content, frontmatter);
69
+ });
70
+ }
71
+ export function createFromTemplate(app_1, templatePath_1, targetFolder_1, filename_1) {
72
+ return __awaiter(this, arguments, void 0, function* (app, templatePath, targetFolder, filename, openNewNote = false, frontmatter) {
73
+ const templater = yield waitForTemplater(app);
74
+ if (!templater) {
75
+ console.warn("Templater isn't ready yet (or not installed/enabled).");
76
+ new Notice("Templater plugin is not available or enabled. Please ensure it is installed and enabled.");
77
+ return null;
78
+ }
79
+ const templateFile = app.vault.getFileByPath(normalizePath(templatePath));
80
+ if (!templateFile) {
81
+ console.error(`Template not found: ${templatePath}`);
82
+ new Notice(`Template file not found: ${templatePath}. Please ensure the template file exists.`);
83
+ return null;
84
+ }
85
+ try {
86
+ const newFile = yield templater.create_new_note_from_template(templateFile, targetFolder, filename, openNewNote);
87
+ if (!newFile) {
88
+ return null;
89
+ }
90
+ if (frontmatter && Object.keys(frontmatter).length > 0) {
91
+ const readyFile = yield waitForFileReady(app, newFile.path);
92
+ if (readyFile) {
93
+ yield app.fileManager.processFrontMatter(readyFile, (fm) => {
94
+ Object.assign(fm, frontmatter);
95
+ });
96
+ return readyFile;
97
+ }
98
+ }
99
+ return newFile;
100
+ }
101
+ catch (error) {
102
+ console.error("Error creating file from template:", error);
103
+ new Notice("Error creating file from template. Please ensure the template file is valid.");
104
+ return null;
105
+ }
106
+ });
107
+ }
108
+ export function createFileWithTemplate(app, options) {
109
+ return __awaiter(this, void 0, void 0, function* () {
110
+ const { title, targetDirectory, filename, content, frontmatter, templatePath, useTemplater } = options;
111
+ const finalFilename = filename || title;
112
+ // If content is provided, use manual creation to preserve the content
113
+ if (content) {
114
+ return createFileManually(app, targetDirectory, finalFilename, content, frontmatter);
115
+ }
116
+ // Try to use template if requested and available
117
+ if (useTemplater && shouldUseTemplate(app, templatePath)) {
118
+ const templateFile = yield createFromTemplate(app, templatePath, targetDirectory, finalFilename, false, frontmatter);
119
+ if (templateFile) {
120
+ return templateFile;
121
+ }
122
+ }
123
+ return createFileManually(app, targetDirectory, finalFilename, content, frontmatter);
124
+ });
125
+ }
126
+ //# sourceMappingURL=templater.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templater.js","sourceRoot":"","sources":["../../src/file/templater.ts"],"names":[],"mappings":";AAAA,OAAO,EAAY,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAC;AAE/E,MAAM,YAAY,GAAG,oBAAoB,CAAC;AAuB1C,SAAe,gBAAgB;yDAAC,GAAQ,EAAE,SAAS,GAAG,IAAI;;QACzD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;QAE3E,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,SAAS,EAAE,CAAC;YACzC,MAAM,IAAI,GAAQ,MAAA,MAAC,GAAW,CAAC,OAAO,0CAAE,SAAS,mDAAG,YAAY,CAAC,CAAC;YAClE,MAAM,GAAG,GAAG,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,SAAS,mCAAI,IAAI,CAAC;YAEpC,MAAM,QAAQ,GAAyB,MAAA,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,6BAA6B,0CAAE,IAAI,CAAC,GAAG,CAAC,CAAC;YACrF,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;gBACpC,OAAO,EAAE,6BAA6B,EAAE,QAAQ,EAAE,CAAC;YACpD,CAAC;YACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CAAA;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAQ;;IAC5C,MAAM,QAAQ,GAAG,MAAA,MAAC,GAAW,CAAC,OAAO,0CAAE,SAAS,mDAAG,YAAY,CAAC,CAAC;IACjE,OAAO,CAAC,CAAC,QAAQ,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAQ,EAAE,YAAgC;IAC3E,OAAO,CAAC,CAAC,CACR,YAAY;QACZ,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE;QAC1B,oBAAoB,CAAC,GAAG,CAAC;QACzB,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,YAAY,CAAC,CACrC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAgB,gBAAgB,CACrC,GAAQ,EACR,QAAgB,EAChB,OAAgB,EAChB,WAAqC;;QAErC,+BAA+B;QAC/B,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAC/D,IAAI,YAAY,YAAY,KAAK,EAAE,CAAC;YACnC,OAAO,YAAY,CAAC;QACrB,CAAC;QAED,MAAM,WAAW,GAAG,OAAO,IAAI,EAAE,CAAC;QAElC,IAAI,WAAmB,CAAC;QACxB,IAAI,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxD,WAAW,GAAG,gCAAgC,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QAC1E,CAAC;aAAM,CAAC;YACP,WAAW,GAAG,WAAW,CAAC;QAC3B,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACb,CAAC;CAAA;AAED;;;GAGG;AACH,MAAM,UAAgB,kBAAkB,CACvC,GAAQ,EACR,eAAuB,EACvB,QAAgB,EAChB,OAAgB,EAChB,WAAqC;;QAErC,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,GAAG,eAAe,IAAI,QAAQ,KAAK,CAAC;QAErD,OAAO,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAC9D,CAAC;CAAA;AAED,MAAM,UAAgB,kBAAkB;yDACvC,GAAQ,EACR,YAAoB,EACpB,YAAqB,EACrB,QAAiB,EACjB,WAAW,GAAG,KAAK,EACnB,WAAqC;QAErC,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;YACtE,IAAI,MAAM,CACT,0FAA0F,CAC1F,CAAC;YACF,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;QAC1E,IAAI,CAAC,YAAY,EAAE,CAAC;YACnB,OAAO,CAAC,KAAK,CAAC,uBAAuB,YAAY,EAAE,CAAC,CAAC;YACrD,IAAI,MAAM,CAAC,4BAA4B,YAAY,2CAA2C,CAAC,CAAC;YAChG,OAAO,IAAI,CAAC;QACb,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,6BAA6B,CAC5D,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,WAAW,CACX,CAAC;YAEF,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,OAAO,IAAI,CAAC;YACb,CAAC;YAED,IAAI,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxD,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBAE5D,IAAI,SAAS,EAAE,CAAC;oBACf,MAAM,GAAG,CAAC,WAAW,CAAC,kBAAkB,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE;wBAC1D,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;oBAChC,CAAC,CAAC,CAAC;oBACH,OAAO,SAAS,CAAC;gBAClB,CAAC;YACF,CAAC;YAED,OAAO,OAAO,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;YAC3D,IAAI,MAAM,CAAC,8EAA8E,CAAC,CAAC;YAC3F,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;CAAA;AAED,MAAM,UAAgB,sBAAsB,CAC3C,GAAQ,EACR,OAA4B;;QAE5B,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,GAC3F,OAAO,CAAC;QAET,MAAM,aAAa,GAAG,QAAQ,IAAI,KAAK,CAAC;QAExC,sEAAsE;QACtE,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QACtF,CAAC;QAED,iDAAiD;QACjD,IAAI,YAAY,IAAI,iBAAiB,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,CAAC;YAC1D,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAC5C,GAAG,EACH,YAAa,EACb,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,CACX,CAAC;YAEF,IAAI,YAAY,EAAE,CAAC;gBAClB,OAAO,YAAY,CAAC;YACrB,CAAC;QACF,CAAC;QAED,OAAO,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IACtF,CAAC;CAAA","sourcesContent":["import { type App, Notice, normalizePath, TFile } from \"obsidian\";\nimport { waitForFileReady } from \"./file-utils\";\nimport { createFileContentWithFrontmatter } from \"./frontmatter-serialization\";\n\nconst TEMPLATER_ID = \"templater-obsidian\";\n\ntype CreateFn = (\n\ttemplateFile: TFile,\n\tfolder?: string,\n\tfilename?: string,\n\topenNewNote?: boolean\n) => Promise<TFile | undefined>;\n\ninterface TemplaterLike {\n\tcreate_new_note_from_template: CreateFn;\n}\n\nexport interface FileCreationOptions {\n\ttitle: string;\n\ttargetDirectory: string;\n\tfilename?: string;\n\tcontent?: string;\n\tfrontmatter?: Record<string, unknown>;\n\ttemplatePath?: string;\n\tuseTemplater?: boolean;\n}\n\nasync function waitForTemplater(app: App, timeoutMs = 8000): Promise<TemplaterLike | null> {\n\tawait new Promise<void>((resolve) => app.workspace.onLayoutReady(resolve));\n\n\tconst started = Date.now();\n\twhile (Date.now() - started < timeoutMs) {\n\t\tconst plug: any = (app as any).plugins?.getPlugin?.(TEMPLATER_ID);\n\t\tconst api = plug?.templater ?? null;\n\n\t\tconst createFn: CreateFn | undefined = api?.create_new_note_from_template?.bind(api);\n\t\tif (typeof createFn === \"function\") {\n\t\t\treturn { create_new_note_from_template: createFn };\n\t\t}\n\t\tawait new Promise((r) => setTimeout(r, 150));\n\t}\n\treturn null;\n}\n\nexport function isTemplaterAvailable(app: App): boolean {\n\tconst instance = (app as any).plugins?.getPlugin?.(TEMPLATER_ID);\n\treturn !!instance;\n}\n\n/**\n * Checks if a template should be used based on availability and file existence.\n */\nexport function shouldUseTemplate(app: App, templatePath: string | undefined): boolean {\n\treturn !!(\n\t\ttemplatePath &&\n\t\ttemplatePath.trim() !== \"\" &&\n\t\tisTemplaterAvailable(app) &&\n\t\tapp.vault.getFileByPath(templatePath)\n\t);\n}\n\n/**\n * Creates a file at the specified full path with optional frontmatter and content.\n * Returns existing file if it already exists.\n */\nexport async function createFileAtPath(\n\tapp: App,\n\tfilePath: string,\n\tcontent?: string,\n\tfrontmatter?: Record<string, unknown>\n): Promise<TFile> {\n\t// Check if file already exists\n\tconst existingFile = app.vault.getAbstractFileByPath(filePath);\n\tif (existingFile instanceof TFile) {\n\t\treturn existingFile;\n\t}\n\n\tconst bodyContent = content || \"\";\n\n\tlet fileContent: string;\n\tif (frontmatter && Object.keys(frontmatter).length > 0) {\n\t\tfileContent = createFileContentWithFrontmatter(frontmatter, bodyContent);\n\t} else {\n\t\tfileContent = bodyContent;\n\t}\n\n\tconst file = await app.vault.create(filePath, fileContent);\n\treturn file;\n}\n\n/**\n * Creates a file manually with optional frontmatter and content.\n * Returns existing file if it already exists.\n */\nexport async function createFileManually(\n\tapp: App,\n\ttargetDirectory: string,\n\tfilename: string,\n\tcontent?: string,\n\tfrontmatter?: Record<string, unknown>\n): Promise<TFile> {\n\tconst baseName = filename.replace(/\\.md$/, \"\");\n\tconst filePath = `${targetDirectory}/${baseName}.md`;\n\n\treturn createFileAtPath(app, filePath, content, frontmatter);\n}\n\nexport async function createFromTemplate(\n\tapp: App,\n\ttemplatePath: string,\n\ttargetFolder?: string,\n\tfilename?: string,\n\topenNewNote = false,\n\tfrontmatter?: Record<string, unknown>\n): Promise<TFile | null> {\n\tconst templater = await waitForTemplater(app);\n\tif (!templater) {\n\t\tconsole.warn(\"Templater isn't ready yet (or not installed/enabled).\");\n\t\tnew Notice(\n\t\t\t\"Templater plugin is not available or enabled. Please ensure it is installed and enabled.\"\n\t\t);\n\t\treturn null;\n\t}\n\n\tconst templateFile = app.vault.getFileByPath(normalizePath(templatePath));\n\tif (!templateFile) {\n\t\tconsole.error(`Template not found: ${templatePath}`);\n\t\tnew Notice(`Template file not found: ${templatePath}. Please ensure the template file exists.`);\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst newFile = await templater.create_new_note_from_template(\n\t\t\ttemplateFile,\n\t\t\ttargetFolder,\n\t\t\tfilename,\n\t\t\topenNewNote\n\t\t);\n\n\t\tif (!newFile) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (frontmatter && Object.keys(frontmatter).length > 0) {\n\t\t\tconst readyFile = await waitForFileReady(app, newFile.path);\n\n\t\t\tif (readyFile) {\n\t\t\t\tawait app.fileManager.processFrontMatter(readyFile, (fm) => {\n\t\t\t\t\tObject.assign(fm, frontmatter);\n\t\t\t\t});\n\t\t\t\treturn readyFile;\n\t\t\t}\n\t\t}\n\n\t\treturn newFile;\n\t} catch (error) {\n\t\tconsole.error(\"Error creating file from template:\", error);\n\t\tnew Notice(\"Error creating file from template. Please ensure the template file is valid.\");\n\t\treturn null;\n\t}\n}\n\nexport async function createFileWithTemplate(\n\tapp: App,\n\toptions: FileCreationOptions\n): Promise<TFile> {\n\tconst { title, targetDirectory, filename, content, frontmatter, templatePath, useTemplater } =\n\t\toptions;\n\n\tconst finalFilename = filename || title;\n\n\t// If content is provided, use manual creation to preserve the content\n\tif (content) {\n\t\treturn createFileManually(app, targetDirectory, finalFilename, content, frontmatter);\n\t}\n\n\t// Try to use template if requested and available\n\tif (useTemplater && shouldUseTemplate(app, templatePath)) {\n\t\tconst templateFile = await createFromTemplate(\n\t\t\tapp,\n\t\t\ttemplatePath!,\n\t\t\ttargetDirectory,\n\t\t\tfinalFilename,\n\t\t\tfalse,\n\t\t\tfrontmatter\n\t\t);\n\n\t\tif (templateFile) {\n\t\t\treturn templateFile;\n\t\t}\n\t}\n\n\treturn createFileManually(app, targetDirectory, finalFilename, content, frontmatter);\n}\n"]}
@@ -0,0 +1,9 @@
1
+ export * from "./async";
2
+ export * from "./components";
3
+ export * from "./core";
4
+ export * from "./date";
5
+ export * from "./file";
6
+ export * from "./inputs";
7
+ export * from "./settings";
8
+ export * from "./string";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,SAAS,CAAC;AAExB,cAAc,cAAc,CAAC;AAE7B,cAAc,QAAQ,CAAC;AAGvB,cAAc,QAAQ,CAAC;AAEvB,cAAc,QAAQ,CAAC;AAEvB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAE3B,cAAc,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ // Settings
2
+ // Async utilities
3
+ export * from "./async";
4
+ // Components
5
+ export * from "./components";
6
+ // Core utilities
7
+ export * from "./core";
8
+ // Date operations
9
+ export * from "./date";
10
+ // File operations
11
+ export * from "./file";
12
+ // Input utilities
13
+ export * from "./inputs";
14
+ export * from "./settings";
15
+ // String utilities
16
+ export * from "./string";
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AAEX,kBAAkB;AAClB,cAAc,SAAS,CAAC;AACxB,aAAa;AACb,cAAc,cAAc,CAAC;AAC7B,iBAAiB;AACjB,cAAc,QAAQ,CAAC;AAEvB,kBAAkB;AAClB,cAAc,QAAQ,CAAC;AACvB,kBAAkB;AAClB,cAAc,QAAQ,CAAC;AACvB,kBAAkB;AAClB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,mBAAmB;AACnB,cAAc,UAAU,CAAC","sourcesContent":["// Settings\n\n// Async utilities\nexport * from \"./async\";\n// Components\nexport * from \"./components\";\n// Core utilities\nexport * from \"./core\";\n\n// Date operations\nexport * from \"./date\";\n// File operations\nexport * from \"./file\";\n// Input utilities\nexport * from \"./inputs\";\nexport * from \"./settings\";\n// String utilities\nexport * from \"./string\";\n"]}
@@ -0,0 +1,2 @@
1
+ export * from "./input-filter-manager";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inputs/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./input-filter-manager";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/inputs/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC","sourcesContent":["export * from \"./input-filter-manager\";\n"]}