最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Node.js - How to readwrite a markdown file changing its front matter metadata? - Stack Overflow

programmeradmin4浏览0评论

I have a few hundred markdown files and I would like to loop through them and add a new data to their front matter metadata.

For example, this is what my files look like now:

---
title: My title here
---


Markdown content here

And I want to add an id property to them:

---
title: My title here
id: 1982n1x23981u1
---


Markdown content

What would be the cleanest way to do that in Node? I've found a few packages to handle markdown, but all of them aims to convert it to JSON instead.

Thanks in advance!

I have a few hundred markdown files and I would like to loop through them and add a new data to their front matter metadata.

For example, this is what my files look like now:

---
title: My title here
---


Markdown content here

And I want to add an id property to them:

---
title: My title here
id: 1982n1x23981u1
---


Markdown content

What would be the cleanest way to do that in Node? I've found a few packages to handle markdown, but all of them aims to convert it to JSON instead.

Thanks in advance!

Share Improve this question edited Jun 26, 2020 at 0:34 Jonathan asked Jun 25, 2020 at 23:55 JonathanJonathan 1632 silver badges15 bronze badges 2
  • You're talking about Markdown/CommonMark... but you're showing us YAML and talking about conversion to JSON. – Nicholas Carey Commented Jun 25, 2020 at 23:59
  • Hi Nicholas! Thanks for your message. I'm not sure I understand what you mean, but I've edited my question for clarity. It's mon to have YAML front matter data in markdown files when working with the JAMStack – Jonathan Commented Jun 26, 2020 at 0:06
Add a ment  | 

3 Answers 3

Reset to default 13

Here a basic script I used to update frontmatter of all my notes in Markdown script:

// @ts-check
const { readdir, readFile, writeFile } = require("fs/promises");
const matter = require("gray-matter");
const { stringify } = require("yaml");

const directory = "<YOUR-DIRECTORY>";

async function updateFrontMatter(filename) {
  const filepath = `${directory}/${filename}`;

  const { data: frontMatter, content } = matter(await readFile(filepath));

  // remove desc attribute
  if (frontMatter.desc === "") {
    delete frontMatter["desc"];
  }

  // parse created date attribute and convert it as timestamp
  if (typeof frontMatter.created === "string") {
    frontMatter.created = new Date(frontMatter.created).getTime();
  }

  const newContent = `---\n${stringify(frontMatter)}---\n${content}`;

  await writeFile(filepath, newContent);

  console.log(`- [x] ${filepath}`);
}

async function main() {
  const filenames = await readdir(directory);
  const markdownFilenames = filenames.filter((f) => f.endsWith(".md"));

  await Promise.all(markdownFilenames.map(updateFrontMatter));
}

main().catch(console.error);

Assuming you are actually talking about YAML and not Markdown/CommonMark, YAML being data markup like XML or JSON; Markdown/CommonMark being markup for text formatting...

You'll be wanting to user either of these NPM packages:

  • js-yaml @ 15.6 million downloads/week
  • YAML @ 4.9 million downloads/week

If you actually have Markdown/CommonMark, you can use a tool like NPM's monmark which parses the document and loads it into an abstract syntax tree (AST) that you can manipulate and rewrite as Markdown.

Note that there are [many] other Markdown processors in NPM, including this one. Where they are patible with the Markdown you are using... you'll have to figure that out yourself. CommonMark exists because of how the many Markdown implementations have diverged.

Another option would be to use pandoc and write a filter to process the AST that it produces.

I run into a similar challenge and came up with a generalised solution:

import matter from "gray-matter";

function processFrontmatter(md, options) {
  const frontmatter = matter(md).data;
  Object.entries(options).forEach(function ([fieldName, value]) {
    if (value === "del" || value === "-") {
      delete frontmatter[fieldName];
    } else {
      frontmatter[fieldName] = value;
    }
  });

  return matter.stringify(matter(md));
}

This function accepts markdown content (in string format), parses the frontmatter and changes it according to the options dictionary parameter:

// ---
// field: example value
// another_field: some value
// ---
// Markdown content
const md = '---\nfield: example value\nanother_field: some value\n---\nMarkdown content'

const options = {
    field: 'new example value',
    another_field: 'del',
    new_field: 'a new field!'
}

console.log(processFrontmatter(md, options))

Which will yield:

---
field: new example value
new_field: a new field!
---
Markdown content

I published this solution as a node module, see here.

For reading the Markdown content from a file and writing it, I'd refer to the fs module.

发布评论

评论列表(0)

  1. 暂无评论