# Health %% # Path ```dataviewjs let startFile = dv.current().file.name; // Start from the current file name let visited = new Set(); // Track visited files to avoid infinite loops const hierarchy = ['project', 'effort', 'area', 'marker', 'purpose']; // The upward property chain // Function to sanitize file names for Mermaid node identifiers function sanitizeMermaidId(name) { return name.replace(/[^a-zA-Z0-9]/g, '_'); // Replace all non-alphanumeric characters with underscores } // Function to create the Mermaid node with a label and a link function createMermaidNode(fileName) { let cleanFileName = fileName.replace('.md', '').split('/').pop(); // Remove .md and path, keep only file name let nodeId = sanitizeMermaidId(cleanFileName); // Sanitize the file name for the node ID return `${nodeId}["${cleanFileName}"]`; // Display the readable file name } // Function to create a clickable link for the node function createClickableLink(fileName) { let cleanFileName = encodeURIComponent(fileName.replace('.md', '').split('/').pop()); // URL encode the file name let nodeId = sanitizeMermaidId(cleanFileName); // Use the sanitized ID to reference the node return `click ${nodeId} "obsidian://open?vault=tomcewhite&file=${cleanFileName}"`; } // Determine the starting level for the file by checking which properties exist in the file function findStartingLevel(file) { let currentFile = dv.page(file); if (!currentFile) return hierarchy.length; for (let i = 0; i < hierarchy.length; i++) { if (currentFile[hierarchy[i]]) return i; } return hierarchy.length; } // Function to trace paths from the current file upward and build Mermaid chart connections async function tracePaths(file, level = 0, connections = [], path = [], clickableLinks = []) { if (visited.has(file)) return; // Prevent loops visited.add(file); // Mark file as visited let currentFile = dv.page(file); if (!currentFile) return; // Page not found path.unshift(file); // Add current file to the start of the path if (level >= hierarchy.length) return; // Stop if we've reached the top of the hierarchy let property = hierarchy[level]; // Get the current property (like 'project') let linkedFiles = currentFile[property] ?? []; // Get the files linked in this property // Handle cases where the property is a single link, not an array if (!Array.isArray(linkedFiles)) linkedFiles = [linkedFiles]; for (let linked of linkedFiles) { let linkedFileName = linked.path ?? linked; // If the link is an object, get its path // Create Mermaid nodes and clickable links for the current file and linked file let fromNode = createMermaidNode(file); let toNode = createMermaidNode(linkedFileName); let clickLink = createClickableLink(linkedFileName); // Add the Mermaid connection between nodes connections.push(`${fromNode} --> ${toNode}`); clickableLinks.push(clickLink); // Recursively trace paths for the linked file await tracePaths(linkedFileName, level + 1, connections, [...path], clickableLinks); // Clone path to avoid mutation } } // Main logic let connections = []; let clickableLinks = []; let startLevel = findStartingLevel(startFile); tracePaths(startFile, startLevel, connections, [], clickableLinks).then(() => { // Remove duplicate connections for Mermaid clarity let uniqueConnections = Array.from(new Set(connections)); let uniqueClickableLinks = Array.from(new Set(clickableLinks)); // Join the connections and links into Mermaid syntax let mermaidChart = `graph LR\n ${uniqueConnections.join('\n ')}\n ${uniqueClickableLinks.join('\n ')}`; // Render the Mermaid chart dv.paragraph('```mermaid\n' + mermaidChart + '\n```'); }); ``` # Reference ```dataview LIST FROM [[]] OR # AND !outgoing([[]]) AND -"Templates" WHERE file.name != this.file.name SORT file.name ASC ``` # Archive - %%