@nuxtjs/mdc 0.9.5 → 0.11.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/dist/module.d.mts CHANGED
@@ -3,6 +3,7 @@ import { BundledLanguage, LanguageRegistration, BundledTheme, ThemeRegistrationA
3
3
  import { Options } from 'remark-rehype';
4
4
  import { R as RehypeHighlightOption, M as MdcConfig, a as MdcThemeOptions } from './shared/mdc.4762b8bc.mjs';
5
5
  export { A as Awaitable, b as HighlightResult, c as Highlighter, H as HighlighterOptions, d as defineConfig } from './shared/mdc.4762b8bc.mjs';
6
+ import { Options as Options$1 } from 'remark-stringify';
6
7
  import 'unified';
7
8
  import 'hast';
8
9
 
@@ -80,6 +81,14 @@ interface MDCParserResult {
80
81
  toc: Toc | undefined;
81
82
  }
82
83
 
84
+ interface MDCStringifyOptions {
85
+ plugins?: {
86
+ remarkStringify?: {
87
+ options?: Options$1;
88
+ };
89
+ };
90
+ }
91
+
83
92
  interface UnistPlugin {
84
93
  src?: string;
85
94
  options?: Record<string, any>;
@@ -515,6 +524,12 @@ interface Text extends Literal {
515
524
  */
516
525
  type TextData = Data;
517
526
 
527
+ interface MDCRenderOptions {
528
+ documentMeta: MDCData;
529
+ parentScope: any;
530
+ resolveComponent: (component: any) => any;
531
+ }
532
+
518
533
  declare const DefaultHighlightLangs: BundledLanguage[];
519
534
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
520
535
 
@@ -546,4 +561,4 @@ declare module '@nuxt/schema' {
546
561
  }
547
562
  }
548
563
 
549
- export { type Comment, type CommentData, type Content, type Data, DefaultHighlightLangs, type Doctype, type DoctypeData, type Element, type ElementContent, type ElementContentMap, type ElementData, type Literal, type Literals, type MDCComment, type MDCData, type MDCElement, type MDCNode, type MDCParseOptions, type MDCParserResult, type MDCRoot, type MDCText, MdcConfig, MdcThemeOptions, type ModuleOptions, type Node, type Nodes, type Parent, type Parents, type Properties, RehypeHighlightOption, type RehypePlugin, type RemarkPlugin, type Root, type RootContent, type RootContentMap, type RootData, type Text, type TextData, type Toc, type TocLink, type UnistPlugin, _default as default };
564
+ export { type Comment, type CommentData, type Content, type Data, DefaultHighlightLangs, type Doctype, type DoctypeData, type Element, type ElementContent, type ElementContentMap, type ElementData, type Literal, type Literals, type MDCComment, type MDCData, type MDCElement, type MDCNode, type MDCParseOptions, type MDCParserResult, type MDCRenderOptions, type MDCRoot, type MDCStringifyOptions, type MDCText, MdcConfig, MdcThemeOptions, type ModuleOptions, type Node, type Nodes, type Parent, type Parents, type Properties, RehypeHighlightOption, type RehypePlugin, type RemarkPlugin, type Root, type RootContent, type RootContentMap, type RootData, type Text, type TextData, type Toc, type TocLink, type UnistPlugin, _default as default };
package/dist/module.d.ts CHANGED
@@ -3,6 +3,7 @@ import { BundledLanguage, LanguageRegistration, BundledTheme, ThemeRegistrationA
3
3
  import { Options } from 'remark-rehype';
4
4
  import { R as RehypeHighlightOption, M as MdcConfig, a as MdcThemeOptions } from './shared/mdc.4762b8bc.js';
5
5
  export { A as Awaitable, b as HighlightResult, c as Highlighter, H as HighlighterOptions, d as defineConfig } from './shared/mdc.4762b8bc.js';
6
+ import { Options as Options$1 } from 'remark-stringify';
6
7
  import 'unified';
7
8
  import 'hast';
8
9
 
@@ -80,6 +81,14 @@ interface MDCParserResult {
80
81
  toc: Toc | undefined;
81
82
  }
82
83
 
84
+ interface MDCStringifyOptions {
85
+ plugins?: {
86
+ remarkStringify?: {
87
+ options?: Options$1;
88
+ };
89
+ };
90
+ }
91
+
83
92
  interface UnistPlugin {
84
93
  src?: string;
85
94
  options?: Record<string, any>;
@@ -515,6 +524,12 @@ interface Text extends Literal {
515
524
  */
516
525
  type TextData = Data;
517
526
 
527
+ interface MDCRenderOptions {
528
+ documentMeta: MDCData;
529
+ parentScope: any;
530
+ resolveComponent: (component: any) => any;
531
+ }
532
+
518
533
  declare const DefaultHighlightLangs: BundledLanguage[];
519
534
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
520
535
 
@@ -546,4 +561,4 @@ declare module '@nuxt/schema' {
546
561
  }
547
562
  }
548
563
 
549
- export { type Comment, type CommentData, type Content, type Data, DefaultHighlightLangs, type Doctype, type DoctypeData, type Element, type ElementContent, type ElementContentMap, type ElementData, type Literal, type Literals, type MDCComment, type MDCData, type MDCElement, type MDCNode, type MDCParseOptions, type MDCParserResult, type MDCRoot, type MDCText, MdcConfig, MdcThemeOptions, type ModuleOptions, type Node, type Nodes, type Parent, type Parents, type Properties, RehypeHighlightOption, type RehypePlugin, type RemarkPlugin, type Root, type RootContent, type RootContentMap, type RootData, type Text, type TextData, type Toc, type TocLink, type UnistPlugin, _default as default };
564
+ export { type Comment, type CommentData, type Content, type Data, DefaultHighlightLangs, type Doctype, type DoctypeData, type Element, type ElementContent, type ElementContentMap, type ElementData, type Literal, type Literals, type MDCComment, type MDCData, type MDCElement, type MDCNode, type MDCParseOptions, type MDCParserResult, type MDCRenderOptions, type MDCRoot, type MDCStringifyOptions, type MDCText, MdcConfig, MdcThemeOptions, type ModuleOptions, type Node, type Nodes, type Parent, type Parents, type Properties, RehypeHighlightOption, type RehypePlugin, type RemarkPlugin, type Root, type RootContent, type RootContentMap, type RootData, type Text, type TextData, type Toc, type TocLink, type UnistPlugin, _default as default };
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nuxtjs/mdc",
3
3
  "configKey": "mdc",
4
- "version": "0.9.5",
4
+ "version": "0.11.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "0.8.4",
7
7
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -11,7 +11,9 @@ const registerMDCSlotTransformer = (resolver) => {
11
11
  const compilerOptions = config.vue.template.compilerOptions;
12
12
  compilerOptions.nodeTransforms = [
13
13
  function viteMDCSlot(node, context) {
14
- if (node.tag === "MDCSlot") {
14
+ const isVueSlotWithUnwrap = node.tag === "slot" && node.props.find((p) => p.name === "mdc-unwrap" || p.name === "bind" && p.rawName === ":mdc-unwrap");
15
+ const isMDCSlot = node.tag === "MDCSlot";
16
+ if (isVueSlotWithUnwrap || isMDCSlot) {
15
17
  const transform = context.ssr ? context.nodeTransforms.find((nt) => nt.name === "ssrTransformSlotOutlet") : context.nodeTransforms.find((nt) => nt.name === "transformSlotOutlet");
16
18
  return () => {
17
19
  node.tag = "slot";
@@ -1,15 +1,17 @@
1
1
  <script>
2
- import { h, resolveComponent, reactive, watch, Text, Comment, defineAsyncComponent, defineComponent, toRaw, computed, getCurrentInstance } from "vue";
2
+ import { h, resolveComponent as vueResolveComponent, reactive, watch, Text, Comment, defineAsyncComponent, 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
6
  import htmlTags from "../parser/utils/html-tags-list";
7
7
  import { flatUnwrap } from "../utils/node";
8
+ import { pick } from "../utils";
8
9
  const DEFAULT_SLOT = "default";
9
10
  const rxOn = /^@|^v-on:/;
10
11
  const rxBind = /^:|^v-bind:/;
11
12
  const rxModel = /^v-model/;
12
13
  const nativeInputs = ["select", "textarea", "input"];
14
+ const specialParentTags = ["math", "svg"];
13
15
  const proseComponentMap = Object.fromEntries(["p", "a", "blockquote", "code", "pre", "code", "em", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "img", "ul", "ol", "li", "strong", "table", "thead", "tbody", "td", "th", "tr", "script"].map((t) => [t, `prose-${t}`]));
14
16
  export default defineComponent({
15
17
  name: "MDCRenderer",
@@ -104,20 +106,25 @@ export default defineComponent({
104
106
  return null;
105
107
  }
106
108
  const meta = { ...data, tags, $route: route, runtimeData, updateRuntimeData };
107
- const component = tag !== false ? resolveVueComponent(tag || meta.component?.name || meta.component || "div") : void 0;
109
+ const component = tag !== false ? resolveComponentInstance(tag || meta.component?.name || meta.component || "div") : void 0;
108
110
  return component ? h(component, { ...meta.component?.props, class: ctx.class, ...this.$attrs, key: contentKey }, { default: defaultSlotRenderer }) : defaultSlotRenderer?.();
109
111
  function defaultSlotRenderer() {
112
+ const defaultSlot = _renderSlots(body, h, { documentMeta: meta, parentScope: meta, resolveComponent: resolveComponentInstance });
113
+ if (!defaultSlot?.default) {
114
+ return null;
115
+ }
110
116
  if (unwrap) {
111
117
  return flatUnwrap(
112
- renderSlots(body, h, meta, meta).default(),
118
+ defaultSlot.default(),
113
119
  typeof unwrap === "string" ? unwrap.split(" ") : ["*"]
114
120
  );
115
121
  }
116
- return renderSlots(body, h, meta, meta).default();
122
+ return defaultSlot.default();
117
123
  }
118
124
  }
119
125
  });
120
- function renderNode(node, h2, documentMeta, parentScope = {}) {
126
+ function _renderNode(node, h2, options) {
127
+ const { documentMeta, parentScope, resolveComponent } = options;
121
128
  if (node.type === "text") {
122
129
  return h2(Text, node.value);
123
130
  }
@@ -129,7 +136,8 @@ function renderNode(node, h2, documentMeta, parentScope = {}) {
129
136
  if (node.tag === "binding") {
130
137
  return renderBinding(node, h2, documentMeta, parentScope);
131
138
  }
132
- const component = resolveVueComponent(renderTag);
139
+ const _resolveComponent = isUnresolvableTag(renderTag) ? (component2) => component2 : resolveComponent;
140
+ const component = _resolveComponent(renderTag);
133
141
  if (typeof component === "object") {
134
142
  component.tag = originalTag;
135
143
  }
@@ -137,9 +145,59 @@ function renderNode(node, h2, documentMeta, parentScope = {}) {
137
145
  return h2(
138
146
  component,
139
147
  props,
140
- renderSlots(node, h2, documentMeta, { ...parentScope, ...props })
148
+ _renderSlots(
149
+ node,
150
+ h2,
151
+ {
152
+ documentMeta,
153
+ parentScope: { ...parentScope, ...props },
154
+ resolveComponent: _resolveComponent
155
+ }
156
+ )
141
157
  );
142
158
  }
159
+ function _renderSlots(node, h2, options) {
160
+ const { documentMeta, parentScope, resolveComponent } = options;
161
+ const children = node.children || [];
162
+ const slotNodes = children.reduce((data, node2) => {
163
+ if (!isTemplate(node2)) {
164
+ data[DEFAULT_SLOT].children.push(node2);
165
+ return data;
166
+ }
167
+ const slotName = getSlotName(node2);
168
+ data[slotName] = data[slotName] || { props: {}, children: [] };
169
+ if (node2.type === "element") {
170
+ data[slotName].props = node2.props;
171
+ data[slotName].children.push(...node2.children || []);
172
+ }
173
+ return data;
174
+ }, {
175
+ [DEFAULT_SLOT]: { props: {}, children: [] }
176
+ });
177
+ const slots = Object.entries(slotNodes).reduce((slots2, [name, { props, children: children2 }]) => {
178
+ if (!children2.length) {
179
+ return slots2;
180
+ }
181
+ slots2[name] = (data = {}) => {
182
+ const scopedProps = pick(data, Object.keys(props || {}));
183
+ let vNodes = children2.map((child) => _renderNode(
184
+ child,
185
+ h2,
186
+ {
187
+ documentMeta,
188
+ parentScope: { ...parentScope, ...scopedProps },
189
+ resolveComponent
190
+ }
191
+ ));
192
+ if (props?.unwrap) {
193
+ vNodes = flatUnwrap(vNodes, props.unwrap);
194
+ }
195
+ return mergeTextNodes(vNodes);
196
+ };
197
+ return slots2;
198
+ }, {});
199
+ return slots;
200
+ }
143
201
  function renderBinding(node, h2, documentMeta, parentScope = {}) {
144
202
  const data = {
145
203
  ...documentMeta.runtimeData,
@@ -162,34 +220,6 @@ function renderBinding(node, h2, documentMeta, parentScope = {}) {
162
220
  const defaultValue = node.props?.defaultValue;
163
221
  return h2(Text, value ?? defaultValue ?? "");
164
222
  }
165
- function renderSlots(node, h2, documentMeta, parentProps) {
166
- const children = node.children || [];
167
- const slotNodes = children.reduce((data, node2) => {
168
- if (!isTemplate(node2)) {
169
- data[DEFAULT_SLOT].push(node2);
170
- return data;
171
- }
172
- const slotName = getSlotName(node2);
173
- data[slotName] = data[slotName] || [];
174
- if (node2.type === "element") {
175
- data[slotName].push(...node2.children || []);
176
- }
177
- return data;
178
- }, {
179
- [DEFAULT_SLOT]: []
180
- });
181
- const slots = Object.entries(slotNodes).reduce((slots2, [name, children2]) => {
182
- if (!children2.length) {
183
- return slots2;
184
- }
185
- slots2[name] = () => {
186
- const vNodes = children2.map((child) => renderNode(child, h2, documentMeta, parentProps));
187
- return mergeTextNodes(vNodes);
188
- };
189
- return slots2;
190
- }, {});
191
- return slots;
192
- }
193
223
  function propsToData(node, documentMeta) {
194
224
  const { tag = "", props = {} } = node;
195
225
  return Object.keys(props).reduce(function(data, key) {
@@ -244,12 +274,12 @@ function propsToDataRxBind(key, value, data, documentMeta) {
244
274
  data[key] = evalInContext(value, documentMeta);
245
275
  return data;
246
276
  }
247
- const resolveVueComponent = (component) => {
277
+ const resolveComponentInstance = (component) => {
248
278
  if (typeof component === "string") {
249
279
  if (htmlTags.includes(component)) {
250
280
  return component;
251
281
  }
252
- const _component = resolveComponent(pascalCase(component), false);
282
+ const _component = vueResolveComponent(pascalCase(component), false);
253
283
  if (!component || _component?.name === "AsyncComponentWrapper") {
254
284
  return _component;
255
285
  }
@@ -281,6 +311,9 @@ function getSlotName(node) {
281
311
  function isTemplate(node) {
282
312
  return node.tag === "template";
283
313
  }
314
+ function isUnresolvableTag(tag) {
315
+ return specialParentTags.includes(tag);
316
+ }
284
317
  function mergeTextNodes(nodes) {
285
318
  const mergedNodes = [];
286
319
  for (const node of nodes) {
@@ -302,7 +335,7 @@ async function resolveContentComponents(body, meta) {
302
335
  if (c?.render || c?.ssrRender || c?.__ssrInlineRender) {
303
336
  return;
304
337
  }
305
- const resolvedComponent = resolveVueComponent(c);
338
+ const resolvedComponent = resolveComponentInstance(c);
306
339
  if (resolvedComponent?.__asyncLoader && !resolvedComponent.__asyncResolved) {
307
340
  await resolvedComponent.__asyncLoader();
308
341
  }
@@ -313,6 +346,9 @@ async function resolveContentComponents(body, meta) {
313
346
  return [];
314
347
  }
315
348
  const renderTag = findMappedTag(node, documentMeta.tags);
349
+ if (isUnresolvableTag(renderTag)) {
350
+ return [];
351
+ }
316
352
  const components2 = [];
317
353
  if (node.type !== "root" && !htmlTags.includes(renderTag)) {
318
354
  components2.push(renderTag);
@@ -1,4 +1,5 @@
1
- export { parseMarkdown, createMarkdownParser } from './parser/index.js';
1
+ export { parseMarkdown, createMarkdownParser, createParseProcessor } from './parser/index.js';
2
+ export { stringifyMarkdown, createMarkdownStringifier, createStringifyProcessor } from './stringify/index.js';
2
3
  export { rehypeHighlight } from './highlighter/rehype.js';
3
4
  export { createShikiHighlighter } from './highlighter/shiki.js';
4
5
  export * from './utils/node.js';
@@ -1,4 +1,5 @@
1
- export { parseMarkdown, createMarkdownParser } from "./parser/index.js";
1
+ export { parseMarkdown, createMarkdownParser, createParseProcessor } from "./parser/index.js";
2
+ export { stringifyMarkdown, createMarkdownStringifier, createStringifyProcessor } from "./stringify/index.js";
2
3
  export { rehypeHighlight } from "./highlighter/rehype.js";
3
4
  export { createShikiHighlighter } from "./highlighter/shiki.js";
4
5
  export * from "./utils/node.js";
@@ -1,5 +1,6 @@
1
1
  import type { Options as VFileOptions } from 'vfile';
2
2
  import type { MDCParseOptions, MDCParserResult, MDCRoot } from '@nuxtjs/mdc';
3
+ export declare const createParseProcessor: (inlineOptions?: MDCParseOptions) => Promise<import("unified").Processor<undefined, undefined, undefined, undefined, undefined>>;
3
4
  export declare const createMarkdownParser: (inlineOptions?: MDCParseOptions) => Promise<(md: string, { fileOptions }?: {
4
5
  fileOptions?: VFileOptions;
5
6
  }) => Promise<MDCParserResult>>;
@@ -10,7 +10,7 @@ import { generateToc } from "./toc.js";
10
10
  import { compileHast } from "./compiler.js";
11
11
  let moduleOptions;
12
12
  let generatedMdcConfigs;
13
- export const createMarkdownParser = async (inlineOptions = {}) => {
13
+ export const createParseProcessor = async (inlineOptions = {}) => {
14
14
  if (!moduleOptions) {
15
15
  moduleOptions = await import(
16
16
  "#mdc-imports"
@@ -67,6 +67,10 @@ export const createMarkdownParser = async (inlineOptions = {}) => {
67
67
  for (const config of mdcConfigs) {
68
68
  processor = await config.unified?.post?.(processor) || processor;
69
69
  }
70
+ return processor;
71
+ };
72
+ export const createMarkdownParser = async (inlineOptions = {}) => {
73
+ const processor = await createParseProcessor(inlineOptions);
70
74
  return async function parse(md, { fileOptions } = {}) {
71
75
  const { content, data: frontmatter } = await parseFrontMatter(md);
72
76
  const processedFile = await processor.process({ ...fileOptions, value: content, data: frontmatter });
@@ -78,7 +82,7 @@ export const createMarkdownParser = async (inlineOptions = {}) => {
78
82
  );
79
83
  let toc;
80
84
  if (data.toc !== false) {
81
- const tocOption = defu(data.toc || {}, options.toc);
85
+ const tocOption = defu(data.toc || {}, inlineOptions.toc, defaults.toc);
82
86
  toc = generateToc(result.body, tocOption);
83
87
  }
84
88
  return {
@@ -0,0 +1,5 @@
1
+ import { type Processor } from 'unified';
2
+ import type { MDCStringifyOptions, MDCRoot } from '@nuxtjs/mdc';
3
+ export declare function createStringifyProcessor(options?: MDCStringifyOptions): Processor<undefined, import("hast").Root, import("unist").Node, import("mdast").Root, string>;
4
+ export declare function createMarkdownStringifier(options?: MDCStringifyOptions): (value: any, data?: Record<string, any>) => Promise<string>;
5
+ export declare function stringifyMarkdown(MDCAst: MDCRoot, data: Record<string, any>, options?: MDCStringifyOptions): Promise<string | null>;
@@ -0,0 +1,36 @@
1
+ import { unified } from "unified";
2
+ import gfm from "remark-gfm";
3
+ import mdc, { stringifyFrontMatter } from "remark-mdc";
4
+ import stringify from "remark-stringify";
5
+ import { mdcRemark } from "./mdc-remark.js";
6
+ export function createStringifyProcessor(options = {}) {
7
+ return unified().use(function jsonParser() {
8
+ this.parser = function(root) {
9
+ return JSON.parse(root);
10
+ };
11
+ }).use(mdcRemark).use(gfm).use(mdc).use(stringify, {
12
+ bullet: "-",
13
+ emphasis: "_",
14
+ rule: "-",
15
+ listItemIndent: "one",
16
+ fence: "`",
17
+ fences: true,
18
+ ...options?.plugins?.remarkStringify?.options
19
+ });
20
+ }
21
+ export function createMarkdownStringifier(options = {}) {
22
+ const processor = createStringifyProcessor(options);
23
+ async function stringify2(value, data = {}) {
24
+ const result = await processor.process({ value: JSON.stringify(value) });
25
+ if (Object.keys(data).length) {
26
+ return stringifyFrontMatter(data, result.value);
27
+ }
28
+ return result.value;
29
+ }
30
+ return stringify2;
31
+ }
32
+ export async function stringifyMarkdown(MDCAst, data, options = {}) {
33
+ const processor = createMarkdownStringifier(options);
34
+ if (!MDCAst) return null;
35
+ return await processor(MDCAst, data);
36
+ }
@@ -0,0 +1,8 @@
1
+ import type { Root as HastRoot } from 'hast';
2
+ import type { Options as ToMdastOptions } from 'hast-util-to-mdast';
3
+ import type { Root as MDastRoot } from 'mdast';
4
+ import type { VFile } from 'vfile';
5
+ interface Options extends ToMdastOptions {
6
+ }
7
+ export declare function mdcRemark(options?: Options | undefined | null): (node: HastRoot, _file: VFile) => MDastRoot;
8
+ export {};
@@ -0,0 +1,253 @@
1
+ import { defaultHandlers, toMdast } from "hast-util-to-mdast";
2
+ import { nodeTextContent } from "@nuxtjs/mdc/runtime/utils/node";
3
+ import { hasProtocol } from "ufo";
4
+ import { toHtml } from "hast-util-to-html";
5
+ import { visit } from "unist-util-visit";
6
+ import { format } from "hast-util-format";
7
+ import { computeHighlightRanges } from "./utils.js";
8
+ const mdcRemarkElementType = "mdc-element";
9
+ const own = {}.hasOwnProperty;
10
+ export function mdcRemark(options) {
11
+ return function(node, _file) {
12
+ const tree = preProcessElementNodes(node);
13
+ const mdast = toMdast(tree, {
14
+ /**
15
+ * Default to true in rehype-remark
16
+ * @see https://github.com/rehypejs/rehype-remark/blob/main/lib/index.js#L37ckages/remark/lib/index.js#L100
17
+ */
18
+ document: true,
19
+ ...options,
20
+ handlers: {
21
+ ...mdcRemarkHandlers,
22
+ ...options?.handlers
23
+ },
24
+ nodeHandlers: {
25
+ ...mdcRemarkNodeHandlers,
26
+ ...options?.nodeHandlers
27
+ }
28
+ });
29
+ return mdast;
30
+ };
31
+ }
32
+ function preProcessElementNodes(node) {
33
+ if (node.type === "element") {
34
+ if (node.children?.length && (node.children || []).every((child) => child.tag === "template")) {
35
+ node.children = node.children.flatMap((child) => {
36
+ if (typeof child.props?.["v-slot:default"] !== "undefined" && Object.keys(child.props).length === 1) {
37
+ return child.children || [];
38
+ }
39
+ return child;
40
+ });
41
+ }
42
+ const result = {
43
+ type: mdcRemarkElementType,
44
+ tagName: node.tag,
45
+ properties: node.props,
46
+ children: (node.children || []).map(preProcessElementNodes)
47
+ };
48
+ if (!node.children?.length) {
49
+ delete result.children;
50
+ }
51
+ return result;
52
+ }
53
+ if (node?.children) {
54
+ return {
55
+ ...node,
56
+ children: (node.children || []).map(preProcessElementNodes)
57
+ };
58
+ }
59
+ return node;
60
+ }
61
+ const mdcRemarkNodeHandlers = {
62
+ [mdcRemarkElementType]: (state, node, parent) => {
63
+ if (node.properties && node.properties.dataMdast === "ignore") {
64
+ return;
65
+ }
66
+ if (own.call(state.handlers, node.tagName)) {
67
+ return state.handlers[node.tagName](state, node, parent) || void 0;
68
+ }
69
+ if ("value" in node && typeof node.value === "string") {
70
+ const result = { type: "text", value: node.value };
71
+ state.patch(node, result);
72
+ return result;
73
+ }
74
+ const isInlineElement = (parent?.children || []).some((child) => child.type === "text") || ["p", "li"].includes(parent?.tagName);
75
+ if (isInlineElement) {
76
+ return {
77
+ type: "textComponent",
78
+ name: node.tagName,
79
+ attributes: node.properties,
80
+ children: state.all(node)
81
+ };
82
+ }
83
+ return {
84
+ type: "containerComponent",
85
+ name: node.tagName,
86
+ attributes: node.properties,
87
+ children: state.all(node)
88
+ };
89
+ }
90
+ };
91
+ const mdcRemarkHandlers = {
92
+ template: (state, node) => {
93
+ const vSlot = Object.keys(node.properties || {}).find((prop) => prop?.startsWith("v-slot:"))?.replace("v-slot:", "") || "default";
94
+ const attributes = Object.fromEntries(Object.entries(node.properties || {}).filter(([key]) => !key.startsWith("v-slot:")));
95
+ return {
96
+ type: "componentContainerSection",
97
+ name: vSlot,
98
+ attributes,
99
+ children: state.toFlow(state.all(node))
100
+ };
101
+ },
102
+ div: (state, node) => {
103
+ return {
104
+ type: "containerComponent",
105
+ name: "div",
106
+ attributes: node.properties,
107
+ children: state.toFlow(state.all(node))
108
+ };
109
+ },
110
+ code: (state, node) => {
111
+ const attributes = { ...node.properties };
112
+ if ("style" in attributes && !attributes.style) {
113
+ delete attributes.style;
114
+ }
115
+ if ("class" in attributes) {
116
+ attributes.className = String(attributes.class).split(" ").filter(Boolean);
117
+ delete attributes.class;
118
+ }
119
+ if (Array.isArray(attributes.className)) {
120
+ attributes.className = attributes.className.filter((name) => !name.startsWith("language-"));
121
+ if (Array.isArray(attributes.className) && !attributes.className.length) {
122
+ delete attributes.className;
123
+ }
124
+ }
125
+ if (attributes.language) {
126
+ attributes.lang = attributes.language;
127
+ delete attributes.language;
128
+ }
129
+ const result = { type: "inlineCode", value: nodeTextContent(node), attributes };
130
+ state.patch(node, result);
131
+ return result;
132
+ },
133
+ pre: (_state, node) => {
134
+ const meta = [
135
+ node.properties.filename ? `[${String(node.properties.filename).replace(/\]/g, "\\]")}]` : "",
136
+ node.properties.highlights?.length ? `{${computeHighlightRanges(node.properties.highlights)}}` : "",
137
+ node.properties.meta
138
+ ].filter(Boolean).join(" ");
139
+ const value = String(node.properties.code || "").replace(/\n$/, "");
140
+ return {
141
+ type: "code",
142
+ value,
143
+ lang: node.properties.language,
144
+ meta
145
+ };
146
+ },
147
+ binding: (state, node) => {
148
+ return {
149
+ type: "textComponent",
150
+ name: "binding",
151
+ attributes: node.properties,
152
+ children: state.toFlow(state.all(node))
153
+ };
154
+ },
155
+ span: (state, node) => {
156
+ const result = {
157
+ type: "textComponent",
158
+ name: "span",
159
+ attributes: node.properties,
160
+ children: state.all(node)
161
+ };
162
+ state.patch(node, result);
163
+ return result;
164
+ },
165
+ video: (state, node) => {
166
+ return {
167
+ type: "textComponent",
168
+ name: "video",
169
+ attributes: node.properties,
170
+ children: state.toFlow(state.all(node))
171
+ };
172
+ },
173
+ "nuxt-img": (state, node) => {
174
+ return {
175
+ type: "textComponent",
176
+ name: "nuxt-img",
177
+ attributes: node.properties,
178
+ children: state.toFlow(state.all(node))
179
+ };
180
+ },
181
+ "nuxt-picture": (state, node) => {
182
+ return {
183
+ type: "textComponent",
184
+ name: "nuxt-picture",
185
+ attributes: node.properties,
186
+ children: state.toFlow(state.all(node))
187
+ };
188
+ },
189
+ table: (state, node) => {
190
+ visit(node, (node2) => {
191
+ if (node2.type === "rehype-element") {
192
+ node2.type = "element";
193
+ }
194
+ });
195
+ if (Object.keys(node.properties).length) {
196
+ format({ type: "root", children: [node] });
197
+ return {
198
+ type: "html",
199
+ value: toHtml(node)
200
+ };
201
+ }
202
+ return defaultHandlers.table(state, node);
203
+ },
204
+ img: (state, node) => {
205
+ const { src, title, alt, ...attributes } = node.properties || {};
206
+ const result = {
207
+ type: "image",
208
+ url: state.resolve(String(src || "") || null),
209
+ title: title ? String(title) : null,
210
+ alt: alt ? String(alt) : "",
211
+ attributes
212
+ };
213
+ state.patch(node, result);
214
+ return result;
215
+ },
216
+ em: (state, node) => {
217
+ const result = { type: "emphasis", children: state.all(node), attributes: node.properties };
218
+ state.patch(node, result);
219
+ return result;
220
+ },
221
+ strong: (state, node) => {
222
+ const result = { type: "strong", children: state.all(node), attributes: node.properties };
223
+ state.patch(node, result);
224
+ return result;
225
+ },
226
+ a(state, node) {
227
+ const { href, title, ...attributes } = node.properties || {};
228
+ if (hasProtocol(String(href || ""))) {
229
+ if (attributes.target === "_blank") {
230
+ delete attributes.target;
231
+ }
232
+ if (["nofollow,noopener,noreferrer"].includes(String(attributes.rel))) {
233
+ delete attributes.rel;
234
+ }
235
+ }
236
+ const result = {
237
+ type: "link",
238
+ url: state.resolve(String(href || "") || null),
239
+ title: title ? String(title) : null,
240
+ children: state.all(node),
241
+ attributes
242
+ };
243
+ state.patch(node, result);
244
+ return result;
245
+ },
246
+ br(state, node) {
247
+ return {
248
+ type: "textComponent",
249
+ name: "br",
250
+ attributes: node.properties
251
+ };
252
+ }
253
+ };
@@ -0,0 +1 @@
1
+ export declare function computeHighlightRanges(input: string[] | string): string;
@@ -0,0 +1,16 @@
1
+ export function computeHighlightRanges(input) {
2
+ const numbers = Array.isArray(input) ? input.map(Number) : input.split(",").map(Number);
3
+ const ranges = [];
4
+ let start = numbers[0];
5
+ for (let i = 1; i <= numbers.length; i++) {
6
+ if (numbers[i] !== numbers[i - 1] + 1) {
7
+ if (start === numbers[i - 1]) {
8
+ ranges.push(`${start}`);
9
+ } else {
10
+ ranges.push(`${start}-${numbers[i - 1]}`);
11
+ }
12
+ start = numbers[i];
13
+ }
14
+ }
15
+ return ranges.join(",");
16
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Pick keys from an object
3
+ */
4
+ export declare function pick(obj: Record<string, any>, keys: string[]): Record<string, any>;
@@ -0,0 +1,12 @@
1
+ export function pick(obj, keys) {
2
+ return keys.reduce((acc, key) => {
3
+ const value = get(obj, key);
4
+ if (value !== void 0) {
5
+ acc[key] = value;
6
+ }
7
+ return acc;
8
+ }, {});
9
+ }
10
+ function get(obj, key) {
11
+ return key.split(".").reduce((acc, k) => acc && acc[k], obj);
12
+ }
@@ -31,7 +31,7 @@ export function nodeTextContent(node) {
31
31
  return node.map(nodeTextContent).join("");
32
32
  }
33
33
  if (isText(node)) {
34
- return node.children || node.value || "";
34
+ return node.value || node.children || "";
35
35
  }
36
36
  const children = nodeChildren(node);
37
37
  if (Array.isArray(children)) {
@@ -2,7 +2,7 @@ import { renderSlot as _renderSlot } from "vue";
2
2
  import { flatUnwrap } from "./node.js";
3
3
  export const renderSlot = (slots, name, props, ...rest) => {
4
4
  if (slots[name]) {
5
- return _renderSlot({ ...slots, [name]: () => flatUnwrap(slots[name](), props?.unwrap) }, name, props, ...rest);
5
+ return _renderSlot({ ...slots, [name]: () => flatUnwrap(slots[name](), props?.unwrap || props?.mdcUnwrap) }, name, props, ...rest);
6
6
  }
7
7
  return _renderSlot(slots, name, props, ...rest);
8
8
  };
@@ -2,7 +2,7 @@ import { ssrRenderSlot as _ssrRenderSlot } from "vue/server-renderer";
2
2
  import { flatUnwrap } from "./node.js";
3
3
  export const ssrRenderSlot = (slots, name, props, fallbackRenderFn, push, parentComponent, slotScopeId) => {
4
4
  if (slots[name]) {
5
- return _ssrRenderSlot({ ...slots, [name]: () => flatUnwrap(slots[name](), props?.unwrap) }, name, props, fallbackRenderFn, push, parentComponent, slotScopeId);
5
+ return _ssrRenderSlot({ ...slots, [name]: () => flatUnwrap(slots[name](), props?.unwrap || props?.mdcUnwrap) }, name, props, fallbackRenderFn, push, parentComponent, slotScopeId);
6
6
  }
7
7
  return _ssrRenderSlot(slots, name, props, fallbackRenderFn, push, parentComponent, slotScopeId);
8
8
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxtjs/mdc",
3
- "version": "0.9.5",
3
+ "version": "0.11.0",
4
4
  "description": "Nuxt MDC module",
5
5
  "repository": "nuxt-modules/mdc",
6
6
  "license": "MIT",
@@ -72,16 +72,18 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "@nuxt/kit": "^3.14.1592",
75
- "@shikijs/transformers": "^1.23.1",
75
+ "@shikijs/transformers": "^1.24.1",
76
76
  "@types/hast": "^3.0.4",
77
77
  "@types/mdast": "^4.0.4",
78
78
  "@vue/compiler-core": "^3.5.13",
79
79
  "consola": "^3.2.3",
80
- "debug": "^4.3.7",
80
+ "debug": "^4.4.0",
81
81
  "defu": "^6.1.4",
82
82
  "destr": "^2.0.3",
83
83
  "detab": "^3.0.2",
84
84
  "github-slugger": "^2.0.0",
85
+ "hast-util-format": "^1.1.0",
86
+ "hast-util-to-mdast": "^10.1.1",
85
87
  "hast-util-to-string": "^3.0.1",
86
88
  "mdast-util-to-hast": "^13.2.0",
87
89
  "micromark-util-sanitize-uri": "^2.0.1",
@@ -90,17 +92,20 @@
90
92
  "pathe": "^1.1.2",
91
93
  "property-information": "^6.5.0",
92
94
  "rehype-external-links": "^3.0.0",
95
+ "rehype-minify-whitespace": "^6.0.2",
93
96
  "rehype-raw": "^7.0.0",
97
+ "rehype-remark": "^10.0.0",
94
98
  "rehype-slug": "^6.0.0",
95
99
  "rehype-sort-attribute-values": "^5.0.1",
96
100
  "rehype-sort-attributes": "^5.0.1",
97
101
  "remark-emoji": "^5.0.1",
98
102
  "remark-gfm": "^4.0.0",
99
- "remark-mdc": "^3.4.0",
103
+ "remark-mdc": "^3.5.0",
100
104
  "remark-parse": "^11.0.0",
101
105
  "remark-rehype": "^11.1.1",
106
+ "remark-stringify": "^11.0.0",
102
107
  "scule": "^1.3.0",
103
- "shiki": "^1.23.1",
108
+ "shiki": "^1.24.1",
104
109
  "ufo": "^1.5.4",
105
110
  "unified": "^11.0.5",
106
111
  "unist-builder": "^4.0.0",
@@ -110,26 +115,26 @@
110
115
  },
111
116
  "devDependencies": {
112
117
  "@nuxt/devtools": "latest",
113
- "@nuxt/eslint-config": "^0.7.1",
118
+ "@nuxt/eslint-config": "^0.7.2",
114
119
  "@nuxt/module-builder": "^0.8.4",
115
120
  "@nuxt/schema": "^3.14.1592",
116
- "@nuxt/test-utils": "^3.14.4",
117
- "@nuxt/ui": "^2.19.2",
121
+ "@nuxt/test-utils": "^3.15.1",
122
+ "@nuxt/ui": "^2.20.0",
118
123
  "@nuxtjs/mdc": "link:.",
119
- "@types/node": "^22.9.1",
124
+ "@types/node": "^22.10.1",
120
125
  "changelogen": "^0.5.7",
121
- "eslint": "^9.15.0",
126
+ "eslint": "^9.16.0",
122
127
  "nuxt": "^3.14.1592",
123
128
  "rehype": "^13.0.2",
124
129
  "release-it": "^17.10.0",
125
- "typescript": "^5.6.3",
126
- "vitest": "^2.1.5",
130
+ "typescript": "5.6.3",
131
+ "vitest": "^2.1.8",
127
132
  "vue-tsc": "^2.1.10"
128
133
  },
129
134
  "resolutions": {
130
135
  "@nuxtjs/mdc": "workspace:*"
131
136
  },
132
- "packageManager": "pnpm@9.14.1",
137
+ "packageManager": "pnpm@9.15.0",
133
138
  "release-it": {
134
139
  "git": {
135
140
  "commitMessage": "chore(release): release v${version}"