fumadocs-core 14.0.2 → 14.1.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-7CSWJQ5H.js +59 -0
- package/dist/chunk-EMWGTXSW.js +19 -0
- package/dist/chunk-SHGL6VBO.js +33 -0
- package/dist/mdx-plugins/index.d.ts +1 -1
- package/dist/mdx-plugins/index.js +311 -69
- package/dist/search/client.js +1 -1
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.js +8 -0
- package/dist/shiki-FJwEmGMA.d.ts +16 -0
- package/dist/sidebar.js +2 -3
- package/dist/source/index.js +48 -65
- package/dist/toc.js +1 -1
- package/dist/utils/use-on-change.js +1 -1
- package/dist/utils/use-shiki.d.ts +11 -0
- package/dist/utils/use-shiki.js +38 -0
- package/package.json +28 -9
- package/dist/chunk-I5BWASD6.js +0 -13
- package/dist/chunk-UWEEHUJV.js +0 -12
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// src/server/shiki.ts
|
|
2
|
+
import {
|
|
3
|
+
getSingletonHighlighter
|
|
4
|
+
} from "shiki";
|
|
5
|
+
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
|
|
6
|
+
import { Fragment } from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { createOnigurumaEngine } from "shiki/engine/oniguruma";
|
|
9
|
+
function createStyleTransformer() {
|
|
10
|
+
return {
|
|
11
|
+
name: "rehype-code:styles",
|
|
12
|
+
line(hast) {
|
|
13
|
+
if (hast.children.length === 0) {
|
|
14
|
+
hast.children.push({
|
|
15
|
+
type: "text",
|
|
16
|
+
value: " "
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
var defaultThemes = {
|
|
23
|
+
light: "github-light",
|
|
24
|
+
dark: "github-dark"
|
|
25
|
+
};
|
|
26
|
+
async function highlight(code, options) {
|
|
27
|
+
const { lang, components, engine, ...rest } = options;
|
|
28
|
+
let themes = { themes: defaultThemes };
|
|
29
|
+
if ("theme" in options && options.theme) {
|
|
30
|
+
themes = { theme: options.theme };
|
|
31
|
+
} else if ("themes" in options && options.themes) {
|
|
32
|
+
themes = { themes: options.themes };
|
|
33
|
+
}
|
|
34
|
+
const highlighter = await getSingletonHighlighter({
|
|
35
|
+
langs: [lang],
|
|
36
|
+
engine: engine ?? createOnigurumaEngine(() => import("shiki/wasm")),
|
|
37
|
+
themes: "theme" in themes ? [themes.theme] : Object.values(themes.themes).filter((v) => v !== void 0)
|
|
38
|
+
});
|
|
39
|
+
const hast = highlighter.codeToHast(code, {
|
|
40
|
+
lang,
|
|
41
|
+
...rest,
|
|
42
|
+
...themes,
|
|
43
|
+
transformers: [createStyleTransformer(), ...rest.transformers ?? []],
|
|
44
|
+
defaultColor: "themes" in themes ? false : void 0
|
|
45
|
+
});
|
|
46
|
+
return toJsxRuntime(hast, {
|
|
47
|
+
jsx,
|
|
48
|
+
jsxs,
|
|
49
|
+
development: false,
|
|
50
|
+
components,
|
|
51
|
+
Fragment
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export {
|
|
56
|
+
createStyleTransformer,
|
|
57
|
+
defaultThemes,
|
|
58
|
+
highlight
|
|
59
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/utils/use-on-change.ts
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
function isDifferent(a, b) {
|
|
4
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
5
|
+
return b.length !== a.length || a.some((v, i) => isDifferent(v, b[i]));
|
|
6
|
+
}
|
|
7
|
+
return a !== b;
|
|
8
|
+
}
|
|
9
|
+
function useOnChange(value, onChange, isUpdated = isDifferent) {
|
|
10
|
+
const [prev, setPrev] = useState(value);
|
|
11
|
+
if (isUpdated(prev, value)) {
|
|
12
|
+
onChange(value, prev);
|
|
13
|
+
setPrev(value);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
useOnChange
|
|
19
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/utils/path.ts
|
|
2
|
+
function splitPath(path) {
|
|
3
|
+
return path.split("/").filter((p) => p.length > 0);
|
|
4
|
+
}
|
|
5
|
+
function resolvePath(from, join) {
|
|
6
|
+
const v1 = splitPath(from), v2 = splitPath(join);
|
|
7
|
+
while (v2.length > 0) {
|
|
8
|
+
switch (v2[0]) {
|
|
9
|
+
case "..":
|
|
10
|
+
v1.pop();
|
|
11
|
+
break;
|
|
12
|
+
case ".":
|
|
13
|
+
break;
|
|
14
|
+
default:
|
|
15
|
+
v1.push(v2[0]);
|
|
16
|
+
}
|
|
17
|
+
v2.shift();
|
|
18
|
+
}
|
|
19
|
+
return v1.join("/");
|
|
20
|
+
}
|
|
21
|
+
function slash(path) {
|
|
22
|
+
const isExtendedLengthPath = path.startsWith("\\\\?\\");
|
|
23
|
+
if (isExtendedLengthPath) {
|
|
24
|
+
return path;
|
|
25
|
+
}
|
|
26
|
+
return path.replaceAll("\\", "/");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
splitPath,
|
|
31
|
+
resolvePath,
|
|
32
|
+
slash
|
|
33
|
+
};
|
|
@@ -3,8 +3,13 @@ import {
|
|
|
3
3
|
remarkHeading
|
|
4
4
|
} from "../chunk-4MNUWZIW.js";
|
|
5
5
|
import {
|
|
6
|
+
resolvePath,
|
|
6
7
|
slash
|
|
7
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-SHGL6VBO.js";
|
|
9
|
+
import {
|
|
10
|
+
createStyleTransformer,
|
|
11
|
+
defaultThemes
|
|
12
|
+
} from "../chunk-7CSWJQ5H.js";
|
|
8
13
|
import "../chunk-MLKGABMK.js";
|
|
9
14
|
|
|
10
15
|
// src/mdx-plugins/index.ts
|
|
@@ -14,11 +19,254 @@ import {
|
|
|
14
19
|
|
|
15
20
|
// src/mdx-plugins/rehype-code.ts
|
|
16
21
|
import rehypeShikiFromHighlighter from "@shikijs/rehype/core";
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
// ../../node_modules/.pnpm/shiki-transformers@1.0.0_shiki@1.22.2/node_modules/shiki-transformers/dist/index.js
|
|
24
|
+
var matchers = [
|
|
25
|
+
[/^(<!--)(.+)(-->)$/, true],
|
|
26
|
+
[/^(\/\*)(.+)(\*\/)$/, true],
|
|
27
|
+
[/^(\/\/|["']|;{1,2}|%{1,2}|--|#)(.+)$/, false]
|
|
28
|
+
];
|
|
29
|
+
function parseComments(lines, jsx) {
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const line of lines) {
|
|
32
|
+
const elements = line.children;
|
|
33
|
+
const start = jsx ? elements.length - 2 : elements.length - 1;
|
|
34
|
+
for (let i = Math.max(start, 0); i < elements.length; i++) {
|
|
35
|
+
const token = elements[i];
|
|
36
|
+
if (token.type !== "element")
|
|
37
|
+
continue;
|
|
38
|
+
const isLast = i === elements.length - 1;
|
|
39
|
+
const match = matchToken(token, isLast);
|
|
40
|
+
if (!match) continue;
|
|
41
|
+
if (jsx && !isLast && i !== 0) {
|
|
42
|
+
const left = elements[i - 1];
|
|
43
|
+
const right = elements[i + 1];
|
|
44
|
+
out.push({
|
|
45
|
+
info: match,
|
|
46
|
+
line,
|
|
47
|
+
token,
|
|
48
|
+
jsxIntercept: isValue(left, "{") && isValue(right, "}")
|
|
49
|
+
});
|
|
50
|
+
} else {
|
|
51
|
+
out.push({
|
|
52
|
+
info: match,
|
|
53
|
+
line,
|
|
54
|
+
token,
|
|
55
|
+
jsxIntercept: false
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
function isValue(element, value) {
|
|
63
|
+
if (element.type !== "element") return false;
|
|
64
|
+
const text = element.children[0];
|
|
65
|
+
if (text.type !== "text")
|
|
66
|
+
return false;
|
|
67
|
+
return text.value.trim() === value;
|
|
68
|
+
}
|
|
69
|
+
function matchToken(token, last) {
|
|
70
|
+
const text = token.children[0];
|
|
71
|
+
if (text.type !== "text")
|
|
72
|
+
return;
|
|
73
|
+
for (const [matcher, lastOnly] of matchers) {
|
|
74
|
+
if (!lastOnly && !last) continue;
|
|
75
|
+
let trimmed = text.value.trimStart();
|
|
76
|
+
const spaceFront = text.value.length - trimmed.length;
|
|
77
|
+
trimmed = trimmed.trimEnd();
|
|
78
|
+
const spaceEnd = text.value.length - trimmed.length - spaceFront;
|
|
79
|
+
const result = matcher.exec(trimmed);
|
|
80
|
+
if (!result) continue;
|
|
81
|
+
return [
|
|
82
|
+
" ".repeat(spaceFront) + result[1],
|
|
83
|
+
result[2],
|
|
84
|
+
result[3] ? result[3] + " ".repeat(spaceEnd) : void 0
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function createCommentNotationTransformer(name, regex, onMatch) {
|
|
89
|
+
return {
|
|
90
|
+
name,
|
|
91
|
+
code(code) {
|
|
92
|
+
const lines = code.children.filter((i) => i.type === "element");
|
|
93
|
+
const linesToRemove = [];
|
|
94
|
+
code.data ??= {};
|
|
95
|
+
const data = code.data;
|
|
96
|
+
const parsed = data._shiki_notation ??= parseComments(lines, ["jsx", "tsx"].includes(this.options.lang));
|
|
97
|
+
for (const comment of parsed) {
|
|
98
|
+
if (comment.info[1].length === 0) continue;
|
|
99
|
+
const isLineCommentOnly = comment.line.children.length === (comment.jsxIntercept ? 3 : 1);
|
|
100
|
+
let lineIdx = lines.indexOf(comment.line);
|
|
101
|
+
if (isLineCommentOnly) lineIdx++;
|
|
102
|
+
comment.info[1] = comment.info[1].replace(regex, (...match) => {
|
|
103
|
+
if (onMatch.call(this, match, comment.line, comment.token, lines, lineIdx)) {
|
|
104
|
+
return "";
|
|
105
|
+
}
|
|
106
|
+
return match[0];
|
|
107
|
+
});
|
|
108
|
+
const isEmpty = comment.info[1].trim().length === 0;
|
|
109
|
+
if (isEmpty) comment.info[1] = "";
|
|
110
|
+
if (isEmpty && isLineCommentOnly) {
|
|
111
|
+
linesToRemove.push(comment.line);
|
|
112
|
+
} else if (isEmpty && comment.jsxIntercept) {
|
|
113
|
+
comment.line.children.splice(comment.line.children.indexOf(comment.token) - 1, 3);
|
|
114
|
+
} else if (isEmpty) {
|
|
115
|
+
comment.line.children.splice(comment.line.children.indexOf(comment.token), 1);
|
|
116
|
+
} else {
|
|
117
|
+
const head = comment.token.children[0];
|
|
118
|
+
if (head.type === "text") {
|
|
119
|
+
head.value = comment.info.join("");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
for (const line of linesToRemove)
|
|
124
|
+
code.children.splice(code.children.indexOf(line), 1);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function escapeRegExp(str) {
|
|
129
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
130
|
+
}
|
|
131
|
+
function transformerNotationMap(options = {}, name = "@shikijs/transformers:notation-map") {
|
|
132
|
+
const {
|
|
133
|
+
classMap = {},
|
|
134
|
+
classActivePre = void 0
|
|
135
|
+
} = options;
|
|
136
|
+
return createCommentNotationTransformer(
|
|
137
|
+
name,
|
|
138
|
+
new RegExp(`\\s*\\[!code (${Object.keys(classMap).map(escapeRegExp).join("|")})(:\\d+)?\\]`),
|
|
139
|
+
function([_, match, range = ":1"], _line, _comment, lines, index) {
|
|
140
|
+
const lineNum = Number.parseInt(range.slice(1), 10);
|
|
141
|
+
lines.slice(index, index + lineNum).forEach((line) => {
|
|
142
|
+
this.addClassToHast(line, classMap[match]);
|
|
143
|
+
});
|
|
144
|
+
if (classActivePre)
|
|
145
|
+
this.addClassToHast(this.pre, classActivePre);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
function transformerNotationDiff(options = {}) {
|
|
151
|
+
const {
|
|
152
|
+
classLineAdd = "diff add",
|
|
153
|
+
classLineRemove = "diff remove",
|
|
154
|
+
classActivePre = "has-diff"
|
|
155
|
+
} = options;
|
|
156
|
+
return transformerNotationMap(
|
|
157
|
+
{
|
|
158
|
+
classMap: {
|
|
159
|
+
"++": classLineAdd,
|
|
160
|
+
"--": classLineRemove
|
|
161
|
+
},
|
|
162
|
+
classActivePre
|
|
163
|
+
},
|
|
164
|
+
"@shikijs/transformers:notation-diff"
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
function transformerNotationHighlight(options = {}) {
|
|
168
|
+
const {
|
|
169
|
+
classActiveLine = "highlighted",
|
|
170
|
+
classActivePre = "has-highlighted"
|
|
171
|
+
} = options;
|
|
172
|
+
return transformerNotationMap(
|
|
173
|
+
{
|
|
174
|
+
classMap: {
|
|
175
|
+
highlight: classActiveLine,
|
|
176
|
+
hl: classActiveLine
|
|
177
|
+
},
|
|
178
|
+
classActivePre
|
|
179
|
+
},
|
|
180
|
+
"@shikijs/transformers:notation-highlight"
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
function highlightWordInLine(line, ignoredElement, word, className) {
|
|
184
|
+
const content = getTextContent(line);
|
|
185
|
+
let index = content.indexOf(word);
|
|
186
|
+
while (index !== -1) {
|
|
187
|
+
highlightRange.call(this, line.children, ignoredElement, index, word.length, className);
|
|
188
|
+
index = content.indexOf(word, index + 1);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function getTextContent(element) {
|
|
192
|
+
if (element.type === "text")
|
|
193
|
+
return element.value;
|
|
194
|
+
if (element.type === "element" && element.tagName === "span")
|
|
195
|
+
return element.children.map(getTextContent).join("");
|
|
196
|
+
return "";
|
|
197
|
+
}
|
|
198
|
+
function highlightRange(elements, ignoredElement, index, len, className) {
|
|
199
|
+
let currentIdx = 0;
|
|
200
|
+
for (let i = 0; i < elements.length; i++) {
|
|
201
|
+
const element = elements[i];
|
|
202
|
+
if (element.type !== "element" || element.tagName !== "span" || element === ignoredElement)
|
|
203
|
+
continue;
|
|
204
|
+
const textNode = element.children[0];
|
|
205
|
+
if (textNode.type !== "text")
|
|
206
|
+
continue;
|
|
207
|
+
if (hasOverlap([currentIdx, currentIdx + textNode.value.length - 1], [index, index + len])) {
|
|
208
|
+
const start = Math.max(0, index - currentIdx);
|
|
209
|
+
const length = len - Math.max(0, currentIdx - index);
|
|
210
|
+
if (length === 0)
|
|
211
|
+
continue;
|
|
212
|
+
const separated = separateToken(element, textNode, start, length);
|
|
213
|
+
this.addClassToHast(separated[1], className);
|
|
214
|
+
const output = separated.filter(Boolean);
|
|
215
|
+
elements.splice(i, 1, ...output);
|
|
216
|
+
i += output.length - 1;
|
|
217
|
+
}
|
|
218
|
+
currentIdx += textNode.value.length;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function hasOverlap(range1, range2) {
|
|
222
|
+
return range1[0] <= range2[1] && range1[1] >= range2[0];
|
|
223
|
+
}
|
|
224
|
+
function separateToken(span, textNode, index, len) {
|
|
225
|
+
const text = textNode.value;
|
|
226
|
+
const createNode = (value) => inheritElement(span, {
|
|
227
|
+
children: [
|
|
228
|
+
{
|
|
229
|
+
type: "text",
|
|
230
|
+
value
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
});
|
|
234
|
+
return [
|
|
235
|
+
index > 0 ? createNode(text.slice(0, index)) : void 0,
|
|
236
|
+
createNode(text.slice(index, index + len)),
|
|
237
|
+
index + len < text.length ? createNode(text.slice(index + len)) : void 0
|
|
238
|
+
];
|
|
239
|
+
}
|
|
240
|
+
function inheritElement(original, overrides) {
|
|
241
|
+
return {
|
|
242
|
+
...original,
|
|
243
|
+
properties: {
|
|
244
|
+
...original.properties
|
|
245
|
+
},
|
|
246
|
+
...overrides
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function transformerNotationWordHighlight(options = {}) {
|
|
250
|
+
const {
|
|
251
|
+
classActiveWord = "highlighted-word",
|
|
252
|
+
classActivePre = void 0
|
|
253
|
+
} = options;
|
|
254
|
+
return createCommentNotationTransformer(
|
|
255
|
+
"@shikijs/transformers:notation-highlight-word",
|
|
256
|
+
/\s*\[!code word:((?:\\.|[^:\]])+)(:\d+)?\]/,
|
|
257
|
+
function([_, word, range], _line, comment, lines, index) {
|
|
258
|
+
const lineNum = range ? Number.parseInt(range.slice(1), 10) : lines.length;
|
|
259
|
+
word = word.replace(/\\(.)/g, "$1");
|
|
260
|
+
lines.slice(index, index + lineNum).forEach((line) => highlightWordInLine.call(this, line, comment, word, classActiveWord));
|
|
261
|
+
if (classActivePre)
|
|
262
|
+
this.addClassToHast(this.pre, classActivePre);
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
var symbol = Symbol("highlighted-lines");
|
|
268
|
+
|
|
269
|
+
// src/mdx-plugins/rehype-code.ts
|
|
22
270
|
import {
|
|
23
271
|
getSingletonHighlighter,
|
|
24
272
|
bundledLanguages
|
|
@@ -185,14 +433,12 @@ var metaValues = [
|
|
|
185
433
|
}
|
|
186
434
|
];
|
|
187
435
|
var rehypeCodeDefaultOptions = {
|
|
188
|
-
themes:
|
|
189
|
-
|
|
190
|
-
dark: "github-dark"
|
|
191
|
-
},
|
|
436
|
+
themes: defaultThemes,
|
|
437
|
+
defaultColor: false,
|
|
192
438
|
defaultLanguage: "plaintext",
|
|
193
439
|
experimentalJSEngine: false,
|
|
194
|
-
defaultColor: false,
|
|
195
440
|
transformers: [
|
|
441
|
+
createStyleTransformer(),
|
|
196
442
|
transformerNotationHighlight(),
|
|
197
443
|
transformerNotationWordHighlight(),
|
|
198
444
|
transformerNotationDiff()
|
|
@@ -229,14 +475,6 @@ function rehypeCode(options = {}) {
|
|
|
229
475
|
meta.__raw = codeOptions.filterMetaString(meta.__raw ?? "");
|
|
230
476
|
}
|
|
231
477
|
return code.replace(/\n$/, "");
|
|
232
|
-
},
|
|
233
|
-
line(hast) {
|
|
234
|
-
if (hast.children.length === 0) {
|
|
235
|
-
hast.children.push({
|
|
236
|
-
type: "text",
|
|
237
|
-
value: " "
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
478
|
}
|
|
241
479
|
},
|
|
242
480
|
...codeOptions.transformers
|
|
@@ -313,57 +551,58 @@ function remarkImage({
|
|
|
313
551
|
const promises = [];
|
|
314
552
|
function getImportPath(src) {
|
|
315
553
|
if (!src.startsWith("/")) return src;
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
path.join(publicDir, src)
|
|
320
|
-
);
|
|
554
|
+
const to = path.join(publicDir, src);
|
|
555
|
+
if (file.dirname) {
|
|
556
|
+
const relative = slash(path.relative(file.dirname, to));
|
|
321
557
|
return relative.startsWith("./") ? relative : `./${relative}`;
|
|
322
558
|
}
|
|
323
|
-
return
|
|
559
|
+
return slash(to);
|
|
324
560
|
}
|
|
325
561
|
visit(tree, "image", (node) => {
|
|
326
|
-
const
|
|
327
|
-
if (!
|
|
328
|
-
const isExternal = EXTERNAL_URL_REGEX.test(
|
|
562
|
+
const url = decodeURI(node.url);
|
|
563
|
+
if (!url) return;
|
|
564
|
+
const isExternal = EXTERNAL_URL_REGEX.test(url);
|
|
329
565
|
if (isExternal && external || !useImport) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
566
|
+
const task = getImageSize(url, publicDir).then((size) => {
|
|
567
|
+
if (!size.width || !size.height) return;
|
|
568
|
+
Object.assign(node, {
|
|
569
|
+
type: "mdxJsxFlowElement",
|
|
570
|
+
name: "img",
|
|
571
|
+
attributes: [
|
|
572
|
+
{
|
|
573
|
+
type: "mdxJsxAttribute",
|
|
574
|
+
name: "alt",
|
|
575
|
+
value: node.alt ?? "image"
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
type: "mdxJsxAttribute",
|
|
579
|
+
name: "src",
|
|
580
|
+
value: url
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
type: "mdxJsxAttribute",
|
|
584
|
+
name: "width",
|
|
585
|
+
value: size.width.toString()
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
type: "mdxJsxAttribute",
|
|
589
|
+
name: "height",
|
|
590
|
+
value: size.height.toString()
|
|
591
|
+
}
|
|
592
|
+
]
|
|
593
|
+
});
|
|
594
|
+
}).catch(() => {
|
|
595
|
+
console.error(
|
|
596
|
+
`[Remark Image] Failed obtain image size for ${url} with public directory ${publicDir}`
|
|
597
|
+
);
|
|
598
|
+
});
|
|
599
|
+
promises.push(task);
|
|
361
600
|
} else if (!isExternal) {
|
|
362
601
|
const variableName = `__img${importsToInject.length.toString()}`;
|
|
363
|
-
const hasBlur = placeholder === "blur" && VALID_BLUR_EXT.some((ext) =>
|
|
602
|
+
const hasBlur = placeholder === "blur" && VALID_BLUR_EXT.some((ext) => url.endsWith(ext));
|
|
364
603
|
importsToInject.push({
|
|
365
604
|
variableName,
|
|
366
|
-
importPath:
|
|
605
|
+
importPath: getImportPath(url)
|
|
367
606
|
});
|
|
368
607
|
Object.assign(node, {
|
|
369
608
|
type: "mdxJsxFlowElement",
|
|
@@ -428,17 +667,20 @@ function remarkImage({
|
|
|
428
667
|
}
|
|
429
668
|
};
|
|
430
669
|
}
|
|
431
|
-
function resolveSrc(src, dir) {
|
|
432
|
-
return src.startsWith("/") || !path.isAbsolute(src) ? path.join(dir, src) : src;
|
|
433
|
-
}
|
|
434
670
|
async function getImageSize(src, dir) {
|
|
671
|
+
const isRelative = src.startsWith("/") || !path.isAbsolute(src);
|
|
672
|
+
let url;
|
|
435
673
|
if (EXTERNAL_URL_REGEX.test(src)) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
);
|
|
674
|
+
url = src;
|
|
675
|
+
} else if (EXTERNAL_URL_REGEX.test(dir) && isRelative) {
|
|
676
|
+
const base = new URL(dir);
|
|
677
|
+
base.pathname = resolvePath(base.pathname, src);
|
|
678
|
+
url = base.toString();
|
|
679
|
+
} else {
|
|
680
|
+
return sizeOf(isRelative ? path.join(dir, src) : src);
|
|
440
681
|
}
|
|
441
|
-
|
|
682
|
+
const buffer = await fetch(url).then((res) => res.arrayBuffer());
|
|
683
|
+
return sizeOf(new Uint8Array(buffer));
|
|
442
684
|
}
|
|
443
685
|
|
|
444
686
|
// src/mdx-plugins/remark-structure.ts
|
package/dist/search/client.js
CHANGED
package/dist/server/index.d.ts
CHANGED
|
@@ -5,8 +5,12 @@ export { S as SortedResult } from '../types-Ch8gnVgO.js';
|
|
|
5
5
|
import { Metadata } from 'next';
|
|
6
6
|
import { NextRequest } from 'next/server';
|
|
7
7
|
import { LoaderOutput, LoaderConfig, InferPageType } from '../source/index.js';
|
|
8
|
+
export { H as HighlightOptions, c as createStyleTransformer, d as defaultThemes, h as highlight } from '../shiki-FJwEmGMA.js';
|
|
8
9
|
import 'react';
|
|
9
10
|
import '../config-inq6kP6y.js';
|
|
11
|
+
import 'shiki';
|
|
12
|
+
import 'shiki/themes';
|
|
13
|
+
import 'hast-util-to-jsx-runtime';
|
|
10
14
|
|
|
11
15
|
/**
|
|
12
16
|
* Flatten tree to an array of page nodes
|
package/dist/server/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
remarkHeading
|
|
3
3
|
} from "../chunk-4MNUWZIW.js";
|
|
4
|
+
import {
|
|
5
|
+
createStyleTransformer,
|
|
6
|
+
defaultThemes,
|
|
7
|
+
highlight
|
|
8
|
+
} from "../chunk-7CSWJQ5H.js";
|
|
4
9
|
import "../chunk-MLKGABMK.js";
|
|
5
10
|
|
|
6
11
|
// src/server/get-toc.ts
|
|
@@ -147,9 +152,12 @@ function createMetadataImage(options) {
|
|
|
147
152
|
export {
|
|
148
153
|
page_tree_exports as PageTree,
|
|
149
154
|
createMetadataImage,
|
|
155
|
+
createStyleTransformer,
|
|
156
|
+
defaultThemes,
|
|
150
157
|
findNeighbour,
|
|
151
158
|
flattenTree,
|
|
152
159
|
getGithubLastEdit,
|
|
153
160
|
getTableOfContents,
|
|
161
|
+
highlight,
|
|
154
162
|
separatePageTree
|
|
155
163
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ShikiTransformer, CodeToHastOptionsCommon, BundledLanguage, HighlighterCoreOptions, CodeOptionsThemes, CodeOptionsMeta } from 'shiki';
|
|
2
|
+
import { BundledTheme } from 'shiki/themes';
|
|
3
|
+
import { Components } from 'hast-util-to-jsx-runtime';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
|
|
6
|
+
declare function createStyleTransformer(): ShikiTransformer;
|
|
7
|
+
declare const defaultThemes: {
|
|
8
|
+
light: string;
|
|
9
|
+
dark: string;
|
|
10
|
+
};
|
|
11
|
+
type HighlightOptions = CodeToHastOptionsCommon<BundledLanguage> & Pick<HighlighterCoreOptions, 'engine'> & Partial<CodeOptionsThemes<BundledTheme>> & CodeOptionsMeta & {
|
|
12
|
+
components?: Partial<Components>;
|
|
13
|
+
};
|
|
14
|
+
declare function highlight(code: string, options: HighlightOptions): Promise<ReactNode>;
|
|
15
|
+
|
|
16
|
+
export { type HighlightOptions as H, createStyleTransformer as c, defaultThemes as d, highlight as h };
|
package/dist/sidebar.js
CHANGED
|
@@ -3,7 +3,6 @@ import "./chunk-MLKGABMK.js";
|
|
|
3
3
|
|
|
4
4
|
// src/sidebar.tsx
|
|
5
5
|
import {
|
|
6
|
-
useCallback,
|
|
7
6
|
createContext,
|
|
8
7
|
useContext,
|
|
9
8
|
useEffect,
|
|
@@ -38,9 +37,9 @@ function SidebarTrigger({
|
|
|
38
37
|
{
|
|
39
38
|
"aria-label": "Toggle Sidebar",
|
|
40
39
|
"data-open": open,
|
|
41
|
-
onClick:
|
|
40
|
+
onClick: () => {
|
|
42
41
|
setOpen(!open);
|
|
43
|
-
},
|
|
42
|
+
},
|
|
44
43
|
...props
|
|
45
44
|
}
|
|
46
45
|
);
|
package/dist/source/index.js
CHANGED
|
@@ -2,75 +2,14 @@ import {
|
|
|
2
2
|
removeUndefined
|
|
3
3
|
} from "../chunk-2V6SCS43.js";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
resolvePath,
|
|
6
|
+
slash,
|
|
7
|
+
splitPath
|
|
8
|
+
} from "../chunk-SHGL6VBO.js";
|
|
7
9
|
import {
|
|
8
10
|
__export
|
|
9
11
|
} from "../chunk-MLKGABMK.js";
|
|
10
12
|
|
|
11
|
-
// src/source/path.ts
|
|
12
|
-
function parseFilePath(path) {
|
|
13
|
-
const segments = splitPath(slash(path));
|
|
14
|
-
const dirname = segments.slice(0, -1).join("/");
|
|
15
|
-
const base = segments.at(-1) ?? "";
|
|
16
|
-
const dotIdx = base.lastIndexOf(".");
|
|
17
|
-
const nameWithLocale = dotIdx !== -1 ? base.slice(0, dotIdx) : base;
|
|
18
|
-
const flattenedPath = [dirname, nameWithLocale].filter((p) => p.length > 0).join("/");
|
|
19
|
-
const [name, locale] = getLocale(nameWithLocale);
|
|
20
|
-
return {
|
|
21
|
-
dirname,
|
|
22
|
-
name,
|
|
23
|
-
flattenedPath,
|
|
24
|
-
locale,
|
|
25
|
-
path: segments.join("/")
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
function parseFolderPath(path) {
|
|
29
|
-
const segments = splitPath(slash(path));
|
|
30
|
-
const base = segments.at(-1) ?? "";
|
|
31
|
-
const [name, locale] = getLocale(base);
|
|
32
|
-
const flattenedPath = segments.join("/");
|
|
33
|
-
return {
|
|
34
|
-
dirname: segments.slice(0, -1).join("/"),
|
|
35
|
-
name,
|
|
36
|
-
flattenedPath,
|
|
37
|
-
locale,
|
|
38
|
-
path: flattenedPath
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
function getLocale(name) {
|
|
42
|
-
const sep = name.lastIndexOf(".");
|
|
43
|
-
if (sep === -1) return [name];
|
|
44
|
-
const locale = name.slice(sep + 1);
|
|
45
|
-
if (/\d+/.exec(locale)) return [name];
|
|
46
|
-
return [name.slice(0, sep), locale];
|
|
47
|
-
}
|
|
48
|
-
function normalizePath(path) {
|
|
49
|
-
const segments = splitPath(slash(path));
|
|
50
|
-
if (segments[0] === "." || segments[0] === "..")
|
|
51
|
-
throw new Error("It must not start with './' or '../'");
|
|
52
|
-
return segments.join("/");
|
|
53
|
-
}
|
|
54
|
-
function splitPath(path) {
|
|
55
|
-
return path.split("/").filter((p) => p.length > 0);
|
|
56
|
-
}
|
|
57
|
-
function resolvePath(from, join) {
|
|
58
|
-
const v1 = splitPath(from), v2 = splitPath(join);
|
|
59
|
-
while (v2.length > 0) {
|
|
60
|
-
switch (v2[0]) {
|
|
61
|
-
case "..":
|
|
62
|
-
v1.pop();
|
|
63
|
-
break;
|
|
64
|
-
case ".":
|
|
65
|
-
break;
|
|
66
|
-
default:
|
|
67
|
-
v1.push(v2[0]);
|
|
68
|
-
}
|
|
69
|
-
v2.shift();
|
|
70
|
-
}
|
|
71
|
-
return v1.join("/");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
13
|
// src/source/page-tree-builder.ts
|
|
75
14
|
var group = /^\((?<name>.+)\)$/;
|
|
76
15
|
var link = /^(?:\[(?<icon>[^\]]+)])?\[(?<name>[^\]]+)]\((?<url>[^)]+)\)$/;
|
|
@@ -249,6 +188,50 @@ function pathToName(name, resolveGroup = false) {
|
|
|
249
188
|
return result.join("");
|
|
250
189
|
}
|
|
251
190
|
|
|
191
|
+
// src/source/path.ts
|
|
192
|
+
function parseFilePath(path) {
|
|
193
|
+
const segments = splitPath(slash(path));
|
|
194
|
+
const dirname = segments.slice(0, -1).join("/");
|
|
195
|
+
const base = segments.at(-1) ?? "";
|
|
196
|
+
const dotIdx = base.lastIndexOf(".");
|
|
197
|
+
const nameWithLocale = dotIdx !== -1 ? base.slice(0, dotIdx) : base;
|
|
198
|
+
const flattenedPath = [dirname, nameWithLocale].filter((p) => p.length > 0).join("/");
|
|
199
|
+
const [name, locale] = getLocale(nameWithLocale);
|
|
200
|
+
return {
|
|
201
|
+
dirname,
|
|
202
|
+
name,
|
|
203
|
+
flattenedPath,
|
|
204
|
+
locale,
|
|
205
|
+
path: segments.join("/")
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function parseFolderPath(path) {
|
|
209
|
+
const segments = splitPath(slash(path));
|
|
210
|
+
const base = segments.at(-1) ?? "";
|
|
211
|
+
const [name, locale] = getLocale(base);
|
|
212
|
+
const flattenedPath = segments.join("/");
|
|
213
|
+
return {
|
|
214
|
+
dirname: segments.slice(0, -1).join("/"),
|
|
215
|
+
name,
|
|
216
|
+
flattenedPath,
|
|
217
|
+
locale,
|
|
218
|
+
path: flattenedPath
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function getLocale(name) {
|
|
222
|
+
const sep = name.lastIndexOf(".");
|
|
223
|
+
if (sep === -1) return [name];
|
|
224
|
+
const locale = name.slice(sep + 1);
|
|
225
|
+
if (/\d+/.exec(locale)) return [name];
|
|
226
|
+
return [name.slice(0, sep), locale];
|
|
227
|
+
}
|
|
228
|
+
function normalizePath(path) {
|
|
229
|
+
const segments = splitPath(slash(path));
|
|
230
|
+
if (segments[0] === "." || segments[0] === "..")
|
|
231
|
+
throw new Error("It must not start with './' or '../'");
|
|
232
|
+
return segments.join("/");
|
|
233
|
+
}
|
|
234
|
+
|
|
252
235
|
// src/source/file-system.ts
|
|
253
236
|
var file_system_exports = {};
|
|
254
237
|
__export(file_system_exports, {
|
package/dist/toc.js
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactNode, DependencyList } from 'react';
|
|
2
|
+
import { H as HighlightOptions } from '../shiki-FJwEmGMA.js';
|
|
3
|
+
import 'shiki';
|
|
4
|
+
import 'shiki/themes';
|
|
5
|
+
import 'hast-util-to-jsx-runtime';
|
|
6
|
+
|
|
7
|
+
declare function useShiki(code: string, options: HighlightOptions & {
|
|
8
|
+
defaultValue?: ReactNode;
|
|
9
|
+
}, deps?: DependencyList): ReactNode;
|
|
10
|
+
|
|
11
|
+
export { useShiki };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
highlight
|
|
4
|
+
} from "../chunk-7CSWJQ5H.js";
|
|
5
|
+
import "../chunk-MLKGABMK.js";
|
|
6
|
+
|
|
7
|
+
// src/utils/use-shiki.tsx
|
|
8
|
+
import {
|
|
9
|
+
useEffect,
|
|
10
|
+
useState
|
|
11
|
+
} from "react";
|
|
12
|
+
import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
|
|
13
|
+
import { jsx } from "react/jsx-runtime";
|
|
14
|
+
var jsEngine;
|
|
15
|
+
function useShiki(code, options, deps) {
|
|
16
|
+
const [out, setOut] = useState(() => {
|
|
17
|
+
if (options.defaultValue) return options.defaultValue;
|
|
18
|
+
const { pre: Pre = "pre", code: Code = "code" } = options.components ?? {};
|
|
19
|
+
return /* @__PURE__ */ jsx(Pre, { children: /* @__PURE__ */ jsx(Code, { children: code }) });
|
|
20
|
+
});
|
|
21
|
+
if (!options.engine && !jsEngine) {
|
|
22
|
+
jsEngine = createJavaScriptRegexEngine();
|
|
23
|
+
}
|
|
24
|
+
useEffect(
|
|
25
|
+
() => {
|
|
26
|
+
void highlight(code, {
|
|
27
|
+
...options,
|
|
28
|
+
engine: options.engine ?? jsEngine
|
|
29
|
+
}).then(setOut);
|
|
30
|
+
},
|
|
31
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- custom deps
|
|
32
|
+
deps ?? [code, options.lang]
|
|
33
|
+
);
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
useShiki
|
|
38
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumadocs-core",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.1.1",
|
|
4
4
|
"description": "The library for building a documentation website in Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NextJs",
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
"import": "./dist/utils/use-on-change.js",
|
|
49
49
|
"types": "./dist/utils/use-on-change.d.ts"
|
|
50
50
|
},
|
|
51
|
+
"./utils/use-shiki": {
|
|
52
|
+
"import": "./dist/utils/use-shiki.js",
|
|
53
|
+
"types": "./dist/utils/use-shiki.d.ts"
|
|
54
|
+
},
|
|
51
55
|
"./link": {
|
|
52
56
|
"import": "./dist/link.js",
|
|
53
57
|
"types": "./dist/link.d.ts"
|
|
@@ -65,19 +69,19 @@
|
|
|
65
69
|
"dist/*"
|
|
66
70
|
],
|
|
67
71
|
"dependencies": {
|
|
68
|
-
"@formatjs/intl-localematcher": "^0.5.
|
|
72
|
+
"@formatjs/intl-localematcher": "^0.5.6",
|
|
69
73
|
"@orama/orama": "^3.0.1",
|
|
70
|
-
"@shikijs/rehype": "^1.22.
|
|
71
|
-
"@shikijs/transformers": "^1.22.0",
|
|
74
|
+
"@shikijs/rehype": "^1.22.2",
|
|
72
75
|
"github-slugger": "^2.0.0",
|
|
73
76
|
"hast-util-to-estree": "^3.1.0",
|
|
77
|
+
"hast-util-to-jsx-runtime": "^2.3.2",
|
|
74
78
|
"image-size": "^1.1.1",
|
|
75
79
|
"negotiator": "^1.0.0",
|
|
76
80
|
"react-remove-scroll": "^2.6.0",
|
|
77
81
|
"remark": "^15.0.0",
|
|
78
82
|
"remark-gfm": "^4.0.0",
|
|
79
83
|
"scroll-into-view-if-needed": "^3.1.0",
|
|
80
|
-
"shiki": "^1.22.
|
|
84
|
+
"shiki": "^1.22.2",
|
|
81
85
|
"unist-util-visit": "^5.0.0"
|
|
82
86
|
},
|
|
83
87
|
"devDependencies": {
|
|
@@ -87,8 +91,8 @@
|
|
|
87
91
|
"@types/hast": "^3.0.4",
|
|
88
92
|
"@types/mdast": "^4.0.3",
|
|
89
93
|
"@types/negotiator": "^0.6.3",
|
|
90
|
-
"@types/node": "22.
|
|
91
|
-
"@types/react": "^18.3.
|
|
94
|
+
"@types/node": "22.8.1",
|
|
95
|
+
"@types/react": "^18.3.12",
|
|
92
96
|
"@types/react-dom": "^18.3.1",
|
|
93
97
|
"algoliasearch": "4.24.0",
|
|
94
98
|
"mdast-util-mdx-jsx": "^3.1.3",
|
|
@@ -96,16 +100,31 @@
|
|
|
96
100
|
"next": "^15.0.0",
|
|
97
101
|
"remark-mdx": "^3.1.0",
|
|
98
102
|
"remark-rehype": "^11.1.1",
|
|
103
|
+
"shiki-transformers": "^1.0.0",
|
|
99
104
|
"unified": "^11.0.5",
|
|
100
105
|
"eslint-config-custom": "0.0.0",
|
|
101
106
|
"tsconfig": "0.0.0"
|
|
102
107
|
},
|
|
103
|
-
"
|
|
108
|
+
"peerDependencies": {
|
|
104
109
|
"algoliasearch": "4.24.0",
|
|
105
|
-
"next": "15.
|
|
110
|
+
"next": "14.x.x || 15.x.x",
|
|
106
111
|
"react": ">= 18",
|
|
107
112
|
"react-dom": ">= 18"
|
|
108
113
|
},
|
|
114
|
+
"peerDependenciesMeta": {
|
|
115
|
+
"algoliasearch": {
|
|
116
|
+
"optional": true
|
|
117
|
+
},
|
|
118
|
+
"next": {
|
|
119
|
+
"optional": true
|
|
120
|
+
},
|
|
121
|
+
"react": {
|
|
122
|
+
"optional": true
|
|
123
|
+
},
|
|
124
|
+
"react-dom": {
|
|
125
|
+
"optional": true
|
|
126
|
+
}
|
|
127
|
+
},
|
|
109
128
|
"publishConfig": {
|
|
110
129
|
"access": "public"
|
|
111
130
|
},
|
package/dist/chunk-I5BWASD6.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// src/utils/use-on-change.ts
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
function useOnChange(value, onChange, isUpdated = (prev, current) => prev !== current) {
|
|
4
|
-
const [prev, setPrev] = useState(value);
|
|
5
|
-
if (isUpdated(prev, value)) {
|
|
6
|
-
onChange(value, prev);
|
|
7
|
-
setPrev(value);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export {
|
|
12
|
-
useOnChange
|
|
13
|
-
};
|
package/dist/chunk-UWEEHUJV.js
DELETED