Skip to content

Instantly share code, notes, and snippets.

@shazron
Last active May 23, 2024 05:16
Show Gist options
  • Save shazron/155d0c5f470ab9576318fd0c104d5560 to your computer and use it in GitHub Desktop.
Save shazron/155d0c5f470ab9576318fd0c104d5560 to your computer and use it in GitHub Desktop.
Update the front-matter title property of Markdown files from the first heading title
const fs = require('node:fs');
const path = require('node:path');
const matter = require('gray-matter');
const MarkdownIt = require('markdown-it');
const MarkdownItFrontMatter = require('markdown-it-front-matter');
if (!matter || !MarkdownIt || !MarkdownItFrontMatter) {
console.error('Module "gray-matter", "markdown-it", or "markdown-it-front-matter" not found. Run "npm install"');
process.exit(1);
}
// Function to parse command line arguments
function parseArgs() {
const args = process.argv.slice(2);
const flags = {};
const positionalArgs = [];
args.forEach(arg => {
if (arg.startsWith('--')) {
const [flag, value] = arg.split('=');
const flagName = flag.slice(2);
flags[flagName] = value || true;
} else if (arg.startsWith('-')) {
const flagName = arg.slice(1);
flags[flagName] = true;
} else {
positionalArgs.push(arg);
}
});
return { flags, positionalArgs };
}
// Function to get the first heading of a Markdown file
function getFirstHeading(filePath) {
// Read the file content
const fileContent = fs.readFileSync(filePath, 'utf8');
// Initialize Markdown-It
const md = new MarkdownIt().use(MarkdownItFrontMatter, () => { });
// Parse the Markdown content
const tokens = md.parse(fileContent, {});
// Find the first heading
for (let token of tokens) {
if (token.type === 'heading_open') {
// The next token is the heading text
const headingTextToken = tokens[tokens.indexOf(token) + 1];
return headingTextToken.content;
}
}
// No heading found
return null;
}
// Function to read, edit, and write the front matter of a Markdown file
function editFrontMatter(filePath, flags) {
// Read the file content
const fileContent = fs.readFileSync(filePath, 'utf8');
// Parse the front matter
const parsedContent = matter(fileContent);
// Modify the front matter (example: adding a new field 'modified' with the current date)
const doWrite = !(flags['skip-existing'] && parsedContent.data.title)
if (doWrite) {
const firstHeading = getFirstHeading(filePath)
if (firstHeading) {
parsedContent.data.title = firstHeading;
} else {
parsedContent.data.title = 'TODO: please update with the correct title';
}
// Convert back to string with updated front matter
const newContent = matter.stringify(parsedContent.content, parsedContent.data);
// Write the new content back to the file
fs.writeFileSync(filePath, newContent, 'utf8');
}
}
// Function to iterate through a folder and process Markdown files
function processMarkdownFiles(folderPath, flags) {
// Read the contents of the folder
const files = fs.readdirSync(folderPath);
// Iterate through each file/directory in the folder
files.forEach(file => {
const filePath = path.join(folderPath, file);
// Check if the file is a directory
if (fs.statSync(filePath).isDirectory()) {
// Recursively process the subdirectory
processMarkdownFiles(filePath, flags);
} else if (path.extname(file) === '.md') {
// If it's a Markdown file, edit its front matter
console.log(`Processing file: ${filePath}`);
editFrontMatter(filePath, flags);
}
});
}
async function main() {
const { flags, positionalArgs } = parseArgs();
// Sample script functionality based on parsed arguments
if (flags.help) {
console.log('Update the front-matter title of your Markdown files based on the first heading');
console.log(`Usage: node ${path.relative(process.cwd(), __filename)} [options] MD_FOLDER_PATH`);
console.log('Options:');
console.log(' --help Show this help message');
console.log(' --skip-existing Skip overwriting existing title front-matter');
return;
}
if (positionalArgs.length < 1) {
throw new Error('Please provide the markdown folder path');
}
const folderPath = positionalArgs[0];
processMarkdownFiles(folderPath, flags);
}
main()
.catch(console.error)
@shazron
Copy link
Author

shazron commented May 23, 2024

Installation:

  1. In your Terminal app, create a new folder, cd into that new folder
  2. Download the script into that folder, name it update_fm_in_md.js
  3. Run npm init -y
  4. Run npm install gray-matter markdown-it markdown-it-front-matter
  5. Run node ./update_fm_in_md.js --help to see instructions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment