@nuxtjs/mdc 0.10.0 → 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 +16 -1
- package/dist/module.d.ts +16 -1
- package/dist/module.json +1 -1
- package/dist/runtime/components/MDCRenderer.vue +64 -34
- package/dist/runtime/index.d.ts +2 -1
- package/dist/runtime/index.js +2 -1
- package/dist/runtime/parser/index.d.ts +1 -1
- package/dist/runtime/parser/index.js +2 -2
- package/dist/runtime/stringify/index.d.ts +5 -0
- package/dist/runtime/stringify/index.js +36 -0
- package/dist/runtime/stringify/mdc-remark.d.ts +8 -0
- package/dist/runtime/stringify/mdc-remark.js +253 -0
- package/dist/runtime/stringify/utils.d.ts +1 -0
- package/dist/runtime/stringify/utils.js +16 -0
- package/package.json +14 -10
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,5 +1,5 @@
|
|
|
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";
|
|
@@ -11,6 +11,7 @@ const rxOn = /^@|^v-on:/;
|
|
|
11
11
|
const rxBind = /^:|^v-bind:/;
|
|
12
12
|
const rxModel = /^v-model/;
|
|
13
13
|
const nativeInputs = ["select", "textarea", "input"];
|
|
14
|
+
const specialParentTags = ["math", "svg"];
|
|
14
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}`]));
|
|
15
16
|
export default defineComponent({
|
|
16
17
|
name: "MDCRenderer",
|
|
@@ -105,20 +106,25 @@ export default defineComponent({
|
|
|
105
106
|
return null;
|
|
106
107
|
}
|
|
107
108
|
const meta = { ...data, tags, $route: route, runtimeData, updateRuntimeData };
|
|
108
|
-
const component = tag !== false ?
|
|
109
|
+
const component = tag !== false ? resolveComponentInstance(tag || meta.component?.name || meta.component || "div") : void 0;
|
|
109
110
|
return component ? h(component, { ...meta.component?.props, class: ctx.class, ...this.$attrs, key: contentKey }, { default: defaultSlotRenderer }) : defaultSlotRenderer?.();
|
|
110
111
|
function defaultSlotRenderer() {
|
|
112
|
+
const defaultSlot = _renderSlots(body, h, { documentMeta: meta, parentScope: meta, resolveComponent: resolveComponentInstance });
|
|
113
|
+
if (!defaultSlot?.default) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
111
116
|
if (unwrap) {
|
|
112
117
|
return flatUnwrap(
|
|
113
|
-
|
|
118
|
+
defaultSlot.default(),
|
|
114
119
|
typeof unwrap === "string" ? unwrap.split(" ") : ["*"]
|
|
115
120
|
);
|
|
116
121
|
}
|
|
117
|
-
return
|
|
122
|
+
return defaultSlot.default();
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
125
|
});
|
|
121
|
-
function
|
|
126
|
+
function _renderNode(node, h2, options) {
|
|
127
|
+
const { documentMeta, parentScope, resolveComponent } = options;
|
|
122
128
|
if (node.type === "text") {
|
|
123
129
|
return h2(Text, node.value);
|
|
124
130
|
}
|
|
@@ -130,7 +136,8 @@ function renderNode(node, h2, documentMeta, parentScope = {}) {
|
|
|
130
136
|
if (node.tag === "binding") {
|
|
131
137
|
return renderBinding(node, h2, documentMeta, parentScope);
|
|
132
138
|
}
|
|
133
|
-
const
|
|
139
|
+
const _resolveComponent = isUnresolvableTag(renderTag) ? (component2) => component2 : resolveComponent;
|
|
140
|
+
const component = _resolveComponent(renderTag);
|
|
134
141
|
if (typeof component === "object") {
|
|
135
142
|
component.tag = originalTag;
|
|
136
143
|
}
|
|
@@ -138,32 +145,19 @@ function renderNode(node, h2, documentMeta, parentScope = {}) {
|
|
|
138
145
|
return h2(
|
|
139
146
|
component,
|
|
140
147
|
props,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
$document: documentMeta,
|
|
149
|
-
$doc: documentMeta
|
|
150
|
-
};
|
|
151
|
-
const splitter = /\.|\[(\d+)\]/;
|
|
152
|
-
const keys = node.props?.value.trim().split(splitter).filter(Boolean);
|
|
153
|
-
const value = keys.reduce((data2, key) => {
|
|
154
|
-
if (data2 && key in data2) {
|
|
155
|
-
if (typeof data2[key] === "function") {
|
|
156
|
-
return data2[key]();
|
|
157
|
-
} else {
|
|
158
|
-
return data2[key];
|
|
148
|
+
_renderSlots(
|
|
149
|
+
node,
|
|
150
|
+
h2,
|
|
151
|
+
{
|
|
152
|
+
documentMeta,
|
|
153
|
+
parentScope: { ...parentScope, ...props },
|
|
154
|
+
resolveComponent: _resolveComponent
|
|
159
155
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}, data);
|
|
163
|
-
const defaultValue = node.props?.defaultValue;
|
|
164
|
-
return h2(Text, value ?? defaultValue ?? "");
|
|
156
|
+
)
|
|
157
|
+
);
|
|
165
158
|
}
|
|
166
|
-
function
|
|
159
|
+
function _renderSlots(node, h2, options) {
|
|
160
|
+
const { documentMeta, parentScope, resolveComponent } = options;
|
|
167
161
|
const children = node.children || [];
|
|
168
162
|
const slotNodes = children.reduce((data, node2) => {
|
|
169
163
|
if (!isTemplate(node2)) {
|
|
@@ -186,7 +180,15 @@ function renderSlots(node, h2, documentMeta, parentProps) {
|
|
|
186
180
|
}
|
|
187
181
|
slots2[name] = (data = {}) => {
|
|
188
182
|
const scopedProps = pick(data, Object.keys(props || {}));
|
|
189
|
-
let vNodes = children2.map((child) =>
|
|
183
|
+
let vNodes = children2.map((child) => _renderNode(
|
|
184
|
+
child,
|
|
185
|
+
h2,
|
|
186
|
+
{
|
|
187
|
+
documentMeta,
|
|
188
|
+
parentScope: { ...parentScope, ...scopedProps },
|
|
189
|
+
resolveComponent
|
|
190
|
+
}
|
|
191
|
+
));
|
|
190
192
|
if (props?.unwrap) {
|
|
191
193
|
vNodes = flatUnwrap(vNodes, props.unwrap);
|
|
192
194
|
}
|
|
@@ -196,6 +198,28 @@ function renderSlots(node, h2, documentMeta, parentProps) {
|
|
|
196
198
|
}, {});
|
|
197
199
|
return slots;
|
|
198
200
|
}
|
|
201
|
+
function renderBinding(node, h2, documentMeta, parentScope = {}) {
|
|
202
|
+
const data = {
|
|
203
|
+
...documentMeta.runtimeData,
|
|
204
|
+
...parentScope,
|
|
205
|
+
$document: documentMeta,
|
|
206
|
+
$doc: documentMeta
|
|
207
|
+
};
|
|
208
|
+
const splitter = /\.|\[(\d+)\]/;
|
|
209
|
+
const keys = node.props?.value.trim().split(splitter).filter(Boolean);
|
|
210
|
+
const value = keys.reduce((data2, key) => {
|
|
211
|
+
if (data2 && key in data2) {
|
|
212
|
+
if (typeof data2[key] === "function") {
|
|
213
|
+
return data2[key]();
|
|
214
|
+
} else {
|
|
215
|
+
return data2[key];
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return void 0;
|
|
219
|
+
}, data);
|
|
220
|
+
const defaultValue = node.props?.defaultValue;
|
|
221
|
+
return h2(Text, value ?? defaultValue ?? "");
|
|
222
|
+
}
|
|
199
223
|
function propsToData(node, documentMeta) {
|
|
200
224
|
const { tag = "", props = {} } = node;
|
|
201
225
|
return Object.keys(props).reduce(function(data, key) {
|
|
@@ -250,12 +274,12 @@ function propsToDataRxBind(key, value, data, documentMeta) {
|
|
|
250
274
|
data[key] = evalInContext(value, documentMeta);
|
|
251
275
|
return data;
|
|
252
276
|
}
|
|
253
|
-
const
|
|
277
|
+
const resolveComponentInstance = (component) => {
|
|
254
278
|
if (typeof component === "string") {
|
|
255
279
|
if (htmlTags.includes(component)) {
|
|
256
280
|
return component;
|
|
257
281
|
}
|
|
258
|
-
const _component =
|
|
282
|
+
const _component = vueResolveComponent(pascalCase(component), false);
|
|
259
283
|
if (!component || _component?.name === "AsyncComponentWrapper") {
|
|
260
284
|
return _component;
|
|
261
285
|
}
|
|
@@ -287,6 +311,9 @@ function getSlotName(node) {
|
|
|
287
311
|
function isTemplate(node) {
|
|
288
312
|
return node.tag === "template";
|
|
289
313
|
}
|
|
314
|
+
function isUnresolvableTag(tag) {
|
|
315
|
+
return specialParentTags.includes(tag);
|
|
316
|
+
}
|
|
290
317
|
function mergeTextNodes(nodes) {
|
|
291
318
|
const mergedNodes = [];
|
|
292
319
|
for (const node of nodes) {
|
|
@@ -308,7 +335,7 @@ async function resolveContentComponents(body, meta) {
|
|
|
308
335
|
if (c?.render || c?.ssrRender || c?.__ssrInlineRender) {
|
|
309
336
|
return;
|
|
310
337
|
}
|
|
311
|
-
const resolvedComponent =
|
|
338
|
+
const resolvedComponent = resolveComponentInstance(c);
|
|
312
339
|
if (resolvedComponent?.__asyncLoader && !resolvedComponent.__asyncResolved) {
|
|
313
340
|
await resolvedComponent.__asyncLoader();
|
|
314
341
|
}
|
|
@@ -319,6 +346,9 @@ async function resolveContentComponents(body, meta) {
|
|
|
319
346
|
return [];
|
|
320
347
|
}
|
|
321
348
|
const renderTag = findMappedTag(node, documentMeta.tags);
|
|
349
|
+
if (isUnresolvableTag(renderTag)) {
|
|
350
|
+
return [];
|
|
351
|
+
}
|
|
322
352
|
const components2 = [];
|
|
323
353
|
if (node.type !== "root" && !htmlTags.includes(renderTag)) {
|
|
324
354
|
components2.push(renderTag);
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -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';
|
package/dist/runtime/index.js
CHANGED
|
@@ -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,6 +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
|
|
3
|
+
export declare const createParseProcessor: (inlineOptions?: MDCParseOptions) => Promise<import("unified").Processor<undefined, undefined, undefined, undefined, undefined>>;
|
|
4
4
|
export declare const createMarkdownParser: (inlineOptions?: MDCParseOptions) => Promise<(md: string, { fileOptions }?: {
|
|
5
5
|
fileOptions?: VFileOptions;
|
|
6
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
|
|
13
|
+
export const createParseProcessor = async (inlineOptions = {}) => {
|
|
14
14
|
if (!moduleOptions) {
|
|
15
15
|
moduleOptions = await import(
|
|
16
16
|
"#mdc-imports"
|
|
@@ -70,7 +70,7 @@ export const createProcessor = async (inlineOptions = {}) => {
|
|
|
70
70
|
return processor;
|
|
71
71
|
};
|
|
72
72
|
export const createMarkdownParser = async (inlineOptions = {}) => {
|
|
73
|
-
const processor = await
|
|
73
|
+
const processor = await createParseProcessor(inlineOptions);
|
|
74
74
|
return async function parse(md, { fileOptions } = {}) {
|
|
75
75
|
const { content, data: frontmatter } = await parseFrontMatter(md);
|
|
76
76
|
const processedFile = await processor.process({ ...fileOptions, value: content, data: frontmatter });
|
|
@@ -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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxtjs/mdc",
|
|
3
|
-
"version": "0.
|
|
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.24.
|
|
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.
|
|
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,7 +92,9 @@
|
|
|
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",
|
|
@@ -99,8 +103,9 @@
|
|
|
99
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.24.
|
|
108
|
+
"shiki": "^1.24.1",
|
|
104
109
|
"ufo": "^1.5.4",
|
|
105
110
|
"unified": "^11.0.5",
|
|
106
111
|
"unist-builder": "^4.0.0",
|
|
@@ -113,8 +118,8 @@
|
|
|
113
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.
|
|
117
|
-
"@nuxt/ui": "^2.
|
|
121
|
+
"@nuxt/test-utils": "^3.15.1",
|
|
122
|
+
"@nuxt/ui": "^2.20.0",
|
|
118
123
|
"@nuxtjs/mdc": "link:.",
|
|
119
124
|
"@types/node": "^22.10.1",
|
|
120
125
|
"changelogen": "^0.5.7",
|
|
@@ -123,14 +128,13 @@
|
|
|
123
128
|
"rehype": "^13.0.2",
|
|
124
129
|
"release-it": "^17.10.0",
|
|
125
130
|
"typescript": "5.6.3",
|
|
126
|
-
"vitest": "^2.1.
|
|
131
|
+
"vitest": "^2.1.8",
|
|
127
132
|
"vue-tsc": "^2.1.10"
|
|
128
133
|
},
|
|
129
134
|
"resolutions": {
|
|
130
|
-
"@nuxtjs/mdc": "workspace:*"
|
|
131
|
-
"remark-mdc": "npm:remark-mdc-edge@latest"
|
|
135
|
+
"@nuxtjs/mdc": "workspace:*"
|
|
132
136
|
},
|
|
133
|
-
"packageManager": "pnpm@9.
|
|
137
|
+
"packageManager": "pnpm@9.15.0",
|
|
134
138
|
"release-it": {
|
|
135
139
|
"git": {
|
|
136
140
|
"commitMessage": "chore(release): release v${version}"
|