fumadocs-core 15.3.4 → 15.4.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/{algolia-NTWLS6J3.js → algolia-RQ5VQJAB.js} +17 -17
- package/dist/content/index.d.ts +16 -0
- package/dist/content/index.js +30 -0
- package/dist/highlight/client.d.ts +5 -2
- package/dist/highlight/client.js +8 -13
- package/dist/search/algolia.d.ts +11 -5
- package/dist/search/algolia.js +28 -16
- package/dist/search/client.d.ts +10 -5
- package/dist/search/client.js +2 -3
- package/dist/server/index.js +2 -2
- package/dist/source/index.d.ts +1 -0
- package/dist/source/index.js +94 -79
- package/package.json +11 -8
|
@@ -23,25 +23,25 @@ function groupResults(hits) {
|
|
|
23
23
|
}
|
|
24
24
|
return grouped;
|
|
25
25
|
}
|
|
26
|
-
async function searchDocs(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
async function searchDocs(query, tag, locale, { indexName, onSearch, client }) {
|
|
27
|
+
if (query.length > 0) {
|
|
28
|
+
const result = onSearch ? await onSearch(query, tag, locale) : await client.searchForHits({
|
|
29
|
+
requests: [
|
|
30
|
+
{
|
|
31
|
+
type: "default",
|
|
32
|
+
indexName,
|
|
33
|
+
query,
|
|
34
|
+
distinct: 5,
|
|
35
|
+
hitsPerPage: 10,
|
|
36
|
+
filters: tag ? `tag:${tag}` : void 0
|
|
37
|
+
}
|
|
38
|
+
]
|
|
35
39
|
});
|
|
36
|
-
return groupResults(
|
|
40
|
+
return groupResults(result.results[0].hits).filter(
|
|
41
|
+
(hit) => hit.type === "page"
|
|
42
|
+
);
|
|
37
43
|
}
|
|
38
|
-
|
|
39
|
-
distinct: 5,
|
|
40
|
-
hitsPerPage: 10,
|
|
41
|
-
...options,
|
|
42
|
-
filters
|
|
43
|
-
});
|
|
44
|
-
return groupResults(result.hits);
|
|
44
|
+
return [];
|
|
45
45
|
}
|
|
46
46
|
export {
|
|
47
47
|
groupResults,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { VFile } from 'vfile';
|
|
4
|
+
import { Components } from 'hast-util-to-jsx-runtime';
|
|
5
|
+
import { PluggableList } from 'unified';
|
|
6
|
+
|
|
7
|
+
interface MarkdownProps {
|
|
8
|
+
components?: Components;
|
|
9
|
+
}
|
|
10
|
+
declare function Markdown({ children: content, remarkPlugins, rehypePlugins, ...options }: MarkdownProps & {
|
|
11
|
+
remarkPlugins?: PluggableList;
|
|
12
|
+
rehypePlugins?: PluggableList;
|
|
13
|
+
children: string | VFile;
|
|
14
|
+
}): Promise<react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | (string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined)>;
|
|
15
|
+
|
|
16
|
+
export { Markdown };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "../chunk-MLKGABMK.js";
|
|
2
|
+
|
|
3
|
+
// src/content/index.ts
|
|
4
|
+
import { remark } from "remark";
|
|
5
|
+
import remarkGfm from "remark-gfm";
|
|
6
|
+
import remarkRehype from "remark-rehype";
|
|
7
|
+
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
|
|
8
|
+
import * as JsxRuntime from "react/jsx-runtime";
|
|
9
|
+
function rehypeReact(options = {}) {
|
|
10
|
+
this.compiler = (tree, file) => {
|
|
11
|
+
return toJsxRuntime(tree, {
|
|
12
|
+
development: false,
|
|
13
|
+
filePath: file.path,
|
|
14
|
+
...JsxRuntime,
|
|
15
|
+
...options
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
async function Markdown({
|
|
20
|
+
children: content,
|
|
21
|
+
remarkPlugins = [],
|
|
22
|
+
rehypePlugins = [],
|
|
23
|
+
...options
|
|
24
|
+
}) {
|
|
25
|
+
const processor = remark().use(remarkGfm).use(remarkPlugins).use(remarkRehype).use(rehypePlugins).use(rehypeReact, options);
|
|
26
|
+
return (await processor.process(content)).result;
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
Markdown
|
|
30
|
+
};
|
|
@@ -4,9 +4,12 @@ import 'shiki';
|
|
|
4
4
|
import 'shiki/themes';
|
|
5
5
|
import 'hast-util-to-jsx-runtime';
|
|
6
6
|
|
|
7
|
-
declare function useShiki(code: string, {
|
|
7
|
+
declare function useShiki(code: string, { withPrerenderScript, loading, ...options }: HighlightOptions & {
|
|
8
8
|
withPrerenderScript?: boolean;
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Displayed before highlighter is loaded.
|
|
11
|
+
*/
|
|
12
|
+
loading?: ReactNode;
|
|
10
13
|
}, deps?: DependencyList): ReactNode;
|
|
11
14
|
|
|
12
15
|
export { useShiki };
|
package/dist/highlight/client.js
CHANGED
|
@@ -8,30 +8,28 @@ import "../chunk-MLKGABMK.js";
|
|
|
8
8
|
|
|
9
9
|
// src/highlight/client.tsx
|
|
10
10
|
import {
|
|
11
|
+
use,
|
|
11
12
|
useId,
|
|
13
|
+
useLayoutEffect,
|
|
12
14
|
useMemo,
|
|
13
15
|
useRef,
|
|
14
|
-
|
|
15
|
-
useState,
|
|
16
|
-
useLayoutEffect
|
|
16
|
+
useState
|
|
17
17
|
} from "react";
|
|
18
18
|
import { jsx } from "react/jsx-runtime";
|
|
19
19
|
var jsEngine;
|
|
20
20
|
function getHighlightOptions(from) {
|
|
21
21
|
if (from.engine) return from;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
);
|
|
26
|
-
}
|
|
22
|
+
jsEngine ??= import("shiki/engine/javascript").then(
|
|
23
|
+
(res) => res.createJavaScriptRegexEngine()
|
|
24
|
+
);
|
|
27
25
|
return {
|
|
28
26
|
...from,
|
|
29
27
|
engine: jsEngine
|
|
30
28
|
};
|
|
31
29
|
}
|
|
32
30
|
function useShiki(code, {
|
|
33
|
-
defaultValue,
|
|
34
31
|
withPrerenderScript = false,
|
|
32
|
+
loading,
|
|
35
33
|
...options
|
|
36
34
|
}, deps) {
|
|
37
35
|
const markupId = useId();
|
|
@@ -45,7 +43,6 @@ function useShiki(code, {
|
|
|
45
43
|
aborted: false
|
|
46
44
|
});
|
|
47
45
|
const [rendered, setRendered] = useState(() => {
|
|
48
|
-
if (defaultValue) return defaultValue;
|
|
49
46
|
const element = withPrerenderScript && typeof document !== "undefined" ? document.querySelector(`[data-markup-id="${markupId}"]`) : null;
|
|
50
47
|
const attr = element?.getAttribute("data-markup");
|
|
51
48
|
if (attr) {
|
|
@@ -53,9 +50,7 @@ function useShiki(code, {
|
|
|
53
50
|
return renderHighlightWithMarkup(markupId, hast, shikiOptions, attr);
|
|
54
51
|
}
|
|
55
52
|
currentTask.current = void 0;
|
|
56
|
-
|
|
57
|
-
const Code = options.components?.code ?? "code";
|
|
58
|
-
return /* @__PURE__ */ jsx(Pre, { children: /* @__PURE__ */ jsx(Code, { children: code }) });
|
|
53
|
+
return loading;
|
|
59
54
|
});
|
|
60
55
|
useLayoutEffect(() => {
|
|
61
56
|
if (currentTask.current?.key === key) return;
|
package/dist/search/algolia.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Algoliasearch } from 'algoliasearch';
|
|
2
2
|
import { S as StructuredData } from '../remark-structure-DVje0Sib.js';
|
|
3
3
|
import 'mdast';
|
|
4
4
|
import 'unified';
|
|
@@ -27,9 +27,15 @@ interface DocumentRecord {
|
|
|
27
27
|
}
|
|
28
28
|
interface SyncOptions {
|
|
29
29
|
/**
|
|
30
|
-
* Index Name for documents
|
|
30
|
+
* Index Name for documents.
|
|
31
|
+
*
|
|
32
|
+
* @deprecated Use `indexName` instead
|
|
31
33
|
*/
|
|
32
34
|
document?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Index Name for documents.
|
|
37
|
+
*/
|
|
38
|
+
indexName?: string;
|
|
33
39
|
/**
|
|
34
40
|
* Search indexes
|
|
35
41
|
*/
|
|
@@ -41,9 +47,9 @@ interface SyncOptions {
|
|
|
41
47
|
* @param client - Algolia Admin Client
|
|
42
48
|
* @param options - Index Options
|
|
43
49
|
*/
|
|
44
|
-
declare function sync(client:
|
|
45
|
-
declare function setIndexSettings(
|
|
46
|
-
declare function updateDocuments(
|
|
50
|
+
declare function sync(client: Algoliasearch, options: SyncOptions): Promise<void>;
|
|
51
|
+
declare function setIndexSettings(client: Algoliasearch, indexName: string): Promise<void>;
|
|
52
|
+
declare function updateDocuments(client: Algoliasearch, indexName: string, documents: DocumentRecord[]): Promise<void>;
|
|
47
53
|
interface BaseIndex {
|
|
48
54
|
objectID: string;
|
|
49
55
|
title: string;
|
package/dist/search/algolia.js
CHANGED
|
@@ -2,18 +2,26 @@ import "../chunk-MLKGABMK.js";
|
|
|
2
2
|
|
|
3
3
|
// src/search/algolia.ts
|
|
4
4
|
async function sync(client, options) {
|
|
5
|
-
const { document = "document", documents } = options;
|
|
6
|
-
|
|
7
|
-
await
|
|
8
|
-
await updateDocuments(index, documents);
|
|
5
|
+
const { document = "document", indexName = document, documents } = options;
|
|
6
|
+
await setIndexSettings(client, indexName);
|
|
7
|
+
await updateDocuments(client, indexName, documents);
|
|
9
8
|
}
|
|
10
|
-
async function setIndexSettings(
|
|
11
|
-
await
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
async function setIndexSettings(client, indexName) {
|
|
10
|
+
await client.setSettings({
|
|
11
|
+
indexName,
|
|
12
|
+
indexSettings: {
|
|
13
|
+
attributeForDistinct: "page_id",
|
|
14
|
+
attributesToRetrieve: [
|
|
15
|
+
"title",
|
|
16
|
+
"section",
|
|
17
|
+
"content",
|
|
18
|
+
"url",
|
|
19
|
+
"section_id"
|
|
20
|
+
],
|
|
21
|
+
searchableAttributes: ["title", "section", "content"],
|
|
22
|
+
attributesToSnippet: [],
|
|
23
|
+
attributesForFaceting: ["tag"]
|
|
24
|
+
}
|
|
17
25
|
});
|
|
18
26
|
}
|
|
19
27
|
function toIndex(page) {
|
|
@@ -35,20 +43,24 @@ function toIndex(page) {
|
|
|
35
43
|
}
|
|
36
44
|
if (page.description)
|
|
37
45
|
indexes.push(createIndex(void 0, void 0, page.description));
|
|
38
|
-
page.structured
|
|
39
|
-
|
|
46
|
+
const { headings, contents } = page.structured;
|
|
47
|
+
for (const p of contents) {
|
|
48
|
+
const heading = p.heading ? headings.find((h) => p.heading === h.id) : null;
|
|
40
49
|
const index = createIndex(heading?.content, heading?.id, p.content);
|
|
41
50
|
if (heading && !scannedHeadings.has(heading.id)) {
|
|
42
51
|
scannedHeadings.add(heading.id);
|
|
43
52
|
indexes.push(createIndex(heading.content, heading.id, heading.content));
|
|
44
53
|
}
|
|
45
54
|
indexes.push(index);
|
|
46
|
-
}
|
|
55
|
+
}
|
|
47
56
|
return indexes;
|
|
48
57
|
}
|
|
49
|
-
async function updateDocuments(
|
|
58
|
+
async function updateDocuments(client, indexName, documents) {
|
|
50
59
|
const objects = documents.flatMap(toIndex);
|
|
51
|
-
await
|
|
60
|
+
await client.replaceAllObjects({
|
|
61
|
+
indexName,
|
|
62
|
+
objects
|
|
63
|
+
});
|
|
52
64
|
}
|
|
53
65
|
export {
|
|
54
66
|
setIndexSettings,
|
package/dist/search/client.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { S as SortedResult } from '../types-Ch8gnVgO.js';
|
|
2
2
|
import { AnyOrama } from '@orama/orama';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import '../remark-structure-DVje0Sib.js';
|
|
3
|
+
import { BaseIndex } from './algolia.js';
|
|
4
|
+
import { LiteClient, SearchResponse } from 'algoliasearch/lite';
|
|
6
5
|
import { OramaClient, ClientSearchParams } from '@oramacloud/client';
|
|
6
|
+
import 'algoliasearch';
|
|
7
|
+
import '../remark-structure-DVje0Sib.js';
|
|
7
8
|
import 'mdast';
|
|
8
9
|
import 'unified';
|
|
9
10
|
import 'mdast-util-mdx-jsx';
|
|
@@ -23,8 +24,12 @@ interface StaticOptions {
|
|
|
23
24
|
initOrama?: (locale?: string) => AnyOrama | Promise<AnyOrama>;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
interface AlgoliaOptions
|
|
27
|
-
|
|
27
|
+
interface AlgoliaOptions {
|
|
28
|
+
indexName: string;
|
|
29
|
+
client: LiteClient;
|
|
30
|
+
onSearch?: (query: string, tag?: string, locale?: string) => Promise<{
|
|
31
|
+
results: SearchResponse<BaseIndex>[];
|
|
32
|
+
}>;
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
interface OramaCloudOptions {
|
package/dist/search/client.js
CHANGED
|
@@ -48,9 +48,8 @@ function useDocsSearch(client, locale, tag, delayMs = 100, allowEmpty = false, k
|
|
|
48
48
|
return fetchDocs(debouncedValue, locale, tag, client);
|
|
49
49
|
}
|
|
50
50
|
if (client.type === "algolia") {
|
|
51
|
-
const {
|
|
52
|
-
|
|
53
|
-
return searchDocs(index, debouncedValue, tag, rest);
|
|
51
|
+
const { searchDocs } = await import("../algolia-RQ5VQJAB.js");
|
|
52
|
+
return searchDocs(debouncedValue, tag, locale, client);
|
|
54
53
|
}
|
|
55
54
|
if (client.type === "orama-cloud") {
|
|
56
55
|
const { searchDocs } = await import("../orama-cloud-USLSOSXS.js");
|
package/dist/server/index.js
CHANGED
|
@@ -32,8 +32,8 @@ function flattenTree(tree) {
|
|
|
32
32
|
function findNeighbour(tree, url, options) {
|
|
33
33
|
const { separateRoot = true } = options ?? {};
|
|
34
34
|
const roots = separateRoot ? getPageTreeRoots(tree) : [tree];
|
|
35
|
-
const
|
|
36
|
-
|
|
35
|
+
for (const root of roots) {
|
|
36
|
+
const list = flattenTree(root.children);
|
|
37
37
|
for (let i = 0; i < list.length; i++) {
|
|
38
38
|
if (list[i].url === url) {
|
|
39
39
|
return {
|
package/dist/source/index.d.ts
CHANGED
|
@@ -119,6 +119,7 @@ interface LoaderOutput<Config extends LoaderConfig> {
|
|
|
119
119
|
pageTree: Config['i18n'] extends true ? Record<string, Root> : Root;
|
|
120
120
|
getPageTree: (locale?: string) => Root;
|
|
121
121
|
getPageByHref: (href: string, options?: {
|
|
122
|
+
language?: string;
|
|
122
123
|
/**
|
|
123
124
|
* resolve relative file paths in `href` from specified dirname, must be a virtual path.
|
|
124
125
|
*/
|
package/dist/source/index.js
CHANGED
|
@@ -18,42 +18,46 @@ var excludePrefix = "!";
|
|
|
18
18
|
function isPageFile(node) {
|
|
19
19
|
return "data" in node && node.format === "page";
|
|
20
20
|
}
|
|
21
|
-
function buildAll(nodes, ctx,
|
|
21
|
+
function buildAll(nodes, ctx, filter, reversed = false) {
|
|
22
|
+
const { localeStorage } = ctx;
|
|
22
23
|
const output = [];
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
(a
|
|
26
|
-
|
|
24
|
+
for (const node of [...nodes].sort((a, b) => {
|
|
25
|
+
let result;
|
|
26
|
+
if (isPageFile(a) && "children" in b) result = -1;
|
|
27
|
+
else if ("children" in a && isPageFile(b)) result = 1;
|
|
28
|
+
else result = a.file.name.localeCompare(b.file.name);
|
|
29
|
+
return reversed ? result * -1 : result;
|
|
30
|
+
})) {
|
|
31
|
+
if (filter && !filter(node)) continue;
|
|
27
32
|
if (isPageFile(node)) {
|
|
28
|
-
const localized =
|
|
33
|
+
const localized = localeStorage?.read(
|
|
29
34
|
joinPath(node.file.dirname, node.file.name),
|
|
30
35
|
"page"
|
|
31
36
|
);
|
|
32
37
|
const treeNode = buildFileNode(localized ?? node, ctx);
|
|
33
38
|
if (node.file.name === "index") {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
output.push(treeNode);
|
|
39
|
+
output.unshift(treeNode);
|
|
40
|
+
continue;
|
|
37
41
|
}
|
|
38
|
-
|
|
39
|
-
if ("children" in node) {
|
|
40
|
-
|
|
42
|
+
output.push(treeNode);
|
|
43
|
+
} else if ("children" in node) {
|
|
44
|
+
output.push(buildFolderNode(node, false, ctx));
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
|
-
output.push(...folders);
|
|
44
47
|
return output;
|
|
45
48
|
}
|
|
46
49
|
function resolveFolderItem(folder, item, ctx, idx, addedNodePaths) {
|
|
47
50
|
if (item === rest || item === restReversed) return item;
|
|
51
|
+
const { options, storage, localeStorage } = ctx;
|
|
48
52
|
let match = separator.exec(item);
|
|
49
53
|
if (match?.groups) {
|
|
50
54
|
const node = {
|
|
51
55
|
$id: `${folder.file.path}#${idx}`,
|
|
52
56
|
type: "separator",
|
|
53
|
-
icon:
|
|
57
|
+
icon: options.resolveIcon?.(match.groups.icon),
|
|
54
58
|
name: match.groups.name
|
|
55
59
|
};
|
|
56
|
-
return [
|
|
60
|
+
return [options.attachSeparator?.(node) ?? node];
|
|
57
61
|
}
|
|
58
62
|
match = link.exec(item);
|
|
59
63
|
if (match?.groups) {
|
|
@@ -61,14 +65,15 @@ function resolveFolderItem(folder, item, ctx, idx, addedNodePaths) {
|
|
|
61
65
|
const isRelative = url.startsWith("/") || url.startsWith("#") || url.startsWith(".");
|
|
62
66
|
const node = {
|
|
63
67
|
type: "page",
|
|
64
|
-
icon:
|
|
68
|
+
icon: options.resolveIcon?.(icon),
|
|
65
69
|
name,
|
|
66
70
|
url,
|
|
67
71
|
external: !isRelative
|
|
68
72
|
};
|
|
69
|
-
return [
|
|
73
|
+
return [options.attachFile?.(node) ?? node];
|
|
70
74
|
}
|
|
71
|
-
const isExcept = item.startsWith(excludePrefix)
|
|
75
|
+
const isExcept = item.startsWith(excludePrefix);
|
|
76
|
+
const isExtract = !isExcept && item.startsWith(extractPrefix);
|
|
72
77
|
let filename = item;
|
|
73
78
|
if (isExcept) {
|
|
74
79
|
filename = item.slice(excludePrefix.length);
|
|
@@ -76,7 +81,7 @@ function resolveFolderItem(folder, item, ctx, idx, addedNodePaths) {
|
|
|
76
81
|
filename = item.slice(extractPrefix.length);
|
|
77
82
|
}
|
|
78
83
|
const path = joinPath(folder.file.path, filename);
|
|
79
|
-
const itemNode =
|
|
84
|
+
const itemNode = storage.readDir(path) ?? localeStorage?.read(path, "page") ?? storage.read(path, "page");
|
|
80
85
|
if (!itemNode) return [];
|
|
81
86
|
addedNodePaths.add(itemNode.file.path);
|
|
82
87
|
if (isExcept) return [];
|
|
@@ -87,71 +92,81 @@ function resolveFolderItem(folder, item, ctx, idx, addedNodePaths) {
|
|
|
87
92
|
return [buildFileNode(itemNode, ctx)];
|
|
88
93
|
}
|
|
89
94
|
function buildFolderNode(folder, isGlobalRoot, ctx) {
|
|
95
|
+
const { storage, localeStorage, options } = ctx;
|
|
90
96
|
const metaPath = joinPath(folder.file.path, "meta");
|
|
91
|
-
const meta =
|
|
97
|
+
const meta = localeStorage?.read(metaPath, "meta") ?? storage.read(metaPath, "meta");
|
|
92
98
|
const indexPath = joinPath(folder.file.path, "index");
|
|
93
|
-
const indexFile =
|
|
99
|
+
const indexFile = localeStorage?.read(indexPath, "page") ?? storage.read(indexPath, "page");
|
|
94
100
|
const isRoot = meta?.data.root ?? isGlobalRoot;
|
|
95
|
-
|
|
96
|
-
const addedNodePaths = /* @__PURE__ */ new Set();
|
|
101
|
+
let index;
|
|
97
102
|
let children;
|
|
98
103
|
if (!meta?.data.pages) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return resolveFolderItem(folder, item, ctx, i, addedNodePaths);
|
|
104
|
+
if (indexFile) index = buildFileNode(indexFile, ctx);
|
|
105
|
+
children = buildAll(folder.children, ctx, (node2) => {
|
|
106
|
+
return node2.file.name !== "index" || isRoot;
|
|
103
107
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
} else {
|
|
109
|
+
const addedNodePaths = /* @__PURE__ */ new Set();
|
|
110
|
+
const resolved = meta.data.pages.flatMap((item, i) => resolveFolderItem(folder, item, ctx, i, addedNodePaths));
|
|
111
|
+
if (indexFile && (isRoot || !addedNodePaths.has(indexFile.file.path))) {
|
|
112
|
+
index = buildFileNode(indexFile, ctx);
|
|
113
|
+
}
|
|
114
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
115
|
+
if (resolved[i] === rest || resolved[i] === restReversed) {
|
|
116
|
+
resolved.splice(
|
|
117
|
+
i,
|
|
118
|
+
1,
|
|
119
|
+
...buildAll(
|
|
120
|
+
folder.children,
|
|
121
|
+
ctx,
|
|
122
|
+
(node2) => {
|
|
123
|
+
if (node2.file.name === "index" && !isRoot) return false;
|
|
124
|
+
return !addedNodePaths.has(node2.file.path);
|
|
125
|
+
},
|
|
126
|
+
resolved[i] === restReversed
|
|
127
|
+
)
|
|
128
|
+
);
|
|
129
|
+
break;
|
|
114
130
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
children = nodes ?? restNodes;
|
|
131
|
+
}
|
|
132
|
+
children = resolved;
|
|
118
133
|
}
|
|
119
134
|
const node = {
|
|
120
135
|
type: "folder",
|
|
121
136
|
name: meta?.data.title ?? index?.name ?? // resolve folder groups like (group_name)
|
|
122
137
|
pathToName(group.exec(folder.file.name)?.[1] ?? folder.file.name),
|
|
123
|
-
icon:
|
|
138
|
+
icon: options.resolveIcon?.(meta?.data.icon) ?? index?.icon,
|
|
124
139
|
root: meta?.data.root,
|
|
125
140
|
defaultOpen: meta?.data.defaultOpen,
|
|
126
141
|
description: meta?.data.description,
|
|
127
|
-
index
|
|
142
|
+
index,
|
|
128
143
|
children,
|
|
129
144
|
$id: folder.file.path,
|
|
130
|
-
$ref: !
|
|
145
|
+
$ref: !options.noRef ? {
|
|
131
146
|
metaFile: meta?.file.path
|
|
132
147
|
} : void 0
|
|
133
148
|
};
|
|
134
|
-
return
|
|
149
|
+
return options.attachFolder?.(node, folder, meta) ?? node;
|
|
135
150
|
}
|
|
136
|
-
function buildFileNode(file,
|
|
151
|
+
function buildFileNode(file, { options, getUrl, locale }) {
|
|
137
152
|
const item = {
|
|
138
153
|
$id: file.file.path,
|
|
139
154
|
type: "page",
|
|
140
155
|
name: file.data.data.title ?? pathToName(file.file.name),
|
|
141
156
|
description: file.data.data.description,
|
|
142
|
-
icon:
|
|
143
|
-
url:
|
|
144
|
-
$ref: !
|
|
157
|
+
icon: options.resolveIcon?.(file.data.data.icon),
|
|
158
|
+
url: getUrl(file.data.slugs, locale),
|
|
159
|
+
$ref: !options.noRef ? {
|
|
145
160
|
file: file.file.path
|
|
146
161
|
} : void 0
|
|
147
162
|
};
|
|
148
|
-
return
|
|
163
|
+
return options.attachFile?.(item, file) ?? item;
|
|
149
164
|
}
|
|
150
165
|
function build(ctx) {
|
|
151
166
|
const root = ctx.storage.root();
|
|
152
167
|
const folder = buildFolderNode(root, true, ctx);
|
|
153
168
|
return {
|
|
154
|
-
$id: ctx.locale
|
|
169
|
+
$id: ctx.locale ?? "root",
|
|
155
170
|
name: folder.name,
|
|
156
171
|
children: folder.children
|
|
157
172
|
};
|
|
@@ -208,7 +223,9 @@ function parseFilePath(path) {
|
|
|
208
223
|
name,
|
|
209
224
|
path: segments.join("/"),
|
|
210
225
|
ext,
|
|
211
|
-
flattenedPath
|
|
226
|
+
get flattenedPath() {
|
|
227
|
+
return [dirname, name].filter((p) => p.length > 0).join("/");
|
|
228
|
+
}
|
|
212
229
|
};
|
|
213
230
|
}
|
|
214
231
|
function parseFolderPath(path) {
|
|
@@ -269,7 +286,7 @@ var Storage = class {
|
|
|
269
286
|
);
|
|
270
287
|
}
|
|
271
288
|
list() {
|
|
272
|
-
return
|
|
289
|
+
return Array.from(this.files.values());
|
|
273
290
|
}
|
|
274
291
|
makeDir(path) {
|
|
275
292
|
const segments = splitPath(path);
|
|
@@ -414,13 +431,14 @@ function createOutput(options) {
|
|
|
414
431
|
if (!options.url && !options.baseUrl) {
|
|
415
432
|
console.warn("`loader()` now requires a `baseUrl` option to be defined.");
|
|
416
433
|
}
|
|
417
|
-
const { source, slugs: slugsFn = getSlugs } = options;
|
|
434
|
+
const { source, slugs: slugsFn = getSlugs, i18n } = options;
|
|
435
|
+
const defaultLanguage = i18n?.defaultLanguage ?? "";
|
|
418
436
|
const getUrl = options.url ?? createGetUrl(options.baseUrl ?? "/", options.i18n);
|
|
419
437
|
const files = typeof source.files === "function" ? source.files() : source.files;
|
|
420
|
-
const storages =
|
|
438
|
+
const storages = i18n ? loadFilesI18n(files, {
|
|
421
439
|
i18n: {
|
|
422
|
-
...
|
|
423
|
-
parser:
|
|
440
|
+
...i18n,
|
|
441
|
+
parser: i18n.parser ?? "dot"
|
|
424
442
|
},
|
|
425
443
|
transformers: options.transformers,
|
|
426
444
|
getSlugs: slugsFn
|
|
@@ -430,17 +448,17 @@ function createOutput(options) {
|
|
|
430
448
|
getSlugs: slugsFn
|
|
431
449
|
})
|
|
432
450
|
};
|
|
433
|
-
const walker = indexPages(storages, getUrl,
|
|
451
|
+
const walker = indexPages(storages, getUrl, i18n);
|
|
434
452
|
const builder = createPageTreeBuilder(getUrl);
|
|
435
453
|
let pageTree;
|
|
436
454
|
return {
|
|
437
|
-
_i18n:
|
|
455
|
+
_i18n: i18n,
|
|
438
456
|
get pageTree() {
|
|
439
|
-
if (
|
|
457
|
+
if (i18n) {
|
|
440
458
|
pageTree ??= builder.buildI18n({
|
|
441
459
|
storages,
|
|
442
460
|
resolveIcon: options.icon,
|
|
443
|
-
i18n
|
|
461
|
+
i18n,
|
|
444
462
|
...options.pageTree
|
|
445
463
|
});
|
|
446
464
|
} else {
|
|
@@ -455,26 +473,23 @@ function createOutput(options) {
|
|
|
455
473
|
set pageTree(v) {
|
|
456
474
|
pageTree = v;
|
|
457
475
|
},
|
|
458
|
-
getPageByHref(href, { dir = "" } = {}) {
|
|
459
|
-
const pages =
|
|
476
|
+
getPageByHref(href, { dir = "", language } = {}) {
|
|
477
|
+
const pages = this.getPages(language);
|
|
460
478
|
const [value, hash] = href.split("#", 2);
|
|
479
|
+
let target;
|
|
461
480
|
if (value.startsWith(".") && (value.endsWith(".md") || value.endsWith(".mdx"))) {
|
|
462
481
|
const hrefPath = joinPath(dir, value);
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
page: target2,
|
|
467
|
-
hash
|
|
468
|
-
};
|
|
482
|
+
target = pages.find((item) => item.file.path === hrefPath);
|
|
483
|
+
} else {
|
|
484
|
+
target = pages.find((item) => item.url === value);
|
|
469
485
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
};
|
|
486
|
+
if (!target) return;
|
|
487
|
+
return {
|
|
488
|
+
page: target,
|
|
489
|
+
hash
|
|
490
|
+
};
|
|
476
491
|
},
|
|
477
|
-
getPages(language =
|
|
492
|
+
getPages(language = defaultLanguage) {
|
|
478
493
|
const pages = [];
|
|
479
494
|
for (const key of walker.pages.keys()) {
|
|
480
495
|
if (key.startsWith(`${language}.`)) pages.push(walker.pages.get(key));
|
|
@@ -492,16 +507,16 @@ function createOutput(options) {
|
|
|
492
507
|
}
|
|
493
508
|
return list;
|
|
494
509
|
},
|
|
495
|
-
getPage(slugs = [], language =
|
|
510
|
+
getPage(slugs = [], language = defaultLanguage) {
|
|
496
511
|
return walker.pages.get(`${language}.${slugs.join("/")}`);
|
|
497
512
|
},
|
|
498
|
-
getNodeMeta(node, language =
|
|
513
|
+
getNodeMeta(node, language = defaultLanguage) {
|
|
499
514
|
const ref = node.$ref?.metaFile;
|
|
500
515
|
if (!ref) return;
|
|
501
516
|
const file = storages[language].list().find((v) => v.format === "meta" && v.file.path === ref);
|
|
502
517
|
if (file) return walker.getResultFromFile(file);
|
|
503
518
|
},
|
|
504
|
-
getNodePage(node, language =
|
|
519
|
+
getNodePage(node, language = defaultLanguage) {
|
|
505
520
|
const ref = node.$ref?.file;
|
|
506
521
|
if (!ref) return;
|
|
507
522
|
const file = storages[language].list().find((v) => v.format === "page" && v.file.path === ref);
|
|
@@ -509,7 +524,7 @@ function createOutput(options) {
|
|
|
509
524
|
},
|
|
510
525
|
getPageTree(locale) {
|
|
511
526
|
if (options.i18n) {
|
|
512
|
-
return this.pageTree[locale ??
|
|
527
|
+
return this.pageTree[locale ?? defaultLanguage];
|
|
513
528
|
}
|
|
514
529
|
return this.pageTree;
|
|
515
530
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumadocs-core",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.4.1",
|
|
4
4
|
"description": "The library for building a documentation website in Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NextJs",
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
"import": "./dist/toc.js",
|
|
25
25
|
"types": "./dist/toc.d.ts"
|
|
26
26
|
},
|
|
27
|
+
"./content": {
|
|
28
|
+
"import": "./dist/content/index.js",
|
|
29
|
+
"types": "./dist/content/index.d.ts"
|
|
30
|
+
},
|
|
27
31
|
"./search/*": {
|
|
28
32
|
"import": "./dist/search/*.js",
|
|
29
33
|
"types": "./dist/search/*.d.ts"
|
|
@@ -89,29 +93,28 @@
|
|
|
89
93
|
"react-remove-scroll": "^2.6.3",
|
|
90
94
|
"remark": "^15.0.0",
|
|
91
95
|
"remark-gfm": "^4.0.1",
|
|
96
|
+
"remark-rehype": "^11.1.2",
|
|
92
97
|
"scroll-into-view-if-needed": "^3.1.0",
|
|
93
98
|
"shiki": "^3.4.2",
|
|
94
99
|
"unist-util-visit": "^5.0.0"
|
|
95
100
|
},
|
|
96
101
|
"devDependencies": {
|
|
97
|
-
"@algolia/client-search": "4.24.0",
|
|
98
102
|
"@mdx-js/mdx": "^3.1.0",
|
|
99
103
|
"@oramacloud/client": "^2.1.4",
|
|
100
|
-
"@tanstack/react-router": "^1.120.
|
|
104
|
+
"@tanstack/react-router": "^1.120.9",
|
|
101
105
|
"@types/estree-jsx": "^1.0.5",
|
|
102
106
|
"@types/hast": "^3.0.4",
|
|
103
107
|
"@types/mdast": "^4.0.3",
|
|
104
108
|
"@types/negotiator": "^0.6.3",
|
|
105
|
-
"@types/node": "22.15.
|
|
106
|
-
"@types/react": "^19.1.
|
|
109
|
+
"@types/node": "22.15.21",
|
|
110
|
+
"@types/react": "^19.1.5",
|
|
107
111
|
"@types/react-dom": "^19.1.5",
|
|
108
|
-
"algoliasearch": "
|
|
112
|
+
"algoliasearch": "5.25.0",
|
|
109
113
|
"mdast-util-mdx-jsx": "^3.2.0",
|
|
110
114
|
"mdast-util-mdxjs-esm": "^2.0.1",
|
|
111
115
|
"next": "^15.3.2",
|
|
112
116
|
"react-router": "^7.6.0",
|
|
113
117
|
"remark-mdx": "^3.1.0",
|
|
114
|
-
"remark-rehype": "^11.1.2",
|
|
115
118
|
"typescript": "^5.8.3",
|
|
116
119
|
"unified": "^11.0.5",
|
|
117
120
|
"vfile": "^6.0.3",
|
|
@@ -120,7 +123,7 @@
|
|
|
120
123
|
},
|
|
121
124
|
"peerDependencies": {
|
|
122
125
|
"@oramacloud/client": "1.x.x || 2.x.x",
|
|
123
|
-
"algoliasearch": "
|
|
126
|
+
"algoliasearch": "5.x.x",
|
|
124
127
|
"next": "14.x.x || 15.x.x",
|
|
125
128
|
"react": "18.x.x || 19.x.x",
|
|
126
129
|
"react-dom": "18.x.x || 19.x.x"
|