@docubook/core 1.8.0 → 1.8.1
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/chunk-HZJLRYAI.js +45 -0
- package/dist/chunk-HZJLRYAI.js.map +1 -0
- package/dist/index.d.ts +118 -11
- package/dist/index.js +514 -7
- package/dist/index.js.map +1 -1
- package/dist/utils.d.ts +12 -10
- package/dist/utils.js +16 -38
- package/dist/utils.js.map +1 -1
- package/package.json +5 -3
- package/dist/__tests__/compile.test.d.ts +0 -2
- package/dist/__tests__/compile.test.d.ts.map +0 -1
- package/dist/__tests__/compile.test.js +0 -122
- package/dist/__tests__/compile.test.js.map +0 -1
- package/dist/__tests__/content.test.d.ts +0 -2
- package/dist/__tests__/content.test.d.ts.map +0 -1
- package/dist/__tests__/content.test.js +0 -109
- package/dist/__tests__/content.test.js.map +0 -1
- package/dist/__tests__/extract.test.d.ts +0 -2
- package/dist/__tests__/extract.test.d.ts.map +0 -1
- package/dist/__tests__/extract.test.js +0 -95
- package/dist/__tests__/extract.test.js.map +0 -1
- package/dist/__tests__/plugins/handleCodeExpandable.test.d.ts +0 -2
- package/dist/__tests__/plugins/handleCodeExpandable.test.d.ts.map +0 -1
- package/dist/__tests__/plugins/handleCodeExpandable.test.js +0 -191
- package/dist/__tests__/plugins/handleCodeExpandable.test.js.map +0 -1
- package/dist/__tests__/plugins/handleCodeTitles.test.d.ts +0 -2
- package/dist/__tests__/plugins/handleCodeTitles.test.d.ts.map +0 -1
- package/dist/__tests__/plugins/handleCodeTitles.test.js +0 -99
- package/dist/__tests__/plugins/handleCodeTitles.test.js.map +0 -1
- package/dist/compile.d.ts +0 -28
- package/dist/compile.d.ts.map +0 -1
- package/dist/compile.js +0 -90
- package/dist/compile.js.map +0 -1
- package/dist/content.d.ts +0 -52
- package/dist/content.d.ts.map +0 -1
- package/dist/content.js +0 -102
- package/dist/content.js.map +0 -1
- package/dist/extract.d.ts +0 -13
- package/dist/extract.d.ts.map +0 -1
- package/dist/extract.js +0 -96
- package/dist/extract.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/plugins/handleCodeExpandable.d.ts +0 -4
- package/dist/plugins/handleCodeExpandable.d.ts.map +0 -1
- package/dist/plugins/handleCodeExpandable.js +0 -174
- package/dist/plugins/handleCodeExpandable.js.map +0 -1
- package/dist/plugins/handleCodeTitles.d.ts +0 -3
- package/dist/plugins/handleCodeTitles.d.ts.map +0 -1
- package/dist/plugins/handleCodeTitles.js +0 -38
- package/dist/plugins/handleCodeTitles.js.map +0 -1
- package/dist/plugins/rehypeMermaid.d.ts +0 -11
- package/dist/plugins/rehypeMermaid.d.ts.map +0 -1
- package/dist/plugins/rehypeMermaid.js +0 -34
- package/dist/plugins/rehypeMermaid.js.map +0 -1
- package/dist/types.d.ts +0 -12
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/utils.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,515 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import {
|
|
2
|
+
cn,
|
|
3
|
+
formatDate,
|
|
4
|
+
formatDate2,
|
|
5
|
+
parseDate,
|
|
6
|
+
stringToDate,
|
|
7
|
+
toIsoDateOnly
|
|
8
|
+
} from "./chunk-HZJLRYAI.js";
|
|
9
|
+
|
|
10
|
+
// src/compile.ts
|
|
11
|
+
import { compileMDX } from "next-mdx-remote/rsc";
|
|
12
|
+
import { serialize } from "next-mdx-remote/serialize";
|
|
13
|
+
import { visit as visit4 } from "unist-util-visit";
|
|
14
|
+
import remarkGfm from "remark-gfm";
|
|
15
|
+
import rehypePrism from "rehype-prism-plus";
|
|
16
|
+
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
|
17
|
+
import rehypeSlug from "rehype-slug";
|
|
18
|
+
import rehypeCodeTitles from "rehype-code-titles";
|
|
19
|
+
|
|
20
|
+
// src/plugins/handleCodeTitles.ts
|
|
21
|
+
import { visit } from "unist-util-visit";
|
|
22
|
+
var handleCodeTitles = () => (tree) => {
|
|
23
|
+
const toRemove = [];
|
|
24
|
+
visit(tree, "element", (node, index, parent) => {
|
|
25
|
+
if (!parent || index === null || node.tagName !== "div") {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const isTitleDiv = node.properties?.className?.includes("rehype-code-title");
|
|
29
|
+
if (!isTitleDiv) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
let nextElement = null;
|
|
33
|
+
for (let i = index + 1; i < parent.children.length; i++) {
|
|
34
|
+
const sibling = parent.children[i];
|
|
35
|
+
if (sibling.type === "element") {
|
|
36
|
+
nextElement = sibling;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (nextElement?.tagName === "pre") {
|
|
41
|
+
const titleNode = node.children?.[0];
|
|
42
|
+
if (titleNode?.type === "text") {
|
|
43
|
+
if (!nextElement.properties) {
|
|
44
|
+
nextElement.properties = {};
|
|
45
|
+
}
|
|
46
|
+
nextElement.properties["data-title"] = titleNode.value;
|
|
47
|
+
nextElement.codeTitle = titleNode.value;
|
|
48
|
+
toRemove.push({ parent, index });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
for (let i = toRemove.length - 1; i >= 0; i--) {
|
|
53
|
+
const { parent, index } = toRemove[i];
|
|
54
|
+
parent.children.splice(index, 1);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/plugins/handleCodeExpandable.ts
|
|
59
|
+
import { visit as visit2 } from "unist-util-visit";
|
|
60
|
+
function escapeMeta(s) {
|
|
61
|
+
let out = "";
|
|
62
|
+
for (let i = 0; i < s.length; i++) {
|
|
63
|
+
const ch = s[i];
|
|
64
|
+
if (ch === "<" && s[i + 1] === "/") {
|
|
65
|
+
out += "\\u003C/";
|
|
66
|
+
i++;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (ch === "`" || ch === "$" || ch === "{" || ch === "}" || ch === '"' || ch === "\\") {
|
|
70
|
+
out += `\\${ch}`;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
out += ch;
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
function countCodeLines(raw) {
|
|
78
|
+
let normalized = raw.replace(/\r\n/g, "\n");
|
|
79
|
+
if (normalized.startsWith("\n")) normalized = normalized.slice(1);
|
|
80
|
+
if (normalized.endsWith("\n")) normalized = normalized.slice(0, -1);
|
|
81
|
+
if (normalized.length === 0) return 0;
|
|
82
|
+
return normalized.split("\n").length;
|
|
83
|
+
}
|
|
84
|
+
var handleCodeExpandableRemark = () => (tree) => {
|
|
85
|
+
visit2(tree, "code", (node) => {
|
|
86
|
+
if (!node.meta) return;
|
|
87
|
+
const isExpandable = node.meta.includes("Expandable");
|
|
88
|
+
const [languagePart, titlePart] = (node.lang ?? "").split(":");
|
|
89
|
+
const normalizedLanguage = languagePart?.trim();
|
|
90
|
+
const normalizedTitle = titlePart?.trim();
|
|
91
|
+
if (!isExpandable) return;
|
|
92
|
+
const lineCount = countCodeLines(node.value);
|
|
93
|
+
if (!node.data) {
|
|
94
|
+
node.data = {};
|
|
95
|
+
}
|
|
96
|
+
if (!node.data.hProperties) {
|
|
97
|
+
node.data.hProperties = {};
|
|
98
|
+
}
|
|
99
|
+
node.data.hProperties["data-expandable"] = "true";
|
|
100
|
+
node.data.hProperties["data-expandable-lines"] = lineCount.toString();
|
|
101
|
+
if (normalizedLanguage) {
|
|
102
|
+
node.data.hProperties["data-language"] = normalizedLanguage;
|
|
103
|
+
}
|
|
104
|
+
if (normalizedTitle) {
|
|
105
|
+
node.data.hProperties["data-title"] = normalizedTitle;
|
|
106
|
+
}
|
|
107
|
+
const currentClassName = node.data.hProperties.className;
|
|
108
|
+
const classList = Array.isArray(currentClassName) ? currentClassName : typeof currentClassName === "string" ? currentClassName.split(" ").filter(Boolean) : [];
|
|
109
|
+
if (!classList.includes("mdx-expandable-meta")) {
|
|
110
|
+
classList.push("mdx-expandable-meta");
|
|
111
|
+
}
|
|
112
|
+
node.data.hProperties.className = classList;
|
|
113
|
+
if (normalizedLanguage && !node.meta.includes("dbLang(")) {
|
|
114
|
+
node.meta = `${node.meta} dbLang(${escapeMeta(normalizedLanguage)})`.trim();
|
|
115
|
+
}
|
|
116
|
+
if (normalizedTitle && !node.meta.includes("dbTitle(")) {
|
|
117
|
+
node.meta = `${node.meta} dbTitle(${escapeMeta(normalizedTitle)})`.trim();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
var handleCodeExpandable = () => (tree) => {
|
|
122
|
+
visit2(tree, "element", (node) => {
|
|
123
|
+
if (node.tagName !== "pre") return;
|
|
124
|
+
const codeElement = node.children?.find((child) => {
|
|
125
|
+
const element = child;
|
|
126
|
+
return element.type === "element" && element.tagName === "code";
|
|
127
|
+
});
|
|
128
|
+
const codeClassName = codeElement?.properties?.className;
|
|
129
|
+
const codeClassList = Array.isArray(codeClassName) ? codeClassName : typeof codeClassName === "string" ? codeClassName.split(" ").filter(Boolean) : [];
|
|
130
|
+
const codeMeta = codeElement?.data && typeof codeElement.data === "object" && typeof codeElement.data["meta"] === "string" ? codeElement.data["meta"] : void 0;
|
|
131
|
+
const languageFromMeta = codeMeta?.match(/dbLang\(([^)]+)\)/)?.[1];
|
|
132
|
+
const titleFromMeta = codeMeta?.match(/dbTitle\(([^)]+)\)/)?.[1];
|
|
133
|
+
const languageFromProps = typeof codeElement?.properties?.["data-language"] === "string" ? codeElement.properties["data-language"] : void 0;
|
|
134
|
+
const titleFromProps = typeof codeElement?.properties?.["data-title"] === "string" ? codeElement.properties["data-title"] : void 0;
|
|
135
|
+
const languageFromCodeClass = codeClassList.find((item) => item.startsWith("language-"))?.replace("language-", "");
|
|
136
|
+
const existingPreLanguage = typeof node.properties?.["data-language"] === "string" ? node.properties["data-language"] : void 0;
|
|
137
|
+
const existingPreTitle = typeof node.properties?.["data-title"] === "string" ? node.properties["data-title"] : void 0;
|
|
138
|
+
const isExpandable = codeElement?.properties?.["data-expandable"] === "true" || codeClassList.includes("mdx-expandable-meta") || codeMeta?.includes("Expandable") === true;
|
|
139
|
+
const expandableLines = codeElement?.properties?.["data-expandable-lines"];
|
|
140
|
+
if (!isExpandable) return;
|
|
141
|
+
if (!node.properties) {
|
|
142
|
+
node.properties = {};
|
|
143
|
+
}
|
|
144
|
+
node.properties["data-expandable"] = "true";
|
|
145
|
+
if (typeof expandableLines === "string" || typeof expandableLines === "number") {
|
|
146
|
+
node.properties["data-expandable-lines"] = expandableLines.toString();
|
|
147
|
+
} else if (node.raw) {
|
|
148
|
+
node.properties["data-expandable-lines"] = countCodeLines(node.raw).toString();
|
|
149
|
+
}
|
|
150
|
+
const resolvedLanguage = languageFromProps || languageFromMeta || languageFromCodeClass || existingPreLanguage || node.language;
|
|
151
|
+
const resolvedTitle = titleFromProps || titleFromMeta || existingPreTitle || node.codeTitle;
|
|
152
|
+
if (resolvedLanguage) {
|
|
153
|
+
node.properties["data-language"] = resolvedLanguage;
|
|
154
|
+
}
|
|
155
|
+
if (resolvedTitle) {
|
|
156
|
+
node.properties["data-title"] = resolvedTitle;
|
|
157
|
+
}
|
|
158
|
+
const className = node.properties.className;
|
|
159
|
+
if (!className) {
|
|
160
|
+
node.properties.className = [];
|
|
161
|
+
}
|
|
162
|
+
if (Array.isArray(node.properties.className)) {
|
|
163
|
+
if (!node.properties.className.includes("mdx-expandable-code")) {
|
|
164
|
+
node.properties.className.push("mdx-expandable-code");
|
|
165
|
+
}
|
|
166
|
+
} else if (typeof className === "string") {
|
|
167
|
+
const hasMarker = className.split(" ").includes("mdx-expandable-code");
|
|
168
|
+
if (!hasMarker) {
|
|
169
|
+
node.properties.className = `${className} mdx-expandable-code`.trim().split(" ");
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
node.properties.className = ["mdx-expandable-code"];
|
|
173
|
+
}
|
|
174
|
+
if (codeElement?.properties) {
|
|
175
|
+
const cleanedCodeClassList = codeClassList.filter((item) => item !== "mdx-expandable-meta");
|
|
176
|
+
codeElement.properties.className = cleanedCodeClassList;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// src/plugins/rehypeMermaid.ts
|
|
182
|
+
import { visit as visit3 } from "unist-util-visit";
|
|
183
|
+
var rehypeMermaid = () => (tree) => {
|
|
184
|
+
visit3(tree, "element", (node, index, parent) => {
|
|
185
|
+
if (!parent || index === null || node.tagName !== "pre") return;
|
|
186
|
+
const codeEl = node.children?.find(
|
|
187
|
+
(child) => child.type === "element" && child.tagName === "code"
|
|
188
|
+
);
|
|
189
|
+
if (!codeEl) return;
|
|
190
|
+
const classList = Array.isArray(codeEl.properties?.className) ? codeEl.properties.className : typeof codeEl.properties?.className === "string" ? codeEl.properties.className.split(" ").filter(Boolean) : [];
|
|
191
|
+
if (!classList.includes("language-mermaid")) return;
|
|
192
|
+
const textNode = codeEl.children?.find((child) => child.type === "text");
|
|
193
|
+
const chart = textNode?.value ?? "";
|
|
194
|
+
parent.children[index] = {
|
|
195
|
+
type: "element",
|
|
196
|
+
tagName: "Mermaid",
|
|
197
|
+
properties: { chart },
|
|
198
|
+
children: []
|
|
199
|
+
};
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// src/compile.ts
|
|
204
|
+
import { MDXRemote } from "next-mdx-remote";
|
|
205
|
+
var preProcess = () => (tree) => {
|
|
206
|
+
visit4(tree, (node) => {
|
|
207
|
+
const element = node;
|
|
208
|
+
if (element?.type === "element" && element?.tagName === "pre" && element.children) {
|
|
209
|
+
const [codeEl] = element.children;
|
|
210
|
+
if (codeEl.tagName !== "code" || !codeEl.children?.[0]) return;
|
|
211
|
+
const className = codeEl.properties?.className;
|
|
212
|
+
const classList = Array.isArray(className) ? className : typeof className === "string" ? className.split(" ").filter(Boolean) : [];
|
|
213
|
+
const languageClass = classList.find((item) => item.startsWith("language-"));
|
|
214
|
+
if (languageClass) {
|
|
215
|
+
element.language = languageClass.replace("language-", "").split(":")[0];
|
|
216
|
+
}
|
|
217
|
+
const textNode = codeEl.children[0];
|
|
218
|
+
if (textNode.type === "text" && textNode.value) {
|
|
219
|
+
element.raw = textNode.value;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
return tree;
|
|
224
|
+
};
|
|
225
|
+
var postProcess = () => (tree) => {
|
|
226
|
+
visit4(tree, "element", (node) => {
|
|
227
|
+
const element = node;
|
|
228
|
+
if (element?.type === "element" && element?.tagName === "pre") {
|
|
229
|
+
if (element.properties && element.raw) {
|
|
230
|
+
element.properties.raw = element.raw;
|
|
231
|
+
}
|
|
232
|
+
if (element.properties && element.language && !element.properties["data-language"]) {
|
|
233
|
+
element.properties["data-language"] = element.language;
|
|
234
|
+
}
|
|
235
|
+
if (element.properties && element.codeTitle && !element.properties["data-title"]) {
|
|
236
|
+
element.properties["data-title"] = element.codeTitle;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
return tree;
|
|
241
|
+
};
|
|
242
|
+
function createDefaultRehypePlugins() {
|
|
243
|
+
return [
|
|
244
|
+
preProcess,
|
|
245
|
+
rehypeMermaid,
|
|
246
|
+
// Transform ```mermaid before code transforms
|
|
247
|
+
rehypeCodeTitles,
|
|
248
|
+
handleCodeTitles,
|
|
249
|
+
handleCodeExpandable,
|
|
250
|
+
// Copy expandable metadata from <code> to <pre> before prism transforms nodes.
|
|
251
|
+
rehypePrism,
|
|
252
|
+
handleCodeExpandable,
|
|
253
|
+
// Re-apply expandable attrs after prism tokenization.
|
|
254
|
+
rehypeSlug,
|
|
255
|
+
rehypeAutolinkHeadings,
|
|
256
|
+
postProcess
|
|
257
|
+
];
|
|
258
|
+
}
|
|
259
|
+
function createDefaultRemarkPlugins() {
|
|
260
|
+
return [remarkGfm, handleCodeExpandableRemark];
|
|
261
|
+
}
|
|
262
|
+
async function parseMdx(rawMdx, options = {}) {
|
|
263
|
+
const rehypePlugins = options.rehypePlugins ?? createDefaultRehypePlugins();
|
|
264
|
+
const remarkPlugins = options.remarkPlugins ?? createDefaultRemarkPlugins();
|
|
265
|
+
return await compileMDX({
|
|
266
|
+
source: rawMdx,
|
|
267
|
+
options: {
|
|
268
|
+
parseFrontmatter: options.parseFrontmatter ?? true,
|
|
269
|
+
mdxOptions: {
|
|
270
|
+
rehypePlugins,
|
|
271
|
+
remarkPlugins
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
components: options.components
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// src/extract.ts
|
|
279
|
+
import matter from "@11ty/gray-matter";
|
|
280
|
+
var FENCE_MARKER_REGEX = /^(````|```)(?!`)/;
|
|
281
|
+
var HEADING_REGEX = /^(#{2,4})\s+(.+)$/;
|
|
282
|
+
var RELEASE_VERSION_ATTR_REGEX = /\bversion\s*=\s*"([^"]+)"/;
|
|
283
|
+
function sluggify(text) {
|
|
284
|
+
const normalized = text.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
285
|
+
const slug = normalized.toLowerCase().replace(/\s+/g, "-");
|
|
286
|
+
return slug.replace(/[^a-z0-9-]/g, "");
|
|
287
|
+
}
|
|
288
|
+
function parseReleaseVersionFromLine(line) {
|
|
289
|
+
const releaseStart = line.indexOf("<Release");
|
|
290
|
+
if (releaseStart === -1) {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
const fragment = line.slice(releaseStart, releaseStart + 512);
|
|
294
|
+
const closingIndex = fragment.indexOf(">");
|
|
295
|
+
if (closingIndex === -1) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
const tag = fragment.slice(0, closingIndex + 1);
|
|
299
|
+
if (!/^<Release\b/.test(tag)) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
const attrMatch = RELEASE_VERSION_ATTR_REGEX.exec(tag);
|
|
303
|
+
const version = attrMatch?.[1] ?? "";
|
|
304
|
+
return version.trim() || null;
|
|
305
|
+
}
|
|
306
|
+
function extractTocsFromRawMdx(rawMdx) {
|
|
307
|
+
const extractedHeadings = [];
|
|
308
|
+
const lines = rawMdx.split(/\r?\n/);
|
|
309
|
+
let inFence = false;
|
|
310
|
+
let fenceLength = 0;
|
|
311
|
+
for (const line of lines) {
|
|
312
|
+
const trimmed = line.trimStart();
|
|
313
|
+
const fenceMatch = FENCE_MARKER_REGEX.exec(trimmed);
|
|
314
|
+
if (fenceMatch) {
|
|
315
|
+
const marker = fenceMatch[1];
|
|
316
|
+
if (!inFence) {
|
|
317
|
+
inFence = true;
|
|
318
|
+
fenceLength = marker.length;
|
|
319
|
+
} else if (marker.length === fenceLength) {
|
|
320
|
+
inFence = false;
|
|
321
|
+
}
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (inFence) {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
const headingMatch = HEADING_REGEX.exec(trimmed);
|
|
328
|
+
if (headingMatch) {
|
|
329
|
+
const headingLevel = headingMatch[1].length;
|
|
330
|
+
const headingText = headingMatch[2].trim().replace(/\s+#+\s*$/, "");
|
|
331
|
+
extractedHeadings.push({
|
|
332
|
+
level: headingLevel,
|
|
333
|
+
text: headingText,
|
|
334
|
+
href: `#${sluggify(headingText)}`
|
|
335
|
+
});
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
const version = parseReleaseVersionFromLine(line);
|
|
339
|
+
if (version) {
|
|
340
|
+
extractedHeadings.push({
|
|
341
|
+
level: 2,
|
|
342
|
+
text: `v${version}`,
|
|
343
|
+
href: `#${version}`
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return extractedHeadings;
|
|
348
|
+
}
|
|
349
|
+
function extractFrontmatter(content) {
|
|
350
|
+
try {
|
|
351
|
+
return matter(content).data;
|
|
352
|
+
} catch (error) {
|
|
353
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
354
|
+
throw new Error(`Failed to extract frontmatter: ${reason}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function extractFrontmatterWithContent(content) {
|
|
358
|
+
try {
|
|
359
|
+
const { data, content: strippedContent } = matter(content);
|
|
360
|
+
return { frontmatter: data, strippedContent };
|
|
361
|
+
} catch (error) {
|
|
362
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
363
|
+
throw new Error(`Failed to extract frontmatter: ${reason}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// src/content.ts
|
|
368
|
+
import path from "node:path";
|
|
369
|
+
import { promises as fs } from "node:fs";
|
|
370
|
+
async function readMdxFileBySlug(slug, options = {}) {
|
|
371
|
+
if (!slug || slug.trim() === "") {
|
|
372
|
+
slug = "index";
|
|
373
|
+
}
|
|
374
|
+
const docsDir = options.docsDir ?? "docs";
|
|
375
|
+
const docsRoot = options.rootDir ? path.join(
|
|
376
|
+
/*turbopackIgnore: true*/
|
|
377
|
+
options.rootDir,
|
|
378
|
+
docsDir
|
|
379
|
+
) : path.join(
|
|
380
|
+
/*turbopackIgnore: true*/
|
|
381
|
+
process.cwd(),
|
|
382
|
+
docsDir
|
|
383
|
+
);
|
|
384
|
+
const resolvedRoot = path.resolve(
|
|
385
|
+
/*turbopackIgnore: true*/
|
|
386
|
+
docsRoot
|
|
387
|
+
);
|
|
388
|
+
const paths = [
|
|
389
|
+
path.join(
|
|
390
|
+
/*turbopackIgnore: true*/
|
|
391
|
+
docsRoot,
|
|
392
|
+
`${slug}.mdx`
|
|
393
|
+
),
|
|
394
|
+
path.join(
|
|
395
|
+
/*turbopackIgnore: true*/
|
|
396
|
+
docsRoot,
|
|
397
|
+
slug,
|
|
398
|
+
"index.mdx"
|
|
399
|
+
)
|
|
400
|
+
];
|
|
401
|
+
for (const p of paths) {
|
|
402
|
+
const resolvedP = path.resolve(
|
|
403
|
+
/*turbopackIgnore: true*/
|
|
404
|
+
p
|
|
405
|
+
);
|
|
406
|
+
if (!resolvedP.startsWith(resolvedRoot + path.sep) && resolvedP !== resolvedRoot) {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
try {
|
|
410
|
+
const content = await fs.readFile(
|
|
411
|
+
/*turbopackIgnore: true*/
|
|
412
|
+
p,
|
|
413
|
+
"utf-8"
|
|
414
|
+
);
|
|
415
|
+
return {
|
|
416
|
+
content,
|
|
417
|
+
filePath: `${docsDir}/${path.relative(
|
|
418
|
+
/*turbopackIgnore: true*/
|
|
419
|
+
docsRoot,
|
|
420
|
+
p
|
|
421
|
+
)}`,
|
|
422
|
+
absoluteFilePath: p
|
|
423
|
+
};
|
|
424
|
+
} catch (error) {
|
|
425
|
+
if (error.code === "ENOENT") continue;
|
|
426
|
+
throw error;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
throw new Error("Could not find mdx file for the requested slug.");
|
|
430
|
+
}
|
|
431
|
+
function parseMdxFile(raw, options = {}) {
|
|
432
|
+
const tocsExtractor = options.tocsExtractor ?? ((mdx) => extractTocsFromRawMdx(mdx));
|
|
433
|
+
const { frontmatter, strippedContent } = extractFrontmatterWithContent(raw.content);
|
|
434
|
+
return {
|
|
435
|
+
content: strippedContent,
|
|
436
|
+
filePath: raw.filePath,
|
|
437
|
+
frontmatter,
|
|
438
|
+
tocs: tocsExtractor(raw.content)
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
async function compileParsedMdxFile(parsed, options = {}) {
|
|
442
|
+
const compiled = await parseMdx(parsed.content, {
|
|
443
|
+
...options,
|
|
444
|
+
parseFrontmatter: false
|
|
445
|
+
});
|
|
446
|
+
return {
|
|
447
|
+
...compiled,
|
|
448
|
+
frontmatter: parsed.frontmatter,
|
|
449
|
+
filePath: parsed.filePath,
|
|
450
|
+
tocs: parsed.tocs
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
function createMdxContentService(options = {}) {
|
|
454
|
+
const identityCache = (fn) => fn;
|
|
455
|
+
const cacheFn = options.cacheFn ?? identityCache;
|
|
456
|
+
const getParsedForSlug = cacheFn(async (slug) => {
|
|
457
|
+
const raw = await readMdxFileBySlug(slug, options.readOptions);
|
|
458
|
+
const parsed = parseMdxFile(raw, { tocsExtractor: options.tocsExtractor });
|
|
459
|
+
if (options.frontmatterEnricher && raw.absoluteFilePath) {
|
|
460
|
+
parsed.frontmatter = await options.frontmatterEnricher(
|
|
461
|
+
parsed.frontmatter,
|
|
462
|
+
raw.absoluteFilePath
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
return parsed;
|
|
466
|
+
});
|
|
467
|
+
const getCompiledForSlug = cacheFn(
|
|
468
|
+
async (slug) => {
|
|
469
|
+
const parsed = await getParsedForSlug(slug);
|
|
470
|
+
return compileParsedMdxFile(parsed, options.parseOptions);
|
|
471
|
+
}
|
|
472
|
+
);
|
|
473
|
+
async function getFrontmatterForSlug(slug) {
|
|
474
|
+
const parsed = await getParsedForSlug(slug);
|
|
475
|
+
return parsed.frontmatter;
|
|
476
|
+
}
|
|
477
|
+
async function getTocsForSlug(slug) {
|
|
478
|
+
const parsed = await getParsedForSlug(slug);
|
|
479
|
+
return parsed.tocs;
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
getParsedForSlug,
|
|
483
|
+
getCompiledForSlug,
|
|
484
|
+
getFrontmatterForSlug,
|
|
485
|
+
getTocsForSlug
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
export {
|
|
489
|
+
MDXRemote,
|
|
490
|
+
cn,
|
|
491
|
+
compileParsedMdxFile,
|
|
492
|
+
createDefaultRehypePlugins,
|
|
493
|
+
createDefaultRemarkPlugins,
|
|
494
|
+
createMdxContentService,
|
|
495
|
+
extractFrontmatter,
|
|
496
|
+
extractFrontmatterWithContent,
|
|
497
|
+
extractTocsFromRawMdx,
|
|
498
|
+
formatDate,
|
|
499
|
+
formatDate2,
|
|
500
|
+
handleCodeExpandable,
|
|
501
|
+
handleCodeExpandableRemark,
|
|
502
|
+
handleCodeTitles,
|
|
503
|
+
parseDate,
|
|
504
|
+
parseMdx,
|
|
505
|
+
parseMdxFile,
|
|
506
|
+
postProcess,
|
|
507
|
+
preProcess,
|
|
508
|
+
readMdxFileBySlug,
|
|
509
|
+
rehypeMermaid,
|
|
510
|
+
serialize,
|
|
511
|
+
sluggify,
|
|
512
|
+
stringToDate,
|
|
513
|
+
toIsoDateOnly
|
|
514
|
+
};
|
|
8
515
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC9F,OAAO,EACL,QAAQ,EACR,SAAS,EACT,SAAS,EACT,UAAU,EACV,WAAW,EACX,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAClG,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EACL,kBAAkB,EAClB,6BAA6B,EAC7B,qBAAqB,EACrB,QAAQ,GACT,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"sources":["../src/compile.ts","../src/plugins/handleCodeTitles.ts","../src/plugins/handleCodeExpandable.ts","../src/plugins/rehypeMermaid.ts","../src/extract.ts","../src/content.ts"],"sourcesContent":["import { compileMDX } from \"next-mdx-remote/rsc\";\nimport { serialize } from \"next-mdx-remote/serialize\";\nimport type { Node } from \"unist\";\nimport { visit } from \"unist-util-visit\";\nimport remarkGfm from \"remark-gfm\";\nimport rehypePrism from \"rehype-prism-plus\";\nimport rehypeAutolinkHeadings from \"rehype-autolink-headings\";\nimport rehypeSlug from \"rehype-slug\";\nimport rehypeCodeTitles from \"rehype-code-titles\";\nimport { handleCodeTitles } from \"./plugins/handleCodeTitles\";\nimport { handleCodeExpandableRemark, handleCodeExpandable } from \"./plugins/handleCodeExpandable\";\nimport { rehypeMermaid } from \"./plugins/rehypeMermaid\";\nimport type { MdxCompileResult } from \"./types\";\nimport type { ElementNode } from \"./utils\";\nimport type { Pluggable } from \"unified\";\n\n// Re-export serialize for non-RSC usage\nexport { serialize };\n\n// Re-export MDXRemote for client-side hydration\nexport { MDXRemote } from \"next-mdx-remote\";\n\ninterface TextNode extends Node {\n type: \"text\";\n value: string;\n}\n\ntype CompileMdxInput = Parameters<typeof compileMDX<Record<string, unknown>>>[0];\ntype CompileMdxOptions = NonNullable<CompileMdxInput[\"options\"]>;\ntype CompilerMdxOptions = NonNullable<CompileMdxOptions[\"mdxOptions\"]>;\n\nexport type ParseMdxOptions = {\n components?: CompileMdxInput[\"components\"];\n rehypePlugins?: CompilerMdxOptions[\"rehypePlugins\"];\n remarkPlugins?: CompilerMdxOptions[\"remarkPlugins\"];\n /**\n * Whether to parse frontmatter during MDX compilation.\n * Set to `false` when frontmatter is already extracted separately\n * (e.g. via gray-matter) to avoid redundant parsing.\n * Defaults to `true`.\n */\n parseFrontmatter?: boolean;\n};\n\nexport const preProcess = () => (tree: Node) => {\n visit(tree, (node: Node) => {\n const element = node as ElementNode;\n if (element?.type === \"element\" && element?.tagName === \"pre\" && element.children) {\n const [codeEl] = element.children as ElementNode[];\n if (codeEl.tagName !== \"code\" || !codeEl.children?.[0]) return;\n\n const className = codeEl.properties?.className;\n const classList = Array.isArray(className)\n ? className\n : typeof className === \"string\"\n ? className.split(\" \").filter(Boolean)\n : [];\n const languageClass = classList.find((item: string) => item.startsWith(\"language-\"));\n if (languageClass) {\n element.language = languageClass.replace(\"language-\", \"\").split(\":\")[0];\n }\n\n const textNode = codeEl.children[0] as TextNode;\n if (textNode.type === \"text\" && textNode.value) {\n element.raw = textNode.value;\n }\n }\n });\n\n return tree;\n};\n\nexport const postProcess = () => (tree: Node) => {\n visit(tree, \"element\", (node: Node) => {\n const element = node as ElementNode;\n if (element?.type === \"element\" && element?.tagName === \"pre\") {\n if (element.properties && element.raw) {\n element.properties.raw = element.raw;\n }\n if (element.properties && element.language && !element.properties[\"data-language\"]) {\n element.properties[\"data-language\"] = element.language;\n }\n if (element.properties && element.codeTitle && !element.properties[\"data-title\"]) {\n element.properties[\"data-title\"] = element.codeTitle;\n }\n }\n });\n\n return tree;\n};\n\nexport function createDefaultRehypePlugins(): Pluggable[] {\n return [\n preProcess,\n rehypeMermaid, // Transform ```mermaid before code transforms\n rehypeCodeTitles,\n handleCodeTitles,\n handleCodeExpandable, // Copy expandable metadata from <code> to <pre> before prism transforms nodes.\n rehypePrism,\n handleCodeExpandable, // Re-apply expandable attrs after prism tokenization.\n rehypeSlug,\n rehypeAutolinkHeadings,\n postProcess,\n ];\n}\n\nexport function createDefaultRemarkPlugins(): Pluggable[] {\n return [remarkGfm, handleCodeExpandableRemark];\n}\n\nexport async function parseMdx<Frontmatter>(\n rawMdx: string,\n options: ParseMdxOptions = {}\n): Promise<MdxCompileResult<Frontmatter>> {\n const rehypePlugins =\n options.rehypePlugins ?? (createDefaultRehypePlugins() as CompilerMdxOptions[\"rehypePlugins\"]);\n const remarkPlugins =\n options.remarkPlugins ?? (createDefaultRemarkPlugins() as CompilerMdxOptions[\"remarkPlugins\"]);\n\n return await compileMDX<Frontmatter>({\n source: rawMdx,\n options: {\n parseFrontmatter: options.parseFrontmatter ?? true,\n mdxOptions: {\n rehypePlugins,\n remarkPlugins,\n },\n },\n components: options.components,\n });\n}\n","import type { Node, Parent } from \"unist\"\nimport { visit } from \"unist-util-visit\"\nimport type { ElementNode } from \"../utils\"\n\ninterface TextNode extends Node {\n type: \"text\"\n value: string\n}\n\nexport const handleCodeTitles = () => (tree: Node) => {\n const toRemove: { parent: Parent; index: number }[] = []\n\n visit(tree, \"element\", (node: ElementNode, index: number | null, parent: Parent | null) => {\n if (!parent || index === null || node.tagName !== \"div\") {\n return\n }\n\n const isTitleDiv = node.properties?.className?.includes(\"rehype-code-title\")\n if (!isTitleDiv) {\n return\n }\n\n let nextElement: ElementNode | null = null\n for (let i = index + 1; i < parent.children.length; i++) {\n const sibling = parent.children[i]\n if (sibling.type === \"element\") {\n nextElement = sibling as ElementNode\n break\n }\n }\n\n if (nextElement?.tagName === \"pre\") {\n const titleNode = node.children?.[0] as TextNode\n if (titleNode?.type === \"text\") {\n if (!nextElement.properties) {\n nextElement.properties = {}\n }\n nextElement.properties[\"data-title\"] = titleNode.value\n nextElement.codeTitle = titleNode.value\n toRemove.push({ parent, index })\n }\n }\n })\n\n // Remove title divs in reverse order to preserve indices\n for (let i = toRemove.length - 1; i >= 0; i--) {\n const { parent, index } = toRemove[i]\n parent.children.splice(index, 1)\n }\n}\n","import type { Node } from \"unist\";\nimport { visit } from \"unist-util-visit\";\nimport type { ElementNode } from \"../utils\";\n\n/**\n * Escape metadata values that are interpolated into MDX-compiled JavaScript.\n *\n * References:\n * - HTML spec (script data state): escape `</` as `\\u003C/` to prevent premature\n * `</script>` closing when the compiled JS is embedded as JSON in a <script> tag.\n * - Bun.escapeHTML(): escapes `< > \" ' &` for HTML context; for JS/JSON context\n * we use `\\uXXXX` JSON Unicode escapes instead so the value survives round-trip\n * through JSON.parse on the client side.\n * - React: JSX auto-escapes attribute values via `{expression}`, so values set\n * as HAST properties (data-language, data-title) are HTML-safe at render time.\n */\nfunction escapeMeta(s: string): string {\n let out = \"\";\n for (let i = 0; i < s.length; i++) {\n const ch = s[i];\n\n // HTML spec: prevent </script> in script/JSON context\n if (ch === \"<\" && s[i + 1] === \"/\") {\n out += \"\\\\u003C/\";\n i++;\n continue;\n }\n\n // JS string: escape template literal & string special chars\n if (ch === \"`\" || ch === \"$\" || ch === \"{\" || ch === \"}\" || ch === \"\\\"\" || ch === \"\\\\\") {\n out += `\\\\${ch}`;\n continue;\n }\n\n out += ch;\n }\n return out;\n}\n\ninterface CodeNode extends Node {\n type: \"code\";\n lang?: string;\n meta?: string;\n value: string;\n data?: {\n meta?: string;\n hProperties?: Record<string, unknown>;\n };\n}\n\nfunction countCodeLines(raw: string): number {\n let normalized = raw.replace(/\\r\\n/g, \"\\n\");\n if (normalized.startsWith(\"\\n\")) normalized = normalized.slice(1);\n if (normalized.endsWith(\"\\n\")) normalized = normalized.slice(0, -1);\n\n if (normalized.length === 0) return 0;\n return normalized.split(\"\\n\").length;\n}\n\nexport const handleCodeExpandableRemark = () => (tree: Node) => {\n visit(tree, \"code\", (node: CodeNode) => {\n if (!node.meta) return;\n\n const isExpandable = node.meta.includes(\"Expandable\");\n const [languagePart, titlePart] = (node.lang ?? \"\").split(\":\");\n const normalizedLanguage = languagePart?.trim();\n const normalizedTitle = titlePart?.trim();\n\n if (!isExpandable) return;\n\n const lineCount = countCodeLines(node.value);\n\n if (!node.data) {\n node.data = {};\n }\n if (!node.data.hProperties) {\n node.data.hProperties = {};\n }\n\n node.data.hProperties[\"data-expandable\"] = \"true\";\n node.data.hProperties[\"data-expandable-lines\"] = lineCount.toString();\n\n if (normalizedLanguage) {\n node.data.hProperties[\"data-language\"] = normalizedLanguage;\n }\n if (normalizedTitle) {\n node.data.hProperties[\"data-title\"] = normalizedTitle;\n }\n\n const currentClassName = node.data.hProperties.className;\n const classList = Array.isArray(currentClassName)\n ? currentClassName\n : typeof currentClassName === \"string\"\n ? currentClassName.split(\" \").filter(Boolean)\n : [];\n\n if (!classList.includes(\"mdx-expandable-meta\")) {\n classList.push(\"mdx-expandable-meta\");\n }\n\n node.data.hProperties.className = classList;\n\n if (normalizedLanguage && !node.meta.includes(\"dbLang(\")) {\n node.meta = `${node.meta} dbLang(${escapeMeta(normalizedLanguage)})`.trim();\n }\n if (normalizedTitle && !node.meta.includes(\"dbTitle(\")) {\n node.meta = `${node.meta} dbTitle(${escapeMeta(normalizedTitle)})`.trim();\n }\n });\n};\n\nexport const handleCodeExpandable = () => (tree: Node) => {\n visit(tree, \"element\", (node: ElementNode) => {\n if (node.tagName !== \"pre\") return;\n\n const codeElement = node.children?.find((child) => {\n const element = child as ElementNode;\n return element.type === \"element\" && element.tagName === \"code\";\n }) as ElementNode | undefined;\n\n const codeClassName = codeElement?.properties?.className;\n const codeClassList = Array.isArray(codeClassName)\n ? codeClassName\n : typeof codeClassName === \"string\"\n ? codeClassName.split(\" \").filter(Boolean)\n : [];\n\n const codeMeta =\n codeElement?.data &&\n typeof codeElement.data === \"object\" &&\n typeof codeElement.data[\"meta\"] === \"string\"\n ? (codeElement.data[\"meta\"] as string)\n : undefined;\n\n const languageFromMeta = codeMeta?.match(/dbLang\\(([^)]+)\\)/)?.[1];\n const titleFromMeta = codeMeta?.match(/dbTitle\\(([^)]+)\\)/)?.[1];\n\n const languageFromProps =\n typeof codeElement?.properties?.[\"data-language\"] === \"string\"\n ? (codeElement.properties[\"data-language\"] as string)\n : undefined;\n const titleFromProps =\n typeof codeElement?.properties?.[\"data-title\"] === \"string\"\n ? (codeElement.properties[\"data-title\"] as string)\n : undefined;\n\n const languageFromCodeClass = codeClassList\n .find((item) => item.startsWith(\"language-\"))\n ?.replace(\"language-\", \"\");\n\n const existingPreLanguage =\n typeof node.properties?.[\"data-language\"] === \"string\"\n ? (node.properties[\"data-language\"] as string)\n : undefined;\n const existingPreTitle =\n typeof node.properties?.[\"data-title\"] === \"string\"\n ? (node.properties[\"data-title\"] as string)\n : undefined;\n\n const isExpandable =\n codeElement?.properties?.[\"data-expandable\"] === \"true\" ||\n codeClassList.includes(\"mdx-expandable-meta\") ||\n codeMeta?.includes(\"Expandable\") === true;\n\n const expandableLines = codeElement?.properties?.[\"data-expandable-lines\"];\n if (!isExpandable) return;\n\n if (!node.properties) {\n node.properties = {};\n }\n\n node.properties[\"data-expandable\"] = \"true\";\n if (typeof expandableLines === \"string\" || typeof expandableLines === \"number\") {\n node.properties[\"data-expandable-lines\"] = expandableLines.toString();\n } else if (node.raw) {\n node.properties[\"data-expandable-lines\"] = countCodeLines(node.raw).toString();\n }\n\n const resolvedLanguage =\n languageFromProps ||\n languageFromMeta ||\n languageFromCodeClass ||\n existingPreLanguage ||\n node.language;\n const resolvedTitle = titleFromProps || titleFromMeta || existingPreTitle || node.codeTitle;\n\n if (resolvedLanguage) {\n node.properties[\"data-language\"] = resolvedLanguage;\n }\n if (resolvedTitle) {\n node.properties[\"data-title\"] = resolvedTitle;\n }\n\n const className = node.properties.className;\n if (!className) {\n node.properties.className = [];\n }\n\n if (Array.isArray(node.properties.className)) {\n if (!node.properties.className.includes(\"mdx-expandable-code\")) {\n node.properties.className.push(\"mdx-expandable-code\");\n }\n } else if (typeof className === \"string\") {\n const hasMarker = className.split(\" \").includes(\"mdx-expandable-code\");\n if (!hasMarker) {\n node.properties.className = `${className} mdx-expandable-code`.trim().split(\" \");\n }\n } else {\n node.properties.className = [\"mdx-expandable-code\"];\n }\n\n if (codeElement?.properties) {\n const cleanedCodeClassList = codeClassList.filter((item) => item !== \"mdx-expandable-meta\");\n codeElement.properties.className = cleanedCodeClassList;\n }\n });\n};\n","import type { Node, Parent } from \"unist\";\nimport { visit } from \"unist-util-visit\";\nimport type { ElementNode } from \"../utils\";\n\ninterface TextNode extends Node {\n type: \"text\";\n value: string;\n}\n\n/**\n * Rehype plugin that transforms `<pre><code class=\"language-mermaid\">` fenced\n * blocks into `<Mermaid chart=\"...\">` elements.\n *\n * This allows Mermaid diagram definitions to be authored via standard fenced\n * code blocks (````mermaid) which avoids JSX parsing collisions with\n * Mermaid's `{...}` (decision nodes) and `[...]` (label nodes) syntax.\n */\nexport const rehypeMermaid = () => (tree: Node) => {\n visit(tree, \"element\", (node: ElementNode, index: number | null, parent: Parent | null) => {\n if (!parent || index === null || node.tagName !== \"pre\") return;\n\n const codeEl = node.children?.find(\n (child) =>\n (child as ElementNode).type === \"element\" && (child as ElementNode).tagName === \"code\"\n ) as ElementNode | undefined;\n\n if (!codeEl) return;\n\n const classList = Array.isArray(codeEl.properties?.className)\n ? (codeEl.properties.className as string[])\n : typeof codeEl.properties?.className === \"string\"\n ? (codeEl.properties.className as string).split(\" \").filter(Boolean)\n : [];\n\n if (!classList.includes(\"language-mermaid\")) return;\n\n const textNode = codeEl.children?.find((child) => (child as TextNode).type === \"text\") as\n | TextNode\n | undefined;\n\n const chart = textNode?.value ?? \"\";\n\n parent.children[index] = {\n type: \"element\",\n tagName: \"Mermaid\",\n properties: { chart },\n children: [],\n } as unknown as ElementNode;\n });\n};\n","import matter from \"@11ty/gray-matter\";\nimport type { TocItem } from \"./types\";\n\nconst FENCE_MARKER_REGEX = /^(````|```)(?!`)/;\nconst HEADING_REGEX = /^(#{2,4})\\s+(.+)$/;\nconst RELEASE_VERSION_ATTR_REGEX = /\\bversion\\s*=\\s*\"([^\"]+)\"/;\n\nexport function sluggify(text: string): string {\n const normalized = text.normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\"); // Remove accents\n const slug = normalized.toLowerCase().replace(/\\s+/g, \"-\");\n return slug.replace(/[^a-z0-9-]/g, \"\");\n}\n\nfunction parseReleaseVersionFromLine(line: string): string | null {\n const releaseStart = line.indexOf(\"<Release\");\n if (releaseStart === -1) {\n return null;\n }\n\n // Parse only the first tag fragment on the line to avoid broad regex scans.\n const fragment = line.slice(releaseStart, releaseStart + 512);\n const closingIndex = fragment.indexOf(\">\");\n if (closingIndex === -1) {\n return null;\n }\n\n const tag = fragment.slice(0, closingIndex + 1);\n if (!/^<Release\\b/.test(tag)) {\n return null;\n }\n\n const attrMatch = RELEASE_VERSION_ATTR_REGEX.exec(tag);\n const version = attrMatch?.[1] ?? \"\";\n return version.trim() || null;\n}\n\nexport function extractTocsFromRawMdx(rawMdx: string): TocItem[] {\n const extractedHeadings: TocItem[] = [];\n\n const lines = rawMdx.split(/\\r?\\n/);\n let inFence = false;\n let fenceLength = 0;\n\n for (const line of lines) {\n const trimmed = line.trimStart();\n\n const fenceMatch = FENCE_MARKER_REGEX.exec(trimmed);\n if (fenceMatch) {\n const marker = fenceMatch[1];\n\n if (!inFence) {\n inFence = true;\n fenceLength = marker.length;\n } else if (marker.length === fenceLength) {\n inFence = false;\n }\n\n continue;\n }\n\n if (inFence) {\n continue;\n }\n\n const headingMatch = HEADING_REGEX.exec(trimmed);\n if (headingMatch) {\n const headingLevel = headingMatch[1].length;\n const headingText = headingMatch[2].trim().replace(/\\s+#+\\s*$/, \"\");\n extractedHeadings.push({\n level: headingLevel,\n text: headingText,\n href: `#${sluggify(headingText)}`,\n });\n continue;\n }\n\n const version = parseReleaseVersionFromLine(line);\n if (version) {\n extractedHeadings.push({\n level: 2,\n text: `v${version}`,\n href: `#${version}`,\n });\n }\n }\n\n return extractedHeadings;\n}\n\nexport function extractFrontmatter<Frontmatter>(content: string): Frontmatter {\n try {\n return matter(content).data as Frontmatter;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to extract frontmatter: ${reason}`);\n }\n}\n\n/**\n * Extract frontmatter and return both the parsed data and the content\n * with the frontmatter block stripped. Avoids a second parse by compileMDX.\n */\nexport function extractFrontmatterWithContent<Frontmatter>(content: string): {\n frontmatter: Frontmatter;\n strippedContent: string;\n} {\n try {\n const { data, content: strippedContent } = matter(content);\n return { frontmatter: data as Frontmatter, strippedContent };\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to extract frontmatter: ${reason}`);\n }\n}\n","import path from \"node:path\";\nimport { promises as fs } from \"node:fs\";\nimport { extractFrontmatterWithContent, extractTocsFromRawMdx } from \"./extract\";\nimport { parseMdx, type ParseMdxOptions } from \"./compile\";\nimport type { MdxCompileResult, TocItem } from \"./types\";\n\ntype CacheFn = <T extends (...args: any[]) => any>(fn: T) => T;\n\nexport type ReadMdxFileResult = {\n content: string;\n /** Relative path used for UI links (e.g. \"docs/getting-started/index.mdx\"). */\n filePath: string;\n /** Absolute path on disk — available when file was read by readMdxFileBySlug. */\n absoluteFilePath?: string;\n};\n\nexport type ParsedMdxFile<Frontmatter, T extends TocItem = TocItem> = {\n /** Raw content with frontmatter block stripped — ready to pass to compileMDX. */\n content: string;\n filePath: string;\n frontmatter: Frontmatter;\n tocs: T[];\n};\n\nexport type CompiledMdxFile<\n Frontmatter,\n T extends TocItem = TocItem,\n> = MdxCompileResult<Frontmatter> & {\n filePath: string;\n tocs: T[];\n};\n\ntype ReadMdxBySlugOptions = {\n rootDir?: string;\n docsDir?: string;\n};\n\nexport async function readMdxFileBySlug(\n slug: string,\n options: ReadMdxBySlugOptions = {}\n): Promise<ReadMdxFileResult> {\n if (!slug || slug.trim() === \"\") {\n // Handle root slug as \"index\"\n slug = \"index\";\n }\n const docsDir = options.docsDir ?? \"docs\";\n // Keep file-system path operations ignored by Turbopack tracing.\n // The runtime path is constrained to docsDir and slug candidates below.\n const docsRoot = options.rootDir\n ? path.join(/*turbopackIgnore: true*/ options.rootDir, docsDir)\n : path.join(/*turbopackIgnore: true*/ process.cwd(), docsDir);\n\n // Resolve once for path-traversal guard — all candidate paths must stay\n // escaping the docs directory, especially important with dynamicParams=true.\n const resolvedRoot = path.resolve(/*turbopackIgnore: true*/ docsRoot);\n\n const paths = [\n path.join(/*turbopackIgnore: true*/ docsRoot, `${slug}.mdx`),\n path.join(/*turbopackIgnore: true*/ docsRoot, slug, \"index.mdx\"),\n ];\n // console.log(`Attempting to read slug: \"${slug}\", paths:`, paths); // Debug log\n\n for (const p of paths) {\n // Guard: reject any path that escapes the docs root.\n const resolvedP = path.resolve(/*turbopackIgnore: true*/ p);\n if (!resolvedP.startsWith(resolvedRoot + path.sep) && resolvedP !== resolvedRoot) {\n continue;\n }\n\n try {\n const content = await fs.readFile(/*turbopackIgnore: true*/ p, \"utf-8\");\n return {\n content,\n filePath: `${docsDir}/${path.relative(/*turbopackIgnore: true*/ docsRoot, p)}`,\n absoluteFilePath: p,\n };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n throw error;\n }\n }\n\n throw new Error(\"Could not find mdx file for the requested slug.\");\n}\n\ntype ParseMdxFileOptions<T extends TocItem> = {\n tocsExtractor?: (rawMdx: string) => T[];\n};\n\nexport function parseMdxFile<Frontmatter, T extends TocItem = TocItem>(\n raw: ReadMdxFileResult,\n options: ParseMdxFileOptions<T> = {}\n): ParsedMdxFile<Frontmatter, T> {\n const tocsExtractor = options.tocsExtractor ?? ((mdx) => extractTocsFromRawMdx(mdx) as T[]);\n // Extract frontmatter and stripped content in one gray-matter call.\n // strippedContent is passed to compileMDX so it doesn't need to re-parse frontmatter.\n const { frontmatter, strippedContent } = extractFrontmatterWithContent<Frontmatter>(raw.content);\n\n return {\n content: strippedContent,\n filePath: raw.filePath,\n frontmatter,\n tocs: tocsExtractor(raw.content),\n };\n}\n\nexport async function compileParsedMdxFile<Frontmatter, T extends TocItem = TocItem>(\n parsed: ParsedMdxFile<Frontmatter, T>,\n options: ParseMdxOptions = {}\n): Promise<CompiledMdxFile<Frontmatter, T>> {\n // Content in parsed is already stripped of frontmatter by parseMdxFile.\n // Set parseFrontmatter:false — no re-parse needed, avoids double work.\n const compiled = await parseMdx<Frontmatter>(parsed.content, {\n ...options,\n parseFrontmatter: false,\n });\n\n return {\n ...compiled,\n frontmatter: parsed.frontmatter,\n filePath: parsed.filePath,\n tocs: parsed.tocs,\n };\n}\n\nexport type CreateMdxContentServiceOptions<Frontmatter, T extends TocItem = TocItem> = {\n parseOptions?: ParseMdxOptions;\n readOptions?: ReadMdxBySlugOptions;\n tocsExtractor?: (rawMdx: string) => T[];\n cacheFn?: CacheFn;\n /**\n * Optional hook to enrich or transform frontmatter after parsing.\n * Called with the parsed frontmatter and the absolute file path.\n * Runs at build time during static generation — ideal for injecting\n * fallback values (e.g. git last-modified date when `date` is absent).\n */\n frontmatterEnricher?: (\n frontmatter: Frontmatter,\n absoluteFilePath: string\n ) => Frontmatter | Promise<Frontmatter>;\n};\n\nexport function createMdxContentService<Frontmatter, T extends TocItem = TocItem>(\n options: CreateMdxContentServiceOptions<Frontmatter, T> = {}\n) {\n const identityCache: CacheFn = (fn) => fn;\n const cacheFn = options.cacheFn ?? identityCache;\n\n const getParsedForSlug = cacheFn(async (slug: string): Promise<ParsedMdxFile<Frontmatter, T>> => {\n const raw = await readMdxFileBySlug(slug, options.readOptions);\n const parsed = parseMdxFile<Frontmatter, T>(raw, { tocsExtractor: options.tocsExtractor });\n if (options.frontmatterEnricher && raw.absoluteFilePath) {\n parsed.frontmatter = await options.frontmatterEnricher(\n parsed.frontmatter,\n raw.absoluteFilePath\n );\n }\n return parsed;\n });\n\n const getCompiledForSlug = cacheFn(\n async (slug: string): Promise<CompiledMdxFile<Frontmatter, T>> => {\n const parsed = await getParsedForSlug(slug);\n return compileParsedMdxFile<Frontmatter, T>(parsed, options.parseOptions);\n }\n );\n\n async function getFrontmatterForSlug(slug: string): Promise<Frontmatter> {\n const parsed = await getParsedForSlug(slug);\n return parsed.frontmatter;\n }\n\n async function getTocsForSlug(slug: string): Promise<T[]> {\n const parsed = await getParsedForSlug(slug);\n return parsed.tocs;\n }\n\n return {\n getParsedForSlug,\n getCompiledForSlug,\n getFrontmatterForSlug,\n getTocsForSlug,\n };\n}\n"],"mappings":"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","names":["visit","visit","visit","visit"]}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
1
|
+
import { ClassValue } from 'clsx';
|
|
2
|
+
import { Node } from 'unist';
|
|
3
|
+
|
|
4
|
+
interface ElementNode extends Node {
|
|
4
5
|
type: string;
|
|
5
6
|
tagName?: string;
|
|
6
7
|
properties?: Record<string, unknown> & {
|
|
@@ -13,13 +14,14 @@ export interface ElementNode extends Node {
|
|
|
13
14
|
language?: string;
|
|
14
15
|
codeTitle?: string;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
17
18
|
/** Parse both `dd-MM-yyyy` and ISO 8601 date strings into a Date object. */
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
declare function parseDate(dateStr: string): Date;
|
|
20
|
+
declare function stringToDate(date: string | Date): Date;
|
|
20
21
|
/** Format date to long format (e.g. "Thursday, April 5, 2026") */
|
|
21
|
-
|
|
22
|
+
declare function formatDate(dateStrOrDate: string | Date): string;
|
|
22
23
|
/** Format date to short format (e.g. "Apr 5, 2026") */
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
declare function formatDate2(dateStrOrDate: string | Date): string;
|
|
25
|
+
declare function toIsoDateOnly(dateStrOrDate: string | Date): string;
|
|
26
|
+
|
|
27
|
+
export { type ElementNode, cn, formatDate, formatDate2, parseDate, stringToDate, toIsoDateOnly };
|