From 20a66bde5250bc6f8e96620378fc2dad2ba78b45 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Fri, 27 May 2022 10:09:25 +0200 Subject: [PATCH 01/15] feat: call hooks before and after parse --- src/runtime/server/transformers/index.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/runtime/server/transformers/index.ts b/src/runtime/server/transformers/index.ts index 279b6e396..ff1e4cdad 100644 --- a/src/runtime/server/transformers/index.ts +++ b/src/runtime/server/transformers/index.ts @@ -6,6 +6,12 @@ import { getParser, getTransformers } from '#content/virtual/transformers' * Parse content file using registered plugins */ export async function parseContent (id: string, content: string) { + const nitroApp = useNitroApp() + + // Call hook before parsing the file + const file = { id, content } + await nitroApp.hooks.callHook('content:file:beforeParse', file) + const ext = extname(id) const plugin: ContentTransformer = getParser(ext) if (!plugin) { @@ -26,5 +32,8 @@ export async function parseContent (id: string, content: string) { return cur.transform!(next) }, Promise.resolve(parsed)) + // Call hook after parsing the file + await nitroApp.hooks.callHook('content:file:afterParse', result) + return result } From 2a72b6d99c7a71af921d4866ef58247eac9fd798 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Fri, 27 May 2022 10:14:44 +0200 Subject: [PATCH 02/15] fix: add missing import --- src/runtime/server/transformers/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/server/transformers/index.ts b/src/runtime/server/transformers/index.ts index ff1e4cdad..05e4b7eb8 100644 --- a/src/runtime/server/transformers/index.ts +++ b/src/runtime/server/transformers/index.ts @@ -1,7 +1,7 @@ import { extname } from 'pathe' import type { ParsedContent, ContentTransformer } from '../../types' import { getParser, getTransformers } from '#content/virtual/transformers' - +import { useNitroApp } from '#imports' /** * Parse content file using registered plugins */ From f3e107c3d9ef11b9580d474745f8a76b47fe7813 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Fri, 27 May 2022 10:16:26 +0200 Subject: [PATCH 03/15] fix: lint --- src/runtime/server/transformers/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/server/transformers/index.ts b/src/runtime/server/transformers/index.ts index 05e4b7eb8..b7e2e6b60 100644 --- a/src/runtime/server/transformers/index.ts +++ b/src/runtime/server/transformers/index.ts @@ -1,6 +1,7 @@ import { extname } from 'pathe' import type { ParsedContent, ContentTransformer } from '../../types' import { getParser, getTransformers } from '#content/virtual/transformers' +// eslint-disable-next-line import/named import { useNitroApp } from '#imports' /** * Parse content file using registered plugins From 7e6372daaa93d94f8e6a6d8f0babb8f2f4501c3a Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Fri, 27 May 2022 13:00:43 +0200 Subject: [PATCH 04/15] fix: use `_id` --- src/runtime/server/transformers/index.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/runtime/server/transformers/index.ts b/src/runtime/server/transformers/index.ts index b7e2e6b60..2450a8d70 100644 --- a/src/runtime/server/transformers/index.ts +++ b/src/runtime/server/transformers/index.ts @@ -10,7 +10,7 @@ export async function parseContent (id: string, content: string) { const nitroApp = useNitroApp() // Call hook before parsing the file - const file = { id, content } + const file = { _id: id, content } await nitroApp.hooks.callHook('content:file:beforeParse', file) const ext = extname(id) @@ -18,13 +18,10 @@ export async function parseContent (id: string, content: string) { if (!plugin) { // eslint-disable-next-line no-console console.warn(`${ext} files are not supported, "${id}" falling back to raw content`) - return { - _id: id, - body: content - } + return file } - const parsed: ParsedContent = await plugin.parse!(id, content) + const parsed: ParsedContent = await plugin.parse!(file._id, file.content) const transformers = getTransformers(ext) const result = await transformers.reduce(async (prev, cur) => { From c482b8e5906cba0fe15e8f981e28166018944964 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 30 May 2022 09:39:33 +0200 Subject: [PATCH 05/15] test: test hooks with nitro plugin --- test/basic.test.ts | 3 ++ test/features/parser-hooks.ts | 37 ++++++++++++++++++++++ test/fixtures/basic/addons/nitro-plugin.ts | 17 ++++++++++ test/fixtures/basic/nuxt.config.ts | 5 +++ 4 files changed, 62 insertions(+) create mode 100644 test/features/parser-hooks.ts create mode 100644 test/fixtures/basic/addons/nitro-plugin.ts diff --git a/test/basic.test.ts b/test/basic.test.ts index f2d606e52..e4f74fdc8 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -11,6 +11,7 @@ import { testJSONParser } from './features/parser-json' import { testCSVParser } from './features/parser-csv' import { testRegex } from './features/regex' import { testMarkdownParserExcerpt } from './features/parser-markdown-excerpt' +import { testParserHooks } from './features/parser-hooks' describe('fixtures:basic', async () => { await setup({ @@ -114,4 +115,6 @@ describe('fixtures:basic', async () => { // testMDCComponent() testRegex() + + testParserHooks() }) diff --git a/test/features/parser-hooks.ts b/test/features/parser-hooks.ts new file mode 100644 index 000000000..ba7e63009 --- /dev/null +++ b/test/features/parser-hooks.ts @@ -0,0 +1,37 @@ +import { describe, test, expect, assert } from 'vitest' +import { $fetch } from '@nuxt/test-utils' + +export const testParserHooks = () => { + describe('parser:hooks', () => { + test('beforeParse', async () => { + const parsed = await $fetch('/api/parse', { + method: 'POST', + body: { + id: 'content:index.md', + content: '# hello' + } + }) + + expect(parsed).toHaveProperty('_id') + assert(parsed._id === 'content:index.md') + + expect(parsed).toHaveProperty('__beforeParse', true) + }) + + test('afterParse', async () => { + const parsed = await $fetch('/api/parse', { + method: 'POST', + body: { + id: 'content:index.md', + content: '# hello' + } + }) + + expect(parsed).toHaveProperty('_id') + assert(parsed._id === 'content:index.md') + + expect(parsed).haveOwnProperty('body') + expect(parsed).toHaveProperty('__afterParse', true) + }) + }) +} diff --git a/test/fixtures/basic/addons/nitro-plugin.ts b/test/fixtures/basic/addons/nitro-plugin.ts new file mode 100644 index 000000000..63ba6765e --- /dev/null +++ b/test/fixtures/basic/addons/nitro-plugin.ts @@ -0,0 +1,17 @@ +export default defineNitroPlugin((nitroApp) => { + nitroApp.hooks.hook('content:file:beforeParse', (file) => { + if (file._id.endsWith('.md')) { + if (file.content.startsWith('---')) { + const lines = file.content.split('\n') + lines.splice(1, 0, '__beforeParse: true') + file.content = lines.join('\n') + } else { + file.content = '---\n__beforeParse: true\n---\n' + file.content + } + } + }) + + nitroApp.hooks.hook('content:file:afterParse', (file) => { + file.__afterParse = true + }) +}) diff --git a/test/fixtures/basic/nuxt.config.ts b/test/fixtures/basic/nuxt.config.ts index 1c1abfc92..d06739c2c 100644 --- a/test/fixtures/basic/nuxt.config.ts +++ b/test/fixtures/basic/nuxt.config.ts @@ -3,6 +3,11 @@ import { resolve } from 'pathe' import contentModule from '../../..' export default defineNuxtConfig({ + nitro: { + plugins: [ + '~/addons/nitro-plugin.ts' + ] + }, components: { dirs: [ { From c7032dcd84ebcb67c9869f7c504eabacb42874e8 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 30 May 2022 10:15:10 +0200 Subject: [PATCH 06/15] chore: rename content to body --- src/runtime/server/transformers/index.ts | 4 ++-- test/fixtures/basic/addons/nitro-plugin.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/runtime/server/transformers/index.ts b/src/runtime/server/transformers/index.ts index 2450a8d70..c4fbbd2fc 100644 --- a/src/runtime/server/transformers/index.ts +++ b/src/runtime/server/transformers/index.ts @@ -10,7 +10,7 @@ export async function parseContent (id: string, content: string) { const nitroApp = useNitroApp() // Call hook before parsing the file - const file = { _id: id, content } + const file = { _id: id, body: content } await nitroApp.hooks.callHook('content:file:beforeParse', file) const ext = extname(id) @@ -21,7 +21,7 @@ export async function parseContent (id: string, content: string) { return file } - const parsed: ParsedContent = await plugin.parse!(file._id, file.content) + const parsed: ParsedContent = await plugin.parse!(file._id, file.body) const transformers = getTransformers(ext) const result = await transformers.reduce(async (prev, cur) => { diff --git a/test/fixtures/basic/addons/nitro-plugin.ts b/test/fixtures/basic/addons/nitro-plugin.ts index 63ba6765e..068c645ba 100644 --- a/test/fixtures/basic/addons/nitro-plugin.ts +++ b/test/fixtures/basic/addons/nitro-plugin.ts @@ -1,12 +1,12 @@ export default defineNitroPlugin((nitroApp) => { nitroApp.hooks.hook('content:file:beforeParse', (file) => { if (file._id.endsWith('.md')) { - if (file.content.startsWith('---')) { - const lines = file.content.split('\n') + if (file.body.startsWith('---')) { + const lines = file.body.split('\n') lines.splice(1, 0, '__beforeParse: true') - file.content = lines.join('\n') + file.body = lines.join('\n') } else { - file.content = '---\n__beforeParse: true\n---\n' + file.content + file.body = '---\n__beforeParse: true\n---\n' + file.content } } }) From b909d6b684ea3d41d3093ba7f134f57c4e91efc6 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 30 May 2022 10:15:25 +0200 Subject: [PATCH 07/15] docs: add advanced api --- docs/content/4.api/4.advanced.md | 62 ++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/content/4.api/4.advanced.md diff --git a/docs/content/4.api/4.advanced.md b/docs/content/4.api/4.advanced.md new file mode 100644 index 000000000..81366d2f6 --- /dev/null +++ b/docs/content/4.api/4.advanced.md @@ -0,0 +1,62 @@ +--- +title: 'Advanced' +description: 'You can configure Nuxt Content with the content property in your nuxt.config.js|ts file.' +icon: heroicons-outline:lightning-bolt +--- + +## Hooks + +The module adds some hooks you can use: + +::alert +In order to use `content:file:*` hooks you need to create custom [nitro plugin](https://nitro.unjs.io/guide/plugins.html). +:: + +### `content:file:beforeParse` + +Allows you to modify the contents of a file before it is handled by the parsers. + +Arguments: +- file + - Type: `Object` + - Properties: + - _id: `String` + - body: `String` + +### Example + +Changing all appearances of react to vue in all Markdown files: + + +```ts [my-nitro-plugin.ts] +export default defineNitroPlugin((nitroApp) => { + nitroApp.hooks.hook('content:file:beforeParse', (file) => { + if (file._id.endsWith('.md')) { + file.body = file.body.replace(/react/g, 'vue') + } + }) +}) +``` + +### `content:file:afterParse` + +Allows you to modify a document after being parsed by parsers. + +### Example + +Using content's first picture as cover image. + +```ts [my-nitro-plugin.ts] +import { visit } from 'unist-util-visit' + +export default defineNitroPlugin((nitroApp) => { + nitroApp.hooks.hook('content:file:afterParse', (file) => { + if (file._id.endsWith('.md')) { + visit(file.body, (n:any) => n.tag === 'img', (node) => { + file.coverImage = node.props.src + }) + } + }) +}) + +``` \ No newline at end of file From 86805a56c8217e2480ffd29c76d03adde79e168f Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 30 May 2022 10:32:37 +0200 Subject: [PATCH 08/15] test: fix --- test/fixtures/basic/addons/nitro-plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/basic/addons/nitro-plugin.ts b/test/fixtures/basic/addons/nitro-plugin.ts index 068c645ba..1ffc16453 100644 --- a/test/fixtures/basic/addons/nitro-plugin.ts +++ b/test/fixtures/basic/addons/nitro-plugin.ts @@ -6,7 +6,7 @@ export default defineNitroPlugin((nitroApp) => { lines.splice(1, 0, '__beforeParse: true') file.body = lines.join('\n') } else { - file.body = '---\n__beforeParse: true\n---\n' + file.content + file.body = '---\n__beforeParse: true\n---\n' + file.body } } }) From 888761f1e80acaeb31e1cc165bc4e013d60ee155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Mon, 30 May 2022 19:54:09 +0200 Subject: [PATCH 09/15] Update docs/content/4.api/4.advanced.md --- docs/content/4.api/4.advanced.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/4.api/4.advanced.md b/docs/content/4.api/4.advanced.md index 81366d2f6..2239da691 100644 --- a/docs/content/4.api/4.advanced.md +++ b/docs/content/4.api/4.advanced.md @@ -1,6 +1,6 @@ --- title: 'Advanced' -description: 'You can configure Nuxt Content with the content property in your nuxt.config.js|ts file.' +description: 'Nuxt Content is highly customizable, giving you freedom and control over how the data is transformed.' icon: heroicons-outline:lightning-bolt --- From 7eeb76ceb521de6dde3350095af294b0de32c705 Mon Sep 17 00:00:00 2001 From: Ahad Birang Date: Mon, 30 May 2022 20:08:49 +0200 Subject: [PATCH 10/15] Update docs/content/4.api/4.advanced.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Chopin --- docs/content/4.api/4.advanced.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/4.api/4.advanced.md b/docs/content/4.api/4.advanced.md index 2239da691..bcd2394d8 100644 --- a/docs/content/4.api/4.advanced.md +++ b/docs/content/4.api/4.advanced.md @@ -25,7 +25,7 @@ Arguments: ### Example -Changing all appearances of react to vue in all Markdown files: +Changing all occurrences of react to vue in all Markdown files: ```ts [my-nitro-plugin.ts] From 93a5039ef9950840d0a333108a58a08c0cb9d98b Mon Sep 17 00:00:00 2001 From: Ahad Birang Date: Mon, 30 May 2022 20:08:55 +0200 Subject: [PATCH 11/15] Update docs/content/4.api/4.advanced.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Chopin --- docs/content/4.api/4.advanced.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/4.api/4.advanced.md b/docs/content/4.api/4.advanced.md index bcd2394d8..95c0c62d5 100644 --- a/docs/content/4.api/4.advanced.md +++ b/docs/content/4.api/4.advanced.md @@ -28,7 +28,7 @@ Arguments: Changing all occurrences of react to vue in all Markdown files: -```ts [my-nitro-plugin.ts] +```ts [server/plugins/content.ts] export default defineNitroPlugin((nitroApp) => { nitroApp.hooks.hook('content:file:beforeParse', (file) => { if (file._id.endsWith('.md')) { From ab5df62b759c077f48e1b8ae16365d66207d1734 Mon Sep 17 00:00:00 2001 From: Ahad Birang Date: Mon, 30 May 2022 20:09:03 +0200 Subject: [PATCH 12/15] Update docs/content/4.api/4.advanced.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Chopin --- docs/content/4.api/4.advanced.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/4.api/4.advanced.md b/docs/content/4.api/4.advanced.md index 95c0c62d5..ba16aef75 100644 --- a/docs/content/4.api/4.advanced.md +++ b/docs/content/4.api/4.advanced.md @@ -46,7 +46,7 @@ Allows you to modify a document after being parsed by parsers. Using content's first picture as cover image. -```ts [my-nitro-plugin.ts] +```ts [server/plugins/content.ts] import { visit } from 'unist-util-visit' export default defineNitroPlugin((nitroApp) => { From a6712b2dac63cd640583fea00d619ed87cd048b5 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Tue, 31 May 2022 09:53:35 +0200 Subject: [PATCH 13/15] docs: add nitro plugin registeration --- docs/content/4.api/4.advanced.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/content/4.api/4.advanced.md b/docs/content/4.api/4.advanced.md index ba16aef75..705a00373 100644 --- a/docs/content/4.api/4.advanced.md +++ b/docs/content/4.api/4.advanced.md @@ -8,9 +8,26 @@ icon: heroicons-outline:lightning-bolt The module adds some hooks you can use: -::alert -In order to use `content:file:*` hooks you need to create custom [nitro plugin](https://nitro.unjs.io/guide/plugins.html). -:: +`content:file:*` hooks are available in nitro runtime, in order to use them you need to create custom [nitro plugin](https://nitro.unjs.io/guide/plugins.html). + +- Create your custom plugin + + ```ts [server/plugins/content.ts] + export default defineNitroPlugin((nitroApp) => { + // ... + }) + ``` + +- Register your plugin in `nuxt.config.ts` + + ```ts [nuxt.config.ts] + export default defineNuxtConfig({ + // ... + nitro: { + plugins: ['~/server/plugins/content.ts'] + } + }) + ``` ### `content:file:beforeParse` From b712a1cc3d6b1f3ea639782c20e85e64f4a092e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Tue, 31 May 2022 12:11:44 +0200 Subject: [PATCH 14/15] Update docs/content/4.api/4.advanced.md --- docs/content/4.api/4.advanced.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/4.api/4.advanced.md b/docs/content/4.api/4.advanced.md index 705a00373..d333d18d0 100644 --- a/docs/content/4.api/4.advanced.md +++ b/docs/content/4.api/4.advanced.md @@ -10,7 +10,7 @@ The module adds some hooks you can use: `content:file:*` hooks are available in nitro runtime, in order to use them you need to create custom [nitro plugin](https://nitro.unjs.io/guide/plugins.html). -- Create your custom plugin +- Create a plugin in the `server/plugins/` directory ```ts [server/plugins/content.ts] export default defineNitroPlugin((nitroApp) => { From d2fad05db56fdc6c62baa7e10d5cdec0b7d4899b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Tue, 31 May 2022 12:11:48 +0200 Subject: [PATCH 15/15] Update docs/content/4.api/4.advanced.md --- docs/content/4.api/4.advanced.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/4.api/4.advanced.md b/docs/content/4.api/4.advanced.md index d333d18d0..54406a53b 100644 --- a/docs/content/4.api/4.advanced.md +++ b/docs/content/4.api/4.advanced.md @@ -18,7 +18,7 @@ The module adds some hooks you can use: }) ``` -- Register your plugin in `nuxt.config.ts` +- Register the plugin in `nuxt.config.ts` ```ts [nuxt.config.ts] export default defineNuxtConfig({