@void/md 0.26.1 → 0.28.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.
|
@@ -33,29 +33,26 @@ function createContainer(md, klass, defaultTitle) {
|
|
|
33
33
|
* Custom container blocks: :::tip, :::info, :::warning, :::danger, :::details
|
|
34
34
|
* Ported from VitePress.
|
|
35
35
|
*/
|
|
36
|
-
function containerPlugin(md
|
|
37
|
-
md.use(...createContainer(md, "tip",
|
|
36
|
+
function containerPlugin(md) {
|
|
37
|
+
md.use(...createContainer(md, "tip", "TIP")).use(...createContainer(md, "info", "INFO")).use(...createContainer(md, "warning", "WARNING")).use(...createContainer(md, "danger", "DANGER")).use(...createContainer(md, "details", "Details"));
|
|
38
38
|
}
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/plugins/github-alerts.ts
|
|
41
41
|
const markerRE = /^\[!(TIP|NOTE|INFO|IMPORTANT|WARNING|CAUTION|DANGER)\]([^\n\r]*)/i;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const titleMark = {
|
|
43
|
+
tip: "TIP",
|
|
44
|
+
note: "NOTE",
|
|
45
|
+
info: "INFO",
|
|
46
|
+
important: "IMPORTANT",
|
|
47
|
+
warning: "WARNING",
|
|
48
|
+
caution: "CAUTION",
|
|
49
|
+
danger: "DANGER"
|
|
50
|
+
};
|
|
45
51
|
/**
|
|
46
52
|
* GitHub-flavored alerts: > [!NOTE], > [!TIP], > [!WARNING], etc.
|
|
47
53
|
* Ported from VitePress.
|
|
48
54
|
*/
|
|
49
|
-
function gitHubAlertsPlugin(md
|
|
50
|
-
const titleMark = {
|
|
51
|
-
tip: options?.tipLabel ?? "TIP",
|
|
52
|
-
note: options?.noteLabel ?? "NOTE",
|
|
53
|
-
info: options?.infoLabel ?? "INFO",
|
|
54
|
-
important: options?.importantLabel ?? "IMPORTANT",
|
|
55
|
-
warning: options?.warningLabel ?? "WARNING",
|
|
56
|
-
caution: options?.cautionLabel ?? "CAUTION",
|
|
57
|
-
danger: options?.dangerLabel ?? "DANGER"
|
|
58
|
-
};
|
|
55
|
+
function gitHubAlertsPlugin(md) {
|
|
59
56
|
const rule = (state) => {
|
|
60
57
|
const tokens = state.tokens;
|
|
61
58
|
for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) if (tokens[tokenIndex].type === "blockquote_open") {
|
|
@@ -70,7 +67,7 @@ function gitHubAlertsPlugin(md, options) {
|
|
|
70
67
|
const match = firstContent.content.match(markerRE);
|
|
71
68
|
if (!match) continue;
|
|
72
69
|
const type = match[1].toLowerCase();
|
|
73
|
-
const title = match[2].trim() || titleMark[type]
|
|
70
|
+
const title = match[2].trim() || titleMark[type];
|
|
74
71
|
firstContent.content = firstContent.content.slice(match[0].length).trimStart();
|
|
75
72
|
open.type = "github_alert_open";
|
|
76
73
|
open.tag = "div";
|
|
@@ -111,17 +108,17 @@ function imagePlugin(md, options) {
|
|
|
111
108
|
//#endregion
|
|
112
109
|
//#region src/plugins/line-numbers.ts
|
|
113
110
|
/**
|
|
114
|
-
* Adds line number gutter to code blocks
|
|
115
|
-
*
|
|
111
|
+
* Adds a line number gutter to code blocks that opt in with `:line-numbers`.
|
|
112
|
+
* `{=N}` sets the start line.
|
|
116
113
|
* Ported from VitePress.
|
|
117
114
|
*/
|
|
118
|
-
function lineNumberPlugin(md
|
|
115
|
+
function lineNumberPlugin(md) {
|
|
119
116
|
const fence = md.renderer.rules.fence;
|
|
120
117
|
md.renderer.rules.fence = async (...args) => {
|
|
121
118
|
const rawCode = await fence(...args);
|
|
122
119
|
const [tokens, idx] = args;
|
|
123
120
|
const info = tokens[idx].info;
|
|
124
|
-
if (
|
|
121
|
+
if (!/:line-numbers\b/.test(info)) return rawCode;
|
|
125
122
|
let startLineNumber = 1;
|
|
126
123
|
const matchStart = info.match(/=(\d+)/);
|
|
127
124
|
if (matchStart?.[1]) startLineNumber = parseInt(matchStart[1]);
|
|
@@ -133,23 +130,23 @@ function lineNumberPlugin(md, enable = false) {
|
|
|
133
130
|
//#endregion
|
|
134
131
|
//#region src/plugins/link.ts
|
|
135
132
|
const EXTERNAL_URL_RE = /^[a-z]+:/i;
|
|
133
|
+
const EXTERNAL_ATTRS = {
|
|
134
|
+
target: "_blank",
|
|
135
|
+
rel: "noreferrer"
|
|
136
|
+
};
|
|
136
137
|
/**
|
|
137
138
|
* Adds target="_blank" and rel="noreferrer" to external links.
|
|
138
139
|
* Normalizes internal .md links to route paths.
|
|
139
140
|
* Ported from VitePress.
|
|
140
141
|
*/
|
|
141
|
-
function linkPlugin(md
|
|
142
|
-
const externalAttrs = options?.externalAttrs ?? {
|
|
143
|
-
target: "_blank",
|
|
144
|
-
rel: "noreferrer"
|
|
145
|
-
};
|
|
142
|
+
function linkPlugin(md) {
|
|
146
143
|
md.renderer.rules.link_open = (tokens, idx, mdOptions, _env, self) => {
|
|
147
144
|
const token = tokens[idx];
|
|
148
145
|
const hrefIndex = token.attrIndex("href");
|
|
149
146
|
if (hrefIndex < 0) return self.renderToken(tokens, idx, mdOptions);
|
|
150
147
|
const url = token.attrs?.[hrefIndex]?.[1] ?? "";
|
|
151
148
|
if (url.startsWith("#") || token.attrGet("class") === "header-anchor") return self.renderToken(tokens, idx, mdOptions);
|
|
152
|
-
if (EXTERNAL_URL_RE.test(url)) for (const [key, val] of Object.entries(
|
|
149
|
+
if (EXTERNAL_URL_RE.test(url)) for (const [key, val] of Object.entries(EXTERNAL_ATTRS)) token.attrSet(key, val);
|
|
153
150
|
else {
|
|
154
151
|
let normalized = url;
|
|
155
152
|
if (normalized.endsWith(".md")) normalized = normalized.slice(0, -3);
|
|
@@ -168,8 +165,7 @@ function extractLang(info) {
|
|
|
168
165
|
* Wraps fenced code blocks with a language label and copy button.
|
|
169
166
|
* Ported from VitePress.
|
|
170
167
|
*/
|
|
171
|
-
function preWrapperPlugin(md
|
|
172
|
-
const title = options?.codeCopyButtonTitle ?? "Copy Code";
|
|
168
|
+
function preWrapperPlugin(md) {
|
|
173
169
|
const fence = md.renderer.rules.fence;
|
|
174
170
|
md.renderer.rules.fence = async (...args) => {
|
|
175
171
|
const [tokens, idx] = args;
|
|
@@ -179,41 +175,38 @@ function preWrapperPlugin(md, options) {
|
|
|
179
175
|
token.info = token.info.replace(/ active$/, "").replace(/ active /, " ");
|
|
180
176
|
const lang = extractLang(token.info);
|
|
181
177
|
const highlighted = await fence(...args);
|
|
182
|
-
return `<div class="language-${lang}${active}"><button title="
|
|
178
|
+
return `<div class="language-${lang}${active}"><button title="Copy Code" class="copy"></button><span class="lang">${lang}</span>` + highlighted + `</div>`;
|
|
183
179
|
};
|
|
184
180
|
}
|
|
185
181
|
//#endregion
|
|
186
182
|
//#region src/plugins/toc.ts
|
|
187
|
-
|
|
183
|
+
const TOC_RE = /^\[\[toc\]\]$/i;
|
|
184
|
+
const TOC_LEVELS = [2, 3];
|
|
185
|
+
function renderHeaders(headers) {
|
|
188
186
|
if (headers.length === 0) return "";
|
|
189
|
-
let result =
|
|
187
|
+
let result = "<ul>";
|
|
190
188
|
for (const h of headers) result += `<li><a href="#${h.slug}">${h.text}</a></li>`;
|
|
191
|
-
result +=
|
|
189
|
+
result += "</ul>";
|
|
192
190
|
return result;
|
|
193
191
|
}
|
|
194
192
|
/**
|
|
195
193
|
* [[toc]] directive — renders inline table of contents.
|
|
196
194
|
* Ported from VitePress.
|
|
197
195
|
*/
|
|
198
|
-
function tocPlugin(md
|
|
199
|
-
const pattern = options?.pattern ?? /^\[\[toc\]\]$/i;
|
|
200
|
-
const containerTag = options?.containerTag ?? "nav";
|
|
201
|
-
const containerClass = options?.containerClass ?? "table-of-contents";
|
|
202
|
-
const listTag = options?.listTag ?? "ul";
|
|
203
|
-
const level = options?.level ?? [2, 3];
|
|
196
|
+
function tocPlugin(md) {
|
|
204
197
|
md.block.ruler.before("heading", "toc", ((state, startLine, _endLine, silent) => {
|
|
205
198
|
const pos = state.bMarks[startLine] + state.tShift[startLine];
|
|
206
199
|
const max = state.eMarks[startLine];
|
|
207
200
|
const content = state.src.slice(pos, max).trim();
|
|
208
|
-
if (!
|
|
201
|
+
if (!TOC_RE.test(content)) return false;
|
|
209
202
|
if (silent) return true;
|
|
210
203
|
state.line = startLine + 1;
|
|
211
|
-
const openToken = state.push("toc_open",
|
|
204
|
+
const openToken = state.push("toc_open", "nav", 1);
|
|
212
205
|
openToken.markup = content;
|
|
213
|
-
openToken.attrSet("class",
|
|
206
|
+
openToken.attrSet("class", "table-of-contents");
|
|
214
207
|
const bodyToken = state.push("toc_body", "", 0);
|
|
215
208
|
bodyToken.markup = content;
|
|
216
|
-
const closeToken = state.push("toc_close",
|
|
209
|
+
const closeToken = state.push("toc_close", "nav", -1);
|
|
217
210
|
closeToken.markup = content;
|
|
218
211
|
return true;
|
|
219
212
|
}), { alt: [
|
|
@@ -222,7 +215,7 @@ function tocPlugin(md, options) {
|
|
|
222
215
|
"blockquote"
|
|
223
216
|
] });
|
|
224
217
|
md.renderer.rules.toc_body = (tokens) => {
|
|
225
|
-
return renderHeaders(extractHeadings(tokens).filter((heading) =>
|
|
218
|
+
return renderHeaders(extractHeadings(tokens).filter((heading) => TOC_LEVELS.includes(heading.depth)));
|
|
226
219
|
};
|
|
227
220
|
}
|
|
228
221
|
//#endregion
|
|
@@ -275,7 +268,7 @@ async function createCompiler(options) {
|
|
|
275
268
|
markdown.use(containerPlugin);
|
|
276
269
|
markdown.use(imagePlugin, { lazyLoading: true });
|
|
277
270
|
markdown.use(linkPlugin);
|
|
278
|
-
markdown.use(lineNumberPlugin
|
|
271
|
+
markdown.use(lineNumberPlugin);
|
|
279
272
|
markdown.use(gitHubAlertsPlugin);
|
|
280
273
|
const stashFenceInfo = (state) => {
|
|
281
274
|
for (const token of state.tokens) if (token.type === "fence") token.meta = {
|
|
@@ -294,10 +287,11 @@ async function createCompiler(options) {
|
|
|
294
287
|
async function compile(source, options) {
|
|
295
288
|
const { data: frontmatter, content } = matter(source);
|
|
296
289
|
const compiler = await getCompiler(options);
|
|
297
|
-
const
|
|
290
|
+
const env = {};
|
|
291
|
+
const tokens = compiler.parse(content, env);
|
|
298
292
|
const headings = extractHeadings(tokens);
|
|
299
293
|
return {
|
|
300
|
-
html: await compiler.renderAsync(
|
|
294
|
+
html: await compiler.renderer.renderAsync(tokens, compiler.options, env),
|
|
301
295
|
frontmatter,
|
|
302
296
|
headings,
|
|
303
297
|
title: frontmatter.title ?? headings.find((heading) => heading.depth === 1)?.text ?? ""
|
package/dist/plugin.mjs
CHANGED
|
@@ -1,35 +1,11 @@
|
|
|
1
1
|
import { n as extractMetadata } from "./metadata-TdHmXD-i.mjs";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { existsSync,
|
|
3
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
4
4
|
import { dirname, join, relative, resolve } from "pathslash";
|
|
5
5
|
import { glob } from "tinyglobby";
|
|
6
6
|
import { normalizePath } from "vite";
|
|
7
7
|
import { resolvePagesDir } from "void/pages";
|
|
8
8
|
import { editIslandSource, findIslandImports } from "void/pages-islands-plugin";
|
|
9
|
-
//#region src/codegen/md-types.ts
|
|
10
|
-
/**
|
|
11
|
-
* Generate .void/md.d.ts content.
|
|
12
|
-
*
|
|
13
|
-
* Declares the `@void/md/pages` virtual module so TypeScript can resolve it
|
|
14
|
-
* from anywhere in the project (pages/, routes/, etc.) without @ts-ignore.
|
|
15
|
-
*/
|
|
16
|
-
function generateMdTypes() {
|
|
17
|
-
return [
|
|
18
|
-
"// Auto-generated by @void/md — do not edit",
|
|
19
|
-
"",
|
|
20
|
-
"export type VoidMdPage = Readonly<{",
|
|
21
|
-
" path: string;",
|
|
22
|
-
" title: string;",
|
|
23
|
-
" frontmatter: Record<string, unknown>;",
|
|
24
|
-
" headings: ReadonlyArray<{ depth: number; slug: string; text: string }>;",
|
|
25
|
-
"}>;",
|
|
26
|
-
"",
|
|
27
|
-
"declare const pages: ReadonlyArray<VoidMdPage>;",
|
|
28
|
-
"export default pages;",
|
|
29
|
-
""
|
|
30
|
-
].join("\n");
|
|
31
|
-
}
|
|
32
|
-
//#endregion
|
|
33
9
|
//#region src/emit-shared.ts
|
|
34
10
|
const ISLAND_TAG_RE = /<([A-Z]\w*)\s*((?:[^>/"']|"[^"]*"|'[^']*')*)\/\s*>|<([A-Z]\w*)\s*((?:[^>/"']|"[^"]*"|'[^']*')*)>([\s\S]*?)<\/\3\s*>/g;
|
|
35
11
|
function findIslandTags(html, names) {
|
|
@@ -54,10 +30,11 @@ function parseAttrs(attrStr) {
|
|
|
54
30
|
while ((match = attrRe.exec(attrStr)) !== null) result[match[1]] = match[2] ?? match[3] ?? match[4] ?? "";
|
|
55
31
|
return result;
|
|
56
32
|
}
|
|
57
|
-
function toIslandId(imp) {
|
|
58
|
-
return imp.islandId ?? imp.specifier.replace(/\.[^.]+$/, "");
|
|
59
|
-
}
|
|
60
33
|
function buildRenderChunks(html, islandImports) {
|
|
34
|
+
if (islandImports.length === 0) return [{
|
|
35
|
+
type: "html",
|
|
36
|
+
html
|
|
37
|
+
}];
|
|
61
38
|
const islandByName = new Map(islandImports.map((item) => [item.name, item]));
|
|
62
39
|
const tags = findIslandTags(html, new Set(islandByName.keys()));
|
|
63
40
|
const chunks = [];
|
|
@@ -89,28 +66,7 @@ function buildRenderChunks(html, islandImports) {
|
|
|
89
66
|
}
|
|
90
67
|
//#endregion
|
|
91
68
|
//#region src/emit-react.ts
|
|
92
|
-
function emitReactComponent(result) {
|
|
93
|
-
return `
|
|
94
|
-
import React from "react";
|
|
95
|
-
import { FrontmatterContext } from "@void/md";
|
|
96
|
-
|
|
97
|
-
const __frontmatter = ${JSON.stringify(result.frontmatter)};
|
|
98
|
-
const __headings = ${JSON.stringify(result.headings)};
|
|
99
|
-
const __html = ${JSON.stringify(result.html)};
|
|
100
|
-
|
|
101
|
-
export const frontmatter = __frontmatter;
|
|
102
|
-
export const headings = __headings;
|
|
103
|
-
|
|
104
|
-
export default function MarkdownPage() {
|
|
105
|
-
return React.createElement(
|
|
106
|
-
FrontmatterContext.Provider,
|
|
107
|
-
{ value: __frontmatter },
|
|
108
|
-
React.createElement("div", { dangerouslySetInnerHTML: { __html: __html } })
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
`;
|
|
112
|
-
}
|
|
113
|
-
function emitReactComponentWithIslands(result, islandImports) {
|
|
69
|
+
function emitReactComponent(result, islandImports) {
|
|
114
70
|
const chunks = buildRenderChunks(result.html, islandImports);
|
|
115
71
|
let code = `import React from "react";\n`;
|
|
116
72
|
code += `import { FrontmatterContext } from "@void/md";\n`;
|
|
@@ -124,7 +80,7 @@ function emitReactComponentWithIslands(result, islandImports) {
|
|
|
124
80
|
return React.createElement(
|
|
125
81
|
"div",
|
|
126
82
|
{
|
|
127
|
-
"data-island": ${JSON.stringify(
|
|
83
|
+
"data-island": ${JSON.stringify(islandImport.islandId)},
|
|
128
84
|
"data-props": JSON.stringify(props),
|
|
129
85
|
"data-hydrate": ${JSON.stringify(islandImport.strategy)}
|
|
130
86
|
},
|
|
@@ -162,27 +118,7 @@ export default function MarkdownPage() {
|
|
|
162
118
|
}
|
|
163
119
|
//#endregion
|
|
164
120
|
//#region src/emit-solid.ts
|
|
165
|
-
function emitSolidComponent(result) {
|
|
166
|
-
return `
|
|
167
|
-
import { FrontmatterContext } from "@void/md";
|
|
168
|
-
|
|
169
|
-
const __frontmatter = ${JSON.stringify(result.frontmatter)};
|
|
170
|
-
const __headings = ${JSON.stringify(result.headings)};
|
|
171
|
-
const __html = ${JSON.stringify(result.html)};
|
|
172
|
-
|
|
173
|
-
export const frontmatter = __frontmatter;
|
|
174
|
-
export const headings = __headings;
|
|
175
|
-
|
|
176
|
-
export default function MarkdownPage() {
|
|
177
|
-
return (
|
|
178
|
-
<FrontmatterContext.Provider value={__frontmatter}>
|
|
179
|
-
<div innerHTML={__html} />
|
|
180
|
-
</FrontmatterContext.Provider>
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
`;
|
|
184
|
-
}
|
|
185
|
-
function emitSolidComponentWithIslands(result, islandImports) {
|
|
121
|
+
function emitSolidComponent(result, islandImports) {
|
|
186
122
|
const chunks = buildRenderChunks(result.html, islandImports);
|
|
187
123
|
const importAliasByName = /* @__PURE__ */ new Map();
|
|
188
124
|
let code = `import { FrontmatterContext } from "@void/md";\n`;
|
|
@@ -212,7 +148,7 @@ export const headings = __headings;
|
|
|
212
148
|
const importAlias = importAliasByName.get(chunk.islandImport.name) ?? chunk.islandImport.name;
|
|
213
149
|
const propsLiteral = Object.keys(chunk.props).length > 0 ? JSON.stringify(chunk.props) : "{}";
|
|
214
150
|
code += `\nconst ${propsName} = ${propsLiteral};`;
|
|
215
|
-
bodyLines.push(`<div data-island=${JSON.stringify(
|
|
151
|
+
bodyLines.push(`<div data-island=${JSON.stringify(chunk.islandImport.islandId)} data-props={JSON.stringify(${propsName})} data-hydrate=${JSON.stringify(chunk.islandImport.strategy)}><${importAlias} {...${propsName}} /></div>`);
|
|
216
152
|
}
|
|
217
153
|
if (bodyLines.length === 0) bodyLines.push("<></>");
|
|
218
154
|
code += `
|
|
@@ -234,24 +170,7 @@ export default function MarkdownPage() {
|
|
|
234
170
|
function toSvelteLiteral(value) {
|
|
235
171
|
return JSON.stringify(value).replace(/<\//g, "<\\/");
|
|
236
172
|
}
|
|
237
|
-
function emitSvelteComponent(result) {
|
|
238
|
-
const frontmatter = toSvelteLiteral(result.frontmatter);
|
|
239
|
-
return `<script context="module">
|
|
240
|
-
export const frontmatter = ${frontmatter};
|
|
241
|
-
export const headings = ${toSvelteLiteral(result.headings)};
|
|
242
|
-
<\/script>
|
|
243
|
-
|
|
244
|
-
<script>
|
|
245
|
-
import { setFrontmatter } from "@void/md";
|
|
246
|
-
|
|
247
|
-
const __frontmatter = ${frontmatter};
|
|
248
|
-
setFrontmatter(__frontmatter);
|
|
249
|
-
<\/script>
|
|
250
|
-
|
|
251
|
-
{@html ${toSvelteLiteral(result.html)}}
|
|
252
|
-
`;
|
|
253
|
-
}
|
|
254
|
-
function emitSvelteComponentWithIslands(result, islandImports) {
|
|
173
|
+
function emitSvelteComponent(result, islandImports) {
|
|
255
174
|
const chunks = buildRenderChunks(result.html, islandImports);
|
|
256
175
|
const importAliasByName = /* @__PURE__ */ new Map();
|
|
257
176
|
const frontmatter = toSvelteLiteral(result.frontmatter);
|
|
@@ -286,7 +205,7 @@ setFrontmatter(__frontmatter);
|
|
|
286
205
|
const propsLiteral = Object.keys(chunk.props).length > 0 ? toSvelteLiteral(chunk.props) : "{}";
|
|
287
206
|
source += `const ${propsName} = ${propsLiteral};
|
|
288
207
|
`;
|
|
289
|
-
body.push(`<div data-island="${
|
|
208
|
+
body.push(`<div data-island="${chunk.islandImport.islandId}" data-props={JSON.stringify(${propsName})} data-hydrate="${chunk.islandImport.strategy}"><${alias} {...${propsName}} /></div>`);
|
|
290
209
|
}
|
|
291
210
|
source += `<\/script>
|
|
292
211
|
|
|
@@ -296,26 +215,7 @@ ${body.join("\n")}
|
|
|
296
215
|
}
|
|
297
216
|
//#endregion
|
|
298
217
|
//#region src/emit-vue.ts
|
|
299
|
-
function emitVueComponent(result) {
|
|
300
|
-
return `
|
|
301
|
-
import { defineComponent, createStaticVNode, provide } from "vue";
|
|
302
|
-
|
|
303
|
-
const __frontmatter = ${JSON.stringify(result.frontmatter)};
|
|
304
|
-
const __headings = ${JSON.stringify(result.headings)};
|
|
305
|
-
const __html = ${JSON.stringify(result.html)};
|
|
306
|
-
|
|
307
|
-
export const frontmatter = __frontmatter;
|
|
308
|
-
export const headings = __headings;
|
|
309
|
-
|
|
310
|
-
export default defineComponent({
|
|
311
|
-
setup() {
|
|
312
|
-
provide("__void_frontmatter", __frontmatter);
|
|
313
|
-
return () => createStaticVNode(__html, 1);
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
`;
|
|
317
|
-
}
|
|
318
|
-
function emitVueComponentWithIslands(result, islandImports) {
|
|
218
|
+
function emitVueComponent(result, islandImports) {
|
|
319
219
|
const chunks = buildRenderChunks(result.html, islandImports);
|
|
320
220
|
let code = `import { defineComponent, h, createStaticVNode, provide } from "vue";\n`;
|
|
321
221
|
for (let islandIndex = 0; islandIndex < islandImports.length; islandIndex++) {
|
|
@@ -327,7 +227,7 @@ function emitVueComponentWithIslands(result, islandImports) {
|
|
|
327
227
|
code += `const ${islandImport.name} = { inheritAttrs: false, render() {
|
|
328
228
|
const props = this.$attrs;
|
|
329
229
|
return h("div", {
|
|
330
|
-
"data-island": ${JSON.stringify(
|
|
230
|
+
"data-island": ${JSON.stringify(islandImport.islandId)},
|
|
331
231
|
"data-props": JSON.stringify(props),
|
|
332
232
|
"data-hydrate": ${JSON.stringify(islandImport.strategy)}
|
|
333
233
|
}, h(_raw_island_${islandIndex}, props));
|
|
@@ -339,6 +239,7 @@ function emitVueComponentWithIslands(result, islandImports) {
|
|
|
339
239
|
const propsStr = Object.keys(chunk.props).length > 0 ? JSON.stringify(chunk.props) : "null";
|
|
340
240
|
vnodes.push(`h(${chunk.islandImport.name}, ${propsStr})`);
|
|
341
241
|
}
|
|
242
|
+
const root = islandImports.length > 0 ? `[\n ${vnodes.join(",\n ")}\n ]` : vnodes[0];
|
|
342
243
|
code += `
|
|
343
244
|
const __frontmatter = ${JSON.stringify(result.frontmatter)};
|
|
344
245
|
const __headings = ${JSON.stringify(result.headings)};
|
|
@@ -349,9 +250,7 @@ export const headings = __headings;
|
|
|
349
250
|
export default defineComponent({
|
|
350
251
|
setup() {
|
|
351
252
|
provide("__void_frontmatter", __frontmatter);
|
|
352
|
-
return () =>
|
|
353
|
-
${vnodes.join(",\n ")}
|
|
354
|
-
];
|
|
253
|
+
return () => ${root};
|
|
355
254
|
}
|
|
356
255
|
});
|
|
357
256
|
`;
|
|
@@ -450,11 +349,6 @@ function voidMarkdown(options) {
|
|
|
450
349
|
};
|
|
451
350
|
}))).sort((leftPage, rightPage) => leftPage.path.localeCompare(rightPage.path));
|
|
452
351
|
}
|
|
453
|
-
function writeMdTypes() {
|
|
454
|
-
const outDir = join(root, ".void");
|
|
455
|
-
mkdirSync(outDir, { recursive: true });
|
|
456
|
-
writeFileSync(join(outDir, "md.d.ts"), generateMdTypes());
|
|
457
|
-
}
|
|
458
352
|
return [{
|
|
459
353
|
name: "void-md",
|
|
460
354
|
enforce: "pre",
|
|
@@ -488,7 +382,6 @@ function voidMarkdown(options) {
|
|
|
488
382
|
solidModules.clear();
|
|
489
383
|
clientScripts.clear();
|
|
490
384
|
mdPages = await scanMdPages();
|
|
491
|
-
writeMdTypes();
|
|
492
385
|
},
|
|
493
386
|
configureServer(server) {
|
|
494
387
|
const normalizedPagesDir = normalizePath(pagesDir);
|
|
@@ -574,35 +467,27 @@ export function useFrontmatter() { return useContext(FrontmatterContext) ?? {};
|
|
|
574
467
|
const componentId = stripPageSuffix(_id.slice(pagesPrefix.length)) || "index";
|
|
575
468
|
clientScripts.set(componentId, clientCode);
|
|
576
469
|
}
|
|
577
|
-
|
|
470
|
+
const islands = islandImports.map((imp) => {
|
|
578
471
|
const absPath = resolve(dirname(_id), imp.specifier);
|
|
579
|
-
|
|
580
|
-
}
|
|
581
|
-
const { compile } = await import("./compile-BwShiv84.mjs");
|
|
582
|
-
const result = await compile(body, { shiki: options?.shiki });
|
|
583
|
-
if (adapter === "vue") {
|
|
584
|
-
if (islandImports.length > 0) return {
|
|
585
|
-
code: emitVueComponentWithIslands(result, islandImports),
|
|
586
|
-
map: null
|
|
587
|
-
};
|
|
472
|
+
const islandId = normalizePath(relative(root, absPath)).replace(/\.[^.]+$/, "");
|
|
588
473
|
return {
|
|
589
|
-
|
|
590
|
-
|
|
474
|
+
...imp,
|
|
475
|
+
islandId
|
|
591
476
|
};
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
}
|
|
477
|
+
});
|
|
478
|
+
const { compile } = await import("./compile-BN4Az3Z3.mjs");
|
|
479
|
+
const result = await compile(body, { shiki: options?.shiki });
|
|
480
|
+
if (adapter === "vue") return {
|
|
481
|
+
code: emitVueComponent(result, islands),
|
|
482
|
+
map: null
|
|
483
|
+
};
|
|
484
|
+
if (adapter === "react") return {
|
|
485
|
+
code: emitReactComponent(result, islands),
|
|
486
|
+
map: null
|
|
487
|
+
};
|
|
603
488
|
if (adapter === "svelte") {
|
|
604
489
|
const virtualId = createVirtualModuleId(SVELTE_VIRTUAL_PREFIX, _id, code, "svelte");
|
|
605
|
-
svelteModules.set(virtualId,
|
|
490
|
+
svelteModules.set(virtualId, emitSvelteComponent(result, islands));
|
|
606
491
|
return {
|
|
607
492
|
code: `export { default, frontmatter, headings } from ${JSON.stringify(virtualId)};`,
|
|
608
493
|
map: null
|
|
@@ -610,7 +495,7 @@ export function useFrontmatter() { return useContext(FrontmatterContext) ?? {};
|
|
|
610
495
|
}
|
|
611
496
|
if (adapter === "solid") {
|
|
612
497
|
const virtualId = createVirtualModuleId(SOLID_VIRTUAL_PREFIX, _id, code, "tsx");
|
|
613
|
-
solidModules.set(virtualId,
|
|
498
|
+
solidModules.set(virtualId, emitSolidComponent(result, islands));
|
|
614
499
|
return {
|
|
615
500
|
code: `export { default, frontmatter, headings } from ${JSON.stringify(virtualId)};`,
|
|
616
501
|
map: null
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@void/md",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Markdown pages with layouts and interactive islands for Void.",
|
|
5
5
|
"homepage": "https://void.cloud",
|
|
6
6
|
"bugs": {
|
|
@@ -53,12 +53,11 @@
|
|
|
53
53
|
"@types/node": "^26.6.4",
|
|
54
54
|
"vite": "npm:@voidzero-dev/vite-plus-core@1.1.0",
|
|
55
55
|
"vite-plus": "1.1.0",
|
|
56
|
-
"void": "0.
|
|
57
|
-
"vue": "^3.5.43"
|
|
56
|
+
"void": "0.28.0"
|
|
58
57
|
},
|
|
59
58
|
"peerDependencies": {
|
|
60
59
|
"vite": "^8.0.0",
|
|
61
|
-
"void": "0.
|
|
60
|
+
"void": "0.28.0"
|
|
62
61
|
},
|
|
63
62
|
"scripts": {
|
|
64
63
|
"build": "vp pack",
|