Fix Frontmatter Default Values and Closing Delimiters
Summary
Created frontmatter templates for "Essays" and "Issue Resolutions". Fixed critical issues with frontmatter processing in Markdown files, including missing default values, improper serialization of objects, and missing closing delimiters.
Why Care
These fixes ensure that all Markdown files have properly formatted frontmatter with all required fields populated with appropriate defaults, preventing parsing errors and ensuring consistent metadata across the content collection.
Implementation
Changes Made
- Modified Files:
tidyverse/observers/scripts/assert-frontmatter-template.ts
: Fixed serialization and patching logictidyverse/observers/templates/essays.ts
: Fixed date handling inaddDateCreatedWrapper
- New Files:
tidyverse/tidy-up/tidy-one-property/remove-one-property/removeChangesKeyValuePair.cjs
: Script to remove unwantedchanges:
propertiestidyverse/tidy-up/assure-tidy-frontmatter-delimiters/assureClosingFrontmatterDelimiter.cjs
: Script to ensure proper closing delimiters
Technical Details
assert-frontmatter-template.ts
- Enhanced the
serializeFrontmatterToYAML
function to:- Clean up unexpected properties like
changes
before serialization - Handle empty arrays correctly
- Skip object properties to prevent
[object Object]
from appearing in output
- Improved patching logic to:
- Properly extract date strings from objects returned by
defaultValueFn
- Ensure all required fields have values, even if they weren't detected as missing or empty
- Add special handling for date fields to convert objects to strings
typescript
// Clean up any unexpected or malformed properties
const cleanedObj = { ...obj };
// Remove 'changes' property if it exists at the top level
if ('changes' in cleanedObj) {
delete cleanedObj.changes;
}
typescript
// Ensure we don't store objects for date fields - convert to string if needed
if (defTyped.type === 'date' && typeof defaultValue === 'object' && defaultValue !== null) {
// If it's an object with a date property, extract that
if (defaultValue.date) {
updatedFrontmatter[key] = defaultValue.date;
}
// If it's an object with changes.date_created, extract that
else if (defaultValue.changes && defaultValue.changes.date_created) {
updatedFrontmatter[key] = defaultValue.changes.date_created;
}
// Otherwise use today's date as fallback
else {
const now = new Date();
updatedFrontmatter[key] = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
}
} else {
updatedFrontmatter[key] = defaultValue;
}
essays.ts
- Fixed the
addDateCreatedWrapper
function to properly extract the date string from the object returned byaddDateCreated
- Ensured that
date_authored_initial_draft
has the same value asdate_created
typescript
// addDateCreated returns { changes: { date_created?: string } }
// but we need a simple string for defaultValueFn
const result = addDateCreated(frontmatter ?? {}, filePath);
// Extract date_created if available
if (result.changes && result.changes.date_created) {
return result.changes.date_created;
}
removeChangesKeyValuePair.cjs
- Created a script to remove the
changes:
key-value pair from all Markdown files in the essays directory - Ensures proper preservation of the closing frontmatter delimiter
javascript
// Helper to extract frontmatter block
function extractFrontmatter(markdownContent) {
const fmRegex = /^---\n([\s\S]*?)\n---/;
const match = markdownContent.match(fmRegex);
if (!match) {
return { success: false };
}
const frontmatterString = match[1];
const startIndex = match.index + 4; // after '---\n'
const endIndex = match.index + match[0].length - 4; // before '\n---'
return { frontmatterString, startIndex, endIndex, success: true };
}
assureClosingFrontmatterDelimiter.cjs
- Created a script to ensure all Markdown files have a proper closing frontmatter delimiter
- Identifies files with missing closing delimiters and adds them correctly
javascript
// Find the frontmatter section
const frontmatterMatch = markdownContent.match(/^---\n([\s\S]*?)(\n---|\n\s*\n)/);
if (!frontmatterMatch) {
console.log(`[SKIPPING] ${markdownFilePath} - Could not parse frontmatter`);
continue;
}
// Check if the frontmatter is properly closed with a '---' delimiter
const hasProperClosing = frontmatterMatch[2].trim() === '---';
if (hasProperClosing) {
continue; // Already has proper closing delimiter
}
Integration Points
- These changes ensure that all 38 essay files in the content collection have properly formatted frontmatter with all required fields populated with appropriate defaults
- The scripts can be reused for future content processing tasks to ensure consistent frontmatter formatting
- The improved serialization function in
assert-frontmatter-template.ts
ensures that frontmatter is always properly formatted, even when dealing with complex data types
Documentation
- The issue resolution document at
/content/lost-in-public/issue-resolution/Fixing-Markdown-Frontmatter-Default-Values.md
provides a comprehensive overview of the problem and the solution - The scripts include detailed comments explaining their purpose and functionality