fumadocs-core 15.0.18 → 15.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/breadcrumb.d.ts +1 -1
- 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-QTVCCXFT.js} +2 -2
- package/dist/highlight/client.js +2 -2
- package/dist/highlight/index.js +1 -1
- package/dist/mdx-plugins/index.js +14 -14
- package/dist/{page-tree-CfT5zlWh.d.ts → page-tree-9q98UqWL.d.ts} +1 -0
- package/dist/search/server.d.ts +2 -3
- package/dist/search/server.js +4 -3
- package/dist/server/index.d.ts +7 -4
- package/dist/server/index.js +26 -9
- package/dist/source/index.d.ts +41 -10
- package/dist/source/index.js +113 -66
- package/dist/utils/use-shiki.js +2 -2
- package/package.json +3 -3
package/dist/breadcrumb.d.ts
CHANGED
|
@@ -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,7 +2,7 @@
|
|
|
2
2
|
function splitPath(path) {
|
|
3
3
|
return path.split("/").filter((p) => p.length > 0);
|
|
4
4
|
}
|
|
5
|
-
function
|
|
5
|
+
function joinPath(from, join) {
|
|
6
6
|
const v1 = splitPath(from), v2 = splitPath(join);
|
|
7
7
|
while (v2.length > 0) {
|
|
8
8
|
switch (v2[0]) {
|
|
@@ -28,6 +28,6 @@ function slash(path) {
|
|
|
28
28
|
|
|
29
29
|
export {
|
|
30
30
|
splitPath,
|
|
31
|
-
|
|
31
|
+
joinPath,
|
|
32
32
|
slash
|
|
33
33
|
};
|
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-QTVCCXFT.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';
|
|
@@ -7,7 +6,7 @@ import { LoaderOutput, LoaderConfig, InferPageType } from '../source/index.js';
|
|
|
7
6
|
import 'mdast';
|
|
8
7
|
import 'unified';
|
|
9
8
|
import 'react';
|
|
10
|
-
import '../page-tree-
|
|
9
|
+
import '../page-tree-9q98UqWL.js';
|
|
11
10
|
|
|
12
11
|
type AdvancedDocument = TypedDocument<Orama<typeof advancedSchema>>;
|
|
13
12
|
declare const advancedSchema: {
|
|
@@ -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.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { a as TOCItemType, T as TableOfContents, g as getTableOfContents } from '../get-toc-Cr2URuiP.js';
|
|
2
|
-
import { N as Node, I as Item, R as Root } from '../page-tree-
|
|
3
|
-
export { p as PageTree } from '../page-tree-
|
|
2
|
+
import { N as Node, I as Item, R as Root, F as Folder } from '../page-tree-9q98UqWL.js';
|
|
3
|
+
export { p as PageTree } from '../page-tree-9q98UqWL.js';
|
|
4
4
|
export { S as SortedResult } from '../types-Ch8gnVgO.js';
|
|
5
5
|
import { Metadata } from 'next';
|
|
6
6
|
import { NextRequest } from 'next/server';
|
|
@@ -21,10 +21,13 @@ declare function flattenTree(tree: Node[]): Item[];
|
|
|
21
21
|
/**
|
|
22
22
|
* Get neighbours of a page, useful for implementing "previous & next" buttons
|
|
23
23
|
*/
|
|
24
|
-
declare function findNeighbour(tree: Root, url: string
|
|
24
|
+
declare function findNeighbour(tree: Root, url: string, options?: {
|
|
25
|
+
separateRoot?: boolean;
|
|
26
|
+
}): {
|
|
25
27
|
previous?: Item;
|
|
26
28
|
next?: Item;
|
|
27
29
|
};
|
|
30
|
+
declare function getPageTreeRoots(pageTree: Root | Folder): (Root | Folder)[];
|
|
28
31
|
/**
|
|
29
32
|
* Separate the folder nodes of a root into multiple roots
|
|
30
33
|
*/
|
|
@@ -111,4 +114,4 @@ declare function createMetadataImage<S extends LoaderOutput<LoaderConfig>>(optio
|
|
|
111
114
|
}) => Response | Promise<Response>) => (request: NextRequest, options: any) => Response | Promise<Response>;
|
|
112
115
|
};
|
|
113
116
|
|
|
114
|
-
export { type GetGithubLastCommitOptions, createMetadataImage, findNeighbour, flattenTree, getGithubLastEdit, separatePageTree };
|
|
117
|
+
export { type GetGithubLastCommitOptions, createMetadataImage, findNeighbour, flattenTree, getGithubLastEdit, getPageTreeRoots, separatePageTree };
|
package/dist/server/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import "../chunk-WQMD6AUR.js";
|
|
|
5
5
|
import {
|
|
6
6
|
createStyleTransformer,
|
|
7
7
|
highlight
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-BUCUQ3WX.js";
|
|
9
9
|
import "../chunk-MLKGABMK.js";
|
|
10
10
|
|
|
11
11
|
// src/server/get-toc.ts
|
|
@@ -34,18 +34,34 @@ function flattenTree(tree) {
|
|
|
34
34
|
return [node];
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
|
-
function findNeighbour(tree, url) {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
function findNeighbour(tree, url, options) {
|
|
38
|
+
const { separateRoot = true } = options ?? {};
|
|
39
|
+
const roots = separateRoot ? getPageTreeRoots(tree) : [tree];
|
|
40
|
+
const lists = roots.map((node) => flattenTree(node.children));
|
|
41
|
+
for (const list of lists) {
|
|
42
|
+
for (let i = 0; i < list.length; i++) {
|
|
43
|
+
if (list[i].url === url) {
|
|
44
|
+
return {
|
|
45
|
+
next: list[i + 1],
|
|
46
|
+
previous: list[i - 1]
|
|
47
|
+
};
|
|
48
|
+
}
|
|
45
49
|
}
|
|
46
50
|
}
|
|
47
51
|
return {};
|
|
48
52
|
}
|
|
53
|
+
function getPageTreeRoots(pageTree) {
|
|
54
|
+
const result = pageTree.children.flatMap((child) => {
|
|
55
|
+
if (child.type !== "folder") return [];
|
|
56
|
+
const roots = getPageTreeRoots(child);
|
|
57
|
+
if (child.root) {
|
|
58
|
+
roots.push(child);
|
|
59
|
+
}
|
|
60
|
+
return roots;
|
|
61
|
+
});
|
|
62
|
+
if (!("type" in pageTree)) result.push(pageTree);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
49
65
|
function separatePageTree(pageTree) {
|
|
50
66
|
return pageTree.children.flatMap((child) => {
|
|
51
67
|
if (child.type !== "folder") return [];
|
|
@@ -162,6 +178,7 @@ export {
|
|
|
162
178
|
findNeighbour,
|
|
163
179
|
flattenTree,
|
|
164
180
|
getGithubLastEdit,
|
|
181
|
+
getPageTreeRoots,
|
|
165
182
|
getTableOfContents,
|
|
166
183
|
highlight,
|
|
167
184
|
separatePageTree
|
package/dist/source/index.d.ts
CHANGED
|
@@ -1,28 +1,49 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
2
|
import { I as I18nConfig } from '../config-inq6kP6y.js';
|
|
3
|
-
import { R as Root, I as Item, F as Folder$1, S as Separator } from '../page-tree-
|
|
3
|
+
import { R as Root, I as Item, F as Folder$1, S as Separator } from '../page-tree-9q98UqWL.js';
|
|
4
4
|
|
|
5
5
|
interface FileInfo {
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* locale extension from the last second `.`, like `.en`
|
|
8
|
+
*
|
|
9
|
+
* empty string if no locale
|
|
10
|
+
*/
|
|
11
|
+
locale: string;
|
|
12
|
+
/**
|
|
13
|
+
* File path without extension
|
|
14
|
+
*
|
|
15
|
+
* @deprecated obtain it with `join(dirname, name)`
|
|
8
16
|
*/
|
|
9
|
-
|
|
17
|
+
flattenedPath: string;
|
|
10
18
|
/**
|
|
11
19
|
* Original path of file
|
|
12
20
|
*/
|
|
13
21
|
path: string;
|
|
14
22
|
/**
|
|
15
|
-
* File
|
|
23
|
+
* File name without locale and extension
|
|
16
24
|
*/
|
|
17
|
-
|
|
25
|
+
name: string;
|
|
18
26
|
/**
|
|
19
|
-
*
|
|
27
|
+
* file extension from the last `.`, like `.md`
|
|
28
|
+
*
|
|
29
|
+
* empty string if no file extension
|
|
30
|
+
*/
|
|
31
|
+
ext: string;
|
|
32
|
+
dirname: string;
|
|
33
|
+
}
|
|
34
|
+
interface FolderInfo {
|
|
35
|
+
/**
|
|
36
|
+
* Original path of folder
|
|
37
|
+
*/
|
|
38
|
+
path: string;
|
|
39
|
+
/**
|
|
40
|
+
* folder name
|
|
20
41
|
*/
|
|
21
42
|
name: string;
|
|
22
43
|
dirname: string;
|
|
23
44
|
}
|
|
24
45
|
declare function parseFilePath(path: string): FileInfo;
|
|
25
|
-
declare function parseFolderPath(path: string):
|
|
46
|
+
declare function parseFolderPath(path: string): FolderInfo;
|
|
26
47
|
|
|
27
48
|
interface LoadOptions {
|
|
28
49
|
transformers?: Transformer[];
|
|
@@ -102,7 +123,16 @@ interface LanguageEntry<Data = PageData> {
|
|
|
102
123
|
}
|
|
103
124
|
interface LoaderOutput<Config extends LoaderConfig> {
|
|
104
125
|
pageTree: Config['i18n'] extends true ? Record<string, Root> : Root;
|
|
105
|
-
getPageTree(locale?: string)
|
|
126
|
+
getPageTree: (locale?: string) => Root;
|
|
127
|
+
getPageByHref: (href: string, options?: {
|
|
128
|
+
/**
|
|
129
|
+
* resolve relative file paths in `href` from specified dirname, must be a virtual path.
|
|
130
|
+
*/
|
|
131
|
+
dir?: string;
|
|
132
|
+
}) => {
|
|
133
|
+
page: Page<Config['source']['pageData']>;
|
|
134
|
+
hash?: string;
|
|
135
|
+
} | undefined;
|
|
106
136
|
_i18n?: I18nConfig;
|
|
107
137
|
/**
|
|
108
138
|
* Get list of pages from language, empty if language hasn't specified
|
|
@@ -141,6 +171,7 @@ interface MetaData {
|
|
|
141
171
|
interface PageData {
|
|
142
172
|
icon?: string | undefined;
|
|
143
173
|
title?: string;
|
|
174
|
+
description?: string | undefined;
|
|
144
175
|
}
|
|
145
176
|
type InferPageType<Utils extends LoaderOutput<any>> = Utils extends LoaderOutput<infer Config> ? Page<Config['source']['pageData']> : never;
|
|
146
177
|
type InferMetaType<Utils extends LoaderOutput<any>> = Utils extends LoaderOutput<infer Config> ? Meta<Config['source']['metaData']> : never;
|
|
@@ -164,7 +195,7 @@ interface PageFile {
|
|
|
164
195
|
}
|
|
165
196
|
type File = MetaFile | PageFile;
|
|
166
197
|
interface Folder {
|
|
167
|
-
file:
|
|
198
|
+
file: FolderInfo;
|
|
168
199
|
children: (File | Folder)[];
|
|
169
200
|
}
|
|
170
201
|
/**
|
|
@@ -229,4 +260,4 @@ interface PageTreeBuilder {
|
|
|
229
260
|
}
|
|
230
261
|
declare function createPageTreeBuilder(): PageTreeBuilder;
|
|
231
262
|
|
|
232
|
-
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-QTVCCXFT.js";
|
|
6
6
|
import {
|
|
7
7
|
__export
|
|
8
8
|
} from "../chunk-MLKGABMK.js";
|
|
@@ -24,8 +24,14 @@ 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
|
-
|
|
27
|
+
if (isPageFile(node)) {
|
|
28
|
+
if (node.file.locale.length > 0 && node.file.locale.slice(1) !== ctx.defaultLanguage)
|
|
29
|
+
continue;
|
|
30
|
+
const localized = ctx.storage.read(
|
|
31
|
+
joinPath(node.file.dirname, `${node.file.name}.${ctx.lang}`),
|
|
32
|
+
"page"
|
|
33
|
+
);
|
|
34
|
+
const treeNode = buildFileNode(localized ?? node, ctx);
|
|
29
35
|
if (node.file.name === "index") {
|
|
30
36
|
if (!skipIndex) output.unshift(treeNode);
|
|
31
37
|
continue;
|
|
@@ -33,10 +39,11 @@ function buildAll(nodes, ctx, skipIndex) {
|
|
|
33
39
|
output.push(treeNode);
|
|
34
40
|
}
|
|
35
41
|
if ("children" in node) {
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
const folder = buildFolderNode(node, false, ctx);
|
|
43
|
+
if (folder.children.length === 0 && folder.index) {
|
|
44
|
+
output.push(folder.index);
|
|
38
45
|
} else {
|
|
39
|
-
folders.push(
|
|
46
|
+
folders.push(folder);
|
|
40
47
|
}
|
|
41
48
|
}
|
|
42
49
|
}
|
|
@@ -75,8 +82,11 @@ function resolveFolderItem(folder, item, ctx, idx, addedNodePaths) {
|
|
|
75
82
|
} else if (isExtract) {
|
|
76
83
|
filename = item.slice(extractPrefix.length);
|
|
77
84
|
}
|
|
78
|
-
const path =
|
|
79
|
-
|
|
85
|
+
const path = joinPath(folder.file.path, filename);
|
|
86
|
+
let itemNode = ctx.storage.readDir(path);
|
|
87
|
+
if (!itemNode) {
|
|
88
|
+
itemNode = (ctx.lang ? ctx.storage.read(`${path}.${ctx.lang}`, "page") : null) ?? ctx.storage.read(`${path}.${ctx.defaultLanguage}`, "page") ?? ctx.storage.read(path, "page");
|
|
89
|
+
}
|
|
80
90
|
if (!itemNode) return [];
|
|
81
91
|
addedNodePaths.add(itemNode.file.path);
|
|
82
92
|
if (isExcept) return [];
|
|
@@ -87,10 +97,10 @@ function resolveFolderItem(folder, item, ctx, idx, addedNodePaths) {
|
|
|
87
97
|
return [buildFileNode(itemNode, ctx)];
|
|
88
98
|
}
|
|
89
99
|
function buildFolderNode(folder, isGlobalRoot, ctx) {
|
|
90
|
-
const metaPath =
|
|
91
|
-
const meta =
|
|
100
|
+
const metaPath = joinPath(folder.file.path, "meta");
|
|
101
|
+
const meta = ctx.storage.read(`${metaPath}.${ctx.lang}`, "meta") ?? ctx.storage.read(`${metaPath}.${ctx.defaultLanguage}`, "meta") ?? ctx.storage.read(metaPath, "meta");
|
|
92
102
|
const indexFile = ctx.storage.read(
|
|
93
|
-
|
|
103
|
+
joinPath(folder.file.path, "index"),
|
|
94
104
|
"page"
|
|
95
105
|
);
|
|
96
106
|
const metadata = meta?.data;
|
|
@@ -137,15 +147,15 @@ function buildFolderNode(folder, isGlobalRoot, ctx) {
|
|
|
137
147
|
return ctx.options.attachFolder?.(node, folder, meta) ?? node;
|
|
138
148
|
}
|
|
139
149
|
function buildFileNode(file, ctx) {
|
|
140
|
-
const localized = findLocalizedFile(file.file.flattenedPath, "page", ctx) ?? file;
|
|
141
150
|
const item = {
|
|
142
|
-
$id:
|
|
151
|
+
$id: file.file.path,
|
|
143
152
|
type: "page",
|
|
144
|
-
name:
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
name: file.data.data.title ?? pathToName(file.file.name),
|
|
154
|
+
description: file.data.data.description,
|
|
155
|
+
icon: ctx.options.resolveIcon?.(file.data.data.icon),
|
|
156
|
+
url: ctx.options.getUrl(file.data.slugs, ctx.lang),
|
|
147
157
|
$ref: !ctx.options.noRef ? {
|
|
148
|
-
file:
|
|
158
|
+
file: file.file.path
|
|
149
159
|
} : void 0
|
|
150
160
|
};
|
|
151
161
|
return ctx.options.attachFile?.(item, file) ?? item;
|
|
@@ -174,7 +184,7 @@ function createPageTreeBuilder() {
|
|
|
174
184
|
options,
|
|
175
185
|
builder: this,
|
|
176
186
|
storage: options.storage,
|
|
177
|
-
i18n
|
|
187
|
+
defaultLanguage: i18n.defaultLanguage
|
|
178
188
|
});
|
|
179
189
|
return [lang, tree];
|
|
180
190
|
});
|
|
@@ -182,10 +192,6 @@ function createPageTreeBuilder() {
|
|
|
182
192
|
}
|
|
183
193
|
};
|
|
184
194
|
}
|
|
185
|
-
function findLocalizedFile(path, format, ctx) {
|
|
186
|
-
if (!ctx.lang) return;
|
|
187
|
-
return ctx.storage.read(`${path}.${ctx.lang}`, format);
|
|
188
|
-
}
|
|
189
195
|
function pathToName(name) {
|
|
190
196
|
const result = [];
|
|
191
197
|
for (const c of name) {
|
|
@@ -200,39 +206,40 @@ function pathToName(name) {
|
|
|
200
206
|
function parseFilePath(path) {
|
|
201
207
|
const segments = splitPath(slash(path));
|
|
202
208
|
const dirname = segments.slice(0, -1).join("/");
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
209
|
+
let name = segments.at(-1) ?? "";
|
|
210
|
+
let ext = "";
|
|
211
|
+
let locale = "";
|
|
212
|
+
let dotIdx = name.lastIndexOf(".");
|
|
213
|
+
if (dotIdx !== -1) {
|
|
214
|
+
ext = name.substring(dotIdx);
|
|
215
|
+
name = name.substring(0, dotIdx);
|
|
216
|
+
}
|
|
217
|
+
dotIdx = name.lastIndexOf(".");
|
|
218
|
+
if (dotIdx !== -1 && isLocale(name.substring(dotIdx))) {
|
|
219
|
+
locale = name.substring(dotIdx);
|
|
220
|
+
name = name.substring(0, dotIdx);
|
|
221
|
+
}
|
|
208
222
|
return {
|
|
209
223
|
dirname,
|
|
210
224
|
name,
|
|
211
|
-
flattenedPath,
|
|
212
225
|
locale,
|
|
213
|
-
path: segments.join("/")
|
|
226
|
+
path: segments.join("/"),
|
|
227
|
+
ext,
|
|
228
|
+
flattenedPath: [dirname, `${name}${locale}`].filter((p) => p.length > 0).join("/")
|
|
214
229
|
};
|
|
215
230
|
}
|
|
231
|
+
function isLocale(code) {
|
|
232
|
+
return code.length > 0 && !/\d+/.test(code);
|
|
233
|
+
}
|
|
216
234
|
function parseFolderPath(path) {
|
|
217
235
|
const segments = splitPath(slash(path));
|
|
218
236
|
const base = segments.at(-1) ?? "";
|
|
219
|
-
const [name, locale] = getLocale(base);
|
|
220
|
-
const flattenedPath = segments.join("/");
|
|
221
237
|
return {
|
|
222
238
|
dirname: segments.slice(0, -1).join("/"),
|
|
223
|
-
name,
|
|
224
|
-
|
|
225
|
-
locale,
|
|
226
|
-
path: flattenedPath
|
|
239
|
+
name: base,
|
|
240
|
+
path: segments.join("/")
|
|
227
241
|
};
|
|
228
242
|
}
|
|
229
|
-
function getLocale(name) {
|
|
230
|
-
const sep = name.lastIndexOf(".");
|
|
231
|
-
if (sep === -1) return [name];
|
|
232
|
-
const locale = name.slice(sep + 1);
|
|
233
|
-
if (/\d+/.exec(locale)) return [name];
|
|
234
|
-
return [name.slice(0, sep), locale];
|
|
235
|
-
}
|
|
236
243
|
function normalizePath(path) {
|
|
237
244
|
const segments = splitPath(slash(path));
|
|
238
245
|
if (segments[0] === "." || segments[0] === "..")
|
|
@@ -276,7 +283,13 @@ var Storage = class {
|
|
|
276
283
|
};
|
|
277
284
|
this.makeDir(node.file.dirname);
|
|
278
285
|
this.readDir(node.file.dirname)?.children.push(node);
|
|
279
|
-
this.files.set(
|
|
286
|
+
this.files.set(
|
|
287
|
+
joinPath(
|
|
288
|
+
node.file.dirname,
|
|
289
|
+
`${node.file.name}${node.file.locale}.${node.format}`
|
|
290
|
+
),
|
|
291
|
+
node
|
|
292
|
+
);
|
|
280
293
|
}
|
|
281
294
|
list() {
|
|
282
295
|
return [...this.files.values()];
|
|
@@ -334,17 +347,20 @@ function indexPages(storage, getUrl, i18n) {
|
|
|
334
347
|
if (item.format === "meta")
|
|
335
348
|
pathToFile.set(item.file.path, fileToMeta(item));
|
|
336
349
|
if (item.format === "page") {
|
|
337
|
-
|
|
350
|
+
if (item.file.locale.length > 0 && item.file.locale.slice(1) !== defaultLanguage)
|
|
351
|
+
continue;
|
|
352
|
+
const page = fileToPage(item, getUrl, defaultLanguage);
|
|
338
353
|
pathToFile.set(item.file.path, page);
|
|
339
|
-
if (item.file.locale) continue;
|
|
340
354
|
map.set(`${defaultLanguage}.${page.slugs.join("/")}`, page);
|
|
341
355
|
if (!i18n) continue;
|
|
356
|
+
const basePath = joinPath(item.file.dirname, item.file.name);
|
|
342
357
|
for (const lang of i18n.languages) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
"page"
|
|
358
|
+
if (lang === defaultLanguage) continue;
|
|
359
|
+
const localizedPage = fileToPage(
|
|
360
|
+
storage.read(`${basePath}.${lang}`, "page") ?? item,
|
|
361
|
+
getUrl,
|
|
362
|
+
lang
|
|
346
363
|
);
|
|
347
|
-
const localizedPage = fileToPage(localized ?? item, getUrl, lang);
|
|
348
364
|
map.set(`${lang}.${localizedPage.slugs.join("/")}`, localizedPage);
|
|
349
365
|
}
|
|
350
366
|
}
|
|
@@ -355,6 +371,7 @@ function indexPages(storage, getUrl, i18n) {
|
|
|
355
371
|
};
|
|
356
372
|
}
|
|
357
373
|
function createGetUrl(baseUrl, i18n) {
|
|
374
|
+
const baseSlugs = baseUrl.split("/");
|
|
358
375
|
return (slugs, locale) => {
|
|
359
376
|
const hideLocale = i18n?.hideLocale ?? "never";
|
|
360
377
|
let urlLocale;
|
|
@@ -363,7 +380,8 @@ function createGetUrl(baseUrl, i18n) {
|
|
|
363
380
|
} else if (hideLocale === "default-locale" && locale !== i18n?.defaultLanguage) {
|
|
364
381
|
urlLocale = locale;
|
|
365
382
|
}
|
|
366
|
-
const paths =
|
|
383
|
+
const paths = [...baseSlugs, ...slugs];
|
|
384
|
+
if (urlLocale) paths.unshift(urlLocale);
|
|
367
385
|
return `/${paths.filter((v) => v.length > 0).join("/")}`;
|
|
368
386
|
};
|
|
369
387
|
}
|
|
@@ -395,21 +413,50 @@ function createOutput(options) {
|
|
|
395
413
|
);
|
|
396
414
|
const walker = indexPages(storage, getUrl, options.i18n);
|
|
397
415
|
const builder = createPageTreeBuilder();
|
|
398
|
-
|
|
399
|
-
storage,
|
|
400
|
-
resolveIcon: options.icon,
|
|
401
|
-
getUrl,
|
|
402
|
-
...options.pageTree
|
|
403
|
-
}) : builder.buildI18n({
|
|
404
|
-
storage,
|
|
405
|
-
resolveIcon: options.icon,
|
|
406
|
-
getUrl,
|
|
407
|
-
i18n: options.i18n,
|
|
408
|
-
...options.pageTree
|
|
409
|
-
});
|
|
416
|
+
let pageTree;
|
|
410
417
|
return {
|
|
411
418
|
_i18n: options.i18n,
|
|
412
|
-
pageTree
|
|
419
|
+
get pageTree() {
|
|
420
|
+
if (options.i18n) {
|
|
421
|
+
pageTree ??= builder.buildI18n({
|
|
422
|
+
storage,
|
|
423
|
+
resolveIcon: options.icon,
|
|
424
|
+
getUrl,
|
|
425
|
+
i18n: options.i18n,
|
|
426
|
+
...options.pageTree
|
|
427
|
+
});
|
|
428
|
+
} else {
|
|
429
|
+
pageTree ??= builder.build({
|
|
430
|
+
storage,
|
|
431
|
+
resolveIcon: options.icon,
|
|
432
|
+
getUrl,
|
|
433
|
+
...options.pageTree
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
return pageTree;
|
|
437
|
+
},
|
|
438
|
+
set pageTree(v) {
|
|
439
|
+
pageTree = v;
|
|
440
|
+
},
|
|
441
|
+
getPageByHref(href, { dir = "" } = {}) {
|
|
442
|
+
const pages = Array.from(walker.pages.values());
|
|
443
|
+
const [value, hash] = href.split("#", 2);
|
|
444
|
+
if (value.startsWith(".") && (value.endsWith(".md") || value.endsWith(".mdx"))) {
|
|
445
|
+
const hrefPath = joinPath(dir, value);
|
|
446
|
+
const target2 = pages.find((item) => item.file.path === hrefPath);
|
|
447
|
+
if (target2)
|
|
448
|
+
return {
|
|
449
|
+
page: target2,
|
|
450
|
+
hash
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
const target = pages.find((item) => item.url === value);
|
|
454
|
+
if (target)
|
|
455
|
+
return {
|
|
456
|
+
page: target,
|
|
457
|
+
hash
|
|
458
|
+
};
|
|
459
|
+
},
|
|
413
460
|
getPages(language = options.i18n?.defaultLanguage ?? "") {
|
|
414
461
|
const pages = [];
|
|
415
462
|
for (const key of walker.pages.keys()) {
|
|
@@ -437,9 +484,9 @@ function createOutput(options) {
|
|
|
437
484
|
},
|
|
438
485
|
getPageTree(locale) {
|
|
439
486
|
if (options.i18n) {
|
|
440
|
-
return pageTree[locale ?? options.i18n.defaultLanguage];
|
|
487
|
+
return this.pageTree[locale ?? options.i18n.defaultLanguage];
|
|
441
488
|
}
|
|
442
|
-
return pageTree;
|
|
489
|
+
return this.pageTree;
|
|
443
490
|
},
|
|
444
491
|
getNodePage(node) {
|
|
445
492
|
const ref = node.$ref?.file ?? node.$id;
|
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.
|
|
3
|
+
"version": "15.1.1",
|
|
4
4
|
"description": "The library for building a documentation website in Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NextJs",
|
|
@@ -114,12 +114,12 @@
|
|
|
114
114
|
"@types/mdast": "^4.0.3",
|
|
115
115
|
"@types/negotiator": "^0.6.3",
|
|
116
116
|
"@types/node": "22.13.10",
|
|
117
|
-
"@types/react": "^19.0.
|
|
117
|
+
"@types/react": "^19.0.11",
|
|
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",
|