Skip to content

Commit

Permalink
feat(content): pass document data to remark plugins (#782)
Browse files Browse the repository at this point in the history
  • Loading branch information
farnabaz authored Mar 1, 2021
1 parent 7660d0f commit ed56f5a
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 4 deletions.
78 changes: 78 additions & 0 deletions docs/content/en/snippets.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,81 @@ export default {
}
}
```

### Remark Plugin

Nuxt Content used [remark](https://github.com/remarkjs/remark) under the hood to process markdown documents. Creating remark plugins is a way to manipulate document and add new features contents.

#### List all contributors

Let's say you want to list all contributors of the project in a document. You can create a plugin that fetches all contributors and injects them into document data.

- Create the plugin, this plugin fetches the contributors if `fetchContributors` is set to `true`

```js [~~/plugins/contributors.js]
const fetch = require('node-fetch')

module.exports = function () {
return async (tree, { data }) => {
if (data.fetchContributors) {
const contributors = await fetch(
'https://api.github.com/repos/nuxt/content/contributors'
).then(res => res.json())
.then(res => res.map(({ login }) => login))

data.$contributors = [...new Set(contributors)]
}
return tree
}
}
```

- Register plugin in Nuxt config

```js{}[nuxt.config.js]
export default {
contents: {
markdown: {
remarkPlugins: [
'~~/plugins/contributors.js'
]
}
}
}
```

- Create a simple component to show contributors

```vue{}[~~/components/List.vue]
<template>
<ul>
<li v-for="(item, i) in items" :key="i">
{{ item }}
</li>
</ul>
</template>
<script>
export default {
props: {
items: {
type: Array,
default: () => []
}
}
}
```

- Finally use the components and mark document to fetch the contributors

```md{}[document.md]
---
title: Nuxt Content
fetchContributors: true
---
## Contributors
<list :items="$contributors"></list>
```
16 changes: 16 additions & 0 deletions example/components/global/Authors.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<ul>
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</template>

<script>
export default {
props: {
items: {
type: Array,
default: () => []
}
}
}
</script>
9 changes: 9 additions & 0 deletions example/content/authors-page.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: Auto generated authors list

---

Authors list:


<authors />
5 changes: 5 additions & 0 deletions example/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ const config: NuxtConfig = {
nestedProperties: ['categories.slug'],
extendParser: {
'.custom': file => ({ body: file.split('\n').map(line => line.trim()) })
},
markdown: {
remarkPlugins: [
'~/utils/contributors'
]
}
}
};
Expand Down
16 changes: 16 additions & 0 deletions example/pages/authors.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<div>
<nuxt-content :document="markdown" />
</div>
</template>

<script lang="ts">
export default {
async asyncData ({ $content }) {
const markdown = await $content('authors-page').fetch()
return {
markdown
}
}
}
</script>
26 changes: 26 additions & 0 deletions example/utils/contributors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const fetch = require('node-fetch')

module.exports = function () {
return async (tree, file) => {
let filePath
tree.children = tree.children.map((node) => {
const TAG_REGEX = /\s*<(authors)\s*/i
if (node.type === 'html' && node.value.match(TAG_REGEX)) {
filePath = 'README.md' // detect file path
node.value = node.value.replace(TAG_REGEX, '<$1 :items="$authors" ')
}
return node
})
if (filePath) {
const commits = await fetch(
'https://api.github.com/repos/nuxt/content/commits?path=' + filePath
).then(res => res.json())
const authors = commits
.map(commit => commit.author.login)
.filter(Boolean)

file.data.$authors = [...new Set(authors)]
}
return tree
}
}
10 changes: 6 additions & 4 deletions packages/content/parsers/markdown/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ class Markdown {
/**
* Generate json body
* @param {string} content - JSON AST generated from markdown.
* @param {object} data - document data
* @returns {object} JSON AST body
*/
async generateBody (content) {
async generateBody (content, data = {}) {
let { highlighter } = this.options
if (typeof highlighter === 'function' && highlighter.length === 0) {
highlighter = await highlighter()
Expand All @@ -93,7 +94,7 @@ class Markdown {

stream
.use(jsonCompiler)
.process(content, (error, file) => {
.process({ data, contents: content }, (error, file) => {
/* istanbul ignore if */
if (error) {
return reject(error)
Expand All @@ -120,8 +121,9 @@ class Markdown {
async toJSON (file) {
const { data, content, ...rest } = matter(file, { excerpt: true, excerpt_separator: '<!--more-->' })

const documentData = data || {}
// Compile markdown from file content to JSON
const body = await this.generateBody(content)
const body = await this.generateBody(content, documentData)
// Generate toc from body
const toc = this.generateToc(body)

Expand All @@ -134,7 +136,7 @@ class Markdown {

return {
description,
...data,
...documentData,
toc,
body,
text: content,
Expand Down

0 comments on commit ed56f5a

Please sign in to comment.