1
0
Fork 0
freesewing/sites/shared/mdx/remark-intro-plugin.mjs
2022-06-17 12:02:09 +02:00

77 lines
2 KiB
JavaScript

import { visit } from 'unist-util-visit'
/*
* This is a remark plugin that will pull the (text of the)
* first paragraph out of a markdown document and add it as
* the `intro` field in the documents's frontmatter.
*
* As such, it will only do anything if the document has
* frontmatter.
*
* I wrote this specifically to pull the intro out of our
* markdown content for SEO and open graph.
* I'm not publishing this as a proper remark plugin because
* while this works for our use-cases, it may or may not
* work for the many different ways people use markdown and
* remark out there.
*/
// These are child types of a paragraph of which we'll extract the text
const asText = [
'text',
'strong',
'emphasis',
'inlineCode',
]
// The actual plugin starts here
export const remarkIntroPlugin = (opts={}) => {
const { intro=[] } = opts
// Check to see whether the node has frontmatter
const hasFrontmatter = node => (node?.children?.[0]?.type === 'yaml')
// Pulls text out of a paragraph
const extractIntro = node => {
const text = []
for (const child of node.children) {
if (asText.indexOf(child.type) !== -1) text.push(child.value)
else if (child.type === 'link') text.push(child.children[0].value)
}
return text.map(item => item ? item.trim() : '').join(' ')
}
// Pulls the first paragraph out of a root node
const extractFirstParagraph = node => {
for (const child of node.children) {
if (child.type === 'paragraph') return extractIntro(child)
}
return 'FIXME_no_intro'
}
// Tree visitor
const visitor = (node) => {
const nodeIntro = extractFirstParagraph(node)
// Forgive me for this hack
intro.push(nodeIntro)
if (hasFrontmatter(node)) {
node.children[0].value += `\nintro: "${nodeIntro}"\n`
} else {
node.children.unshift({
type: 'yaml',
value: `intro: "${nodeIntro}"`
})
}
}
// Transformer method using the visitor pattern
const transform = (tree) => {
visit(tree, 'root', visitor)
}
return transform
}