fumadocs-core 15.1.0 → 15.1.2
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-Q73QZKHO.js → chunk-62S4EN7J.js} +1 -1
- package/dist/{chunk-E7AASGCN.js → chunk-BUCUQ3WX.js} +36 -6
- package/dist/{chunk-SHGL6VBO.js → chunk-XMCPKVJQ.js} +10 -9
- package/dist/highlight/client.js +2 -2
- package/dist/highlight/index.js +1 -1
- package/dist/mdx-plugins/index.js +14 -14
- package/dist/search/server.d.ts +1 -2
- package/dist/search/server.js +4 -3
- package/dist/server/index.js +1 -1
- package/dist/source/index.d.ts +42 -21
- package/dist/source/index.js +124 -89
- package/dist/utils/use-shiki.js +2 -2
- package/package.json +4 -4
|
@@ -19,9 +19,8 @@ var defaultThemes = {
|
|
|
19
19
|
light: "github-light",
|
|
20
20
|
dark: "github-dark"
|
|
21
21
|
};
|
|
22
|
-
var
|
|
22
|
+
var highlighters = /* @__PURE__ */ new Map();
|
|
23
23
|
async function _highlight(code, options) {
|
|
24
|
-
const { getSingletonHighlighter } = await import("shiki");
|
|
25
24
|
const { lang, components: _, engine, ...rest } = options;
|
|
26
25
|
let themes = { themes: defaultThemes };
|
|
27
26
|
if ("theme" in options && options.theme) {
|
|
@@ -29,11 +28,9 @@ async function _highlight(code, options) {
|
|
|
29
28
|
} else if ("themes" in options && options.themes) {
|
|
30
29
|
themes = { themes: options.themes };
|
|
31
30
|
}
|
|
32
|
-
const highlighter = await
|
|
31
|
+
const highlighter = await getHighlighter("custom", {
|
|
32
|
+
engine,
|
|
33
33
|
langs: [lang],
|
|
34
|
-
engine: engine ?? (defaultEngine ??= await import("shiki/engine/oniguruma").then(
|
|
35
|
-
(res) => res.createOnigurumaEngine(import("shiki/wasm"))
|
|
36
|
-
)),
|
|
37
34
|
themes: "theme" in themes ? [themes.theme] : Object.values(themes.themes).filter((v) => v !== void 0)
|
|
38
35
|
});
|
|
39
36
|
return highlighter.codeToHast(code, {
|
|
@@ -53,6 +50,38 @@ function _renderHighlight(hast, options) {
|
|
|
53
50
|
Fragment
|
|
54
51
|
});
|
|
55
52
|
}
|
|
53
|
+
async function getHighlighter(engineType, options) {
|
|
54
|
+
const { createHighlighter } = await import("shiki");
|
|
55
|
+
let highlighter = highlighters.get(engineType);
|
|
56
|
+
if (!highlighter) {
|
|
57
|
+
let engine = options.engine;
|
|
58
|
+
if (engineType === "js") {
|
|
59
|
+
engine = import("shiki/engine/javascript").then(
|
|
60
|
+
(res) => res.createJavaScriptRegexEngine()
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
if (engineType === "oniguruma" || !engine) {
|
|
64
|
+
engine = import("shiki/engine/oniguruma").then(
|
|
65
|
+
(res) => res.createOnigurumaEngine(import("shiki/wasm"))
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
highlighter = createHighlighter({
|
|
69
|
+
...options,
|
|
70
|
+
engine
|
|
71
|
+
});
|
|
72
|
+
highlighters.set(engineType, highlighter);
|
|
73
|
+
return highlighter;
|
|
74
|
+
}
|
|
75
|
+
return highlighter.then(async (instance) => {
|
|
76
|
+
await Promise.all([
|
|
77
|
+
// @ts-expect-error unknown
|
|
78
|
+
instance.loadLanguage(...options.langs),
|
|
79
|
+
// @ts-expect-error unknown
|
|
80
|
+
instance.loadTheme(...options.themes)
|
|
81
|
+
]);
|
|
82
|
+
return instance;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
56
85
|
async function highlight(code, options) {
|
|
57
86
|
return _renderHighlight(await _highlight(code, options), options);
|
|
58
87
|
}
|
|
@@ -62,5 +91,6 @@ export {
|
|
|
62
91
|
defaultThemes,
|
|
63
92
|
_highlight,
|
|
64
93
|
_renderHighlight,
|
|
94
|
+
getHighlighter,
|
|
65
95
|
highlight
|
|
66
96
|
};
|
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
function splitPath(path) {
|
|
3
3
|
return path.split("/").filter((p) => p.length > 0);
|
|
4
4
|
}
|
|
5
|
-
function
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
function joinPath(...paths) {
|
|
6
|
+
const out = [];
|
|
7
|
+
const parsed = paths.flatMap(splitPath);
|
|
8
|
+
while (parsed.length > 0) {
|
|
9
|
+
switch (parsed[0]) {
|
|
9
10
|
case "..":
|
|
10
|
-
|
|
11
|
+
out.pop();
|
|
11
12
|
break;
|
|
12
13
|
case ".":
|
|
13
14
|
break;
|
|
14
15
|
default:
|
|
15
|
-
|
|
16
|
+
out.push(parsed[0]);
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
+
parsed.shift();
|
|
18
19
|
}
|
|
19
|
-
return
|
|
20
|
+
return out.join("/");
|
|
20
21
|
}
|
|
21
22
|
function slash(path) {
|
|
22
23
|
const isExtendedLengthPath = path.startsWith("\\\\?\\");
|
|
@@ -28,6 +29,6 @@ function slash(path) {
|
|
|
28
29
|
|
|
29
30
|
export {
|
|
30
31
|
splitPath,
|
|
31
|
-
|
|
32
|
+
joinPath,
|
|
32
33
|
slash
|
|
33
34
|
};
|
package/dist/highlight/client.js
CHANGED
package/dist/highlight/index.js
CHANGED
|
@@ -3,13 +3,14 @@ import {
|
|
|
3
3
|
remarkHeading
|
|
4
4
|
} from "../chunk-IYQ35KI2.js";
|
|
5
5
|
import {
|
|
6
|
-
|
|
6
|
+
joinPath,
|
|
7
7
|
slash
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-XMCPKVJQ.js";
|
|
9
9
|
import {
|
|
10
10
|
createStyleTransformer,
|
|
11
|
-
defaultThemes
|
|
12
|
-
|
|
11
|
+
defaultThemes,
|
|
12
|
+
getHighlighter
|
|
13
|
+
} from "../chunk-BUCUQ3WX.js";
|
|
13
14
|
import "../chunk-MLKGABMK.js";
|
|
14
15
|
|
|
15
16
|
// src/mdx-plugins/index.ts
|
|
@@ -25,11 +26,8 @@ import {
|
|
|
25
26
|
transformerNotationWordHighlight
|
|
26
27
|
} from "@shikijs/transformers";
|
|
27
28
|
import {
|
|
28
|
-
getSingletonHighlighter,
|
|
29
29
|
bundledLanguages
|
|
30
30
|
} from "shiki";
|
|
31
|
-
import { createOnigurumaEngine } from "shiki/engine/oniguruma";
|
|
32
|
-
import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
|
|
33
31
|
|
|
34
32
|
// src/mdx-plugins/transformer-icon.ts
|
|
35
33
|
var defaultShortcuts = {
|
|
@@ -248,13 +246,15 @@ function rehypeCode(_options = {}) {
|
|
|
248
246
|
if (options.tab !== false) {
|
|
249
247
|
transformers.push(transformerTab());
|
|
250
248
|
}
|
|
251
|
-
const highlighter =
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
249
|
+
const highlighter = getHighlighter(
|
|
250
|
+
options.experimentalJSEngine ? "js" : "oniguruma",
|
|
251
|
+
{
|
|
252
|
+
themes: "themes" in options ? Object.values(options.themes).filter(Boolean) : [options.theme],
|
|
253
|
+
langs: options.langs ?? (options.lazy ? [] : Object.keys(bundledLanguages))
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
256
|
const transformer = highlighter.then(
|
|
257
|
-
(
|
|
257
|
+
(loaded) => rehypeShikiFromHighlighter(loaded, {
|
|
258
258
|
...options,
|
|
259
259
|
transformers
|
|
260
260
|
})
|
|
@@ -430,7 +430,7 @@ async function getImageSize(src, dir) {
|
|
|
430
430
|
url = src;
|
|
431
431
|
} else if (EXTERNAL_URL_REGEX.test(dir) && isRelative) {
|
|
432
432
|
const base = new URL(dir);
|
|
433
|
-
base.pathname =
|
|
433
|
+
base.pathname = joinPath(base.pathname, src);
|
|
434
434
|
url = base.toString();
|
|
435
435
|
} else {
|
|
436
436
|
return imageSizeFromFile(isRelative ? path.join(dir, src) : src);
|
package/dist/search/server.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { TypedDocument, Orama, Language, RawData, create, SearchParams } from '@orama/orama';
|
|
2
|
-
import { NextRequest } from 'next/server';
|
|
3
2
|
import { S as StructuredData } from '../remark-structure-1kvQbrfH.js';
|
|
4
3
|
import { S as SortedResult } from '../types-Ch8gnVgO.js';
|
|
5
4
|
import { I as I18nConfig } from '../config-inq6kP6y.js';
|
|
@@ -70,7 +69,7 @@ interface SearchServer {
|
|
|
70
69
|
export: () => Promise<ExportedData>;
|
|
71
70
|
}
|
|
72
71
|
interface SearchAPI extends SearchServer {
|
|
73
|
-
GET: (request:
|
|
72
|
+
GET: (request: Request) => Promise<Response>;
|
|
74
73
|
/**
|
|
75
74
|
* `GET` route handler that exports search indexes for static search.
|
|
76
75
|
*/
|
package/dist/search/server.js
CHANGED
|
@@ -19,12 +19,13 @@ function createEndpoint(server) {
|
|
|
19
19
|
return Response.json(await server.export());
|
|
20
20
|
},
|
|
21
21
|
async GET(request) {
|
|
22
|
-
const
|
|
22
|
+
const url = new URL(request.url);
|
|
23
|
+
const query = url.searchParams.get("query");
|
|
23
24
|
if (!query) return Response.json([]);
|
|
24
25
|
return Response.json(
|
|
25
26
|
await search(query, {
|
|
26
|
-
tag:
|
|
27
|
-
locale:
|
|
27
|
+
tag: url.searchParams.get("tag") ?? void 0,
|
|
28
|
+
locale: url.searchParams.get("locale") ?? void 0
|
|
28
29
|
})
|
|
29
30
|
);
|
|
30
31
|
}
|
package/dist/server/index.js
CHANGED
package/dist/source/index.d.ts
CHANGED
|
@@ -4,31 +4,52 @@ import { R as Root, I as Item, F as Folder$1, S as Separator } from '../page-tre
|
|
|
4
4
|
|
|
5
5
|
interface FileInfo {
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* File path without extension
|
|
8
|
+
*
|
|
9
|
+
* @deprecated obtain it with `join(dirname, name)`
|
|
8
10
|
*/
|
|
9
|
-
|
|
11
|
+
flattenedPath: string;
|
|
10
12
|
/**
|
|
11
13
|
* Original path of file
|
|
12
14
|
*/
|
|
13
15
|
path: string;
|
|
14
16
|
/**
|
|
15
|
-
* File
|
|
17
|
+
* File name without locale and extension
|
|
16
18
|
*/
|
|
17
|
-
|
|
19
|
+
name: string;
|
|
18
20
|
/**
|
|
19
|
-
*
|
|
21
|
+
* file extension from the last `.`, like `.md`
|
|
22
|
+
*
|
|
23
|
+
* empty string if no file extension
|
|
24
|
+
*/
|
|
25
|
+
ext: string;
|
|
26
|
+
dirname: string;
|
|
27
|
+
}
|
|
28
|
+
interface FolderInfo {
|
|
29
|
+
/**
|
|
30
|
+
* Original path of folder
|
|
31
|
+
*/
|
|
32
|
+
path: string;
|
|
33
|
+
/**
|
|
34
|
+
* folder name
|
|
20
35
|
*/
|
|
21
36
|
name: string;
|
|
22
37
|
dirname: string;
|
|
23
38
|
}
|
|
24
39
|
declare function parseFilePath(path: string): FileInfo;
|
|
25
|
-
declare function parseFolderPath(path: string):
|
|
40
|
+
declare function parseFolderPath(path: string): FolderInfo;
|
|
26
41
|
|
|
27
42
|
interface LoadOptions {
|
|
28
43
|
transformers?: Transformer[];
|
|
29
|
-
rootDir?: string;
|
|
30
44
|
getSlugs: (info: FileInfo) => string[];
|
|
31
45
|
}
|
|
46
|
+
interface I18nLoadOptions extends LoadOptions {
|
|
47
|
+
i18n: {
|
|
48
|
+
parser: 'dot' | 'dir';
|
|
49
|
+
languages: string[];
|
|
50
|
+
defaultLanguage: string;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
32
53
|
interface VirtualFile {
|
|
33
54
|
/**
|
|
34
55
|
* Relative path
|
|
@@ -47,7 +68,7 @@ type Transformer = (context: {
|
|
|
47
68
|
storage: Storage;
|
|
48
69
|
options: LoadOptions;
|
|
49
70
|
}) => void;
|
|
50
|
-
declare function loadFiles(files: VirtualFile[], options:
|
|
71
|
+
declare function loadFiles<O extends LoadOptions>(files: VirtualFile[], options: O): Storage;
|
|
51
72
|
|
|
52
73
|
interface LoaderConfig {
|
|
53
74
|
source: SourceConfig;
|
|
@@ -58,11 +79,6 @@ interface SourceConfig {
|
|
|
58
79
|
metaData: MetaData;
|
|
59
80
|
}
|
|
60
81
|
interface LoaderOptions {
|
|
61
|
-
/**
|
|
62
|
-
* @deprecated It is now recommended to filter files on `source` level
|
|
63
|
-
* @defaultValue `''`
|
|
64
|
-
*/
|
|
65
|
-
rootDir?: string;
|
|
66
82
|
baseUrl: string;
|
|
67
83
|
icon?: NonNullable<BuildPageTreeOptions['resolveIcon']>;
|
|
68
84
|
slugs?: LoadOptions['getSlugs'];
|
|
@@ -76,14 +92,16 @@ interface LoaderOptions {
|
|
|
76
92
|
/**
|
|
77
93
|
* Configure i18n
|
|
78
94
|
*/
|
|
79
|
-
i18n?: I18nConfig
|
|
95
|
+
i18n?: I18nConfig & {
|
|
96
|
+
parser?: I18nLoadOptions['i18n']['parser'];
|
|
97
|
+
};
|
|
80
98
|
}
|
|
81
99
|
interface Source<Config extends SourceConfig> {
|
|
82
100
|
/**
|
|
83
101
|
* @internal
|
|
84
102
|
*/
|
|
85
103
|
_config?: Config;
|
|
86
|
-
files: VirtualFile[] | ((
|
|
104
|
+
files: VirtualFile[] | (() => VirtualFile[]);
|
|
87
105
|
}
|
|
88
106
|
interface Page<Data = PageData> {
|
|
89
107
|
file: FileInfo;
|
|
@@ -105,7 +123,7 @@ interface LoaderOutput<Config extends LoaderConfig> {
|
|
|
105
123
|
getPageTree: (locale?: string) => Root;
|
|
106
124
|
getPageByHref: (href: string, options?: {
|
|
107
125
|
/**
|
|
108
|
-
* resolve relative file paths in `href` from specified
|
|
126
|
+
* resolve relative file paths in `href` from specified dirname, must be a virtual path.
|
|
109
127
|
*/
|
|
110
128
|
dir?: string;
|
|
111
129
|
}) => {
|
|
@@ -174,7 +192,7 @@ interface PageFile {
|
|
|
174
192
|
}
|
|
175
193
|
type File = MetaFile | PageFile;
|
|
176
194
|
interface Folder {
|
|
177
|
-
file:
|
|
195
|
+
file: FolderInfo;
|
|
178
196
|
children: (File | Folder)[];
|
|
179
197
|
}
|
|
180
198
|
/**
|
|
@@ -213,7 +231,7 @@ declare namespace fileSystem {
|
|
|
213
231
|
export { type fileSystem_File as File, type fileSystem_Folder as Folder, type fileSystem_MetaFile as MetaFile, type fileSystem_PageFile as PageFile, fileSystem_Storage as Storage };
|
|
214
232
|
}
|
|
215
233
|
|
|
216
|
-
interface
|
|
234
|
+
interface Options {
|
|
217
235
|
/**
|
|
218
236
|
* Remove references to the file path of original nodes (`$ref`)
|
|
219
237
|
*
|
|
@@ -223,11 +241,14 @@ interface BuildPageTreeOptions {
|
|
|
223
241
|
attachFile?: (node: Item, file?: PageFile) => Item;
|
|
224
242
|
attachFolder?: (node: Folder$1, folder: Folder, meta?: MetaFile) => Folder$1;
|
|
225
243
|
attachSeparator?: (node: Separator) => Separator;
|
|
226
|
-
storage: Storage;
|
|
227
244
|
getUrl: UrlFn;
|
|
228
245
|
resolveIcon?: (icon: string | undefined) => ReactElement | undefined;
|
|
229
246
|
}
|
|
230
|
-
interface
|
|
247
|
+
interface BuildPageTreeOptions extends Options {
|
|
248
|
+
storage: Storage;
|
|
249
|
+
}
|
|
250
|
+
interface BuildPageTreeOptionsWithI18n extends Options {
|
|
251
|
+
storages: Record<string, Storage>;
|
|
231
252
|
i18n: I18nConfig;
|
|
232
253
|
}
|
|
233
254
|
interface PageTreeBuilder {
|
|
@@ -239,4 +260,4 @@ interface PageTreeBuilder {
|
|
|
239
260
|
}
|
|
240
261
|
declare function createPageTreeBuilder(): PageTreeBuilder;
|
|
241
262
|
|
|
242
|
-
export { type BuildPageTreeOptions, type BuildPageTreeOptionsWithI18n, type FileInfo, fileSystem as FileSystem, type InferMetaType, type InferPageType, type LanguageEntry, type LoadOptions, type LoaderConfig, type LoaderOptions, type LoaderOutput, type Meta, type MetaData, type Page, type PageData, type PageTreeBuilder, type Source, type SourceConfig, type Transformer, type UrlFn, type VirtualFile, createGetUrl, createPageTreeBuilder, getSlugs, loadFiles, loader, parseFilePath, parseFolderPath };
|
|
263
|
+
export { type BuildPageTreeOptions, type BuildPageTreeOptionsWithI18n, type FileInfo, fileSystem as FileSystem, type FolderInfo, type InferMetaType, type InferPageType, type LanguageEntry, type LoadOptions, type LoaderConfig, type LoaderOptions, type LoaderOutput, type Meta, type MetaData, type Page, type PageData, type PageTreeBuilder, type Source, type SourceConfig, type Transformer, type UrlFn, type VirtualFile, createGetUrl, createPageTreeBuilder, getSlugs, loadFiles, loader, parseFilePath, parseFolderPath };
|
package/dist/source/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
joinPath,
|
|
3
3
|
slash,
|
|
4
4
|
splitPath
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-XMCPKVJQ.js";
|
|
6
6
|
import {
|
|
7
7
|
__export
|
|
8
8
|
} from "../chunk-MLKGABMK.js";
|
|
@@ -24,8 +24,12 @@ function buildAll(nodes, ctx, skipIndex) {
|
|
|
24
24
|
for (const node of [...nodes].sort(
|
|
25
25
|
(a, b) => a.file.name.localeCompare(b.file.name)
|
|
26
26
|
)) {
|
|
27
|
-
if (isPageFile(node)
|
|
28
|
-
const
|
|
27
|
+
if (isPageFile(node)) {
|
|
28
|
+
const localized = ctx.localeStorage?.read(
|
|
29
|
+
joinPath(node.file.dirname, node.file.name),
|
|
30
|
+
"page"
|
|
31
|
+
);
|
|
32
|
+
const treeNode = buildFileNode(localized ?? node, ctx);
|
|
29
33
|
if (node.file.name === "index") {
|
|
30
34
|
if (!skipIndex) output.unshift(treeNode);
|
|
31
35
|
continue;
|
|
@@ -33,10 +37,11 @@ function buildAll(nodes, ctx, skipIndex) {
|
|
|
33
37
|
output.push(treeNode);
|
|
34
38
|
}
|
|
35
39
|
if ("children" in node) {
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
const folder = buildFolderNode(node, false, ctx);
|
|
41
|
+
if (folder.children.length === 0 && folder.index) {
|
|
42
|
+
output.push(folder.index);
|
|
38
43
|
} else {
|
|
39
|
-
folders.push(
|
|
44
|
+
folders.push(folder);
|
|
40
45
|
}
|
|
41
46
|
}
|
|
42
47
|
}
|
|
@@ -75,8 +80,8 @@ function resolveFolderItem(folder, item, ctx, idx, addedNodePaths) {
|
|
|
75
80
|
} else if (isExtract) {
|
|
76
81
|
filename = item.slice(extractPrefix.length);
|
|
77
82
|
}
|
|
78
|
-
const
|
|
79
|
-
const itemNode = ctx.storage.readDir(
|
|
83
|
+
const path = joinPath(folder.file.path, filename);
|
|
84
|
+
const itemNode = ctx.storage.readDir(path) ?? ctx.localeStorage?.read(path, "page") ?? ctx.storage.read(path, "page");
|
|
80
85
|
if (!itemNode) return [];
|
|
81
86
|
addedNodePaths.add(itemNode.file.path);
|
|
82
87
|
if (isExcept) return [];
|
|
@@ -87,10 +92,10 @@ function resolveFolderItem(folder, item, ctx, idx, addedNodePaths) {
|
|
|
87
92
|
return [buildFileNode(itemNode, ctx)];
|
|
88
93
|
}
|
|
89
94
|
function buildFolderNode(folder, isGlobalRoot, ctx) {
|
|
90
|
-
const metaPath =
|
|
91
|
-
const meta =
|
|
95
|
+
const metaPath = joinPath(folder.file.path, "meta");
|
|
96
|
+
const meta = ctx.localeStorage?.read(metaPath, "meta") ?? ctx.storage.read(metaPath, "meta");
|
|
92
97
|
const indexFile = ctx.storage.read(
|
|
93
|
-
|
|
98
|
+
joinPath(folder.file.path, "index"),
|
|
94
99
|
"page"
|
|
95
100
|
);
|
|
96
101
|
const metadata = meta?.data;
|
|
@@ -137,16 +142,15 @@ function buildFolderNode(folder, isGlobalRoot, ctx) {
|
|
|
137
142
|
return ctx.options.attachFolder?.(node, folder, meta) ?? node;
|
|
138
143
|
}
|
|
139
144
|
function buildFileNode(file, ctx) {
|
|
140
|
-
const localized = findLocalizedFile(file.file.flattenedPath, "page", ctx) ?? file;
|
|
141
145
|
const item = {
|
|
142
|
-
$id:
|
|
146
|
+
$id: file.file.path,
|
|
143
147
|
type: "page",
|
|
144
|
-
name:
|
|
145
|
-
description:
|
|
146
|
-
icon: ctx.options.resolveIcon?.(
|
|
147
|
-
url: ctx.options.getUrl(
|
|
148
|
+
name: file.data.data.title ?? pathToName(file.file.name),
|
|
149
|
+
description: file.data.data.description,
|
|
150
|
+
icon: ctx.options.resolveIcon?.(file.data.data.icon),
|
|
151
|
+
url: ctx.options.getUrl(file.data.slugs, ctx.locale),
|
|
148
152
|
$ref: !ctx.options.noRef ? {
|
|
149
|
-
file:
|
|
153
|
+
file: file.file.path
|
|
150
154
|
} : void 0
|
|
151
155
|
};
|
|
152
156
|
return ctx.options.attachFile?.(item, file) ?? item;
|
|
@@ -171,11 +175,11 @@ function createPageTreeBuilder() {
|
|
|
171
175
|
buildI18n({ i18n, ...options }) {
|
|
172
176
|
const entries = i18n.languages.map((lang) => {
|
|
173
177
|
const tree = build({
|
|
174
|
-
lang,
|
|
175
178
|
options,
|
|
176
179
|
builder: this,
|
|
177
|
-
|
|
178
|
-
i18n
|
|
180
|
+
locale: lang,
|
|
181
|
+
storage: options.storages[i18n.defaultLanguage],
|
|
182
|
+
localeStorage: options.storages[lang]
|
|
179
183
|
});
|
|
180
184
|
return [lang, tree];
|
|
181
185
|
});
|
|
@@ -183,10 +187,6 @@ function createPageTreeBuilder() {
|
|
|
183
187
|
}
|
|
184
188
|
};
|
|
185
189
|
}
|
|
186
|
-
function findLocalizedFile(path2, format, ctx) {
|
|
187
|
-
if (!ctx.lang) return;
|
|
188
|
-
return ctx.storage.read(`${path2}.${ctx.lang}`, format);
|
|
189
|
-
}
|
|
190
190
|
function pathToName(name) {
|
|
191
191
|
const result = [];
|
|
192
192
|
for (const c of name) {
|
|
@@ -198,44 +198,35 @@ function pathToName(name) {
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
// src/source/path.ts
|
|
201
|
-
function parseFilePath(
|
|
202
|
-
const segments = splitPath(slash(
|
|
201
|
+
function parseFilePath(path) {
|
|
202
|
+
const segments = splitPath(slash(path));
|
|
203
203
|
const dirname = segments.slice(0, -1).join("/");
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
let name = segments.at(-1) ?? "";
|
|
205
|
+
let ext = "";
|
|
206
|
+
const dotIdx = name.lastIndexOf(".");
|
|
207
|
+
if (dotIdx !== -1) {
|
|
208
|
+
ext = name.substring(dotIdx);
|
|
209
|
+
name = name.substring(0, dotIdx);
|
|
210
|
+
}
|
|
209
211
|
return {
|
|
210
212
|
dirname,
|
|
211
213
|
name,
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
214
|
+
path: segments.join("/"),
|
|
215
|
+
ext,
|
|
216
|
+
flattenedPath: [dirname, name].filter((p) => p.length > 0).join("/")
|
|
215
217
|
};
|
|
216
218
|
}
|
|
217
|
-
function parseFolderPath(
|
|
218
|
-
const segments = splitPath(slash(
|
|
219
|
+
function parseFolderPath(path) {
|
|
220
|
+
const segments = splitPath(slash(path));
|
|
219
221
|
const base = segments.at(-1) ?? "";
|
|
220
|
-
const [name, locale] = getLocale(base);
|
|
221
|
-
const flattenedPath = segments.join("/");
|
|
222
222
|
return {
|
|
223
223
|
dirname: segments.slice(0, -1).join("/"),
|
|
224
|
-
name,
|
|
225
|
-
|
|
226
|
-
locale,
|
|
227
|
-
path: flattenedPath
|
|
224
|
+
name: base,
|
|
225
|
+
path: segments.join("/")
|
|
228
226
|
};
|
|
229
227
|
}
|
|
230
|
-
function
|
|
231
|
-
const
|
|
232
|
-
if (sep === -1) return [name];
|
|
233
|
-
const locale = name.slice(sep + 1);
|
|
234
|
-
if (/\d+/.exec(locale)) return [name];
|
|
235
|
-
return [name.slice(0, sep), locale];
|
|
236
|
-
}
|
|
237
|
-
function normalizePath(path2) {
|
|
238
|
-
const segments = splitPath(slash(path2));
|
|
228
|
+
function normalizePath(path) {
|
|
229
|
+
const segments = splitPath(slash(path));
|
|
239
230
|
if (segments[0] === "." || segments[0] === "..")
|
|
240
231
|
throw new Error("It must not start with './' or '../'");
|
|
241
232
|
return segments.join("/");
|
|
@@ -260,30 +251,33 @@ var Storage = class {
|
|
|
260
251
|
* @param path - flattened path
|
|
261
252
|
* @param format - file format
|
|
262
253
|
*/
|
|
263
|
-
read(
|
|
264
|
-
return this.files.get(`${
|
|
254
|
+
read(path, format) {
|
|
255
|
+
return this.files.get(`${path}.${format}`);
|
|
265
256
|
}
|
|
266
|
-
readDir(
|
|
267
|
-
return this.folders.get(
|
|
257
|
+
readDir(path) {
|
|
258
|
+
return this.folders.get(path);
|
|
268
259
|
}
|
|
269
260
|
root() {
|
|
270
261
|
return this.rootFolder;
|
|
271
262
|
}
|
|
272
|
-
write(
|
|
263
|
+
write(path, format, data) {
|
|
273
264
|
const node = {
|
|
274
265
|
format,
|
|
275
|
-
file: parseFilePath(
|
|
266
|
+
file: parseFilePath(path),
|
|
276
267
|
data
|
|
277
268
|
};
|
|
278
269
|
this.makeDir(node.file.dirname);
|
|
279
270
|
this.readDir(node.file.dirname)?.children.push(node);
|
|
280
|
-
this.files.set(
|
|
271
|
+
this.files.set(
|
|
272
|
+
joinPath(node.file.dirname, `${node.file.name}.${node.format}`),
|
|
273
|
+
node
|
|
274
|
+
);
|
|
281
275
|
}
|
|
282
276
|
list() {
|
|
283
277
|
return [...this.files.values()];
|
|
284
278
|
}
|
|
285
|
-
makeDir(
|
|
286
|
-
const segments = splitPath(
|
|
279
|
+
makeDir(path) {
|
|
280
|
+
const segments = splitPath(path);
|
|
287
281
|
for (let i = 0; i < segments.length; i++) {
|
|
288
282
|
const segment = segments.slice(0, i + 1).join("/");
|
|
289
283
|
if (this.folders.has(segment)) continue;
|
|
@@ -301,20 +295,17 @@ var Storage = class {
|
|
|
301
295
|
function loadFiles(files, options) {
|
|
302
296
|
const { transformers = [] } = options;
|
|
303
297
|
const storage = new Storage();
|
|
304
|
-
const rootDir = normalizePath(options.rootDir ?? "");
|
|
305
298
|
for (const file of files) {
|
|
306
|
-
const
|
|
307
|
-
if (!normalizedPath.startsWith(rootDir)) continue;
|
|
308
|
-
const relativePath = normalizedPath.slice(rootDir.length);
|
|
299
|
+
const parsedPath = normalizePath(file.path);
|
|
309
300
|
if (file.type === "page") {
|
|
310
|
-
const slugs = file.slugs ?? options.getSlugs(parseFilePath(
|
|
311
|
-
storage.write(
|
|
301
|
+
const slugs = file.slugs ?? options.getSlugs(parseFilePath(parsedPath));
|
|
302
|
+
storage.write(parsedPath, file.type, {
|
|
312
303
|
slugs,
|
|
313
304
|
data: file.data
|
|
314
305
|
});
|
|
315
306
|
}
|
|
316
307
|
if (file.type === "meta") {
|
|
317
|
-
storage.write(
|
|
308
|
+
storage.write(parsedPath, file.type, file.data);
|
|
318
309
|
}
|
|
319
310
|
}
|
|
320
311
|
for (const transformer of transformers) {
|
|
@@ -325,28 +316,66 @@ function loadFiles(files, options) {
|
|
|
325
316
|
}
|
|
326
317
|
return storage;
|
|
327
318
|
}
|
|
319
|
+
function loadFilesI18n(files, options) {
|
|
320
|
+
const parser = options.i18n.parser === "dir" ? dirParser : dotParser;
|
|
321
|
+
const storages = {};
|
|
322
|
+
for (const lang of options.i18n.languages) {
|
|
323
|
+
storages[lang] = loadFiles(
|
|
324
|
+
files.flatMap((file) => {
|
|
325
|
+
const [path, locale] = parser(normalizePath(file.path));
|
|
326
|
+
if ((locale ?? options.i18n.defaultLanguage) === lang) {
|
|
327
|
+
return {
|
|
328
|
+
...file,
|
|
329
|
+
path
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
return [];
|
|
333
|
+
}),
|
|
334
|
+
options
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
return storages;
|
|
338
|
+
}
|
|
339
|
+
function dirParser(path) {
|
|
340
|
+
const parsed = path.split("/");
|
|
341
|
+
if (parsed.length >= 2) return [parsed.slice(1).join("/"), parsed[0]];
|
|
342
|
+
return [path];
|
|
343
|
+
}
|
|
344
|
+
function dotParser(path) {
|
|
345
|
+
const segs = path.split("/");
|
|
346
|
+
if (segs.length === 0) return [path];
|
|
347
|
+
const name = segs[segs.length - 1].split(".");
|
|
348
|
+
if (name.length >= 3) {
|
|
349
|
+
const locale = name.splice(name.length - 2, 1)[0];
|
|
350
|
+
if (locale.length > 0 && !/\d+/.test(locale)) {
|
|
351
|
+
segs[segs.length - 1] = name.join(".");
|
|
352
|
+
return [segs.join("/"), locale];
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return [path];
|
|
356
|
+
}
|
|
328
357
|
|
|
329
358
|
// src/source/loader.ts
|
|
330
|
-
|
|
331
|
-
function indexPages(storage, getUrl, i18n) {
|
|
359
|
+
function indexPages(storages, getUrl, i18n) {
|
|
332
360
|
const defaultLanguage = i18n?.defaultLanguage ?? "";
|
|
333
361
|
const map = /* @__PURE__ */ new Map();
|
|
334
362
|
const pathToFile = /* @__PURE__ */ new Map();
|
|
335
|
-
for (const item of
|
|
363
|
+
for (const item of storages[defaultLanguage].list()) {
|
|
336
364
|
if (item.format === "meta")
|
|
337
365
|
pathToFile.set(item.file.path, fileToMeta(item));
|
|
338
366
|
if (item.format === "page") {
|
|
339
|
-
const page = fileToPage(item, getUrl,
|
|
367
|
+
const page = fileToPage(item, getUrl, defaultLanguage);
|
|
340
368
|
pathToFile.set(item.file.path, page);
|
|
341
|
-
if (item.file.locale) continue;
|
|
342
369
|
map.set(`${defaultLanguage}.${page.slugs.join("/")}`, page);
|
|
343
370
|
if (!i18n) continue;
|
|
371
|
+
const path = joinPath(item.file.dirname, item.file.name);
|
|
344
372
|
for (const lang of i18n.languages) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
"page"
|
|
373
|
+
if (lang === defaultLanguage) continue;
|
|
374
|
+
const localizedPage = fileToPage(
|
|
375
|
+
storages[lang].read(path, "page") ?? item,
|
|
376
|
+
getUrl,
|
|
377
|
+
lang
|
|
348
378
|
);
|
|
349
|
-
const localizedPage = fileToPage(localized ?? item, getUrl, lang);
|
|
350
379
|
map.set(`${lang}.${localizedPage.slugs.join("/")}`, localizedPage);
|
|
351
380
|
}
|
|
352
381
|
}
|
|
@@ -387,17 +416,23 @@ function createOutput(options) {
|
|
|
387
416
|
if (!options.url && !options.baseUrl) {
|
|
388
417
|
console.warn("`loader()` now requires a `baseUrl` option to be defined.");
|
|
389
418
|
}
|
|
390
|
-
const { source,
|
|
419
|
+
const { source, slugs: slugsFn = getSlugs } = options;
|
|
391
420
|
const getUrl = options.url ?? createGetUrl(options.baseUrl ?? "/", options.i18n);
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
{
|
|
421
|
+
const files = typeof source.files === "function" ? source.files() : source.files;
|
|
422
|
+
const storages = options.i18n ? loadFilesI18n(files, {
|
|
423
|
+
i18n: {
|
|
424
|
+
...options.i18n,
|
|
425
|
+
parser: options.i18n.parser ?? "dot"
|
|
426
|
+
},
|
|
427
|
+
transformers: options.transformers,
|
|
428
|
+
getSlugs: slugsFn
|
|
429
|
+
}) : {
|
|
430
|
+
"": loadFiles(files, {
|
|
395
431
|
transformers: options.transformers,
|
|
396
|
-
rootDir,
|
|
397
432
|
getSlugs: slugsFn
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
const walker = indexPages(
|
|
433
|
+
})
|
|
434
|
+
};
|
|
435
|
+
const walker = indexPages(storages, getUrl, options.i18n);
|
|
401
436
|
const builder = createPageTreeBuilder();
|
|
402
437
|
let pageTree;
|
|
403
438
|
return {
|
|
@@ -405,7 +440,7 @@ function createOutput(options) {
|
|
|
405
440
|
get pageTree() {
|
|
406
441
|
if (options.i18n) {
|
|
407
442
|
pageTree ??= builder.buildI18n({
|
|
408
|
-
|
|
443
|
+
storages,
|
|
409
444
|
resolveIcon: options.icon,
|
|
410
445
|
getUrl,
|
|
411
446
|
i18n: options.i18n,
|
|
@@ -413,7 +448,7 @@ function createOutput(options) {
|
|
|
413
448
|
});
|
|
414
449
|
} else {
|
|
415
450
|
pageTree ??= builder.build({
|
|
416
|
-
storage,
|
|
451
|
+
storage: storages[""],
|
|
417
452
|
resolveIcon: options.icon,
|
|
418
453
|
getUrl,
|
|
419
454
|
...options.pageTree
|
|
@@ -428,7 +463,7 @@ function createOutput(options) {
|
|
|
428
463
|
const pages = Array.from(walker.pages.values());
|
|
429
464
|
const [value, hash] = href.split("#", 2);
|
|
430
465
|
if (value.startsWith(".") && (value.endsWith(".md") || value.endsWith(".mdx"))) {
|
|
431
|
-
const hrefPath =
|
|
466
|
+
const hrefPath = joinPath(dir, value);
|
|
432
467
|
const target2 = pages.find((item) => item.file.path === hrefPath);
|
|
433
468
|
if (target2)
|
|
434
469
|
return {
|
package/dist/utils/use-shiki.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumadocs-core",
|
|
3
|
-
"version": "15.1.
|
|
3
|
+
"version": "15.1.2",
|
|
4
4
|
"description": "The library for building a documentation website in Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NextJs",
|
|
@@ -113,13 +113,13 @@
|
|
|
113
113
|
"@types/hast": "^3.0.4",
|
|
114
114
|
"@types/mdast": "^4.0.3",
|
|
115
115
|
"@types/negotiator": "^0.6.3",
|
|
116
|
-
"@types/node": "22.13.
|
|
117
|
-
"@types/react": "^19.0.
|
|
116
|
+
"@types/node": "22.13.11",
|
|
117
|
+
"@types/react": "^19.0.12",
|
|
118
118
|
"@types/react-dom": "^19.0.4",
|
|
119
119
|
"algoliasearch": "4.24.0",
|
|
120
120
|
"mdast-util-mdx-jsx": "^3.2.0",
|
|
121
121
|
"mdast-util-mdxjs-esm": "^2.0.1",
|
|
122
|
-
"next": "^15.2.
|
|
122
|
+
"next": "^15.2.3",
|
|
123
123
|
"remark-mdx": "^3.1.0",
|
|
124
124
|
"remark-rehype": "^11.1.1",
|
|
125
125
|
"typescript": "^5.8.2",
|