@real1ty-obsidian-plugins/utils 2.5.0 → 2.7.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 (44) hide show
  1. package/dist/core/evaluator/filter.d.ts.map +1 -1
  2. package/dist/core/evaluator/filter.js.map +1 -1
  3. package/dist/core/frontmatter-value.d.ts +143 -0
  4. package/dist/core/frontmatter-value.d.ts.map +1 -0
  5. package/dist/core/frontmatter-value.js +408 -0
  6. package/dist/core/frontmatter-value.js.map +1 -0
  7. package/dist/core/index.d.ts +1 -0
  8. package/dist/core/index.d.ts.map +1 -1
  9. package/dist/core/index.js +1 -0
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/file/index.d.ts +1 -0
  12. package/dist/file/index.d.ts.map +1 -1
  13. package/dist/file/index.js +1 -0
  14. package/dist/file/index.js.map +1 -1
  15. package/dist/file/link-parser.d.ts +26 -0
  16. package/dist/file/link-parser.d.ts.map +1 -1
  17. package/dist/file/link-parser.js +59 -0
  18. package/dist/file/link-parser.js.map +1 -1
  19. package/dist/file/property-utils.d.ts +55 -0
  20. package/dist/file/property-utils.d.ts.map +1 -0
  21. package/dist/file/property-utils.js +90 -0
  22. package/dist/file/property-utils.js.map +1 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +2 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/inputs/index.d.ts +2 -0
  28. package/dist/inputs/index.d.ts.map +1 -0
  29. package/dist/inputs/index.js +2 -0
  30. package/dist/inputs/index.js.map +1 -0
  31. package/dist/inputs/input-filter-manager.d.ts +72 -0
  32. package/dist/inputs/input-filter-manager.d.ts.map +1 -0
  33. package/dist/inputs/input-filter-manager.js +140 -0
  34. package/dist/inputs/input-filter-manager.js.map +1 -0
  35. package/package.json +2 -1
  36. package/src/core/evaluator/filter.ts +0 -2
  37. package/src/core/frontmatter-value.ts +528 -0
  38. package/src/core/index.ts +1 -0
  39. package/src/file/index.ts +1 -0
  40. package/src/file/link-parser.ts +73 -0
  41. package/src/file/property-utils.ts +114 -0
  42. package/src/index.ts +2 -0
  43. package/src/inputs/index.ts +1 -0
  44. package/src/inputs/input-filter-manager.ts +194 -0
@@ -1 +1 @@
1
- {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/filter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAEtD,MAAM,WAAW,UAAW,SAAQ,QAAQ;CAAG;AAE/C;;;;GAIG;AACH,qBAAa,eAAe,CAC3B,SAAS,SAAS;IAAE,iBAAiB,EAAE,MAAM,EAAE,CAAA;CAAE,CAChD,SAAQ,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC;IAC7C,SAAS,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,GAAG,UAAU,EAAE;IAQzD,eAAe,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;CAY9D"}
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAEtD,MAAM,WAAW,UAAW,SAAQ,QAAQ;CAAG;AAE/C;;;;GAIG;AACH,qBAAa,eAAe,CAC3B,SAAS,SAAS;IAAE,iBAAiB,EAAE,MAAM,EAAE,CAAA;CAAE,CAChD,SAAQ,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC;IAC7C,SAAS,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,GAAG,UAAU,EAAE;IAQzD,eAAe,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;CAY9D"}
@@ -1 +1 @@
1
- {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../src/core/evaluator/filter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAiB,MAAM,QAAQ,CAAC;AAItD;;;;GAIG;AACH,MAAM,OAAO,eAEX,SAAQ,aAAoC;IACnC,YAAY,CAAC,QAAmB;QACzC,OAAO,QAAQ,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAC7D,EAAE,EAAE,UAAU,KAAK,EAAE;YACrB,UAAU,EAAE,UAAU,CAAC,IAAI,EAAE;YAC7B,OAAO,EAAE,IAAI;SACb,CAAC,CAAC,CAAC;IACL,CAAC;IAED,eAAe,CAAC,WAAoC;QACnD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACb,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE;YAChC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;gBACvC,OAAO,IAAI,CAAC;YACb,CAAC;YACD,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACJ,CAAC;CACD","sourcesContent":["import type { BehaviorSubject } from \"rxjs\";\n\nimport { BaseEvaluator, type BaseRule } from \"./base\";\n\nexport interface FilterRule extends BaseRule {}\n\n/**\n * Generic evaluator for filtering based on frontmatter expressions.\n * Extends BaseEvaluator to evaluate filter rules against frontmatter.\n * Returns true only if ALL rules evaluate to true.\n */\nexport class FilterEvaluator<\n\tTSettings extends { filterExpressions: string[] },\n> extends BaseEvaluator<FilterRule, TSettings> {\n\tprotected extractRules(settings: TSettings): FilterRule[] {\n\t\treturn settings.filterExpressions.map((expression, index) => ({\n\t\t\tid: `filter-${index}`,\n\t\t\texpression: expression.trim(),\n\t\t\tenabled: true,\n\t\t}));\n\t}\n\n\tevaluateFilters(frontmatter: Record<string, unknown>): boolean {\n\t\tif (this.rules.length === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn this.rules.every((rule) => {\n\t\t\tif (!rule.enabled || !rule.expression) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn this.evaluateRule(rule, frontmatter);\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../src/core/evaluator/filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAiB,MAAM,QAAQ,CAAC;AAItD;;;;GAIG;AACH,MAAM,OAAO,eAEX,SAAQ,aAAoC;IACnC,YAAY,CAAC,QAAmB;QACzC,OAAO,QAAQ,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAC7D,EAAE,EAAE,UAAU,KAAK,EAAE;YACrB,UAAU,EAAE,UAAU,CAAC,IAAI,EAAE;YAC7B,OAAO,EAAE,IAAI;SACb,CAAC,CAAC,CAAC;IACL,CAAC;IAED,eAAe,CAAC,WAAoC;QACnD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACb,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE;YAChC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;gBACvC,OAAO,IAAI,CAAC;YACb,CAAC;YACD,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACJ,CAAC;CACD","sourcesContent":["import { BaseEvaluator, type BaseRule } from \"./base\";\n\nexport interface FilterRule extends BaseRule {}\n\n/**\n * Generic evaluator for filtering based on frontmatter expressions.\n * Extends BaseEvaluator to evaluate filter rules against frontmatter.\n * Returns true only if ALL rules evaluate to true.\n */\nexport class FilterEvaluator<\n\tTSettings extends { filterExpressions: string[] },\n> extends BaseEvaluator<FilterRule, TSettings> {\n\tprotected extractRules(settings: TSettings): FilterRule[] {\n\t\treturn settings.filterExpressions.map((expression, index) => ({\n\t\t\tid: `filter-${index}`,\n\t\t\texpression: expression.trim(),\n\t\t\tenabled: true,\n\t\t}));\n\t}\n\n\tevaluateFilters(frontmatter: Record<string, unknown>): boolean {\n\t\tif (this.rules.length === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn this.rules.every((rule) => {\n\t\t\tif (!rule.enabled || !rule.expression) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn this.evaluateRule(rule, frontmatter);\n\t\t});\n\t}\n}\n"]}
@@ -0,0 +1,143 @@
1
+ export declare function isEmptyValue(value: unknown): boolean;
2
+ /**
3
+ * Serializes a frontmatter value to a string for editing in input fields.
4
+ * Arrays are joined with ", " for easier editing.
5
+ */
6
+ export declare function serializeValue(value: unknown): string;
7
+ /**
8
+ * Parses a string value from an input field into the appropriate type.
9
+ * Handles: booleans, numbers, JSON objects/arrays, comma-separated arrays, and strings.
10
+ */
11
+ export declare function parseValue(rawValue: string): unknown;
12
+ /**
13
+ * Formats a frontmatter value for display in read-only contexts.
14
+ * Converts booleans to "Yes"/"No", numbers to strings, and objects to JSON.
15
+ */
16
+ export declare function formatValue(value: unknown): string;
17
+ /**
18
+ * Parses wiki link syntax from a string value.
19
+ * Supports both [[path]] and [[path|alias]] formats.
20
+ * Returns null if the string is not a wiki link.
21
+ */
22
+ export declare function parseWikiLinkWithDisplay(value: string): {
23
+ linkPath: string;
24
+ displayText: string;
25
+ } | null;
26
+ /**
27
+ * Normalizes frontmatter property values to an array of strings.
28
+ * Handles various YAML formats and ensures consistent output.
29
+ *
30
+ * @param value - The raw frontmatter property value (can be any type)
31
+ * @param propertyName - Optional property name for logging purposes
32
+ * @returns Array of strings, or empty array if value is invalid/unexpected
33
+ *
34
+ * @example
35
+ * // Single string value
36
+ * normalizeProperty("[[link]]") // ["[[link]]"]
37
+ *
38
+ * // Array of strings
39
+ * normalizeProperty(["[[link1]]", "[[link2]]"]) // ["[[link1]]", "[[link2]]"]
40
+ *
41
+ * // Mixed array (filters out non-strings)
42
+ * normalizeProperty(["[[link]]", 42, null]) // ["[[link]]"]
43
+ *
44
+ * // Invalid types
45
+ * normalizeProperty(null) // []
46
+ * normalizeProperty(undefined) // []
47
+ * normalizeProperty(42) // []
48
+ * normalizeProperty({}) // []
49
+ */
50
+ export declare function normalizeProperty(value: unknown, propertyName?: string): string[];
51
+ /**
52
+ * Batch normalize multiple property values from frontmatter.
53
+ * Useful for processing multiple properties at once.
54
+ *
55
+ * @param frontmatter - The frontmatter object
56
+ * @param propertyNames - Array of property names to normalize
57
+ * @returns Map of property names to normalized string arrays
58
+ *
59
+ * @example
60
+ * const frontmatter = {
61
+ * parent: "[[Parent]]",
62
+ * children: ["[[Child1]]", "[[Child2]]"],
63
+ * related: null
64
+ * };
65
+ *
66
+ * const normalized = normalizeProperties(frontmatter, ["parent", "children", "related"]);
67
+ * // Map {
68
+ * // "parent" => ["[[Parent]]"],
69
+ * // "children" => ["[[Child1]]", "[[Child2]]"],
70
+ * // "related" => []
71
+ * // }
72
+ */
73
+ export declare function normalizeProperties(frontmatter: Record<string, unknown>, propertyNames: string[]): Map<string, string[]>;
74
+ /**
75
+ * Truncates a string to a maximum length, adding ellipsis if needed.
76
+ */
77
+ export declare function truncateString(text: string, maxLength: number): string;
78
+ /**
79
+ * Removes wiki link syntax from a string for cleaner display.
80
+ * Converts [[Link|Alias]] to just "Link" or [[Link]] to "Link".
81
+ */
82
+ export declare function removeWikiLinks(text: string): string;
83
+ /**
84
+ * Formats an array as a compact comma-separated string with smart truncation.
85
+ * Shows "item1, item2, +3" if the full list would exceed maxLength.
86
+ */
87
+ export declare function formatArrayCompact(items: string[], maxLength: number): string;
88
+ export interface DisplaySettings {
89
+ hideUnderscoreProperties?: boolean;
90
+ hideEmptyProperties?: boolean;
91
+ }
92
+ /**
93
+ * Filters frontmatter properties based on display settings.
94
+ * Returns an array of [key, value] pairs that should be displayed.
95
+ */
96
+ export declare function filterPropertiesForDisplay<TSettings extends DisplaySettings>(frontmatter: Record<string, unknown>, settings: TSettings): Array<[string, unknown]>;
97
+ /**
98
+ * Filters a specific list of property names from frontmatter.
99
+ * Useful when you want to display only specific properties (like in tooltips).
100
+ */
101
+ export declare function filterSpecificProperties<TSettings extends DisplaySettings>(frontmatter: Record<string, unknown>, propertyNames: string[], settings: TSettings): Array<{
102
+ key: string;
103
+ value: unknown;
104
+ }>;
105
+ export interface WikiLinkSegment {
106
+ type: "text" | "link";
107
+ content: string;
108
+ linkPath?: string;
109
+ displayText?: string;
110
+ }
111
+ /**
112
+ * Parses a string containing inline wiki links into segments.
113
+ * Useful for rendering strings with clickable wiki links mixed with regular text.
114
+ *
115
+ * @example
116
+ * parseInlineWikiLinks("Visit [[Page1]] and [[Page2|Second Page]]")
117
+ * // Returns:
118
+ * // [
119
+ * // { type: "text", content: "Visit " },
120
+ * // { type: "link", content: "[[Page1]]", linkPath: "Page1", displayText: "Page1" },
121
+ * // { type: "text", content: " and " },
122
+ * // { type: "link", content: "[[Page2|Second Page]]", linkPath: "Page2", displayText: "Second Page" }
123
+ * // ]
124
+ */
125
+ export declare function parseInlineWikiLinks(text: string): WikiLinkSegment[];
126
+ /**
127
+ * Formats a frontmatter value for compact display inside graph nodes.
128
+ * Truncates long values and handles arrays gracefully.
129
+ *
130
+ * @param value - The frontmatter value to format
131
+ * @param maxLength - Maximum length before truncation (default: 20)
132
+ * @returns Formatted string suitable for node display
133
+ *
134
+ * @example
135
+ * formatValueForNode("completed") // "completed"
136
+ * formatValueForNode("A very long string that exceeds the limit") // "A very long string..."
137
+ * formatValueForNode(["tag1", "tag2", "tag3"]) // "tag1, tag2, tag3"
138
+ * formatValueForNode(["tag1", "tag2", "tag3", "tag4", "tag5"], 15) // "tag1, tag2, +3"
139
+ * formatValueForNode(true) // "Yes"
140
+ * formatValueForNode(42) // "42"
141
+ */
142
+ export declare function formatValueForNode(value: unknown, maxLength?: number): string;
143
+ //# sourceMappingURL=frontmatter-value.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,408 @@
1
+ // ============================================================================
2
+ // Value Checking
3
+ // ============================================================================
4
+ export function isEmptyValue(value) {
5
+ if (value === null || value === undefined) {
6
+ return true;
7
+ }
8
+ if (typeof value === "string" && value.trim() === "") {
9
+ return true;
10
+ }
11
+ if (Array.isArray(value) && value.length === 0) {
12
+ return true;
13
+ }
14
+ return false;
15
+ }
16
+ // ============================================================================
17
+ // Value Serialization & Parsing (for editing in input fields)
18
+ // ============================================================================
19
+ /**
20
+ * Serializes a frontmatter value to a string for editing in input fields.
21
+ * Arrays are joined with ", " for easier editing.
22
+ */
23
+ export function serializeValue(value) {
24
+ if (value === null || value === undefined) {
25
+ return "";
26
+ }
27
+ if (Array.isArray(value)) {
28
+ return value.map((item) => serializeValue(item)).join(", ");
29
+ }
30
+ if (typeof value === "object") {
31
+ return JSON.stringify(value);
32
+ }
33
+ return String(value);
34
+ }
35
+ /**
36
+ * Parses a string value from an input field into the appropriate type.
37
+ * Handles: booleans, numbers, JSON objects/arrays, comma-separated arrays, and strings.
38
+ */
39
+ export function parseValue(rawValue) {
40
+ const trimmed = rawValue.trim();
41
+ if (trimmed === "") {
42
+ return "";
43
+ }
44
+ // Parse boolean
45
+ if (trimmed.toLowerCase() === "true") {
46
+ return true;
47
+ }
48
+ if (trimmed.toLowerCase() === "false") {
49
+ return false;
50
+ }
51
+ // Parse number
52
+ if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
53
+ const num = Number(trimmed);
54
+ if (!Number.isNaN(num)) {
55
+ return num;
56
+ }
57
+ }
58
+ // Parse JSON object or array (check BEFORE comma-separated arrays)
59
+ if ((trimmed.startsWith("{") && trimmed.endsWith("}")) ||
60
+ (trimmed.startsWith("[") && trimmed.endsWith("]"))) {
61
+ try {
62
+ return JSON.parse(trimmed);
63
+ }
64
+ catch (_a) {
65
+ // If parsing fails, continue to other checks
66
+ }
67
+ }
68
+ // Parse comma-separated array
69
+ if (trimmed.includes(",")) {
70
+ const items = trimmed.split(",").map((item) => item.trim());
71
+ if (items.every((item) => item.length > 0)) {
72
+ return items;
73
+ }
74
+ }
75
+ // Default: return as string
76
+ return trimmed;
77
+ }
78
+ // ============================================================================
79
+ // Value Formatting (for display in read-only contexts)
80
+ // ============================================================================
81
+ /**
82
+ * Formats a frontmatter value for display in read-only contexts.
83
+ * Converts booleans to "Yes"/"No", numbers to strings, and objects to JSON.
84
+ */
85
+ export function formatValue(value) {
86
+ if (typeof value === "boolean") {
87
+ return value ? "Yes" : "No";
88
+ }
89
+ if (typeof value === "number") {
90
+ return value.toString();
91
+ }
92
+ if (typeof value === "object" && value !== null) {
93
+ return JSON.stringify(value, null, 2);
94
+ }
95
+ return String(value);
96
+ }
97
+ // ============================================================================
98
+ // Wiki Link Parsing
99
+ // ============================================================================
100
+ /**
101
+ * Parses wiki link syntax from a string value.
102
+ * Supports both [[path]] and [[path|alias]] formats.
103
+ * Returns null if the string is not a wiki link.
104
+ */
105
+ export function parseWikiLinkWithDisplay(value) {
106
+ const wikiLinkMatch = value.match(/^\[\[([^\]]*)\]\]$/);
107
+ if (!wikiLinkMatch) {
108
+ return null;
109
+ }
110
+ const innerContent = wikiLinkMatch[1];
111
+ const pipeIndex = innerContent.indexOf("|");
112
+ const linkPath = pipeIndex !== -1 ? innerContent.substring(0, pipeIndex).trim() : innerContent.trim();
113
+ const displayText = pipeIndex !== -1 ? innerContent.substring(pipeIndex + 1).trim() : linkPath;
114
+ return { linkPath, displayText };
115
+ }
116
+ // ============================================================================
117
+ // Property Normalization
118
+ // ============================================================================
119
+ /**
120
+ * Normalizes frontmatter property values to an array of strings.
121
+ * Handles various YAML formats and ensures consistent output.
122
+ *
123
+ * @param value - The raw frontmatter property value (can be any type)
124
+ * @param propertyName - Optional property name for logging purposes
125
+ * @returns Array of strings, or empty array if value is invalid/unexpected
126
+ *
127
+ * @example
128
+ * // Single string value
129
+ * normalizeProperty("[[link]]") // ["[[link]]"]
130
+ *
131
+ * // Array of strings
132
+ * normalizeProperty(["[[link1]]", "[[link2]]"]) // ["[[link1]]", "[[link2]]"]
133
+ *
134
+ * // Mixed array (filters out non-strings)
135
+ * normalizeProperty(["[[link]]", 42, null]) // ["[[link]]"]
136
+ *
137
+ * // Invalid types
138
+ * normalizeProperty(null) // []
139
+ * normalizeProperty(undefined) // []
140
+ * normalizeProperty(42) // []
141
+ * normalizeProperty({}) // []
142
+ */
143
+ export function normalizeProperty(value, propertyName) {
144
+ // Handle undefined and null
145
+ if (value === undefined || value === null) {
146
+ return [];
147
+ }
148
+ // Handle string values - convert to single-item array
149
+ if (typeof value === "string") {
150
+ // Empty strings should return empty array
151
+ if (value.trim() === "") {
152
+ return [];
153
+ }
154
+ return [value];
155
+ }
156
+ // Handle array values
157
+ if (Array.isArray(value)) {
158
+ // Empty arrays
159
+ if (value.length === 0) {
160
+ return [];
161
+ }
162
+ // Filter to only string values
163
+ const stringValues = value.filter((item) => {
164
+ if (typeof item === "string") {
165
+ return true;
166
+ }
167
+ // Log warning for non-string items
168
+ if (propertyName) {
169
+ console.warn(`Property "${propertyName}" contains non-string value (${typeof item}), filtering it out:`, item);
170
+ }
171
+ return false;
172
+ });
173
+ // Filter out empty strings
174
+ const nonEmptyStrings = stringValues.filter((s) => s.trim() !== "");
175
+ return nonEmptyStrings;
176
+ }
177
+ // Handle unexpected types (numbers, booleans, objects, etc.)
178
+ if (propertyName) {
179
+ console.warn(`Property "${propertyName}" has unexpected type (${typeof value}), returning empty array. Value:`, value);
180
+ }
181
+ return [];
182
+ }
183
+ /**
184
+ * Batch normalize multiple property values from frontmatter.
185
+ * Useful for processing multiple properties at once.
186
+ *
187
+ * @param frontmatter - The frontmatter object
188
+ * @param propertyNames - Array of property names to normalize
189
+ * @returns Map of property names to normalized string arrays
190
+ *
191
+ * @example
192
+ * const frontmatter = {
193
+ * parent: "[[Parent]]",
194
+ * children: ["[[Child1]]", "[[Child2]]"],
195
+ * related: null
196
+ * };
197
+ *
198
+ * const normalized = normalizeProperties(frontmatter, ["parent", "children", "related"]);
199
+ * // Map {
200
+ * // "parent" => ["[[Parent]]"],
201
+ * // "children" => ["[[Child1]]", "[[Child2]]"],
202
+ * // "related" => []
203
+ * // }
204
+ */
205
+ export function normalizeProperties(frontmatter, propertyNames) {
206
+ const result = new Map();
207
+ for (const propName of propertyNames) {
208
+ const value = frontmatter[propName];
209
+ result.set(propName, normalizeProperty(value, propName));
210
+ }
211
+ return result;
212
+ }
213
+ // ============================================================================
214
+ // String Utilities
215
+ // ============================================================================
216
+ /**
217
+ * Truncates a string to a maximum length, adding ellipsis if needed.
218
+ */
219
+ export function truncateString(text, maxLength) {
220
+ return text.length > maxLength ? `${text.substring(0, maxLength)}...` : text;
221
+ }
222
+ /**
223
+ * Removes wiki link syntax from a string for cleaner display.
224
+ * Converts [[Link|Alias]] to just "Link" or [[Link]] to "Link".
225
+ */
226
+ export function removeWikiLinks(text) {
227
+ return text.replace(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g, "$1");
228
+ }
229
+ // ============================================================================
230
+ // Array Formatting Utilities
231
+ // ============================================================================
232
+ /**
233
+ * Formats an array as a compact comma-separated string with smart truncation.
234
+ * Shows "item1, item2, +3" if the full list would exceed maxLength.
235
+ */
236
+ export function formatArrayCompact(items, maxLength) {
237
+ if (items.length === 0) {
238
+ return "";
239
+ }
240
+ // Single item - just truncate it
241
+ if (items.length === 1) {
242
+ return truncateString(items[0], maxLength);
243
+ }
244
+ const joined = items.join(", ");
245
+ // Fits within limit - return as is
246
+ if (joined.length <= maxLength) {
247
+ return joined;
248
+ }
249
+ // Too long - show first few items + count
250
+ let result = "";
251
+ let count = 0;
252
+ for (const item of items) {
253
+ const testResult = result ? `${result}, ${item}` : item;
254
+ if (testResult.length > maxLength - 5) {
255
+ const remaining = items.length - count;
256
+ return `${result}${remaining > 0 ? `, +${remaining}` : ""}`;
257
+ }
258
+ result = testResult;
259
+ count++;
260
+ }
261
+ return result;
262
+ }
263
+ /**
264
+ * Filters frontmatter properties based on display settings.
265
+ * Returns an array of [key, value] pairs that should be displayed.
266
+ */
267
+ export function filterPropertiesForDisplay(frontmatter, settings) {
268
+ const entries = Object.entries(frontmatter);
269
+ return entries.filter(([key, value]) => {
270
+ // Hide underscore properties if configured
271
+ if (settings.hideUnderscoreProperties && key.startsWith("_")) {
272
+ return false;
273
+ }
274
+ // Hide empty properties if configured
275
+ if (settings.hideEmptyProperties && isEmptyValue(value)) {
276
+ return false;
277
+ }
278
+ return true;
279
+ });
280
+ }
281
+ /**
282
+ * Filters a specific list of property names from frontmatter.
283
+ * Useful when you want to display only specific properties (like in tooltips).
284
+ */
285
+ export function filterSpecificProperties(frontmatter, propertyNames, settings) {
286
+ const result = [];
287
+ for (const propName of propertyNames) {
288
+ // Skip if property doesn't exist in frontmatter
289
+ if (!(propName in frontmatter)) {
290
+ continue;
291
+ }
292
+ const value = frontmatter[propName];
293
+ // Hide underscore properties if configured
294
+ if (settings.hideUnderscoreProperties && propName.startsWith("_")) {
295
+ continue;
296
+ }
297
+ // Hide empty properties if configured
298
+ if (settings.hideEmptyProperties && isEmptyValue(value)) {
299
+ continue;
300
+ }
301
+ result.push({ key: propName, value });
302
+ }
303
+ return result;
304
+ }
305
+ /**
306
+ * Parses a string containing inline wiki links into segments.
307
+ * Useful for rendering strings with clickable wiki links mixed with regular text.
308
+ *
309
+ * @example
310
+ * parseInlineWikiLinks("Visit [[Page1]] and [[Page2|Second Page]]")
311
+ * // Returns:
312
+ * // [
313
+ * // { type: "text", content: "Visit " },
314
+ * // { type: "link", content: "[[Page1]]", linkPath: "Page1", displayText: "Page1" },
315
+ * // { type: "text", content: " and " },
316
+ * // { type: "link", content: "[[Page2|Second Page]]", linkPath: "Page2", displayText: "Second Page" }
317
+ * // ]
318
+ */
319
+ export function parseInlineWikiLinks(text) {
320
+ var _a;
321
+ const segments = [];
322
+ const wikiLinkRegex = /\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g;
323
+ let lastIndex = 0;
324
+ const matches = text.matchAll(wikiLinkRegex);
325
+ for (const match of matches) {
326
+ // Add text before the link
327
+ if (match.index !== undefined && match.index > lastIndex) {
328
+ segments.push({
329
+ type: "text",
330
+ content: text.substring(lastIndex, match.index),
331
+ });
332
+ }
333
+ // Add the link segment
334
+ const linkPath = match[1];
335
+ const displayText = match[2] || linkPath;
336
+ segments.push({
337
+ type: "link",
338
+ content: match[0],
339
+ linkPath,
340
+ displayText,
341
+ });
342
+ lastIndex = ((_a = match.index) !== null && _a !== void 0 ? _a : 0) + match[0].length;
343
+ }
344
+ // Add remaining text
345
+ if (lastIndex < text.length) {
346
+ segments.push({
347
+ type: "text",
348
+ content: text.substring(lastIndex),
349
+ });
350
+ }
351
+ // If no links found, return the entire text as a single segment
352
+ if (segments.length === 0) {
353
+ segments.push({
354
+ type: "text",
355
+ content: text,
356
+ });
357
+ }
358
+ return segments;
359
+ }
360
+ // ============================================================================
361
+ // Node Display Formatting
362
+ // ============================================================================
363
+ /**
364
+ * Formats a frontmatter value for compact display inside graph nodes.
365
+ * Truncates long values and handles arrays gracefully.
366
+ *
367
+ * @param value - The frontmatter value to format
368
+ * @param maxLength - Maximum length before truncation (default: 20)
369
+ * @returns Formatted string suitable for node display
370
+ *
371
+ * @example
372
+ * formatValueForNode("completed") // "completed"
373
+ * formatValueForNode("A very long string that exceeds the limit") // "A very long string..."
374
+ * formatValueForNode(["tag1", "tag2", "tag3"]) // "tag1, tag2, tag3"
375
+ * formatValueForNode(["tag1", "tag2", "tag3", "tag4", "tag5"], 15) // "tag1, tag2, +3"
376
+ * formatValueForNode(true) // "Yes"
377
+ * formatValueForNode(42) // "42"
378
+ */
379
+ export function formatValueForNode(value, maxLength = 20) {
380
+ if (isEmptyValue(value)) {
381
+ return "";
382
+ }
383
+ // Booleans: reuse formatValue logic
384
+ if (typeof value === "boolean") {
385
+ return value ? "Yes" : "No";
386
+ }
387
+ // Numbers: reuse formatValue logic
388
+ if (typeof value === "number") {
389
+ return value.toString();
390
+ }
391
+ // Arrays: extract strings and format compactly
392
+ if (Array.isArray(value)) {
393
+ const stringValues = value.filter((item) => typeof item === "string");
394
+ return formatArrayCompact(stringValues, maxLength);
395
+ }
396
+ // Strings: clean wiki links and truncate
397
+ if (typeof value === "string") {
398
+ const cleaned = removeWikiLinks(value);
399
+ return truncateString(cleaned, maxLength);
400
+ }
401
+ // Objects: stringify and truncate
402
+ if (typeof value === "object" && value !== null) {
403
+ const jsonStr = JSON.stringify(value);
404
+ return truncateString(jsonStr, maxLength);
405
+ }
406
+ return String(value);
407
+ }
408
+ //# sourceMappingURL=frontmatter-value.js.map
@@ -0,0 +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,4 +1,5 @@
1
1
  export * from "./evaluator";
2
2
  export * from "./expression-utils";
3
+ export * from "./frontmatter-value";
3
4
  export * from "./generate";
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export * from "./evaluator";
2
2
  export * from "./expression-utils";
3
+ export * from "./frontmatter-value";
3
4
  export * from "./generate";
4
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC","sourcesContent":["export * from \"./evaluator\";\nexport * from \"./expression-utils\";\nexport * from \"./generate\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC","sourcesContent":["export * from \"./evaluator\";\nexport * from \"./expression-utils\";\nexport * from \"./frontmatter-value\";\nexport * from \"./generate\";\n"]}