@nuxtjs/mdc 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,6 +23,11 @@ MDC supercharges regular Markdown to write documents interacting deeply with any
23
23
 
24
24
  Learn more about the MDC syntax on https://content.nuxtjs.org/guide/writing/mdc
25
25
 
26
+ > [!Note]
27
+ > You may utilize this package inside of your Nuxt project (standard configuration) or within any Vue project.
28
+ >
29
+ > See [Rendering in your Vue project](#rendering-in-your-vue-project) below for more information.
30
+
26
31
  ## Install
27
32
 
28
33
  ```bash
@@ -44,7 +49,7 @@ export default defineNuxtConfig({
44
49
  })
45
50
  ```
46
51
 
47
- That's it! You can start writing and rendering markdown files ✨
52
+ That's it! You can start writing and rendering markdown files in your Nuxt project
48
53
 
49
54
  ## Rendering
50
55
 
@@ -262,6 +267,145 @@ export default defineNuxtConfig({
262
267
 
263
268
  Checkout [`ModuleOptions` types↗︎](https://github.com/nuxt-modules/mdc/blob/main/src/types.ts).
264
269
 
270
+ ## Rendering in your Vue project
271
+
272
+ The `<MDCRenderer>` component in combination with a few exported package utilities may also be utilized inside a normal (non-Nuxt) Vue project.
273
+
274
+ To implement in your standard Vue project, follow the instructions below.
275
+
276
+ ### Install the package
277
+
278
+ Follow the [install instructions above](#install), ignoring the step of adding the Nuxt module to a `nuxt.config.ts` file.
279
+
280
+ ### Stub Nuxt module imports
281
+
282
+ Since you're not using Nuxt, you'll need to stub a few of the module's imports in your Vue projects's Vite config file. This is necessary to avoid errors when the module tries to access Nuxt-specific imports.
283
+
284
+ Create a new file in your Vue project's root directory, such as `stub-mdc-imports.js`, and add the following content:
285
+
286
+ ```ts
287
+ // stub-mdc-imports.js
288
+ export default {}
289
+ ```
290
+
291
+ Next, update your Vue project's Vite config file (e.g. `vite.config.ts`) to alias the module's imports to the stub file:
292
+
293
+ ```ts
294
+ import { defineConfig } from 'vite'
295
+ import path from 'path'
296
+
297
+ export default defineConfig({
298
+ resolve: {
299
+ alias: {
300
+ '#mdc-imports': path.resolve(__dirname, './stub-mdc-imports.js'),
301
+ '#mdc-configs': path.resolve(__dirname, './stub-mdc-imports.js'),
302
+ }
303
+ }
304
+ })
305
+ ```
306
+
307
+ ### Usage
308
+
309
+ Next, let's create a new [Vue composable](https://vuejs.org/guide/reusability/composables.html) to handle parsing the markdown content, as well as adding syntax highlighting to code blocks with [Shiki](https://shiki.style/).
310
+
311
+ ```ts
312
+ // composables/useMarkdownParser.ts
313
+ // Import package exports
314
+ import {
315
+ createMarkdownParser,
316
+ rehypeHighlight,
317
+ createShikiHighlighter,
318
+ } from '@nuxtjs/mdc/runtime'
319
+ // Import desired Shiki themes and languages
320
+ import MaterialThemePalenight from 'shiki/themes/material-theme-palenight.mjs'
321
+ import HtmlLang from 'shiki/langs/html.mjs'
322
+ import MdcLang from 'shiki/langs/mdc.mjs'
323
+ import TsLang from 'shiki/langs/typescript.mjs'
324
+ import VueLang from 'shiki/langs/vue.mjs'
325
+ import ScssLang from 'shiki/langs/scss.mjs'
326
+ import YamlLang from 'shiki/langs/yaml.mjs'
327
+
328
+ export default function useMarkdownParser() {
329
+ let parser: Awaited<ReturnType<typeof createMarkdownParser>>
330
+
331
+ const parse = async (markdown: string) => {
332
+ if (!parser) {
333
+ parser = await createMarkdownParser({
334
+ rehype: {
335
+ plugins: {
336
+ highlight: {
337
+ instance: rehypeHighlight,
338
+ options: {
339
+ // Pass in your desired theme(s)
340
+ theme: 'material-theme-palenight',
341
+ // Create the Shiki highlighter
342
+ highlighter: createShikiHighlighter({
343
+ bundledThemes: {
344
+ 'material-theme-palenight': MaterialThemePalenight,
345
+ },
346
+ // Configure the bundled languages
347
+ bundledLangs: {
348
+ html: HtmlLang,
349
+ mdc: MdcLang,
350
+ vue: VueLang,
351
+ yml: YamlLang,
352
+ scss: ScssLang,
353
+ ts: TsLang,
354
+ typescript: TsLang,
355
+ },
356
+ }),
357
+ },
358
+ },
359
+ },
360
+ },
361
+ })
362
+ }
363
+ return parser(markdown)
364
+ }
365
+
366
+ return parse
367
+ }
368
+ ```
369
+
370
+ Now import the `useMarkdownParser` composable we just created along with an exported type interface into your host project's Vue component, and utilize them to process the raw markdown and initialize the `<MDCRenderer>` component.
371
+
372
+ ```vue
373
+ <script setup lang="ts">
374
+ import { onBeforeMount, ref, watch } from 'vue'
375
+ // Import package exports
376
+ import { MDCRenderer } from '@nuxtjs/mdc/runtime/components/MDCRenderer'
377
+ import type { MDCParserResult } from '@nuxtjs/mdc/runtime/types/index'
378
+ import { useMarkdownParser } from './composables/useMarkdownParser';
379
+
380
+ const md = ref(`
381
+ # Just a Vue app
382
+
383
+ This is markdown content rendered via the \`<MDCRenderer>\` component, including MDC below.
384
+
385
+ ::alert
386
+ Hello MDC
387
+ ::
388
+
389
+ \`\`\`ts
390
+ const a = 1;
391
+ \`\`\`
392
+ `);
393
+
394
+ const ast = ref<MDCParserResult | null>(null)
395
+ const parse = useMarkdownParser()
396
+
397
+ onBeforeMount(async () => {
398
+ ast.value = await parse(md.value)
399
+ })
400
+ </script>
401
+
402
+ <template>
403
+ <Suspense>
404
+ <MDCRenderer v-if="ast?.body" :body="ast.body" :data="ast.data" />
405
+ </Suspense>
406
+ </template>
407
+ ```
408
+
265
409
  ## Contributing
266
410
 
267
411
  You can contribute to this module online with CodeSandbox:
package/dist/module.d.mts CHANGED
@@ -62,6 +62,7 @@ interface ModuleOptions {
62
62
  [heading in 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6']?: boolean;
63
63
  };
64
64
  };
65
+ keepComments?: boolean;
65
66
  components?: {
66
67
  prose?: boolean;
67
68
  map?: Record<string, string>;
package/dist/module.d.ts CHANGED
@@ -62,6 +62,7 @@ interface ModuleOptions {
62
62
  [heading in 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6']?: boolean;
63
63
  };
64
64
  };
65
+ keepComments?: boolean;
65
66
  components?: {
66
67
  prose?: boolean;
67
68
  map?: Record<string, string>;
package/dist/module.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@nuxtjs/mdc",
3
3
  "configKey": "mdc",
4
- "version": "0.5.0"
4
+ "version": "0.6.0"
5
5
  }
package/dist/module.mjs CHANGED
@@ -157,11 +157,12 @@ function processUnistPlugins(plugins) {
157
157
  const imports = [];
158
158
  const definitions = [];
159
159
  Object.entries(plugins).forEach(([name, plugin]) => {
160
- imports.push(`import ${pascalCase(name)} from '${plugin.src || name}'`);
160
+ const instanceName = `_${pascalCase(name).replace(/\W/g, "")}`;
161
+ imports.push(`import ${instanceName} from '${plugin.src || name}'`);
161
162
  if (Object.keys(plugin).length) {
162
- definitions.push(` '${name}': { instance: ${pascalCase(name)}, options: ${JSON.stringify(plugin.options || plugin)} },`);
163
+ definitions.push(` '${name}': { instance: ${instanceName}, options: ${JSON.stringify(plugin.options || plugin)} },`);
163
164
  } else {
164
- definitions.push(` '${name}': { instance: ${pascalCase(name)} },`);
165
+ definitions.push(` '${name}': { instance: ${instanceName} },`);
165
166
  }
166
167
  });
167
168
  return { imports, definitions };
@@ -202,6 +203,7 @@ const module = defineNuxtModule({
202
203
  h6: false
203
204
  }
204
205
  },
206
+ keepComments: false,
205
207
  components: {
206
208
  prose: true,
207
209
  map: {}
@@ -246,7 +248,7 @@ const module = defineNuxtModule({
246
248
  });
247
249
  options.rehypePlugins ||= {};
248
250
  options.rehypePlugins.highlight ||= {};
249
- options.rehypePlugins.highlight.src ||= await resolver.resolvePath("./runtime/highlighter/rehype");
251
+ options.rehypePlugins.highlight.src ||= await resolver.resolvePath("./runtime/highlighter/rehype-nuxt");
250
252
  options.rehypePlugins.highlight.options ||= {};
251
253
  }
252
254
  const registerTemplate = (options2) => {
@@ -4,6 +4,7 @@
4
4
  :body="data?.body"
5
5
  :toc="data?.toc"
6
6
  :excerpt="data?.excerpt"
7
+ :error="error"
7
8
  >
8
9
  <MDCRenderer
9
10
  v-if="body"
@@ -59,7 +60,7 @@ const props = defineProps({
59
60
 
60
61
  const key = computed(() => hash(props.value))
61
62
 
62
- const { data, refresh } = await useAsyncData(key.value, async () => {
63
+ const { data, refresh, error } = await useAsyncData(key.value, async () => {
63
64
  if (typeof props.value !== 'string') {
64
65
  return props.value
65
66
  }
@@ -1,9 +1,8 @@
1
1
  <script>
2
- import { h, resolveComponent, Text, defineComponent, toRaw, computed } from "vue";
2
+ import { h, resolveComponent, Text, Comment, defineComponent, toRaw, computed, getCurrentInstance } from "vue";
3
3
  import destr from "destr";
4
4
  import { kebabCase, pascalCase } from "scule";
5
5
  import { find, html } from "property-information";
6
- import { useRoute, useRuntimeConfig } from "#imports";
7
6
  import htmlTags from "../parser/utils/html-tags-list";
8
7
  const DEFAULT_SLOT = "default";
9
8
  const rxOn = /^@|^v-on:/;
@@ -51,10 +50,12 @@ export default defineComponent({
51
50
  }
52
51
  },
53
52
  async setup(props) {
54
- const { mdc } = useRuntimeConfig().public;
53
+ const $nuxt = getCurrentInstance()?.appContext?.app?.$nuxt;
54
+ const route = $nuxt?.$route;
55
+ const { mdc } = $nuxt?.$config?.public || {};
55
56
  const tags = {
56
- ...mdc.components.prose && props.prose !== false ? proseComponentMap : {},
57
- ...mdc.components.map,
57
+ ...mdc?.components?.prose && props.prose !== false ? proseComponentMap : {},
58
+ ...mdc?.components?.map || {},
58
59
  ...toRaw(props.data?.mdc?.components || {}),
59
60
  ...props.components
60
61
  };
@@ -63,14 +64,14 @@ export default defineComponent({
63
64
  return Array.from(new Set(components)).sort().join(".");
64
65
  });
65
66
  await resolveContentComponents(props.body, { tags });
66
- return { tags, contentKey };
67
+ return { tags, contentKey, route };
67
68
  },
68
69
  render(ctx) {
69
- const { tags, tag, body, data, contentKey } = ctx;
70
+ const { tags, tag, body, data, contentKey, route } = ctx;
70
71
  if (!body) {
71
72
  return null;
72
73
  }
73
- const meta = { ...data, tags };
74
+ const meta = { ...data, tags, $route: route };
74
75
  const component = tag !== false ? resolveVueComponent(tag || meta.component?.name || meta.component || "div") : void 0;
75
76
  const childrenRenderer = renderSlots(body, h, meta, meta);
76
77
  return component ? h(component, { ...meta.component?.props, ...this.$attrs, key: contentKey }, childrenRenderer) : childrenRenderer.default?.();
@@ -80,6 +81,9 @@ function renderNode(node, h2, documentMeta, parentScope = {}) {
80
81
  if (node.type === "text") {
81
82
  return h2(Text, node.value);
82
83
  }
84
+ if (node.type === "comment") {
85
+ return h2(Comment, null, node.value);
86
+ }
83
87
  const originalTag = node.tag;
84
88
  const renderTag = findMappedTag(node, documentMeta.tags);
85
89
  if (node.tag === "binding") {
@@ -99,7 +103,6 @@ function renderNode(node, h2, documentMeta, parentScope = {}) {
99
103
  function renderBinding(node, h2, documentMeta, parentScope = {}) {
100
104
  const data = {
101
105
  ...parentScope,
102
- $route: () => useRoute(),
103
106
  $document: documentMeta,
104
107
  $doc: documentMeta
105
108
  };
@@ -207,7 +210,7 @@ function propsToDataRxBind(key, value, data, documentMeta) {
207
210
  return data;
208
211
  }
209
212
  const resolveVueComponent = (component) => {
210
- if (!htmlTags.includes(component) && !component?.render) {
213
+ if (!htmlTags.includes(component) && !component?.render && !component?.ssrRender) {
211
214
  const componentFn = resolveComponent(pascalCase(component), false);
212
215
  if (typeof componentFn === "object") {
213
216
  return componentFn;
@@ -261,7 +264,7 @@ async function resolveContentComponents(body, meta) {
261
264
  }));
262
265
  function loadComponents(node, documentMeta) {
263
266
  const tag = node.tag;
264
- if (node.type === "text" || tag === "binding") {
267
+ if (node.type === "text" || tag === "binding" || node.type === "comment") {
265
268
  return [];
266
269
  }
267
270
  const renderTag = findMappedTag(node, documentMeta.tags);
@@ -39,6 +39,7 @@ declare const _default: DefineComponent<{
39
39
  }, {
40
40
  tags: any;
41
41
  contentKey: import("vue").ComputedRef<string>;
42
+ route: any;
42
43
  }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
43
44
  /**
44
45
  * Content to render
@@ -5,13 +5,11 @@
5
5
  </template>
6
6
 
7
7
  <script setup lang="ts">
8
- import { computed } from 'vue'
9
-
10
8
  defineProps({
11
9
  src: {
12
10
  type: String,
13
11
  default: ''
14
12
  }
15
13
  })
16
- const isDev = computed(() => process.dev)
14
+ const isDev = import.meta.env
17
15
  </script>
@@ -0,0 +1,3 @@
1
+ import { type RehypeHighlightOption } from './rehype';
2
+ export default rehypeHighlight;
3
+ export declare function rehypeHighlight(opts?: Partial<RehypeHighlightOption>): (tree: import("hast").Root) => Promise<void>;
@@ -0,0 +1,33 @@
1
+ import { rehypeHighlight as rehypeHighlightUniversal } from "./rehype.mjs";
2
+ const defaults = {
3
+ theme: {},
4
+ async highlighter(code, lang, theme, options) {
5
+ try {
6
+ if (process.browser && window.sessionStorage.getItem("mdc-shiki-highlighter") === "browser") {
7
+ return import("#mdc-highlighter").then((h) => h.default(code, lang, theme, options)).catch(() => ({}));
8
+ }
9
+ return await $fetch("/api/_mdc/highlight", {
10
+ params: {
11
+ code,
12
+ lang,
13
+ theme: JSON.stringify(theme),
14
+ options: JSON.stringify(options)
15
+ }
16
+ });
17
+ } catch (e) {
18
+ if (process.browser && e?.response?.status === 404) {
19
+ window.sessionStorage.setItem("mdc-shiki-highlighter", "browser");
20
+ return this.highlighter?.(code, lang, theme, options);
21
+ }
22
+ }
23
+ return Promise.resolve({ tree: [{ type: "text", value: code }], className: "", style: "" });
24
+ }
25
+ };
26
+ export default rehypeHighlight;
27
+ export function rehypeHighlight(opts = {}) {
28
+ const options = { ...defaults, ...opts };
29
+ if (typeof options.highlighter !== "function") {
30
+ options.highlighter = defaults.highlighter;
31
+ }
32
+ return rehypeHighlightUniversal(options);
33
+ }
@@ -5,4 +5,4 @@ export interface RehypeHighlightOption {
5
5
  highlighter?: Highlighter;
6
6
  }
7
7
  export default rehypeHighlight;
8
- export declare function rehypeHighlight(opts?: RehypeHighlightOption): (tree: Root) => Promise<void>;
8
+ export declare function rehypeHighlight(opts: RehypeHighlightOption): (tree: Root) => Promise<void>;
@@ -1,32 +1,8 @@
1
1
  import { visit } from "unist-util-visit";
2
2
  import { toString } from "hast-util-to-string";
3
- const defaults = {
4
- theme: {},
5
- async highlighter(code, lang, theme, options) {
6
- if (process.browser && window.sessionStorage.getItem("mdc-shiki-highlighter") === "browser") {
7
- return import("#mdc-highlighter").then((h) => h.default(code, lang, theme, options));
8
- }
9
- try {
10
- return await $fetch("/api/_mdc/highlight", {
11
- params: {
12
- code,
13
- lang,
14
- theme: JSON.stringify(theme),
15
- options: JSON.stringify(options)
16
- }
17
- });
18
- } catch (e) {
19
- if (process.browser && e?.response?.status === 404) {
20
- window.sessionStorage.setItem("mdc-shiki-highlighter", "browser");
21
- return this.highlighter?.(code, lang, theme, options);
22
- }
23
- }
24
- return Promise.resolve({ tree: [{ type: "text", value: code }], className: "", style: "" });
25
- }
26
- };
27
3
  export default rehypeHighlight;
28
- export function rehypeHighlight(opts = {}) {
29
- const options = { ...defaults, ...opts };
4
+ export function rehypeHighlight(opts) {
5
+ const options = opts;
30
6
  return async (tree) => {
31
7
  const tasks = [];
32
8
  const styles = [];
@@ -53,7 +53,7 @@ export function createShikiHighlighter({
53
53
  if (bundledLangs[lang]) {
54
54
  await shiki2.loadLanguage(bundledLangs[lang]);
55
55
  } else {
56
- if (process.dev) {
56
+ if (import.meta.env) {
57
57
  console.warn(`[@nuxtjs/mdc] Language "${lang}" is not loaded to the Shiki highlighter, fallback to plain text. Add the language to "mdc.highlight.langs" to fix this.`);
58
58
  }
59
59
  lang = "text";
@@ -64,7 +64,7 @@ export function createShikiHighlighter({
64
64
  if (bundledThemes[theme2]) {
65
65
  await shiki2.loadTheme(bundledThemes[theme2]);
66
66
  } else {
67
- if (process.dev) {
67
+ if (import.meta.env) {
68
68
  console.warn(`[@nuxtjs/mdc] Theme "${theme2}" is not loaded to the Shiki highlighter. Add the theme to "mdc.highlight.themes" to fix this.`);
69
69
  }
70
70
  themesObject[color] = "none";
@@ -1,2 +1,4 @@
1
- export { parseMarkdown } from './parser';
1
+ export { parseMarkdown, createMarkdownParser } from './parser';
2
+ export { rehypeHighlight } from './highlighter/rehype';
3
+ export { createShikiHighlighter } from './highlighter/shiki';
2
4
  export * from './utils/node';
@@ -1,2 +1,4 @@
1
- export { parseMarkdown } from "./parser/index.mjs";
1
+ export { parseMarkdown, createMarkdownParser } from "./parser/index.mjs";
2
+ export { rehypeHighlight } from "./highlighter/rehype.mjs";
3
+ export { createShikiHighlighter } from "./highlighter/shiki.mjs";
2
4
  export * from "./utils/node.mjs";
@@ -1 +1,2 @@
1
- export declare function compileHast(this: any): void;
1
+ import type { MDCParseOptions } from '../types';
2
+ export declare function compileHast(this: any, options?: MDCParseOptions): void;
@@ -1,7 +1,7 @@
1
1
  import { toString } from "hast-util-to-string";
2
2
  import Slugger from "github-slugger";
3
3
  import { validateProps } from "./utils/props.mjs";
4
- export function compileHast() {
4
+ export function compileHast(options = {}) {
5
5
  const slugs = new Slugger();
6
6
  function compileToJSON(node, parent) {
7
7
  if (node.type === "root") {
@@ -55,6 +55,12 @@ export function compileHast() {
55
55
  };
56
56
  }
57
57
  }
58
+ if (options.keepComments && node.type === "comment") {
59
+ return {
60
+ type: "comment",
61
+ value: node.value
62
+ };
63
+ }
58
64
  return null;
59
65
  }
60
66
  this.Compiler = (tree) => {
@@ -1,10 +1,6 @@
1
- import type { MDCData, MDCParseOptions, MDCRoot, Toc } from '../types';
2
- export declare const parseMarkdown: (md: string, inlineOptions?: MDCParseOptions) => Promise<{
3
- data: MDCData;
4
- body: MDCRoot;
5
- excerpt: MDCRoot | undefined;
6
- toc: Toc | undefined;
7
- }>;
1
+ import type { MDCParseOptions, MDCParserResult, MDCRoot } from '../types';
2
+ export declare const createMarkdownParser: (inlineOptions?: MDCParseOptions) => Promise<(md: string) => Promise<MDCParserResult>>;
3
+ export declare const parseMarkdown: (md: string, inlineOptions?: MDCParseOptions) => Promise<MDCParserResult>;
8
4
  export declare function contentHeading(body: MDCRoot): {
9
5
  title: string;
10
6
  description: string;
@@ -10,7 +10,7 @@ import { generateToc } from "./toc.mjs";
10
10
  import { nodeTextContent } from "../utils/node.mjs";
11
11
  let moduleOptions;
12
12
  let generatedMdcConfigs;
13
- export const parseMarkdown = async (md, inlineOptions = {}) => {
13
+ export const createMarkdownParser = async (inlineOptions = {}) => {
14
14
  if (!moduleOptions) {
15
15
  moduleOptions = await import(
16
16
  "#mdc-imports"
@@ -44,7 +44,10 @@ export const parseMarkdown = async (md, inlineOptions = {}) => {
44
44
  highlight: moduleOptions?.highlight
45
45
  }, defaults);
46
46
  if (options.rehype?.plugins?.highlight) {
47
- options.rehype.plugins.highlight.options = options.highlight || {};
47
+ options.rehype.plugins.highlight.options = {
48
+ ...options.rehype.plugins.highlight.options || {},
49
+ ...options.highlight || {}
50
+ };
48
51
  }
49
52
  let processor = unified();
50
53
  for (const config of mdcConfigs) {
@@ -60,34 +63,40 @@ export const parseMarkdown = async (md, inlineOptions = {}) => {
60
63
  processor = await config.unified?.rehype?.(processor) || processor;
61
64
  }
62
65
  await useProcessorPlugins(processor, options.rehype?.plugins);
63
- processor.use(compileHast);
66
+ processor.use(compileHast, options);
64
67
  for (const config of mdcConfigs) {
65
68
  processor = await config.unified?.post?.(processor) || processor;
66
69
  }
67
- const { content, data: frontmatter } = await parseFrontMatter(md);
68
- const processedFile = await processor.process({ value: content, data: frontmatter });
69
- const result = processedFile.result;
70
- const data = Object.assign(
71
- contentHeading(result.body),
72
- frontmatter,
73
- processedFile?.data || {}
74
- );
75
- let toc;
76
- if (data.toc !== false) {
77
- const tocOption = defu(data.toc || {}, options.toc);
78
- toc = generateToc(result.body, tocOption);
79
- }
80
- return {
81
- data,
82
- body: result.body,
83
- excerpt: result.excerpt,
84
- toc
70
+ return async (md) => {
71
+ const { content, data: frontmatter } = await parseFrontMatter(md);
72
+ const processedFile = await processor.process({ value: content, data: frontmatter });
73
+ const result = processedFile.result;
74
+ const data = Object.assign(
75
+ contentHeading(result.body),
76
+ frontmatter,
77
+ processedFile?.data || {}
78
+ );
79
+ let toc;
80
+ if (data.toc !== false) {
81
+ const tocOption = defu(data.toc || {}, options.toc);
82
+ toc = generateToc(result.body, tocOption);
83
+ }
84
+ return {
85
+ data,
86
+ body: result.body,
87
+ excerpt: result.excerpt,
88
+ toc
89
+ };
85
90
  };
86
91
  };
92
+ export const parseMarkdown = async (md, inlineOptions = {}) => {
93
+ const parser = await createMarkdownParser(inlineOptions);
94
+ return parser(md);
95
+ };
87
96
  export function contentHeading(body) {
88
97
  let title = "";
89
98
  let description = "";
90
- const children = body.children.filter((node) => node.type !== "text" && node.tag !== "hr");
99
+ const children = body.children.filter((node) => node.type === "element" && node.tag !== "hr");
91
100
  if (children.length && children[0].tag === "h1") {
92
101
  const node = children.shift();
93
102
  title = nodeTextContent(node);
@@ -1,6 +1,8 @@
1
1
  import type { Options as RehypeOption } from 'remark-rehype';
2
2
  import type { RehypeHighlightOption } from '../highlighter/rehype';
3
3
  import type { MdcConfig } from './config';
4
+ import type { MDCData, MDCRoot } from './tree';
5
+ import type { Toc } from './toc';
4
6
  export interface RemarkPlugin {
5
7
  instance?: any;
6
8
  options?: Array<any> | Record<string, any>;
@@ -25,8 +27,15 @@ export interface MDCParseOptions {
25
27
  depth?: number;
26
28
  searchDepth?: number;
27
29
  };
30
+ keepComments?: boolean;
28
31
  /**
29
32
  * Inline mdc.config.ts
30
33
  */
31
34
  configs?: MdcConfig[];
32
35
  }
36
+ export interface MDCParserResult {
37
+ data: MDCData;
38
+ body: MDCRoot;
39
+ excerpt: MDCRoot | undefined;
40
+ toc: Toc | undefined;
41
+ }
@@ -2,13 +2,17 @@ export type MDCText = {
2
2
  type: 'text';
3
3
  value: string;
4
4
  };
5
+ export type MDCComment = {
6
+ type: 'comment';
7
+ value: string;
8
+ };
5
9
  export type MDCElement = {
6
10
  type: 'element';
7
11
  tag: string;
8
12
  props: Record<string, any> | undefined;
9
- children: Array<MDCElement | MDCText>;
13
+ children: Array<MDCElement | MDCText | MDCComment>;
10
14
  };
11
- export type MDCNode = MDCElement | MDCText;
15
+ export type MDCNode = MDCElement | MDCText | MDCComment;
12
16
  export type MDCRoot = {
13
17
  type: 'root';
14
18
  children: Array<MDCNode>;
@@ -1,4 +1,7 @@
1
1
  export function flattenNodeText(node) {
2
+ if (node.type === "comment") {
3
+ return "";
4
+ }
2
5
  if (node.type === "text") {
3
6
  return node.value || "";
4
7
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxtjs/mdc",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Nuxt MDC module",
5
5
  "repository": "nuxt-modules/mdc",
6
6
  "license": "MIT",
@@ -16,10 +16,22 @@
16
16
  "import": "./dist/config.mjs",
17
17
  "require": "./dist/config.cjs"
18
18
  },
19
- "./runtime": "./dist/runtime/index.mjs",
20
- "./dist/runtime": "./dist/runtime/index.mjs",
21
- "./runtime/*": "./dist/runtime/*.mjs",
22
- "./dist/runtime/*": "./dist/runtime/*.mjs"
19
+ "./runtime": {
20
+ "types": "./dist/runtime/index.d.ts",
21
+ "import": "./dist/runtime/index.mjs"
22
+ },
23
+ "./dist/runtime": {
24
+ "types": "./dist/runtime/index.d.ts",
25
+ "import": "./dist/runtime/index.mjs"
26
+ },
27
+ "./runtime/*": {
28
+ "types": "./dist/runtime/*.d.ts",
29
+ "import": "./dist/runtime/*.mjs"
30
+ },
31
+ "./dist/runtime/*": {
32
+ "types": "./dist/runtime/*.d.ts",
33
+ "import": "./dist/runtime/*.mjs"
34
+ }
23
35
  },
24
36
  "main": "./dist/module.cjs",
25
37
  "types": "./dist/types.d.ts",
@@ -50,15 +62,15 @@
50
62
  "test:watch": "vitest watch"
51
63
  },
52
64
  "dependencies": {
53
- "@nuxt/kit": "^3.10.0",
54
- "@shikijs/transformers": "^1.0.0-beta.6",
65
+ "@nuxt/kit": "^3.10.3",
66
+ "@shikijs/transformers": "^1.1.7",
55
67
  "@types/hast": "^3.0.4",
56
68
  "@types/mdast": "^4.0.3",
57
- "@vue/compiler-core": "^3.4.15",
69
+ "@vue/compiler-core": "^3.4.21",
58
70
  "consola": "^3.2.3",
59
71
  "debug": "^4.3.4",
60
72
  "defu": "^6.1.4",
61
- "destr": "^2.0.2",
73
+ "destr": "^2.0.3",
62
74
  "detab": "^3.0.2",
63
75
  "github-slugger": "^2.0.0",
64
76
  "hast-util-to-string": "^3.0.0",
@@ -75,12 +87,12 @@
75
87
  "rehype-sort-attributes": "^5.0.0",
76
88
  "remark-emoji": "^4.0.1",
77
89
  "remark-gfm": "^4.0.0",
78
- "remark-mdc": "^3.0.2",
90
+ "remark-mdc": "^3.1.0",
79
91
  "remark-parse": "^11.0.0",
80
92
  "remark-rehype": "^11.1.0",
81
- "scule": "^1.2.0",
82
- "shiki": "^1.0.0-beta.6",
83
- "ufo": "^1.3.2",
93
+ "scule": "^1.3.0",
94
+ "shiki": "^1.1.7",
95
+ "ufo": "^1.4.0",
84
96
  "unified": "^11.0.4",
85
97
  "unist-builder": "^4.0.0",
86
98
  "unist-util-visit": "^5.0.0",
@@ -90,19 +102,19 @@
90
102
  "@nuxt/devtools": "latest",
91
103
  "@nuxt/eslint-config": "^0.2.0",
92
104
  "@nuxt/module-builder": "^0.5.5",
93
- "@nuxt/schema": "^3.10.0",
105
+ "@nuxt/schema": "^3.10.3",
94
106
  "@nuxt/test-utils": "^3.11.0",
95
- "@nuxt/ui": "^2.13.0",
107
+ "@nuxt/ui": "^2.14.1",
96
108
  "@types/mdurl": "^1.0.5",
97
- "@types/node": "^20.11.16",
109
+ "@types/node": "^20.11.24",
98
110
  "changelogen": "^0.5.5",
99
- "eslint": "^8.56.0",
100
- "nuxt": "^3.10.0",
111
+ "eslint": "^8.57.0",
112
+ "nuxt": "^3.10.3",
101
113
  "rehype": "^13.0.1",
102
- "release-it": "^17.0.3",
103
- "vitest": "^1.2.2"
114
+ "release-it": "^17.1.1",
115
+ "vitest": "^1.3.1"
104
116
  },
105
- "packageManager": "pnpm@8.15.1",
117
+ "packageManager": "pnpm@8.15.4",
106
118
  "release-it": {
107
119
  "git": {
108
120
  "commitMessage": "chore(release): release v${version}"