diff --git a/docs/content/en/snippets.md b/docs/content/en/snippets.md index 8bf8ab1d5..d58ceb598 100644 --- a/docs/content/en/snippets.md +++ b/docs/content/en/snippets.md @@ -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] + + + diff --git a/example/content/authors-page.md b/example/content/authors-page.md new file mode 100644 index 000000000..2f7422de5 --- /dev/null +++ b/example/content/authors-page.md @@ -0,0 +1,9 @@ +--- +title: Auto generated authors list + +--- + +Authors list: + + + \ No newline at end of file diff --git a/example/nuxt.config.ts b/example/nuxt.config.ts index 264bc35f7..297c744d8 100644 --- a/example/nuxt.config.ts +++ b/example/nuxt.config.ts @@ -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' + ] } } }; diff --git a/example/pages/authors.vue b/example/pages/authors.vue new file mode 100644 index 000000000..6f1de230b --- /dev/null +++ b/example/pages/authors.vue @@ -0,0 +1,16 @@ + + + diff --git a/example/utils/contributors.js b/example/utils/contributors.js new file mode 100644 index 000000000..afb8b6f98 --- /dev/null +++ b/example/utils/contributors.js @@ -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 + } +} diff --git a/packages/content/parsers/markdown/index.js b/packages/content/parsers/markdown/index.js index 92440e7ce..3954721df 100644 --- a/packages/content/parsers/markdown/index.js +++ b/packages/content/parsers/markdown/index.js @@ -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() @@ -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) @@ -120,8 +121,9 @@ class Markdown { async toJSON (file) { const { data, content, ...rest } = matter(file, { excerpt: true, excerpt_separator: '' }) + 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) @@ -134,7 +136,7 @@ class Markdown { return { description, - ...data, + ...documentData, toc, body, text: content,