From a2972caacec756e7b0e30251c5ba1a0f39f34ff0 Mon Sep 17 00:00:00 2001 From: Max Litruv Boonzaayer Date: Wed, 26 Mar 2025 22:15:39 +1100 Subject: [PATCH] refactor: enhance frontmatter parsing and type handling for metadata properties --- build-docs.js | 36 +++++++++++++++++++++++------------- index.js | 44 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/build-docs.js b/build-docs.js index 304f702..ce53542 100644 --- a/build-docs.js +++ b/build-docs.js @@ -24,12 +24,24 @@ function parseFrontMatter(content) { if (lines[0].trim() === '---') { let endMetadata = lines.findIndex((line, index) => index > 0 && line.trim() === '---'); if (endMetadata !== -1) { - metadata = Object.fromEntries( - lines.slice(1, endMetadata) - .map(line => line.match(/^([\w-]+):\s*(.*)$/)) - .filter(Boolean) - .map(([, key, value]) => [key, value.trim()]) - ); + // Extract key-value pairs from frontmatter + const frontmatterEntries = lines.slice(1, endMetadata) + .map(line => line.match(/^([\w-]+):\s*(.*)$/)) + .filter(Boolean) + .map(([, key, value]) => { + // Convert specific properties to their proper types + if (key === 'defaultOpen') { + return [key, value.trim().toLowerCase() === 'true']; + } + else if (key === 'sort') { + return [key, parseInt(value.trim(), 10)]; + } + else { + return [key, value.trim()]; + } + }); + + metadata = Object.fromEntries(frontmatterEntries); contentStart = endMetadata + 1; } } @@ -123,20 +135,18 @@ function processFolder(folder, parentSlug = '') { // Sort items items.sort((a, b) => { // Get sort values, default to Infinity for items without sort value - const aHasSort = 'sort' in a; - const bHasSort = 'sort' in b; + const aHasSort = typeof a.sort === 'number'; + const bHasSort = typeof b.sort === 'number'; // If one has sort and the other doesn't, sorted items come first if (aHasSort !== bHasSort) { return aHasSort ? -1 : 1; } - // If both have sort values or both don't + // If both have sort values if (aHasSort && bHasSort) { - const aSort = parseInt(a.sort); - const bSort = parseInt(b.sort); - if (aSort !== bSort) { - return aSort - bSort; + if (a.sort !== b.sort) { + return a.sort - b.sort; } } diff --git a/index.js b/index.js index 7bd2099..dfa3888 100644 --- a/index.js +++ b/index.js @@ -220,16 +220,20 @@ class DOMService { createFileIndexItem(doc, container, level = 0) { if (doc.type === 'folder') { const folderDiv = document.createElement('div'); - folderDiv.className = 'folder' + (doc.defaultOpen !== false ? ' open' : ''); + // Ensure defaultOpen is handled as a boolean + const isOpen = doc.defaultOpen === true; + folderDiv.className = 'folder' + (isOpen ? ' open' : ''); folderDiv.dataset.path = doc.title; folderDiv.style.paddingLeft = `${level * 0.8}rem`; const folderHeader = document.createElement('div'); folderHeader.className = 'folder-header'; folderHeader.setAttribute('role', 'treeitem'); - folderHeader.setAttribute('aria-expanded', doc.defaultOpen !== false ? 'true' : 'false'); + // Update aria-expanded to match the new isOpen state + folderHeader.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); folderHeader.setAttribute('tabindex', '0'); - const iconClass = doc.icon || `fas fa-folder${doc.defaultOpen !== false ? '-open' : ''}`; + // Update icon class to match the folded state + const iconClass = doc.icon || `fas fa-folder${isOpen ? '-open' : ''}`; // Only add folder click handler if showfolderpage is not false if (doc.path && doc.metadata?.showfolderpage !== false) { @@ -593,12 +597,24 @@ class DocumentService { if (lines[0].trim() === '---') { let endMetadata = lines.findIndex((line, index) => index > 0 && line.trim() === '---'); if (endMetadata !== -1) { - metadata = Object.fromEntries( - lines.slice(1, endMetadata) - .map(line => line.match(/^([\w-]+):\s*(.*)$/)) - .filter(Boolean) - .map(([, key, value]) => [key, value.trim()]) - ); + // Extract and convert frontmatter types + const frontmatterEntries = lines.slice(1, endMetadata) + .map(line => line.match(/^([\w-]+):\s*(.*)$/)) + .filter(Boolean) + .map(([, key, value]) => { + // Convert specific properties to their proper types + if (key === 'defaultOpen') { + return [key, value.trim().toLowerCase() === 'true']; + } + else if (key === 'sort') { + return [key, parseInt(value.trim(), 10)]; + } + else { + return [key, value.trim()]; + } + }); + + metadata = Object.fromEntries(frontmatterEntries); contentStart = endMetadata + 1; } } @@ -618,6 +634,16 @@ class DocumentService { let rawContent = await response.text(); const { metadata, content } = this.extractMetadata(rawContent); + + // Ensure proper types for metadata properties + if (metadata.defaultOpen !== undefined) { + metadata.defaultOpen = metadata.defaultOpen === true || metadata.defaultOpen === 'true'; + } + + if (metadata.sort !== undefined) { + metadata.sort = typeof metadata.sort === 'number' ? metadata.sort : parseInt(metadata.sort, 10); + } + const basePath = path.substring(0, path.lastIndexOf('/')); const indexDoc = this.findDocInIndex(path);