@real1ty-obsidian-plugins/utils 2.19.1 → 2.20.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.
@@ -23,12 +23,20 @@ export declare function parseWikiLinkWithDisplay(value: string): {
23
23
  linkPath: string;
24
24
  displayText: string;
25
25
  } | null;
26
+ export interface NormalizePropertyOptions {
27
+ /**
28
+ * Whether to log warnings for unexpected types.
29
+ * Default: false (silent mode)
30
+ */
31
+ logWarnings?: boolean;
32
+ }
26
33
  /**
27
34
  * Normalizes frontmatter property values to an array of strings.
28
35
  * Handles various YAML formats and ensures consistent output.
29
36
  *
30
37
  * @param value - The raw frontmatter property value (can be any type)
31
38
  * @param propertyName - Optional property name for logging purposes
39
+ * @param options - Optional configuration for normalization behavior
32
40
  * @returns Array of strings, or empty array if value is invalid/unexpected
33
41
  *
34
42
  * @example
@@ -38,22 +46,28 @@ export declare function parseWikiLinkWithDisplay(value: string): {
38
46
  * // Array of strings
39
47
  * normalizeProperty(["[[link1]]", "[[link2]]"]) // ["[[link1]]", "[[link2]]"]
40
48
  *
41
- * // Mixed array (filters out non-strings)
49
+ * // Mixed array (filters out non-strings silently)
42
50
  * normalizeProperty(["[[link]]", 42, null]) // ["[[link]]"]
43
51
  *
52
+ * // Mixed array with warnings enabled
53
+ * normalizeProperty(["[[link]]", 42], "myProp", { logWarnings: true })
54
+ * // Logs: Property "myProp" contains non-string value (number), filtering it out: 42
55
+ * // Returns: ["[[link]]"]
56
+ *
44
57
  * // Invalid types
45
58
  * normalizeProperty(null) // []
46
59
  * normalizeProperty(undefined) // []
47
60
  * normalizeProperty(42) // []
48
61
  * normalizeProperty({}) // []
49
62
  */
50
- export declare function normalizeProperty(value: unknown, propertyName?: string): string[];
63
+ export declare function normalizeProperty(value: unknown, propertyName?: string, options?: NormalizePropertyOptions): string[];
51
64
  /**
52
65
  * Batch normalize multiple property values from frontmatter.
53
66
  * Useful for processing multiple properties at once.
54
67
  *
55
68
  * @param frontmatter - The frontmatter object
56
69
  * @param propertyNames - Array of property names to normalize
70
+ * @param options - Optional configuration for normalization behavior
57
71
  * @returns Map of property names to normalized string arrays
58
72
  *
59
73
  * @example
@@ -70,7 +84,7 @@ export declare function normalizeProperty(value: unknown, propertyName?: string)
70
84
  * // "related" => []
71
85
  * // }
72
86
  */
73
- export declare function normalizeProperties(frontmatter: Record<string, unknown>, propertyNames: string[]): Map<string, string[]>;
87
+ export declare function normalizeProperties(frontmatter: Record<string, unknown>, propertyNames: string[], options?: NormalizePropertyOptions): Map<string, string[]>;
74
88
  /**
75
89
  * Truncates a string to a maximum length, adding ellipsis if needed.
76
90
  */
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter-value.d.ts","sourceRoot":"","sources":["../../src/core/frontmatter-value.ts"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAcpD;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAcrD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CA8CpD;AAMD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAclD;AAMD;;;;GAIG;AACH,wBAAgB,wBAAwB,CACvC,KAAK,EAAE,MAAM,GACX;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAelD;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAqDjF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAClC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,aAAa,EAAE,MAAM,EAAE,GACrB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CASvB;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAMD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAkC7E;AAMD,MAAM,WAAW,eAAe;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,SAAS,eAAe,EAC3E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,QAAQ,EAAE,SAAS,GACjB,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAgB1B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,SAAS,eAAe,EACzE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,aAAa,EAAE,MAAM,EAAE,EACvB,QAAQ,EAAE,SAAS,GACjB,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAyBxC;AAMD,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CA+CpE;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,SAAK,GAAG,MAAM,CAkCzE"}
1
+ {"version":3,"file":"frontmatter-value.d.ts","sourceRoot":"","sources":["../../src/core/frontmatter-value.ts"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAcpD;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAcrD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CA8CpD;AAMD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAclD;AAMD;;;;GAIG;AACH,wBAAgB,wBAAwB,CACvC,KAAK,EAAE,MAAM,GACX;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAelD;AAMD,MAAM,WAAW,wBAAwB;IACxC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,OAAO,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,wBAAwB,GAChC,MAAM,EAAE,CA4DV;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CAClC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE,wBAAwB,GAChC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CASvB;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAMD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAkC7E;AAMD,MAAM,WAAW,eAAe;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,SAAS,eAAe,EAC3E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,QAAQ,EAAE,SAAS,GACjB,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAgB1B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,SAAS,eAAe,EACzE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,aAAa,EAAE,MAAM,EAAE,EACvB,QAAQ,EAAE,SAAS,GACjB,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAyBxC;AAMD,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CA+CpE;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,SAAK,GAAG,MAAM,CAkCzE"}
@@ -113,15 +113,13 @@ export function parseWikiLinkWithDisplay(value) {
113
113
  const displayText = pipeIndex !== -1 ? innerContent.substring(pipeIndex + 1).trim() : linkPath;
114
114
  return { linkPath, displayText };
115
115
  }
116
- // ============================================================================
117
- // Property Normalization
118
- // ============================================================================
119
116
  /**
120
117
  * Normalizes frontmatter property values to an array of strings.
121
118
  * Handles various YAML formats and ensures consistent output.
122
119
  *
123
120
  * @param value - The raw frontmatter property value (can be any type)
124
121
  * @param propertyName - Optional property name for logging purposes
122
+ * @param options - Optional configuration for normalization behavior
125
123
  * @returns Array of strings, or empty array if value is invalid/unexpected
126
124
  *
127
125
  * @example
@@ -131,16 +129,22 @@ export function parseWikiLinkWithDisplay(value) {
131
129
  * // Array of strings
132
130
  * normalizeProperty(["[[link1]]", "[[link2]]"]) // ["[[link1]]", "[[link2]]"]
133
131
  *
134
- * // Mixed array (filters out non-strings)
132
+ * // Mixed array (filters out non-strings silently)
135
133
  * normalizeProperty(["[[link]]", 42, null]) // ["[[link]]"]
136
134
  *
135
+ * // Mixed array with warnings enabled
136
+ * normalizeProperty(["[[link]]", 42], "myProp", { logWarnings: true })
137
+ * // Logs: Property "myProp" contains non-string value (number), filtering it out: 42
138
+ * // Returns: ["[[link]]"]
139
+ *
137
140
  * // Invalid types
138
141
  * normalizeProperty(null) // []
139
142
  * normalizeProperty(undefined) // []
140
143
  * normalizeProperty(42) // []
141
144
  * normalizeProperty({}) // []
142
145
  */
143
- export function normalizeProperty(value, propertyName) {
146
+ export function normalizeProperty(value, propertyName, options) {
147
+ const { logWarnings = false } = options !== null && options !== void 0 ? options : {};
144
148
  // Handle undefined and null
145
149
  if (value === undefined || value === null) {
146
150
  return [];
@@ -164,8 +168,12 @@ export function normalizeProperty(value, propertyName) {
164
168
  if (typeof item === "string") {
165
169
  return true;
166
170
  }
167
- // Log warning for non-string items
168
- if (propertyName) {
171
+ // null and undefined are expected in YAML arrays, don't warn
172
+ if (item === null || item === undefined) {
173
+ return false;
174
+ }
175
+ // Log warning for truly unexpected types (numbers, booleans, objects, etc.)
176
+ if (logWarnings && propertyName) {
169
177
  console.warn(`Property "${propertyName}" contains non-string value (${typeof item}), filtering it out:`, item);
170
178
  }
171
179
  return false;
@@ -175,7 +183,7 @@ export function normalizeProperty(value, propertyName) {
175
183
  return nonEmptyStrings;
176
184
  }
177
185
  // Handle unexpected types (numbers, booleans, objects, etc.)
178
- if (propertyName) {
186
+ if (logWarnings && propertyName) {
179
187
  console.warn(`Property "${propertyName}" has unexpected type (${typeof value}), returning empty array. Value:`, value);
180
188
  }
181
189
  return [];
@@ -186,6 +194,7 @@ export function normalizeProperty(value, propertyName) {
186
194
  *
187
195
  * @param frontmatter - The frontmatter object
188
196
  * @param propertyNames - Array of property names to normalize
197
+ * @param options - Optional configuration for normalization behavior
189
198
  * @returns Map of property names to normalized string arrays
190
199
  *
191
200
  * @example
@@ -202,11 +211,11 @@ export function normalizeProperty(value, propertyName) {
202
211
  * // "related" => []
203
212
  * // }
204
213
  */
205
- export function normalizeProperties(frontmatter, propertyNames) {
214
+ export function normalizeProperties(frontmatter, propertyNames, options) {
206
215
  const result = new Map();
207
216
  for (const propName of propertyNames) {
208
217
  const value = frontmatter[propName];
209
- result.set(propName, normalizeProperty(value, propName));
218
+ result.set(propName, normalizeProperty(value, propName, options));
210
219
  }
211
220
  return result;
212
221
  }
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter-value.js","sourceRoot":"","sources":["../../src/core/frontmatter-value.ts"],"names":[],"mappings":"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","sourcesContent":["// ============================================================================\n// Value Checking\n// ============================================================================\n\nexport function isEmptyValue(value: unknown): boolean {\n\tif (value === null || value === undefined) {\n\t\treturn true;\n\t}\n\n\tif (typeof value === \"string\" && value.trim() === \"\") {\n\t\treturn true;\n\t}\n\n\tif (Array.isArray(value) && value.length === 0) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// ============================================================================\n// Value Serialization & Parsing (for editing in input fields)\n// ============================================================================\n\n/**\n * Serializes a frontmatter value to a string for editing in input fields.\n * Arrays are joined with \", \" for easier editing.\n */\nexport function serializeValue(value: unknown): string {\n\tif (value === null || value === undefined) {\n\t\treturn \"\";\n\t}\n\n\tif (Array.isArray(value)) {\n\t\treturn value.map((item) => serializeValue(item)).join(\", \");\n\t}\n\n\tif (typeof value === \"object\") {\n\t\treturn JSON.stringify(value);\n\t}\n\n\treturn String(value);\n}\n\n/**\n * Parses a string value from an input field into the appropriate type.\n * Handles: booleans, numbers, JSON objects/arrays, comma-separated arrays, and strings.\n */\nexport function parseValue(rawValue: string): unknown {\n\tconst trimmed = rawValue.trim();\n\n\tif (trimmed === \"\") {\n\t\treturn \"\";\n\t}\n\n\t// Parse boolean\n\tif (trimmed.toLowerCase() === \"true\") {\n\t\treturn true;\n\t}\n\tif (trimmed.toLowerCase() === \"false\") {\n\t\treturn false;\n\t}\n\n\t// Parse number\n\tif (/^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\n\t\tconst num = Number(trimmed);\n\t\tif (!Number.isNaN(num)) {\n\t\t\treturn num;\n\t\t}\n\t}\n\n\t// Parse JSON object or array (check BEFORE comma-separated arrays)\n\tif (\n\t\t(trimmed.startsWith(\"{\") && trimmed.endsWith(\"}\")) ||\n\t\t(trimmed.startsWith(\"[\") && trimmed.endsWith(\"]\"))\n\t) {\n\t\ttry {\n\t\t\treturn JSON.parse(trimmed);\n\t\t} catch {\n\t\t\t// If parsing fails, continue to other checks\n\t\t}\n\t}\n\n\t// Parse comma-separated array\n\tif (trimmed.includes(\",\")) {\n\t\tconst items = trimmed.split(\",\").map((item) => item.trim());\n\n\t\tif (items.every((item) => item.length > 0)) {\n\t\t\treturn items;\n\t\t}\n\t}\n\n\t// Default: return as string\n\treturn trimmed;\n}\n\n// ============================================================================\n// Value Formatting (for display in read-only contexts)\n// ============================================================================\n\n/**\n * Formats a frontmatter value for display in read-only contexts.\n * Converts booleans to \"Yes\"/\"No\", numbers to strings, and objects to JSON.\n */\nexport function formatValue(value: unknown): string {\n\tif (typeof value === \"boolean\") {\n\t\treturn value ? \"Yes\" : \"No\";\n\t}\n\n\tif (typeof value === \"number\") {\n\t\treturn value.toString();\n\t}\n\n\tif (typeof value === \"object\" && value !== null) {\n\t\treturn JSON.stringify(value, null, 2);\n\t}\n\n\treturn String(value);\n}\n\n// ============================================================================\n// Wiki Link Parsing\n// ============================================================================\n\n/**\n * Parses wiki link syntax from a string value.\n * Supports both [[path]] and [[path|alias]] formats.\n * Returns null if the string is not a wiki link.\n */\nexport function parseWikiLinkWithDisplay(\n\tvalue: string\n): { linkPath: string; displayText: string } | null {\n\tconst wikiLinkMatch = value.match(/^\\[\\[([^\\]]*)\\]\\]$/);\n\tif (!wikiLinkMatch) {\n\t\treturn null;\n\t}\n\n\tconst innerContent = wikiLinkMatch[1];\n\tconst pipeIndex = innerContent.indexOf(\"|\");\n\n\tconst linkPath =\n\t\tpipeIndex !== -1 ? innerContent.substring(0, pipeIndex).trim() : innerContent.trim();\n\n\tconst displayText = pipeIndex !== -1 ? innerContent.substring(pipeIndex + 1).trim() : linkPath;\n\n\treturn { linkPath, displayText };\n}\n\n// ============================================================================\n// Property Normalization\n// ============================================================================\n\n/**\n * Normalizes frontmatter property values to an array of strings.\n * Handles various YAML formats and ensures consistent output.\n *\n * @param value - The raw frontmatter property value (can be any type)\n * @param propertyName - Optional property name for logging purposes\n * @returns Array of strings, or empty array if value is invalid/unexpected\n *\n * @example\n * // Single string value\n * normalizeProperty(\"[[link]]\") // [\"[[link]]\"]\n *\n * // Array of strings\n * normalizeProperty([\"[[link1]]\", \"[[link2]]\"]) // [\"[[link1]]\", \"[[link2]]\"]\n *\n * // Mixed array (filters out non-strings)\n * normalizeProperty([\"[[link]]\", 42, null]) // [\"[[link]]\"]\n *\n * // Invalid types\n * normalizeProperty(null) // []\n * normalizeProperty(undefined) // []\n * normalizeProperty(42) // []\n * normalizeProperty({}) // []\n */\nexport function normalizeProperty(value: unknown, propertyName?: string): string[] {\n\t// Handle undefined and null\n\tif (value === undefined || value === null) {\n\t\treturn [];\n\t}\n\n\t// Handle string values - convert to single-item array\n\tif (typeof value === \"string\") {\n\t\t// Empty strings should return empty array\n\t\tif (value.trim() === \"\") {\n\t\t\treturn [];\n\t\t}\n\t\treturn [value];\n\t}\n\n\t// Handle array values\n\tif (Array.isArray(value)) {\n\t\t// Empty arrays\n\t\tif (value.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Filter to only string values\n\t\tconst stringValues = value.filter((item): item is string => {\n\t\t\tif (typeof item === \"string\") {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// Log warning for non-string items\n\t\t\tif (propertyName) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Property \"${propertyName}\" contains non-string value (${typeof item}), filtering it out:`,\n\t\t\t\t\titem\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\t\t// Filter out empty strings\n\t\tconst nonEmptyStrings = stringValues.filter((s) => s.trim() !== \"\");\n\n\t\treturn nonEmptyStrings;\n\t}\n\n\t// Handle unexpected types (numbers, booleans, objects, etc.)\n\tif (propertyName) {\n\t\tconsole.warn(\n\t\t\t`Property \"${propertyName}\" has unexpected type (${typeof value}), returning empty array. Value:`,\n\t\t\tvalue\n\t\t);\n\t}\n\n\treturn [];\n}\n\n/**\n * Batch normalize multiple property values from frontmatter.\n * Useful for processing multiple properties at once.\n *\n * @param frontmatter - The frontmatter object\n * @param propertyNames - Array of property names to normalize\n * @returns Map of property names to normalized string arrays\n *\n * @example\n * const frontmatter = {\n * parent: \"[[Parent]]\",\n * children: [\"[[Child1]]\", \"[[Child2]]\"],\n * related: null\n * };\n *\n * const normalized = normalizeProperties(frontmatter, [\"parent\", \"children\", \"related\"]);\n * // Map {\n * // \"parent\" => [\"[[Parent]]\"],\n * // \"children\" => [\"[[Child1]]\", \"[[Child2]]\"],\n * // \"related\" => []\n * // }\n */\nexport function normalizeProperties(\n\tfrontmatter: Record<string, unknown>,\n\tpropertyNames: string[]\n): Map<string, string[]> {\n\tconst result = new Map<string, string[]>();\n\n\tfor (const propName of propertyNames) {\n\t\tconst value = frontmatter[propName];\n\t\tresult.set(propName, normalizeProperty(value, propName));\n\t}\n\n\treturn result;\n}\n\n// ============================================================================\n// String Utilities\n// ============================================================================\n\n/**\n * Truncates a string to a maximum length, adding ellipsis if needed.\n */\nexport function truncateString(text: string, maxLength: number): string {\n\treturn text.length > maxLength ? `${text.substring(0, maxLength)}...` : text;\n}\n\n/**\n * Removes wiki link syntax from a string for cleaner display.\n * Converts [[Link|Alias]] to just \"Link\" or [[Link]] to \"Link\".\n */\nexport function removeWikiLinks(text: string): string {\n\treturn text.replace(/\\[\\[([^\\]|]+)(?:\\|[^\\]]+)?\\]\\]/g, \"$1\");\n}\n\n// ============================================================================\n// Array Formatting Utilities\n// ============================================================================\n\n/**\n * Formats an array as a compact comma-separated string with smart truncation.\n * Shows \"item1, item2, +3\" if the full list would exceed maxLength.\n */\nexport function formatArrayCompact(items: string[], maxLength: number): string {\n\tif (items.length === 0) {\n\t\treturn \"\";\n\t}\n\n\t// Single item - just truncate it\n\tif (items.length === 1) {\n\t\treturn truncateString(items[0], maxLength);\n\t}\n\n\tconst joined = items.join(\", \");\n\n\t// Fits within limit - return as is\n\tif (joined.length <= maxLength) {\n\t\treturn joined;\n\t}\n\n\t// Too long - show first few items + count\n\tlet result = \"\";\n\tlet count = 0;\n\n\tfor (const item of items) {\n\t\tconst testResult = result ? `${result}, ${item}` : item;\n\n\t\tif (testResult.length > maxLength - 5) {\n\t\t\tconst remaining = items.length - count;\n\t\t\treturn `${result}${remaining > 0 ? `, +${remaining}` : \"\"}`;\n\t\t}\n\n\t\tresult = testResult;\n\t\tcount++;\n\t}\n\n\treturn result;\n}\n\n// ============================================================================\n// Property Filtering (Generic over Settings)\n// ============================================================================\n\nexport interface DisplaySettings {\n\thideUnderscoreProperties?: boolean;\n\thideEmptyProperties?: boolean;\n}\n\n/**\n * Filters frontmatter properties based on display settings.\n * Returns an array of [key, value] pairs that should be displayed.\n */\nexport function filterPropertiesForDisplay<TSettings extends DisplaySettings>(\n\tfrontmatter: Record<string, unknown>,\n\tsettings: TSettings\n): Array<[string, unknown]> {\n\tconst entries = Object.entries(frontmatter);\n\n\treturn entries.filter(([key, value]) => {\n\t\t// Hide underscore properties if configured\n\t\tif (settings.hideUnderscoreProperties && key.startsWith(\"_\")) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Hide empty properties if configured\n\t\tif (settings.hideEmptyProperties && isEmptyValue(value)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t});\n}\n\n/**\n * Filters a specific list of property names from frontmatter.\n * Useful when you want to display only specific properties (like in tooltips).\n */\nexport function filterSpecificProperties<TSettings extends DisplaySettings>(\n\tfrontmatter: Record<string, unknown>,\n\tpropertyNames: string[],\n\tsettings: TSettings\n): Array<{ key: string; value: unknown }> {\n\tconst result: Array<{ key: string; value: unknown }> = [];\n\n\tfor (const propName of propertyNames) {\n\t\t// Skip if property doesn't exist in frontmatter\n\t\tif (!(propName in frontmatter)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst value = frontmatter[propName];\n\n\t\t// Hide underscore properties if configured\n\t\tif (settings.hideUnderscoreProperties && propName.startsWith(\"_\")) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Hide empty properties if configured\n\t\tif (settings.hideEmptyProperties && isEmptyValue(value)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tresult.push({ key: propName, value });\n\t}\n\n\treturn result;\n}\n\n// ============================================================================\n// Inline Wiki Link Parsing\n// ============================================================================\n\nexport interface WikiLinkSegment {\n\ttype: \"text\" | \"link\";\n\tcontent: string;\n\tlinkPath?: string;\n\tdisplayText?: string;\n}\n\n/**\n * Parses a string containing inline wiki links into segments.\n * Useful for rendering strings with clickable wiki links mixed with regular text.\n *\n * @example\n * parseInlineWikiLinks(\"Visit [[Page1]] and [[Page2|Second Page]]\")\n * // Returns:\n * // [\n * // { type: \"text\", content: \"Visit \" },\n * // { type: \"link\", content: \"[[Page1]]\", linkPath: \"Page1\", displayText: \"Page1\" },\n * // { type: \"text\", content: \" and \" },\n * // { type: \"link\", content: \"[[Page2|Second Page]]\", linkPath: \"Page2\", displayText: \"Second Page\" }\n * // ]\n */\nexport function parseInlineWikiLinks(text: string): WikiLinkSegment[] {\n\tconst segments: WikiLinkSegment[] = [];\n\tconst wikiLinkRegex = /\\[\\[([^\\]|]+)(?:\\|([^\\]]+))?\\]\\]/g;\n\tlet lastIndex = 0;\n\n\tconst matches = text.matchAll(wikiLinkRegex);\n\n\tfor (const match of matches) {\n\t\t// Add text before the link\n\t\tif (match.index !== undefined && match.index > lastIndex) {\n\t\t\tsegments.push({\n\t\t\t\ttype: \"text\",\n\t\t\t\tcontent: text.substring(lastIndex, match.index),\n\t\t\t});\n\t\t}\n\n\t\t// Add the link segment\n\t\tconst linkPath = match[1];\n\t\tconst displayText = match[2] || linkPath;\n\n\t\tsegments.push({\n\t\t\ttype: \"link\",\n\t\t\tcontent: match[0],\n\t\t\tlinkPath,\n\t\t\tdisplayText,\n\t\t});\n\n\t\tlastIndex = (match.index ?? 0) + match[0].length;\n\t}\n\n\t// Add remaining text\n\tif (lastIndex < text.length) {\n\t\tsegments.push({\n\t\t\ttype: \"text\",\n\t\t\tcontent: text.substring(lastIndex),\n\t\t});\n\t}\n\n\t// If no links found, return the entire text as a single segment\n\tif (segments.length === 0) {\n\t\tsegments.push({\n\t\t\ttype: \"text\",\n\t\t\tcontent: text,\n\t\t});\n\t}\n\n\treturn segments;\n}\n\n// ============================================================================\n// Node Display Formatting\n// ============================================================================\n\n/**\n * Formats a frontmatter value for compact display inside graph nodes.\n * Truncates long values and handles arrays gracefully.\n *\n * @param value - The frontmatter value to format\n * @param maxLength - Maximum length before truncation (default: 20)\n * @returns Formatted string suitable for node display\n *\n * @example\n * formatValueForNode(\"completed\") // \"completed\"\n * formatValueForNode(\"A very long string that exceeds the limit\") // \"A very long string...\"\n * formatValueForNode([\"tag1\", \"tag2\", \"tag3\"]) // \"tag1, tag2, tag3\"\n * formatValueForNode([\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"], 15) // \"tag1, tag2, +3\"\n * formatValueForNode(true) // \"Yes\"\n * formatValueForNode(42) // \"42\"\n */\nexport function formatValueForNode(value: unknown, maxLength = 20): string {\n\tif (isEmptyValue(value)) {\n\t\treturn \"\";\n\t}\n\n\t// Booleans: reuse formatValue logic\n\tif (typeof value === \"boolean\") {\n\t\treturn value ? \"Yes\" : \"No\";\n\t}\n\n\t// Numbers: reuse formatValue logic\n\tif (typeof value === \"number\") {\n\t\treturn value.toString();\n\t}\n\n\t// Arrays: extract strings and format compactly\n\tif (Array.isArray(value)) {\n\t\tconst stringValues = value.filter((item): item is string => typeof item === \"string\");\n\t\treturn formatArrayCompact(stringValues, maxLength);\n\t}\n\n\t// Strings: clean wiki links and truncate\n\tif (typeof value === \"string\") {\n\t\tconst cleaned = removeWikiLinks(value);\n\t\treturn truncateString(cleaned, maxLength);\n\t}\n\n\t// Objects: stringify and truncate\n\tif (typeof value === \"object\" && value !== null) {\n\t\tconst jsonStr = JSON.stringify(value);\n\t\treturn truncateString(jsonStr, maxLength);\n\t}\n\n\treturn String(value);\n}\n"]}
1
+ {"version":3,"file":"frontmatter-value.js","sourceRoot":"","sources":["../../src/core/frontmatter-value.ts"],"names":[],"mappings":"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","sourcesContent":["// ============================================================================\n// Value Checking\n// ============================================================================\n\nexport function isEmptyValue(value: unknown): boolean {\n\tif (value === null || value === undefined) {\n\t\treturn true;\n\t}\n\n\tif (typeof value === \"string\" && value.trim() === \"\") {\n\t\treturn true;\n\t}\n\n\tif (Array.isArray(value) && value.length === 0) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// ============================================================================\n// Value Serialization & Parsing (for editing in input fields)\n// ============================================================================\n\n/**\n * Serializes a frontmatter value to a string for editing in input fields.\n * Arrays are joined with \", \" for easier editing.\n */\nexport function serializeValue(value: unknown): string {\n\tif (value === null || value === undefined) {\n\t\treturn \"\";\n\t}\n\n\tif (Array.isArray(value)) {\n\t\treturn value.map((item) => serializeValue(item)).join(\", \");\n\t}\n\n\tif (typeof value === \"object\") {\n\t\treturn JSON.stringify(value);\n\t}\n\n\treturn String(value);\n}\n\n/**\n * Parses a string value from an input field into the appropriate type.\n * Handles: booleans, numbers, JSON objects/arrays, comma-separated arrays, and strings.\n */\nexport function parseValue(rawValue: string): unknown {\n\tconst trimmed = rawValue.trim();\n\n\tif (trimmed === \"\") {\n\t\treturn \"\";\n\t}\n\n\t// Parse boolean\n\tif (trimmed.toLowerCase() === \"true\") {\n\t\treturn true;\n\t}\n\tif (trimmed.toLowerCase() === \"false\") {\n\t\treturn false;\n\t}\n\n\t// Parse number\n\tif (/^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\n\t\tconst num = Number(trimmed);\n\t\tif (!Number.isNaN(num)) {\n\t\t\treturn num;\n\t\t}\n\t}\n\n\t// Parse JSON object or array (check BEFORE comma-separated arrays)\n\tif (\n\t\t(trimmed.startsWith(\"{\") && trimmed.endsWith(\"}\")) ||\n\t\t(trimmed.startsWith(\"[\") && trimmed.endsWith(\"]\"))\n\t) {\n\t\ttry {\n\t\t\treturn JSON.parse(trimmed);\n\t\t} catch {\n\t\t\t// If parsing fails, continue to other checks\n\t\t}\n\t}\n\n\t// Parse comma-separated array\n\tif (trimmed.includes(\",\")) {\n\t\tconst items = trimmed.split(\",\").map((item) => item.trim());\n\n\t\tif (items.every((item) => item.length > 0)) {\n\t\t\treturn items;\n\t\t}\n\t}\n\n\t// Default: return as string\n\treturn trimmed;\n}\n\n// ============================================================================\n// Value Formatting (for display in read-only contexts)\n// ============================================================================\n\n/**\n * Formats a frontmatter value for display in read-only contexts.\n * Converts booleans to \"Yes\"/\"No\", numbers to strings, and objects to JSON.\n */\nexport function formatValue(value: unknown): string {\n\tif (typeof value === \"boolean\") {\n\t\treturn value ? \"Yes\" : \"No\";\n\t}\n\n\tif (typeof value === \"number\") {\n\t\treturn value.toString();\n\t}\n\n\tif (typeof value === \"object\" && value !== null) {\n\t\treturn JSON.stringify(value, null, 2);\n\t}\n\n\treturn String(value);\n}\n\n// ============================================================================\n// Wiki Link Parsing\n// ============================================================================\n\n/**\n * Parses wiki link syntax from a string value.\n * Supports both [[path]] and [[path|alias]] formats.\n * Returns null if the string is not a wiki link.\n */\nexport function parseWikiLinkWithDisplay(\n\tvalue: string\n): { linkPath: string; displayText: string } | null {\n\tconst wikiLinkMatch = value.match(/^\\[\\[([^\\]]*)\\]\\]$/);\n\tif (!wikiLinkMatch) {\n\t\treturn null;\n\t}\n\n\tconst innerContent = wikiLinkMatch[1];\n\tconst pipeIndex = innerContent.indexOf(\"|\");\n\n\tconst linkPath =\n\t\tpipeIndex !== -1 ? innerContent.substring(0, pipeIndex).trim() : innerContent.trim();\n\n\tconst displayText = pipeIndex !== -1 ? innerContent.substring(pipeIndex + 1).trim() : linkPath;\n\n\treturn { linkPath, displayText };\n}\n\n// ============================================================================\n// Property Normalization\n// ============================================================================\n\nexport interface NormalizePropertyOptions {\n\t/**\n\t * Whether to log warnings for unexpected types.\n\t * Default: false (silent mode)\n\t */\n\tlogWarnings?: boolean;\n}\n\n/**\n * Normalizes frontmatter property values to an array of strings.\n * Handles various YAML formats and ensures consistent output.\n *\n * @param value - The raw frontmatter property value (can be any type)\n * @param propertyName - Optional property name for logging purposes\n * @param options - Optional configuration for normalization behavior\n * @returns Array of strings, or empty array if value is invalid/unexpected\n *\n * @example\n * // Single string value\n * normalizeProperty(\"[[link]]\") // [\"[[link]]\"]\n *\n * // Array of strings\n * normalizeProperty([\"[[link1]]\", \"[[link2]]\"]) // [\"[[link1]]\", \"[[link2]]\"]\n *\n * // Mixed array (filters out non-strings silently)\n * normalizeProperty([\"[[link]]\", 42, null]) // [\"[[link]]\"]\n *\n * // Mixed array with warnings enabled\n * normalizeProperty([\"[[link]]\", 42], \"myProp\", { logWarnings: true })\n * // Logs: Property \"myProp\" contains non-string value (number), filtering it out: 42\n * // Returns: [\"[[link]]\"]\n *\n * // Invalid types\n * normalizeProperty(null) // []\n * normalizeProperty(undefined) // []\n * normalizeProperty(42) // []\n * normalizeProperty({}) // []\n */\nexport function normalizeProperty(\n\tvalue: unknown,\n\tpropertyName?: string,\n\toptions?: NormalizePropertyOptions\n): string[] {\n\tconst { logWarnings = false } = options ?? {};\n\n\t// Handle undefined and null\n\tif (value === undefined || value === null) {\n\t\treturn [];\n\t}\n\n\t// Handle string values - convert to single-item array\n\tif (typeof value === \"string\") {\n\t\t// Empty strings should return empty array\n\t\tif (value.trim() === \"\") {\n\t\t\treturn [];\n\t\t}\n\t\treturn [value];\n\t}\n\n\t// Handle array values\n\tif (Array.isArray(value)) {\n\t\t// Empty arrays\n\t\tif (value.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Filter to only string values\n\t\tconst stringValues = value.filter((item): item is string => {\n\t\t\tif (typeof item === \"string\") {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// null and undefined are expected in YAML arrays, don't warn\n\t\t\tif (item === null || item === undefined) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Log warning for truly unexpected types (numbers, booleans, objects, etc.)\n\t\t\tif (logWarnings && propertyName) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Property \"${propertyName}\" contains non-string value (${typeof item}), filtering it out:`,\n\t\t\t\t\titem\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\t\t// Filter out empty strings\n\t\tconst nonEmptyStrings = stringValues.filter((s) => s.trim() !== \"\");\n\n\t\treturn nonEmptyStrings;\n\t}\n\n\t// Handle unexpected types (numbers, booleans, objects, etc.)\n\tif (logWarnings && propertyName) {\n\t\tconsole.warn(\n\t\t\t`Property \"${propertyName}\" has unexpected type (${typeof value}), returning empty array. Value:`,\n\t\t\tvalue\n\t\t);\n\t}\n\n\treturn [];\n}\n\n/**\n * Batch normalize multiple property values from frontmatter.\n * Useful for processing multiple properties at once.\n *\n * @param frontmatter - The frontmatter object\n * @param propertyNames - Array of property names to normalize\n * @param options - Optional configuration for normalization behavior\n * @returns Map of property names to normalized string arrays\n *\n * @example\n * const frontmatter = {\n * parent: \"[[Parent]]\",\n * children: [\"[[Child1]]\", \"[[Child2]]\"],\n * related: null\n * };\n *\n * const normalized = normalizeProperties(frontmatter, [\"parent\", \"children\", \"related\"]);\n * // Map {\n * // \"parent\" => [\"[[Parent]]\"],\n * // \"children\" => [\"[[Child1]]\", \"[[Child2]]\"],\n * // \"related\" => []\n * // }\n */\nexport function normalizeProperties(\n\tfrontmatter: Record<string, unknown>,\n\tpropertyNames: string[],\n\toptions?: NormalizePropertyOptions\n): Map<string, string[]> {\n\tconst result = new Map<string, string[]>();\n\n\tfor (const propName of propertyNames) {\n\t\tconst value = frontmatter[propName];\n\t\tresult.set(propName, normalizeProperty(value, propName, options));\n\t}\n\n\treturn result;\n}\n\n// ============================================================================\n// String Utilities\n// ============================================================================\n\n/**\n * Truncates a string to a maximum length, adding ellipsis if needed.\n */\nexport function truncateString(text: string, maxLength: number): string {\n\treturn text.length > maxLength ? `${text.substring(0, maxLength)}...` : text;\n}\n\n/**\n * Removes wiki link syntax from a string for cleaner display.\n * Converts [[Link|Alias]] to just \"Link\" or [[Link]] to \"Link\".\n */\nexport function removeWikiLinks(text: string): string {\n\treturn text.replace(/\\[\\[([^\\]|]+)(?:\\|[^\\]]+)?\\]\\]/g, \"$1\");\n}\n\n// ============================================================================\n// Array Formatting Utilities\n// ============================================================================\n\n/**\n * Formats an array as a compact comma-separated string with smart truncation.\n * Shows \"item1, item2, +3\" if the full list would exceed maxLength.\n */\nexport function formatArrayCompact(items: string[], maxLength: number): string {\n\tif (items.length === 0) {\n\t\treturn \"\";\n\t}\n\n\t// Single item - just truncate it\n\tif (items.length === 1) {\n\t\treturn truncateString(items[0], maxLength);\n\t}\n\n\tconst joined = items.join(\", \");\n\n\t// Fits within limit - return as is\n\tif (joined.length <= maxLength) {\n\t\treturn joined;\n\t}\n\n\t// Too long - show first few items + count\n\tlet result = \"\";\n\tlet count = 0;\n\n\tfor (const item of items) {\n\t\tconst testResult = result ? `${result}, ${item}` : item;\n\n\t\tif (testResult.length > maxLength - 5) {\n\t\t\tconst remaining = items.length - count;\n\t\t\treturn `${result}${remaining > 0 ? `, +${remaining}` : \"\"}`;\n\t\t}\n\n\t\tresult = testResult;\n\t\tcount++;\n\t}\n\n\treturn result;\n}\n\n// ============================================================================\n// Property Filtering (Generic over Settings)\n// ============================================================================\n\nexport interface DisplaySettings {\n\thideUnderscoreProperties?: boolean;\n\thideEmptyProperties?: boolean;\n}\n\n/**\n * Filters frontmatter properties based on display settings.\n * Returns an array of [key, value] pairs that should be displayed.\n */\nexport function filterPropertiesForDisplay<TSettings extends DisplaySettings>(\n\tfrontmatter: Record<string, unknown>,\n\tsettings: TSettings\n): Array<[string, unknown]> {\n\tconst entries = Object.entries(frontmatter);\n\n\treturn entries.filter(([key, value]) => {\n\t\t// Hide underscore properties if configured\n\t\tif (settings.hideUnderscoreProperties && key.startsWith(\"_\")) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Hide empty properties if configured\n\t\tif (settings.hideEmptyProperties && isEmptyValue(value)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t});\n}\n\n/**\n * Filters a specific list of property names from frontmatter.\n * Useful when you want to display only specific properties (like in tooltips).\n */\nexport function filterSpecificProperties<TSettings extends DisplaySettings>(\n\tfrontmatter: Record<string, unknown>,\n\tpropertyNames: string[],\n\tsettings: TSettings\n): Array<{ key: string; value: unknown }> {\n\tconst result: Array<{ key: string; value: unknown }> = [];\n\n\tfor (const propName of propertyNames) {\n\t\t// Skip if property doesn't exist in frontmatter\n\t\tif (!(propName in frontmatter)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst value = frontmatter[propName];\n\n\t\t// Hide underscore properties if configured\n\t\tif (settings.hideUnderscoreProperties && propName.startsWith(\"_\")) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Hide empty properties if configured\n\t\tif (settings.hideEmptyProperties && isEmptyValue(value)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tresult.push({ key: propName, value });\n\t}\n\n\treturn result;\n}\n\n// ============================================================================\n// Inline Wiki Link Parsing\n// ============================================================================\n\nexport interface WikiLinkSegment {\n\ttype: \"text\" | \"link\";\n\tcontent: string;\n\tlinkPath?: string;\n\tdisplayText?: string;\n}\n\n/**\n * Parses a string containing inline wiki links into segments.\n * Useful for rendering strings with clickable wiki links mixed with regular text.\n *\n * @example\n * parseInlineWikiLinks(\"Visit [[Page1]] and [[Page2|Second Page]]\")\n * // Returns:\n * // [\n * // { type: \"text\", content: \"Visit \" },\n * // { type: \"link\", content: \"[[Page1]]\", linkPath: \"Page1\", displayText: \"Page1\" },\n * // { type: \"text\", content: \" and \" },\n * // { type: \"link\", content: \"[[Page2|Second Page]]\", linkPath: \"Page2\", displayText: \"Second Page\" }\n * // ]\n */\nexport function parseInlineWikiLinks(text: string): WikiLinkSegment[] {\n\tconst segments: WikiLinkSegment[] = [];\n\tconst wikiLinkRegex = /\\[\\[([^\\]|]+)(?:\\|([^\\]]+))?\\]\\]/g;\n\tlet lastIndex = 0;\n\n\tconst matches = text.matchAll(wikiLinkRegex);\n\n\tfor (const match of matches) {\n\t\t// Add text before the link\n\t\tif (match.index !== undefined && match.index > lastIndex) {\n\t\t\tsegments.push({\n\t\t\t\ttype: \"text\",\n\t\t\t\tcontent: text.substring(lastIndex, match.index),\n\t\t\t});\n\t\t}\n\n\t\t// Add the link segment\n\t\tconst linkPath = match[1];\n\t\tconst displayText = match[2] || linkPath;\n\n\t\tsegments.push({\n\t\t\ttype: \"link\",\n\t\t\tcontent: match[0],\n\t\t\tlinkPath,\n\t\t\tdisplayText,\n\t\t});\n\n\t\tlastIndex = (match.index ?? 0) + match[0].length;\n\t}\n\n\t// Add remaining text\n\tif (lastIndex < text.length) {\n\t\tsegments.push({\n\t\t\ttype: \"text\",\n\t\t\tcontent: text.substring(lastIndex),\n\t\t});\n\t}\n\n\t// If no links found, return the entire text as a single segment\n\tif (segments.length === 0) {\n\t\tsegments.push({\n\t\t\ttype: \"text\",\n\t\t\tcontent: text,\n\t\t});\n\t}\n\n\treturn segments;\n}\n\n// ============================================================================\n// Node Display Formatting\n// ============================================================================\n\n/**\n * Formats a frontmatter value for compact display inside graph nodes.\n * Truncates long values and handles arrays gracefully.\n *\n * @param value - The frontmatter value to format\n * @param maxLength - Maximum length before truncation (default: 20)\n * @returns Formatted string suitable for node display\n *\n * @example\n * formatValueForNode(\"completed\") // \"completed\"\n * formatValueForNode(\"A very long string that exceeds the limit\") // \"A very long string...\"\n * formatValueForNode([\"tag1\", \"tag2\", \"tag3\"]) // \"tag1, tag2, tag3\"\n * formatValueForNode([\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"], 15) // \"tag1, tag2, +3\"\n * formatValueForNode(true) // \"Yes\"\n * formatValueForNode(42) // \"42\"\n */\nexport function formatValueForNode(value: unknown, maxLength = 20): string {\n\tif (isEmptyValue(value)) {\n\t\treturn \"\";\n\t}\n\n\t// Booleans: reuse formatValue logic\n\tif (typeof value === \"boolean\") {\n\t\treturn value ? \"Yes\" : \"No\";\n\t}\n\n\t// Numbers: reuse formatValue logic\n\tif (typeof value === \"number\") {\n\t\treturn value.toString();\n\t}\n\n\t// Arrays: extract strings and format compactly\n\tif (Array.isArray(value)) {\n\t\tconst stringValues = value.filter((item): item is string => typeof item === \"string\");\n\t\treturn formatArrayCompact(stringValues, maxLength);\n\t}\n\n\t// Strings: clean wiki links and truncate\n\tif (typeof value === \"string\") {\n\t\tconst cleaned = removeWikiLinks(value);\n\t\treturn truncateString(cleaned, maxLength);\n\t}\n\n\t// Objects: stringify and truncate\n\tif (typeof value === \"object\" && value !== null) {\n\t\tconst jsonStr = JSON.stringify(value);\n\t\treturn truncateString(jsonStr, maxLength);\n\t}\n\n\treturn String(value);\n}\n"]}
@@ -8,4 +8,5 @@ export * from "./frontmatter-propagation";
8
8
  export * from "./link-parser";
9
9
  export * from "./property-utils";
10
10
  export * from "./templater";
11
+ export * from "./templater-service";
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/file/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,QAAQ,CAAC;AACvB,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/file/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,QAAQ,CAAC;AACvB,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC"}
@@ -8,4 +8,5 @@ export * from "./frontmatter-propagation";
8
8
  export * from "./link-parser";
9
9
  export * from "./property-utils";
10
10
  export * from "./templater";
11
+ export * from "./templater-service";
11
12
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/file/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,QAAQ,CAAC;AACvB,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC","sourcesContent":["export * from \"./child-reference\";\nexport * from \"./file\";\nexport * from \"./file-operations\";\nexport * from \"./file-utils\";\nexport * from \"./frontmatter\";\nexport * from \"./frontmatter-diff\";\nexport * from \"./frontmatter-propagation\";\nexport * from \"./link-parser\";\nexport * from \"./property-utils\";\nexport * from \"./templater\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/file/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,QAAQ,CAAC;AACvB,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC","sourcesContent":["export * from \"./child-reference\";\nexport * from \"./file\";\nexport * from \"./file-operations\";\nexport * from \"./file-utils\";\nexport * from \"./frontmatter\";\nexport * from \"./frontmatter-diff\";\nexport * from \"./frontmatter-propagation\";\nexport * from \"./link-parser\";\nexport * from \"./property-utils\";\nexport * from \"./templater\";\nexport * from \"./templater-service\";\n"]}
@@ -0,0 +1,18 @@
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
+ private shouldUseTemplate;
16
+ private createManually;
17
+ }
18
+ //# 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,EAAE,KAAK,GAAG,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGvD,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;IAmC9D,OAAO,CAAC,iBAAiB;YAIX,cAAc;CA8B5B"}
@@ -0,0 +1,70 @@
1
+ import { __awaiter } from "tslib";
2
+ import { TFile } from "obsidian";
3
+ import { createFromTemplate, isTemplaterAvailable } from "./templater";
4
+ // ============================================================================
5
+ // Templater Service (Class-based wrapper)
6
+ // ============================================================================
7
+ export class TemplaterService {
8
+ constructor(app) {
9
+ this.app = app;
10
+ }
11
+ /**
12
+ * Checks if Templater plugin is installed and enabled.
13
+ */
14
+ isAvailable() {
15
+ return isTemplaterAvailable(this.app);
16
+ }
17
+ /**
18
+ * Creates a file using Templater or falls back to manual creation.
19
+ */
20
+ createFile(options) {
21
+ return __awaiter(this, void 0, void 0, function* () {
22
+ const { title, targetDirectory, filename, content, frontmatter, templatePath, useTemplater } = options;
23
+ const finalFilename = filename || title;
24
+ // If content is provided, use manual creation to preserve the content
25
+ if (content) {
26
+ return this.createManually(title, targetDirectory, finalFilename, content, frontmatter);
27
+ }
28
+ // Try to use Templater if requested and available
29
+ if (useTemplater && templatePath && this.shouldUseTemplate(templatePath)) {
30
+ const templateFile = yield createFromTemplate(this.app, templatePath, targetDirectory, finalFilename);
31
+ if (templateFile) {
32
+ // Apply frontmatter if provided
33
+ if (frontmatter && Object.keys(frontmatter).length > 0) {
34
+ yield this.app.fileManager.processFrontMatter(templateFile, (fm) => {
35
+ Object.assign(fm, frontmatter);
36
+ });
37
+ }
38
+ return templateFile;
39
+ }
40
+ }
41
+ // Fallback to manual creation
42
+ return this.createManually(title, targetDirectory, finalFilename, content, frontmatter);
43
+ });
44
+ }
45
+ shouldUseTemplate(templatePath) {
46
+ return !!(templatePath && this.isAvailable() && this.app.vault.getFileByPath(templatePath));
47
+ }
48
+ createManually(title, targetDirectory, filename, customContent, frontmatter) {
49
+ return __awaiter(this, void 0, void 0, function* () {
50
+ const baseName = filename.replace(/\.md$/, "");
51
+ const filePath = `${targetDirectory}/${baseName}.md`;
52
+ // Check if file already exists
53
+ const existingFile = this.app.vault.getAbstractFileByPath(filePath);
54
+ if (existingFile instanceof TFile) {
55
+ return existingFile;
56
+ }
57
+ // Use custom content or default
58
+ const content = customContent || `# ${title}\n\n`;
59
+ const file = yield this.app.vault.create(filePath, content);
60
+ // Apply frontmatter if provided
61
+ if (frontmatter && Object.keys(frontmatter).length > 0) {
62
+ yield this.app.fileManager.processFrontMatter(file, (fm) => {
63
+ Object.assign(fm, frontmatter);
64
+ });
65
+ }
66
+ return file;
67
+ });
68
+ }
69
+ }
70
+ //# sourceMappingURL=templater-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templater-service.js","sourceRoot":"","sources":["../../src/file/templater-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { type App, TFile } from \"obsidian\";\nimport type { FileCreationOptions } from \"./templater\";\nimport { createFromTemplate, isTemplaterAvailable } 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\t// If content is provided, use manual creation to preserve the content\n\t\tif (content) {\n\t\t\treturn this.createManually(title, targetDirectory, finalFilename, content, frontmatter);\n\t\t}\n\n\t\t// Try to use Templater if requested and available\n\t\tif (useTemplater && templatePath && this.shouldUseTemplate(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);\n\n\t\t\tif (templateFile) {\n\t\t\t\t// Apply frontmatter if provided\n\t\t\t\tif (frontmatter && Object.keys(frontmatter).length > 0) {\n\t\t\t\t\tawait this.app.fileManager.processFrontMatter(templateFile, (fm) => {\n\t\t\t\t\t\tObject.assign(fm, frontmatter);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn templateFile;\n\t\t\t}\n\t\t}\n\n\t\t// Fallback to manual creation\n\t\treturn this.createManually(title, targetDirectory, finalFilename, content, frontmatter);\n\t}\n\n\tprivate shouldUseTemplate(templatePath: string): boolean {\n\t\treturn !!(templatePath && this.isAvailable() && this.app.vault.getFileByPath(templatePath));\n\t}\n\n\tprivate async createManually(\n\t\ttitle: string,\n\t\ttargetDirectory: string,\n\t\tfilename: string,\n\t\tcustomContent?: string,\n\t\tfrontmatter?: Record<string, unknown>\n\t): Promise<TFile> {\n\t\tconst baseName = filename.replace(/\\.md$/, \"\");\n\t\tconst filePath = `${targetDirectory}/${baseName}.md`;\n\n\t\t// Check if file already exists\n\t\tconst existingFile = this.app.vault.getAbstractFileByPath(filePath);\n\t\tif (existingFile instanceof TFile) {\n\t\t\treturn existingFile;\n\t\t}\n\n\t\t// Use custom content or default\n\t\tconst content = customContent || `# ${title}\\n\\n`;\n\n\t\tconst file = await this.app.vault.create(filePath, content);\n\n\t\t// Apply frontmatter if provided\n\t\tif (frontmatter && Object.keys(frontmatter).length > 0) {\n\t\t\tawait this.app.fileManager.processFrontMatter(file, (fm) => {\n\t\t\t\tObject.assign(fm, frontmatter);\n\t\t\t});\n\t\t}\n\n\t\treturn file;\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real1ty-obsidian-plugins/utils",
3
- "version": "2.19.1",
3
+ "version": "2.20.0",
4
4
  "description": "Shared utilities for Obsidian plugins",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -150,12 +150,21 @@ export function parseWikiLinkWithDisplay(
150
150
  // Property Normalization
151
151
  // ============================================================================
152
152
 
153
+ export interface NormalizePropertyOptions {
154
+ /**
155
+ * Whether to log warnings for unexpected types.
156
+ * Default: false (silent mode)
157
+ */
158
+ logWarnings?: boolean;
159
+ }
160
+
153
161
  /**
154
162
  * Normalizes frontmatter property values to an array of strings.
155
163
  * Handles various YAML formats and ensures consistent output.
156
164
  *
157
165
  * @param value - The raw frontmatter property value (can be any type)
158
166
  * @param propertyName - Optional property name for logging purposes
167
+ * @param options - Optional configuration for normalization behavior
159
168
  * @returns Array of strings, or empty array if value is invalid/unexpected
160
169
  *
161
170
  * @example
@@ -165,16 +174,27 @@ export function parseWikiLinkWithDisplay(
165
174
  * // Array of strings
166
175
  * normalizeProperty(["[[link1]]", "[[link2]]"]) // ["[[link1]]", "[[link2]]"]
167
176
  *
168
- * // Mixed array (filters out non-strings)
177
+ * // Mixed array (filters out non-strings silently)
169
178
  * normalizeProperty(["[[link]]", 42, null]) // ["[[link]]"]
170
179
  *
180
+ * // Mixed array with warnings enabled
181
+ * normalizeProperty(["[[link]]", 42], "myProp", { logWarnings: true })
182
+ * // Logs: Property "myProp" contains non-string value (number), filtering it out: 42
183
+ * // Returns: ["[[link]]"]
184
+ *
171
185
  * // Invalid types
172
186
  * normalizeProperty(null) // []
173
187
  * normalizeProperty(undefined) // []
174
188
  * normalizeProperty(42) // []
175
189
  * normalizeProperty({}) // []
176
190
  */
177
- export function normalizeProperty(value: unknown, propertyName?: string): string[] {
191
+ export function normalizeProperty(
192
+ value: unknown,
193
+ propertyName?: string,
194
+ options?: NormalizePropertyOptions
195
+ ): string[] {
196
+ const { logWarnings = false } = options ?? {};
197
+
178
198
  // Handle undefined and null
179
199
  if (value === undefined || value === null) {
180
200
  return [];
@@ -202,8 +222,13 @@ export function normalizeProperty(value: unknown, propertyName?: string): string
202
222
  return true;
203
223
  }
204
224
 
205
- // Log warning for non-string items
206
- if (propertyName) {
225
+ // null and undefined are expected in YAML arrays, don't warn
226
+ if (item === null || item === undefined) {
227
+ return false;
228
+ }
229
+
230
+ // Log warning for truly unexpected types (numbers, booleans, objects, etc.)
231
+ if (logWarnings && propertyName) {
207
232
  console.warn(
208
233
  `Property "${propertyName}" contains non-string value (${typeof item}), filtering it out:`,
209
234
  item
@@ -219,7 +244,7 @@ export function normalizeProperty(value: unknown, propertyName?: string): string
219
244
  }
220
245
 
221
246
  // Handle unexpected types (numbers, booleans, objects, etc.)
222
- if (propertyName) {
247
+ if (logWarnings && propertyName) {
223
248
  console.warn(
224
249
  `Property "${propertyName}" has unexpected type (${typeof value}), returning empty array. Value:`,
225
250
  value
@@ -235,6 +260,7 @@ export function normalizeProperty(value: unknown, propertyName?: string): string
235
260
  *
236
261
  * @param frontmatter - The frontmatter object
237
262
  * @param propertyNames - Array of property names to normalize
263
+ * @param options - Optional configuration for normalization behavior
238
264
  * @returns Map of property names to normalized string arrays
239
265
  *
240
266
  * @example
@@ -253,13 +279,14 @@ export function normalizeProperty(value: unknown, propertyName?: string): string
253
279
  */
254
280
  export function normalizeProperties(
255
281
  frontmatter: Record<string, unknown>,
256
- propertyNames: string[]
282
+ propertyNames: string[],
283
+ options?: NormalizePropertyOptions
257
284
  ): Map<string, string[]> {
258
285
  const result = new Map<string, string[]>();
259
286
 
260
287
  for (const propName of propertyNames) {
261
288
  const value = frontmatter[propName];
262
- result.set(propName, normalizeProperty(value, propName));
289
+ result.set(propName, normalizeProperty(value, propName, options));
263
290
  }
264
291
 
265
292
  return result;
package/src/file/index.ts CHANGED
@@ -8,3 +8,4 @@ export * from "./frontmatter-propagation";
8
8
  export * from "./link-parser";
9
9
  export * from "./property-utils";
10
10
  export * from "./templater";
11
+ export * from "./templater-service";
@@ -0,0 +1,93 @@
1
+ import { type App, TFile } from "obsidian";
2
+ import type { FileCreationOptions } from "./templater";
3
+ import { createFromTemplate, isTemplaterAvailable } from "./templater";
4
+
5
+ export type { FileCreationOptions };
6
+
7
+ // ============================================================================
8
+ // Templater Service (Class-based wrapper)
9
+ // ============================================================================
10
+
11
+ export class TemplaterService {
12
+ constructor(private app: App) {}
13
+
14
+ /**
15
+ * Checks if Templater plugin is installed and enabled.
16
+ */
17
+ isAvailable(): boolean {
18
+ return isTemplaterAvailable(this.app);
19
+ }
20
+
21
+ /**
22
+ * Creates a file using Templater or falls back to manual creation.
23
+ */
24
+ async createFile(options: FileCreationOptions): Promise<TFile> {
25
+ const { title, targetDirectory, filename, content, frontmatter, templatePath, useTemplater } =
26
+ options;
27
+
28
+ const finalFilename = filename || title;
29
+
30
+ // If content is provided, use manual creation to preserve the content
31
+ if (content) {
32
+ return this.createManually(title, targetDirectory, finalFilename, content, frontmatter);
33
+ }
34
+
35
+ // Try to use Templater if requested and available
36
+ if (useTemplater && templatePath && this.shouldUseTemplate(templatePath)) {
37
+ const templateFile = await createFromTemplate(
38
+ this.app,
39
+ templatePath,
40
+ targetDirectory,
41
+ finalFilename
42
+ );
43
+
44
+ if (templateFile) {
45
+ // Apply frontmatter if provided
46
+ if (frontmatter && Object.keys(frontmatter).length > 0) {
47
+ await this.app.fileManager.processFrontMatter(templateFile, (fm) => {
48
+ Object.assign(fm, frontmatter);
49
+ });
50
+ }
51
+ return templateFile;
52
+ }
53
+ }
54
+
55
+ // Fallback to manual creation
56
+ return this.createManually(title, targetDirectory, finalFilename, content, frontmatter);
57
+ }
58
+
59
+ private shouldUseTemplate(templatePath: string): boolean {
60
+ return !!(templatePath && this.isAvailable() && this.app.vault.getFileByPath(templatePath));
61
+ }
62
+
63
+ private async createManually(
64
+ title: string,
65
+ targetDirectory: string,
66
+ filename: string,
67
+ customContent?: string,
68
+ frontmatter?: Record<string, unknown>
69
+ ): Promise<TFile> {
70
+ const baseName = filename.replace(/\.md$/, "");
71
+ const filePath = `${targetDirectory}/${baseName}.md`;
72
+
73
+ // Check if file already exists
74
+ const existingFile = this.app.vault.getAbstractFileByPath(filePath);
75
+ if (existingFile instanceof TFile) {
76
+ return existingFile;
77
+ }
78
+
79
+ // Use custom content or default
80
+ const content = customContent || `# ${title}\n\n`;
81
+
82
+ const file = await this.app.vault.create(filePath, content);
83
+
84
+ // Apply frontmatter if provided
85
+ if (frontmatter && Object.keys(frontmatter).length > 0) {
86
+ await this.app.fileManager.processFrontMatter(file, (fm) => {
87
+ Object.assign(fm, frontmatter);
88
+ });
89
+ }
90
+
91
+ return file;
92
+ }
93
+ }