77 lines
2 KiB
JavaScript
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
|
|
}
|
|
|