fumadocs-core 14.7.5 → 14.7.6
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/mdx-plugins/index.d.ts +1 -1
- package/dist/mdx-plugins/index.js +42 -295
- package/package.json +4 -4
|
@@ -48,7 +48,7 @@ type RehypeCodeOptions = RehypeShikiOptions & {
|
|
|
48
48
|
/**
|
|
49
49
|
* Handle codeblocks
|
|
50
50
|
*/
|
|
51
|
-
declare function rehypeCode(this: Processor,
|
|
51
|
+
declare function rehypeCode(this: Processor, _options?: Partial<RehypeCodeOptions>): Transformer<Root, Root>;
|
|
52
52
|
declare function transformerTab(): ShikiTransformer;
|
|
53
53
|
|
|
54
54
|
interface RemarkImageOptions {
|
|
@@ -19,261 +19,11 @@ import {
|
|
|
19
19
|
|
|
20
20
|
// src/mdx-plugins/rehype-code.ts
|
|
21
21
|
import rehypeShikiFromHighlighter from "@shikijs/rehype/core";
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
[/^(\/\/|["']|;{1,2}|%{1,2}|--|#)(.+)$/, true],
|
|
28
|
-
/**
|
|
29
|
-
* for multi-line comments like this
|
|
30
|
-
*/
|
|
31
|
-
[/^(\*)(.+)$/, true]
|
|
32
|
-
];
|
|
33
|
-
function parseComments(lines, jsx) {
|
|
34
|
-
const out = [];
|
|
35
|
-
for (const line of lines) {
|
|
36
|
-
const elements = line.children;
|
|
37
|
-
const start = jsx ? elements.length - 2 : elements.length - 1;
|
|
38
|
-
for (let i = Math.max(start, 0); i < elements.length; i++) {
|
|
39
|
-
const token = elements[i];
|
|
40
|
-
if (token.type !== "element")
|
|
41
|
-
continue;
|
|
42
|
-
const isLast = i === elements.length - 1;
|
|
43
|
-
const match = matchToken(token, isLast);
|
|
44
|
-
if (!match) continue;
|
|
45
|
-
if (jsx && !isLast && i !== 0) {
|
|
46
|
-
const left = elements[i - 1];
|
|
47
|
-
const right = elements[i + 1];
|
|
48
|
-
out.push({
|
|
49
|
-
info: match,
|
|
50
|
-
line,
|
|
51
|
-
token,
|
|
52
|
-
isJsxStyle: isValue(left, "{") && isValue(right, "}")
|
|
53
|
-
});
|
|
54
|
-
} else {
|
|
55
|
-
out.push({
|
|
56
|
-
info: match,
|
|
57
|
-
line,
|
|
58
|
-
token,
|
|
59
|
-
isJsxStyle: false
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return out;
|
|
65
|
-
}
|
|
66
|
-
function isValue(element, value) {
|
|
67
|
-
if (element.type !== "element") return false;
|
|
68
|
-
const text = element.children[0];
|
|
69
|
-
if (text.type !== "text")
|
|
70
|
-
return false;
|
|
71
|
-
return text.value.trim() === value;
|
|
72
|
-
}
|
|
73
|
-
function matchToken(token, isLast) {
|
|
74
|
-
const text = token.children[0];
|
|
75
|
-
if (text.type !== "text")
|
|
76
|
-
return;
|
|
77
|
-
for (const [matcher, endOfLine] of matchers) {
|
|
78
|
-
if (endOfLine && !isLast) continue;
|
|
79
|
-
let trimmed = text.value.trimStart();
|
|
80
|
-
const spaceFront = text.value.length - trimmed.length;
|
|
81
|
-
trimmed = trimmed.trimEnd();
|
|
82
|
-
const spaceEnd = text.value.length - trimmed.length - spaceFront;
|
|
83
|
-
const result = matcher.exec(trimmed);
|
|
84
|
-
if (!result) continue;
|
|
85
|
-
return [
|
|
86
|
-
" ".repeat(spaceFront) + result[1],
|
|
87
|
-
result[2],
|
|
88
|
-
result[3] ? result[3] + " ".repeat(spaceEnd) : void 0
|
|
89
|
-
];
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function createCommentNotationTransformer(name, regex, onMatch) {
|
|
93
|
-
return {
|
|
94
|
-
name,
|
|
95
|
-
code(code) {
|
|
96
|
-
const lines = code.children.filter((i) => i.type === "element");
|
|
97
|
-
const linesToRemove = [];
|
|
98
|
-
code.data ??= {};
|
|
99
|
-
const data = code.data;
|
|
100
|
-
data._shiki_notation ??= parseComments(lines, ["jsx", "tsx"].includes(this.options.lang));
|
|
101
|
-
const parsed = data._shiki_notation;
|
|
102
|
-
for (const comment of parsed) {
|
|
103
|
-
if (comment.info[1].length === 0) continue;
|
|
104
|
-
const isLineCommentOnly = comment.line.children.length === (comment.isJsxStyle ? 3 : 1);
|
|
105
|
-
let lineIdx = lines.indexOf(comment.line);
|
|
106
|
-
if (isLineCommentOnly) lineIdx++;
|
|
107
|
-
comment.info[1] = comment.info[1].replace(regex, (...match) => {
|
|
108
|
-
if (onMatch.call(this, match, comment.line, comment.token, lines, lineIdx)) {
|
|
109
|
-
return "";
|
|
110
|
-
}
|
|
111
|
-
return match[0];
|
|
112
|
-
});
|
|
113
|
-
const isEmpty = comment.info[1].trim().length === 0;
|
|
114
|
-
if (isEmpty) comment.info[1] = "";
|
|
115
|
-
if (isEmpty && isLineCommentOnly) {
|
|
116
|
-
linesToRemove.push(comment.line);
|
|
117
|
-
} else if (isEmpty && comment.isJsxStyle) {
|
|
118
|
-
comment.line.children.splice(comment.line.children.indexOf(comment.token) - 1, 3);
|
|
119
|
-
} else if (isEmpty) {
|
|
120
|
-
comment.line.children.splice(comment.line.children.indexOf(comment.token), 1);
|
|
121
|
-
} else {
|
|
122
|
-
const head = comment.token.children[0];
|
|
123
|
-
if (head.type === "text") {
|
|
124
|
-
head.value = comment.info.join("");
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
for (const line of linesToRemove)
|
|
129
|
-
code.children.splice(code.children.indexOf(line), 1);
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
function escapeRegExp(str) {
|
|
134
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
135
|
-
}
|
|
136
|
-
function transformerNotationMap(options = {}, name = "@shikijs/transformers:notation-map") {
|
|
137
|
-
const {
|
|
138
|
-
classMap = {},
|
|
139
|
-
classActivePre = void 0
|
|
140
|
-
} = options;
|
|
141
|
-
return createCommentNotationTransformer(
|
|
142
|
-
name,
|
|
143
|
-
new RegExp(`\\s*\\[!code (${Object.keys(classMap).map(escapeRegExp).join("|")})(:\\d+)?\\]`),
|
|
144
|
-
function([_, match, range = ":1"], _line, _comment, lines, index) {
|
|
145
|
-
const lineNum = Number.parseInt(range.slice(1), 10);
|
|
146
|
-
for (let i = index; i < Math.min(index + lineNum, lines.length); i++) {
|
|
147
|
-
this.addClassToHast(lines[i], classMap[match]);
|
|
148
|
-
}
|
|
149
|
-
if (classActivePre)
|
|
150
|
-
this.addClassToHast(this.pre, classActivePre);
|
|
151
|
-
return true;
|
|
152
|
-
}
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
function transformerNotationDiff(options = {}) {
|
|
156
|
-
const {
|
|
157
|
-
classLineAdd = "diff add",
|
|
158
|
-
classLineRemove = "diff remove",
|
|
159
|
-
classActivePre = "has-diff"
|
|
160
|
-
} = options;
|
|
161
|
-
return transformerNotationMap(
|
|
162
|
-
{
|
|
163
|
-
classMap: {
|
|
164
|
-
"++": classLineAdd,
|
|
165
|
-
"--": classLineRemove
|
|
166
|
-
},
|
|
167
|
-
classActivePre
|
|
168
|
-
},
|
|
169
|
-
"@shikijs/transformers:notation-diff"
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
function transformerNotationHighlight(options = {}) {
|
|
173
|
-
const {
|
|
174
|
-
classActiveLine = "highlighted",
|
|
175
|
-
classActivePre = "has-highlighted"
|
|
176
|
-
} = options;
|
|
177
|
-
return transformerNotationMap(
|
|
178
|
-
{
|
|
179
|
-
classMap: {
|
|
180
|
-
highlight: classActiveLine,
|
|
181
|
-
hl: classActiveLine
|
|
182
|
-
},
|
|
183
|
-
classActivePre
|
|
184
|
-
},
|
|
185
|
-
"@shikijs/transformers:notation-highlight"
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
function highlightWordInLine(line, ignoredElement, word, className) {
|
|
189
|
-
const content = getTextContent(line);
|
|
190
|
-
let index = content.indexOf(word);
|
|
191
|
-
while (index !== -1) {
|
|
192
|
-
highlightRange.call(this, line.children, ignoredElement, index, word.length, className);
|
|
193
|
-
index = content.indexOf(word, index + 1);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
function getTextContent(element) {
|
|
197
|
-
if (element.type === "text")
|
|
198
|
-
return element.value;
|
|
199
|
-
if (element.type === "element" && element.tagName === "span")
|
|
200
|
-
return element.children.map(getTextContent).join("");
|
|
201
|
-
return "";
|
|
202
|
-
}
|
|
203
|
-
function highlightRange(elements, ignoredElement, index, len, className) {
|
|
204
|
-
let currentIdx = 0;
|
|
205
|
-
for (let i = 0; i < elements.length; i++) {
|
|
206
|
-
const element = elements[i];
|
|
207
|
-
if (element.type !== "element" || element.tagName !== "span" || element === ignoredElement)
|
|
208
|
-
continue;
|
|
209
|
-
const textNode = element.children[0];
|
|
210
|
-
if (textNode.type !== "text")
|
|
211
|
-
continue;
|
|
212
|
-
if (hasOverlap([currentIdx, currentIdx + textNode.value.length - 1], [index, index + len])) {
|
|
213
|
-
const start = Math.max(0, index - currentIdx);
|
|
214
|
-
const length = len - Math.max(0, currentIdx - index);
|
|
215
|
-
if (length === 0)
|
|
216
|
-
continue;
|
|
217
|
-
const separated = separateToken(element, textNode, start, length);
|
|
218
|
-
this.addClassToHast(separated[1], className);
|
|
219
|
-
const output = separated.filter(Boolean);
|
|
220
|
-
elements.splice(i, 1, ...output);
|
|
221
|
-
i += output.length - 1;
|
|
222
|
-
}
|
|
223
|
-
currentIdx += textNode.value.length;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
function hasOverlap(range1, range2) {
|
|
227
|
-
return range1[0] <= range2[1] && range1[1] >= range2[0];
|
|
228
|
-
}
|
|
229
|
-
function separateToken(span, textNode, index, len) {
|
|
230
|
-
const text = textNode.value;
|
|
231
|
-
const createNode = (value) => inheritElement(span, {
|
|
232
|
-
children: [
|
|
233
|
-
{
|
|
234
|
-
type: "text",
|
|
235
|
-
value
|
|
236
|
-
}
|
|
237
|
-
]
|
|
238
|
-
});
|
|
239
|
-
return [
|
|
240
|
-
index > 0 ? createNode(text.slice(0, index)) : void 0,
|
|
241
|
-
createNode(text.slice(index, index + len)),
|
|
242
|
-
index + len < text.length ? createNode(text.slice(index + len)) : void 0
|
|
243
|
-
];
|
|
244
|
-
}
|
|
245
|
-
function inheritElement(original, overrides) {
|
|
246
|
-
return {
|
|
247
|
-
...original,
|
|
248
|
-
properties: {
|
|
249
|
-
...original.properties
|
|
250
|
-
},
|
|
251
|
-
...overrides
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
function transformerNotationWordHighlight(options = {}) {
|
|
255
|
-
const {
|
|
256
|
-
classActiveWord = "highlighted-word",
|
|
257
|
-
classActivePre = void 0
|
|
258
|
-
} = options;
|
|
259
|
-
return createCommentNotationTransformer(
|
|
260
|
-
"@shikijs/transformers:notation-highlight-word",
|
|
261
|
-
/\s*\[!code word:((?:\\.|[^:\]])+)(:\d+)?\]/,
|
|
262
|
-
function([_, word, range], _line, comment, lines, index) {
|
|
263
|
-
const lineNum = range ? Number.parseInt(range.slice(1), 10) : lines.length;
|
|
264
|
-
word = word.replace(/\\(.)/g, "$1");
|
|
265
|
-
for (let i = index; i < Math.min(index + lineNum, lines.length); i++) {
|
|
266
|
-
highlightWordInLine.call(this, lines[i], comment, word, classActiveWord);
|
|
267
|
-
}
|
|
268
|
-
if (classActivePre)
|
|
269
|
-
this.addClassToHast(this.pre, classActivePre);
|
|
270
|
-
return true;
|
|
271
|
-
}
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
var symbol = Symbol("highlighted-lines");
|
|
275
|
-
|
|
276
|
-
// src/mdx-plugins/rehype-code.ts
|
|
22
|
+
import {
|
|
23
|
+
transformerNotationDiff,
|
|
24
|
+
transformerNotationHighlight,
|
|
25
|
+
transformerNotationWordHighlight
|
|
26
|
+
} from "@shikijs/transformers";
|
|
277
27
|
import {
|
|
278
28
|
getSingletonHighlighter,
|
|
279
29
|
bundledLanguages
|
|
@@ -450,9 +200,15 @@ var rehypeCodeDefaultOptions = {
|
|
|
450
200
|
experimentalJSEngine: false,
|
|
451
201
|
transformers: [
|
|
452
202
|
createStyleTransformer(),
|
|
453
|
-
transformerNotationHighlight(
|
|
454
|
-
|
|
455
|
-
|
|
203
|
+
transformerNotationHighlight({
|
|
204
|
+
matchAlgorithm: "v3"
|
|
205
|
+
}),
|
|
206
|
+
transformerNotationWordHighlight({
|
|
207
|
+
matchAlgorithm: "v3"
|
|
208
|
+
}),
|
|
209
|
+
transformerNotationDiff({
|
|
210
|
+
matchAlgorithm: "v3"
|
|
211
|
+
})
|
|
456
212
|
],
|
|
457
213
|
parseMetaString(meta) {
|
|
458
214
|
const map = {};
|
|
@@ -467,53 +223,44 @@ var rehypeCodeDefaultOptions = {
|
|
|
467
223
|
return map;
|
|
468
224
|
}
|
|
469
225
|
};
|
|
470
|
-
function rehypeCode(
|
|
471
|
-
const
|
|
226
|
+
function rehypeCode(_options = {}) {
|
|
227
|
+
const options = {
|
|
472
228
|
...rehypeCodeDefaultOptions,
|
|
473
|
-
...
|
|
229
|
+
..._options
|
|
474
230
|
};
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
delete meta.__parsed_raw;
|
|
483
|
-
}
|
|
484
|
-
if (meta && codeOptions.filterMetaString) {
|
|
485
|
-
meta.__raw = codeOptions.filterMetaString(meta.__raw ?? "");
|
|
486
|
-
}
|
|
487
|
-
return code.replace(/\n$/, "");
|
|
231
|
+
const transformers = [...options.transformers ?? []];
|
|
232
|
+
transformers.unshift({
|
|
233
|
+
name: "rehype-code:pre-process",
|
|
234
|
+
preprocess(code, { meta }) {
|
|
235
|
+
if (meta && "__parsed_raw" in meta) {
|
|
236
|
+
meta.__raw = meta.__parsed_raw;
|
|
237
|
+
delete meta.__parsed_raw;
|
|
488
238
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
}
|
|
498
|
-
if (codeOptions.tab !== false) {
|
|
499
|
-
codeOptions.transformers = [...codeOptions.transformers, transformerTab()];
|
|
239
|
+
if (meta && options.filterMetaString) {
|
|
240
|
+
meta.__raw = options.filterMetaString(meta.__raw ?? "");
|
|
241
|
+
}
|
|
242
|
+
return code.replace(/\n$/, "");
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
if (options.icon !== false) {
|
|
246
|
+
transformers.push(transformerIcon(options.icon));
|
|
500
247
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
themeItems = Object.values(codeOptions.themes);
|
|
504
|
-
} else if ("theme" in codeOptions) {
|
|
505
|
-
themeItems = [codeOptions.theme];
|
|
248
|
+
if (options.tab !== false) {
|
|
249
|
+
transformers.push(transformerTab());
|
|
506
250
|
}
|
|
507
251
|
const highlighter = getSingletonHighlighter({
|
|
508
|
-
engine:
|
|
509
|
-
themes:
|
|
510
|
-
langs:
|
|
252
|
+
engine: options.experimentalJSEngine ? createJavaScriptRegexEngine() : createOnigurumaEngine(() => import("shiki/wasm")),
|
|
253
|
+
themes: "themes" in options ? Object.values(options.themes).filter(Boolean) : [options.theme],
|
|
254
|
+
langs: options.langs ?? (options.lazy ? void 0 : Object.keys(bundledLanguages))
|
|
511
255
|
});
|
|
512
256
|
const transformer = highlighter.then(
|
|
513
|
-
(instance) => rehypeShikiFromHighlighter(instance,
|
|
257
|
+
(instance) => rehypeShikiFromHighlighter(instance, {
|
|
258
|
+
...options,
|
|
259
|
+
transformers
|
|
260
|
+
})
|
|
514
261
|
);
|
|
515
262
|
return async (tree, file) => {
|
|
516
|
-
(await transformer)(tree, file, () => {
|
|
263
|
+
await (await transformer)(tree, file, () => {
|
|
517
264
|
});
|
|
518
265
|
};
|
|
519
266
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumadocs-core",
|
|
3
|
-
"version": "14.7.
|
|
3
|
+
"version": "14.7.6",
|
|
4
4
|
"description": "The library for building a documentation website in Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NextJs",
|
|
@@ -79,7 +79,8 @@
|
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"@formatjs/intl-localematcher": "^0.5.10",
|
|
81
81
|
"@orama/orama": "^2.1.1",
|
|
82
|
-
"@shikijs/rehype": "^
|
|
82
|
+
"@shikijs/rehype": "^2.0.3",
|
|
83
|
+
"@shikijs/transformers": "^2.0.3",
|
|
83
84
|
"github-slugger": "^2.0.0",
|
|
84
85
|
"hast-util-to-estree": "^3.1.1",
|
|
85
86
|
"hast-util-to-jsx-runtime": "^2.3.2",
|
|
@@ -89,7 +90,7 @@
|
|
|
89
90
|
"remark": "^15.0.0",
|
|
90
91
|
"remark-gfm": "^4.0.0",
|
|
91
92
|
"scroll-into-view-if-needed": "^3.1.0",
|
|
92
|
-
"shiki": "^
|
|
93
|
+
"shiki": "^2.0.3",
|
|
93
94
|
"unist-util-visit": "^5.0.0"
|
|
94
95
|
},
|
|
95
96
|
"devDependencies": {
|
|
@@ -110,7 +111,6 @@
|
|
|
110
111
|
"next": "^15.1.5",
|
|
111
112
|
"remark-mdx": "^3.1.0",
|
|
112
113
|
"remark-rehype": "^11.1.1",
|
|
113
|
-
"shiki-transformers": "^1.0.1",
|
|
114
114
|
"typescript": "^5.7.3",
|
|
115
115
|
"unified": "^11.0.5",
|
|
116
116
|
"vfile": "^6.0.3",
|