fumadocs-core 15.7.0 → 15.7.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/{fetch-ITPHBPBE.js → fetch-C3XV44E6.js} +6 -5
- package/dist/i18n/index.d.ts +7 -1
- package/dist/mdx-plugins/index.d.ts +34 -5
- package/dist/mdx-plugins/index.js +117 -93
- package/dist/search/client.js +1 -1
- package/dist/source/index.d.ts +10 -18
- package/dist/source/index.js +70 -56
- package/package.json +6 -6
|
@@ -3,11 +3,12 @@ import "./chunk-JSBRDJBE.js";
|
|
|
3
3
|
// src/search/client/fetch.ts
|
|
4
4
|
var cache = /* @__PURE__ */ new Map();
|
|
5
5
|
async function fetchDocs(query, { api = "/api/search", locale, tag }) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
if (locale)
|
|
9
|
-
if (tag)
|
|
10
|
-
|
|
6
|
+
const url = new URL(api, window.location.origin);
|
|
7
|
+
url.searchParams.set("query", query);
|
|
8
|
+
if (locale) url.searchParams.set("locale", locale);
|
|
9
|
+
if (tag)
|
|
10
|
+
url.searchParams.set("tag", Array.isArray(tag) ? tag.join(",") : tag);
|
|
11
|
+
const key = `${url.pathname}?${url.searchParams}`;
|
|
11
12
|
const cached = cache.get(key);
|
|
12
13
|
if (cached) return cached;
|
|
13
14
|
const res = await fetch(key);
|
package/dist/i18n/index.d.ts
CHANGED
|
@@ -26,7 +26,13 @@ interface I18nConfig<Languages extends string = string> {
|
|
|
26
26
|
*
|
|
27
27
|
* @defaultValue 'dot'
|
|
28
28
|
*/
|
|
29
|
-
parser?: 'dot' | 'dir';
|
|
29
|
+
parser?: 'dot' | 'dir' | 'none';
|
|
30
|
+
/**
|
|
31
|
+
* the fallback language when the page has no translations available for a given locale.
|
|
32
|
+
*
|
|
33
|
+
* Default to ``defaultLanguage`, no fallback when set to `null`.
|
|
34
|
+
*/
|
|
35
|
+
fallbackLanguage?: Languages | null;
|
|
30
36
|
}
|
|
31
37
|
declare function defineI18n<Languages extends string>(config: I18nConfig<Languages>): I18nConfig<Languages>;
|
|
32
38
|
|
|
@@ -3,10 +3,10 @@ import { Root } from 'hast';
|
|
|
3
3
|
import { RehypeShikiOptions } from '@shikijs/rehype';
|
|
4
4
|
import { Processor, Transformer } from 'unified';
|
|
5
5
|
import { ShikiTransformer } from 'shiki';
|
|
6
|
-
import { Root as Root$1, Code } from 'mdast';
|
|
6
|
+
import { Root as Root$1, Code, BlockContent, Text } from 'mdast';
|
|
7
7
|
export { a as StructureOptions, S as StructuredData, r as remarkStructure, s as structure } from '../remark-structure-DVje0Sib.js';
|
|
8
8
|
export { R as RemarkHeadingOptions, r as remarkHeading } from '../remark-heading-BPCoYwjn.js';
|
|
9
|
-
import { MdxJsxFlowElement } from 'mdast-util-mdx-jsx';
|
|
9
|
+
import { MdxJsxFlowElement, MdxJsxAttribute } from 'mdast-util-mdx-jsx';
|
|
10
10
|
|
|
11
11
|
interface CodeBlockIcon {
|
|
12
12
|
viewBox: string;
|
|
@@ -37,7 +37,7 @@ type RehypeCodeOptions = RehypeShikiOptions & {
|
|
|
37
37
|
*
|
|
38
38
|
* @defaultValue true
|
|
39
39
|
*/
|
|
40
|
-
tab?:
|
|
40
|
+
tab?: boolean;
|
|
41
41
|
/**
|
|
42
42
|
* Enable Shiki's experimental JS engine
|
|
43
43
|
*
|
|
@@ -163,10 +163,14 @@ declare function remarkSteps({ steps, step, }?: RemarkStepsOptions): Transformer
|
|
|
163
163
|
|
|
164
164
|
interface PackageManager {
|
|
165
165
|
name: string;
|
|
166
|
+
/**
|
|
167
|
+
* Default to `name`
|
|
168
|
+
*/
|
|
169
|
+
value?: string;
|
|
166
170
|
/**
|
|
167
171
|
* Convert from npm to another package manager
|
|
168
172
|
*/
|
|
169
|
-
command: (command: string) => string;
|
|
173
|
+
command: (command: string) => string | undefined;
|
|
170
174
|
}
|
|
171
175
|
interface RemarkNpmOptions {
|
|
172
176
|
/**
|
|
@@ -184,4 +188,29 @@ interface RemarkNpmOptions {
|
|
|
184
188
|
*/
|
|
185
189
|
declare function remarkNpm({ persist, packageManagers, }?: RemarkNpmOptions): Transformer<Root$1, Root$1>;
|
|
186
190
|
|
|
187
|
-
|
|
191
|
+
interface CodeBlockTabsOptions {
|
|
192
|
+
attributes?: MdxJsxAttribute[];
|
|
193
|
+
defaultValue?: string;
|
|
194
|
+
persist?: {
|
|
195
|
+
id: string;
|
|
196
|
+
} | false;
|
|
197
|
+
triggers: {
|
|
198
|
+
value: string;
|
|
199
|
+
children: (BlockContent | Text)[];
|
|
200
|
+
}[];
|
|
201
|
+
tabs: {
|
|
202
|
+
value: string;
|
|
203
|
+
children: BlockContent[];
|
|
204
|
+
}[];
|
|
205
|
+
}
|
|
206
|
+
declare function generateCodeBlockTabs({ persist, defaultValue, triggers, tabs, ...options }: CodeBlockTabsOptions): MdxJsxFlowElement;
|
|
207
|
+
interface CodeBlockAttributes<Name extends string = string> {
|
|
208
|
+
attributes: Partial<Record<Name, string>>;
|
|
209
|
+
rest: string;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Parse Fumadocs-style code block attributes from meta string, like `title="hello world"`
|
|
213
|
+
*/
|
|
214
|
+
declare function parseCodeBlockAttributes<Name extends string = string>(meta: string, allowedNames?: Name[]): CodeBlockAttributes<Name>;
|
|
215
|
+
|
|
216
|
+
export { type CodeBlockAttributes, type CodeBlockIcon, type CodeBlockTabsOptions, type RehypeCodeOptions, type RehypeTocOptions, type RemarkAdmonitionOptions, type RemarkCodeTabOptions, type RemarkImageOptions, type RemarkNpmOptions, type RemarkStepsOptions, generateCodeBlockTabs, parseCodeBlockAttributes, rehypeCode, rehypeCodeDefaultOptions, rehypeToc, remarkAdmonition, remarkCodeTab, remarkImage, remarkNpm, remarkSteps, transformerIcon, transformerTab };
|
|
@@ -172,29 +172,87 @@ function transformerIcon(options = {}) {
|
|
|
172
172
|
};
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
// src/mdx-plugins/
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
{
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
175
|
+
// src/mdx-plugins/codeblock-utils.ts
|
|
176
|
+
function generateCodeBlockTabs({
|
|
177
|
+
persist = false,
|
|
178
|
+
defaultValue,
|
|
179
|
+
triggers,
|
|
180
|
+
tabs,
|
|
181
|
+
...options
|
|
182
|
+
}) {
|
|
183
|
+
const attributes = [];
|
|
184
|
+
if (options.attributes) attributes.push(...options.attributes);
|
|
185
|
+
if (defaultValue) {
|
|
186
|
+
attributes.push({
|
|
187
|
+
type: "mdxJsxAttribute",
|
|
188
|
+
name: "defaultValue",
|
|
189
|
+
value: defaultValue
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
if (typeof persist === "object") {
|
|
193
|
+
attributes.push(
|
|
194
|
+
{
|
|
195
|
+
type: "mdxJsxAttribute",
|
|
196
|
+
name: "groupId",
|
|
197
|
+
value: persist.id
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
type: "mdxJsxAttribute",
|
|
201
|
+
name: "persist",
|
|
202
|
+
value: null
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
const children = [
|
|
207
|
+
{
|
|
208
|
+
type: "mdxJsxFlowElement",
|
|
209
|
+
name: "CodeBlockTabsList",
|
|
210
|
+
attributes: [],
|
|
211
|
+
children: triggers.map(
|
|
212
|
+
(trigger) => ({
|
|
213
|
+
type: "mdxJsxFlowElement",
|
|
214
|
+
attributes: [
|
|
215
|
+
{ type: "mdxJsxAttribute", name: "value", value: trigger.value }
|
|
216
|
+
],
|
|
217
|
+
name: "CodeBlockTabsTrigger",
|
|
218
|
+
children: trigger.children
|
|
219
|
+
})
|
|
220
|
+
)
|
|
195
221
|
}
|
|
222
|
+
];
|
|
223
|
+
for (const tab of tabs) {
|
|
224
|
+
children.push({
|
|
225
|
+
type: "mdxJsxFlowElement",
|
|
226
|
+
name: "CodeBlockTab",
|
|
227
|
+
attributes: [
|
|
228
|
+
{ type: "mdxJsxAttribute", name: "value", value: tab.value }
|
|
229
|
+
],
|
|
230
|
+
children: tab.children
|
|
231
|
+
});
|
|
196
232
|
}
|
|
197
|
-
|
|
233
|
+
return {
|
|
234
|
+
type: "mdxJsxFlowElement",
|
|
235
|
+
name: "CodeBlockTabs",
|
|
236
|
+
attributes,
|
|
237
|
+
children
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function parseCodeBlockAttributes(meta, allowedNames) {
|
|
241
|
+
let str = meta;
|
|
242
|
+
const StringRegex = /(?<=^|\s)(?<name>\w+)=(?:"([^"]*)"|'([^']*)')/g;
|
|
243
|
+
const attributes = {};
|
|
244
|
+
str = str.replaceAll(StringRegex, (match, name, value_1, value_2) => {
|
|
245
|
+
if (allowedNames && !allowedNames.includes(name)) return match;
|
|
246
|
+
attributes[name] = value_1 ?? value_2;
|
|
247
|
+
return "";
|
|
248
|
+
});
|
|
249
|
+
return {
|
|
250
|
+
rest: str,
|
|
251
|
+
attributes
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/mdx-plugins/rehype-code.ts
|
|
198
256
|
var rehypeCodeDefaultOptions = {
|
|
199
257
|
lazy: true,
|
|
200
258
|
themes: defaultThemes,
|
|
@@ -216,22 +274,21 @@ var rehypeCodeDefaultOptions = {
|
|
|
216
274
|
})
|
|
217
275
|
],
|
|
218
276
|
parseMetaString(meta) {
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
} else {
|
|
225
|
-
const first = args.at(0);
|
|
226
|
-
map[value.name] = typeof first === "string" ? first : "";
|
|
227
|
-
}
|
|
228
|
-
return "";
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
map.__parsed_raw = meta;
|
|
232
|
-
return map;
|
|
277
|
+
const parsed = parseCodeBlockAttributes(meta);
|
|
278
|
+
const data = parsed.attributes;
|
|
279
|
+
parsed.rest = parseLineNumber(parsed.rest, data);
|
|
280
|
+
data.__parsed_raw = parsed.rest;
|
|
281
|
+
return data;
|
|
233
282
|
}
|
|
234
283
|
};
|
|
284
|
+
function parseLineNumber(str, data) {
|
|
285
|
+
return str.replace(/lineNumbers=(\d+)|lineNumbers/, (_, ...args) => {
|
|
286
|
+
data["data-line-numbers"] = true;
|
|
287
|
+
if (args[0] !== void 0)
|
|
288
|
+
data["data-line-numbers-start"] = Number(args[0]);
|
|
289
|
+
return "";
|
|
290
|
+
});
|
|
291
|
+
}
|
|
235
292
|
function rehypeCode(_options = {}) {
|
|
236
293
|
const options = {
|
|
237
294
|
...rehypeCodeDefaultOptions,
|
|
@@ -1159,78 +1216,45 @@ function remarkNpm({
|
|
|
1159
1216
|
} = {}) {
|
|
1160
1217
|
return (tree) => {
|
|
1161
1218
|
visit7(tree, "code", (node) => {
|
|
1162
|
-
if (!node.lang || !aliases.includes(node.lang)) return
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
{
|
|
1166
|
-
type: "mdxJsxAttribute",
|
|
1167
|
-
name: "defaultValue",
|
|
1168
|
-
value: packageManagers[0].name
|
|
1169
|
-
}
|
|
1170
|
-
];
|
|
1171
|
-
if (typeof persist === "object") {
|
|
1172
|
-
attributes.push(
|
|
1173
|
-
{
|
|
1174
|
-
type: "mdxJsxAttribute",
|
|
1175
|
-
name: "groupId",
|
|
1176
|
-
value: persist.id
|
|
1177
|
-
},
|
|
1178
|
-
{
|
|
1179
|
-
type: "mdxJsxAttribute",
|
|
1180
|
-
name: "persist",
|
|
1181
|
-
value: null
|
|
1182
|
-
}
|
|
1183
|
-
);
|
|
1219
|
+
if (!node.lang || !aliases.includes(node.lang)) return;
|
|
1220
|
+
let code = node.value;
|
|
1221
|
+
if (node.lang === "package-install" && !code.startsWith("npm") && !code.startsWith("npx")) {
|
|
1222
|
+
code = `npm install ${code}`;
|
|
1184
1223
|
}
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
}
|
|
1202
|
-
]
|
|
1203
|
-
})
|
|
1204
|
-
)
|
|
1205
|
-
}
|
|
1206
|
-
];
|
|
1207
|
-
for (const { name, command } of packageManagers) {
|
|
1208
|
-
children.push({
|
|
1209
|
-
type: "mdxJsxFlowElement",
|
|
1210
|
-
name: "CodeBlockTab",
|
|
1211
|
-
attributes: [{ type: "mdxJsxAttribute", name: "value", value: name }],
|
|
1224
|
+
const options = {
|
|
1225
|
+
persist,
|
|
1226
|
+
tabs: [],
|
|
1227
|
+
triggers: []
|
|
1228
|
+
};
|
|
1229
|
+
for (const manager of packageManagers) {
|
|
1230
|
+
const value = manager.value ?? manager.name;
|
|
1231
|
+
const command = manager.command(code);
|
|
1232
|
+
if (!command || command.length === 0) continue;
|
|
1233
|
+
options.defaultValue ??= value;
|
|
1234
|
+
options.triggers.push({
|
|
1235
|
+
value,
|
|
1236
|
+
children: [{ type: "text", value: manager.name }]
|
|
1237
|
+
});
|
|
1238
|
+
options.tabs.push({
|
|
1239
|
+
value,
|
|
1212
1240
|
children: [
|
|
1213
1241
|
{
|
|
1214
1242
|
type: "code",
|
|
1215
1243
|
lang: "bash",
|
|
1216
1244
|
meta: node.meta,
|
|
1217
|
-
value: command
|
|
1245
|
+
value: command
|
|
1218
1246
|
}
|
|
1219
1247
|
]
|
|
1220
1248
|
});
|
|
1221
1249
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
name: "CodeBlockTabs",
|
|
1225
|
-
attributes,
|
|
1226
|
-
children
|
|
1227
|
-
};
|
|
1228
|
-
Object.assign(node, tab);
|
|
1229
|
-
return;
|
|
1250
|
+
Object.assign(node, generateCodeBlockTabs(options));
|
|
1251
|
+
return "skip";
|
|
1230
1252
|
});
|
|
1231
1253
|
};
|
|
1232
1254
|
}
|
|
1233
1255
|
export {
|
|
1256
|
+
generateCodeBlockTabs,
|
|
1257
|
+
parseCodeBlockAttributes,
|
|
1234
1258
|
rehypeCode,
|
|
1235
1259
|
rehypeCodeDefaultOptions,
|
|
1236
1260
|
rehypeToc,
|
package/dist/search/client.js
CHANGED
|
@@ -65,7 +65,7 @@ function useDocsSearch(clientOptions, _locale, _tag, _delayMs = 100, _allowEmpty
|
|
|
65
65
|
async function run() {
|
|
66
66
|
if (debouncedValue.length === 0 && !allowEmpty) return "empty";
|
|
67
67
|
if (client.type === "fetch") {
|
|
68
|
-
const { fetchDocs } = await import("../fetch-
|
|
68
|
+
const { fetchDocs } = await import("../fetch-C3XV44E6.js");
|
|
69
69
|
return fetchDocs(debouncedValue, client);
|
|
70
70
|
}
|
|
71
71
|
if (client.type === "algolia") {
|
package/dist/source/index.d.ts
CHANGED
|
@@ -43,21 +43,12 @@ type Transformer = (context: {
|
|
|
43
43
|
storage: ContentStorage;
|
|
44
44
|
options: LoadOptions;
|
|
45
45
|
}) => void;
|
|
46
|
-
declare const parsers: {
|
|
47
|
-
dir(path: string): [string, string?];
|
|
48
|
-
dot(path: string): [string, string?];
|
|
49
|
-
none(path: string): [string, string?];
|
|
50
|
-
};
|
|
51
46
|
/**
|
|
52
47
|
* @returns a map of locale and its content storage.
|
|
53
48
|
*
|
|
54
49
|
* in the storage, locale codes are removed from file paths, hence the same file will have same file paths in every storage.
|
|
55
50
|
*/
|
|
56
|
-
declare function loadFiles(files: VirtualFile[], options: LoadOptions, i18n:
|
|
57
|
-
parser: keyof typeof parsers;
|
|
58
|
-
languages: string[];
|
|
59
|
-
defaultLanguage: string;
|
|
60
|
-
}): Record<string, ContentStorage>;
|
|
51
|
+
declare function loadFiles(files: VirtualFile[], options: LoadOptions, i18n: I18nConfig): Record<string, ContentStorage>;
|
|
61
52
|
|
|
62
53
|
interface FileInfo {
|
|
63
54
|
/**
|
|
@@ -112,7 +103,7 @@ interface LoaderOptions<T extends SourceConfig = SourceConfig, I18n extends I18n
|
|
|
112
103
|
icon?: NonNullable<BaseOptions['resolveIcon']>;
|
|
113
104
|
slugs?: (info: FileInfo) => string[];
|
|
114
105
|
url?: UrlFn;
|
|
115
|
-
source: Source<T
|
|
106
|
+
source: Source<T> | Source<T>[];
|
|
116
107
|
transformers?: Transformer[];
|
|
117
108
|
/**
|
|
118
109
|
* Additional options for page tree builder
|
|
@@ -265,7 +256,7 @@ interface LegacyTransformerOptions<Page extends PageData, Meta extends MetaData>
|
|
|
265
256
|
|
|
266
257
|
interface PageTreeBuilderContext<Page extends PageData = PageData, Meta extends MetaData = MetaData> {
|
|
267
258
|
/**
|
|
268
|
-
* @internal
|
|
259
|
+
* @internal resolve paths without extensions
|
|
269
260
|
*/
|
|
270
261
|
resolveName: (name: string, format: 'meta' | 'page') => string;
|
|
271
262
|
options: BaseOptions<Page, Meta>;
|
|
@@ -275,6 +266,7 @@ interface PageTreeBuilderContext<Page extends PageData = PageData, Meta extends
|
|
|
275
266
|
getUrl: UrlFn;
|
|
276
267
|
storages?: Record<string, ContentStorage<Page, Meta>>;
|
|
277
268
|
locale?: string;
|
|
269
|
+
visitedPaths: Set<string>;
|
|
278
270
|
}
|
|
279
271
|
interface PageTreeTransformer<Page extends PageData = any, Meta extends MetaData = any> {
|
|
280
272
|
name?: string;
|
|
@@ -292,17 +284,17 @@ interface BaseOptions<Page extends PageData = PageData, Meta extends MetaData =
|
|
|
292
284
|
noRef?: boolean;
|
|
293
285
|
transformers?: PageTreeTransformer<Page, Meta>[];
|
|
294
286
|
resolveIcon?: (icon: string | undefined) => ReactNode | undefined;
|
|
287
|
+
/**
|
|
288
|
+
* generate fallback page tree
|
|
289
|
+
*
|
|
290
|
+
* @defaultValue true
|
|
291
|
+
*/
|
|
292
|
+
generateFallback?: boolean;
|
|
295
293
|
}
|
|
296
294
|
interface PageTreeBuilder<Page extends PageData = PageData, Meta extends MetaData = MetaData> {
|
|
297
295
|
build: (options: BaseOptions<Page, Meta> & {
|
|
298
296
|
id?: string;
|
|
299
297
|
storage: ContentStorage<Page, Meta>;
|
|
300
|
-
/**
|
|
301
|
-
* generate fallback page tree
|
|
302
|
-
*
|
|
303
|
-
* @defaultValue true
|
|
304
|
-
*/
|
|
305
|
-
generateFallback?: boolean;
|
|
306
298
|
}) => Root;
|
|
307
299
|
/**
|
|
308
300
|
* Build page tree and fallback to the default language if the localized page doesn't exist
|
package/dist/source/index.js
CHANGED
|
@@ -83,24 +83,26 @@ var rest = "...";
|
|
|
83
83
|
var restReversed = "z...a";
|
|
84
84
|
var extractPrefix = "...";
|
|
85
85
|
var excludePrefix = "!";
|
|
86
|
-
function buildAll(paths, ctx,
|
|
87
|
-
const
|
|
88
|
-
const
|
|
86
|
+
function buildAll(paths, ctx, reversed = false) {
|
|
87
|
+
const items = [];
|
|
88
|
+
const folders = [];
|
|
89
|
+
const sortedPaths = paths.sort(
|
|
89
90
|
(a, b) => a.localeCompare(b) * (reversed ? -1 : 1)
|
|
90
91
|
);
|
|
91
92
|
for (const path of sortedPaths) {
|
|
93
|
+
ctx.visitedPaths.add(path);
|
|
92
94
|
const fileNode = buildFileNode(path, ctx);
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const dirNode = buildFolderNode(
|
|
99
|
-
if (dirNode)
|
|
95
|
+
if (fileNode) {
|
|
96
|
+
if (basename(path, extname(path)) === "index") items.unshift(fileNode);
|
|
97
|
+
else items.push(fileNode);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const dirNode = buildFolderNode(path, false, ctx);
|
|
101
|
+
if (dirNode) folders.push(dirNode);
|
|
100
102
|
}
|
|
101
|
-
return
|
|
103
|
+
return [...items, ...folders];
|
|
102
104
|
}
|
|
103
|
-
function resolveFolderItem(folderPath, item, ctx, idx
|
|
105
|
+
function resolveFolderItem(folderPath, item, ctx, idx) {
|
|
104
106
|
if (item === rest || item === restReversed) return item;
|
|
105
107
|
const { options, resolveName } = ctx;
|
|
106
108
|
let match = separator.exec(item);
|
|
@@ -143,7 +145,7 @@ function resolveFolderItem(folderPath, item, ctx, idx, restNodePaths) {
|
|
|
143
145
|
filename = item.slice(extractPrefix.length);
|
|
144
146
|
}
|
|
145
147
|
const path = resolveName(joinPath(folderPath, filename), "page");
|
|
146
|
-
|
|
148
|
+
ctx.visitedPaths.add(path);
|
|
147
149
|
if (isExcept) return [];
|
|
148
150
|
const dirNode = buildFolderNode(path, false, ctx);
|
|
149
151
|
if (dirNode) {
|
|
@@ -162,27 +164,29 @@ function buildFolderNode(folderPath, isGlobalRoot, ctx) {
|
|
|
162
164
|
if (meta?.format !== "meta") {
|
|
163
165
|
meta = void 0;
|
|
164
166
|
}
|
|
165
|
-
|
|
167
|
+
const isRoot = meta?.data.root ?? isGlobalRoot;
|
|
168
|
+
let index;
|
|
166
169
|
let children;
|
|
170
|
+
function setIndexIfUnused() {
|
|
171
|
+
if (isRoot || ctx.visitedPaths.has(indexPath)) return;
|
|
172
|
+
ctx.visitedPaths.add(indexPath);
|
|
173
|
+
index = buildFileNode(indexPath, ctx);
|
|
174
|
+
}
|
|
167
175
|
if (!meta?.data.pages) {
|
|
176
|
+
setIndexIfUnused();
|
|
168
177
|
children = buildAll(
|
|
169
|
-
files,
|
|
170
|
-
ctx
|
|
171
|
-
(file) => indexDisabled || file !== indexPath
|
|
178
|
+
files.filter((file) => !ctx.visitedPaths.has(file)),
|
|
179
|
+
ctx
|
|
172
180
|
);
|
|
173
181
|
} else {
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
if (!indexDisabled && !restItems.has(indexPath)) {
|
|
177
|
-
indexDisabled = true;
|
|
178
|
-
}
|
|
182
|
+
const resolved = meta.data.pages.flatMap((item, i) => resolveFolderItem(folderPath, item, ctx, i));
|
|
183
|
+
setIndexIfUnused();
|
|
179
184
|
for (let i = 0; i < resolved.length; i++) {
|
|
180
185
|
const item = resolved[i];
|
|
181
186
|
if (item !== rest && item !== restReversed) continue;
|
|
182
187
|
const items = buildAll(
|
|
183
|
-
files,
|
|
188
|
+
files.filter((file) => !ctx.visitedPaths.has(file)),
|
|
184
189
|
ctx,
|
|
185
|
-
(file) => (indexDisabled || file !== indexPath) && restItems.has(file),
|
|
186
190
|
item === restReversed
|
|
187
191
|
);
|
|
188
192
|
resolved.splice(i, 1, ...items);
|
|
@@ -190,7 +194,6 @@ function buildFolderNode(folderPath, isGlobalRoot, ctx) {
|
|
|
190
194
|
}
|
|
191
195
|
children = resolved;
|
|
192
196
|
}
|
|
193
|
-
const index = !indexDisabled ? buildFileNode(indexPath, ctx) : void 0;
|
|
194
197
|
let name = meta?.data.title ?? index?.name;
|
|
195
198
|
if (!name) {
|
|
196
199
|
const folderName = basename(folderPath);
|
|
@@ -252,7 +255,7 @@ function build(id, ctx) {
|
|
|
252
255
|
return root;
|
|
253
256
|
}
|
|
254
257
|
function createPageTreeBuilder(getUrl) {
|
|
255
|
-
function getTransformers(options, generateFallback
|
|
258
|
+
function getTransformers(options, generateFallback) {
|
|
256
259
|
const transformers = [legacyTransformer(options)];
|
|
257
260
|
if (options.transformers) {
|
|
258
261
|
transformers.push(...options.transformers);
|
|
@@ -275,25 +278,21 @@ function createPageTreeBuilder(getUrl) {
|
|
|
275
278
|
};
|
|
276
279
|
}
|
|
277
280
|
return {
|
|
278
|
-
build({ storage, id,
|
|
279
|
-
const
|
|
280
|
-
return
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
getUrl,
|
|
286
|
-
resolveName(name, format) {
|
|
287
|
-
return resolve(name, format) ?? name;
|
|
288
|
-
}
|
|
289
|
-
});
|
|
281
|
+
build({ storage, id, ...options }) {
|
|
282
|
+
const key = "";
|
|
283
|
+
return this.buildI18n({
|
|
284
|
+
id,
|
|
285
|
+
storages: { [key]: storage },
|
|
286
|
+
...options
|
|
287
|
+
})[key];
|
|
290
288
|
},
|
|
291
|
-
buildI18n({ id, storages, ...options }) {
|
|
292
|
-
const transformers = getTransformers(options);
|
|
289
|
+
buildI18n({ id, storages, generateFallback = true, ...options }) {
|
|
290
|
+
const transformers = getTransformers(options, generateFallback);
|
|
293
291
|
const out = {};
|
|
294
292
|
for (const [locale, storage] of Object.entries(storages)) {
|
|
295
293
|
const resolve = createFlattenPathResolver(storage);
|
|
296
|
-
|
|
294
|
+
const branch = locale.length === 0 ? "root" : locale;
|
|
295
|
+
out[locale] = build(id ? `${id}-${branch}` : branch, {
|
|
297
296
|
transformers,
|
|
298
297
|
builder: this,
|
|
299
298
|
options,
|
|
@@ -301,6 +300,7 @@ function createPageTreeBuilder(getUrl) {
|
|
|
301
300
|
locale,
|
|
302
301
|
storage,
|
|
303
302
|
storages,
|
|
303
|
+
visitedPaths: /* @__PURE__ */ new Set(),
|
|
304
304
|
resolveName(name, format) {
|
|
305
305
|
return resolve(name, format) ?? name;
|
|
306
306
|
}
|
|
@@ -401,7 +401,7 @@ var parsers = {
|
|
|
401
401
|
};
|
|
402
402
|
function loadFiles(files, options, i18n) {
|
|
403
403
|
const { buildFile, transformers = [] } = options;
|
|
404
|
-
const parser = parsers[i18n.parser];
|
|
404
|
+
const parser = parsers[i18n.parser ?? "dot"];
|
|
405
405
|
const storages = {};
|
|
406
406
|
const normalized = files.map(
|
|
407
407
|
(file) => buildFile({
|
|
@@ -409,8 +409,16 @@ function loadFiles(files, options, i18n) {
|
|
|
409
409
|
path: normalizePath(file.path)
|
|
410
410
|
})
|
|
411
411
|
);
|
|
412
|
-
|
|
413
|
-
|
|
412
|
+
const fallbackLang = i18n.fallbackLanguage !== null ? i18n.fallbackLanguage ?? i18n.defaultLanguage : null;
|
|
413
|
+
function scan(lang) {
|
|
414
|
+
if (storages[lang]) return;
|
|
415
|
+
let storage;
|
|
416
|
+
if (fallbackLang && fallbackLang !== lang) {
|
|
417
|
+
scan(fallbackLang);
|
|
418
|
+
storage = new FileSystem(storages[fallbackLang]);
|
|
419
|
+
} else {
|
|
420
|
+
storage = new FileSystem();
|
|
421
|
+
}
|
|
414
422
|
for (const item of normalized) {
|
|
415
423
|
const [path, locale = i18n.defaultLanguage] = parser(item.path);
|
|
416
424
|
if (locale === lang) storage.write(path, item);
|
|
@@ -421,12 +429,9 @@ function loadFiles(files, options, i18n) {
|
|
|
421
429
|
options
|
|
422
430
|
});
|
|
423
431
|
}
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
storages[i18n.defaultLanguage] = scan(i18n.defaultLanguage);
|
|
427
|
-
for (const lang of i18n.languages) {
|
|
428
|
-
storages[lang] ??= scan(lang, storages[i18n.defaultLanguage]);
|
|
432
|
+
storages[lang] = storage;
|
|
429
433
|
}
|
|
434
|
+
for (const lang of i18n.languages) scan(lang);
|
|
430
435
|
return storages;
|
|
431
436
|
}
|
|
432
437
|
function normalizePath(path) {
|
|
@@ -479,6 +484,17 @@ function createGetUrl(baseUrl, i18n) {
|
|
|
479
484
|
function loader(options) {
|
|
480
485
|
return createOutput(options);
|
|
481
486
|
}
|
|
487
|
+
function loadSource(source) {
|
|
488
|
+
const out = [];
|
|
489
|
+
for (const item of Array.isArray(source) ? source : [source]) {
|
|
490
|
+
if (typeof item.files === "function") {
|
|
491
|
+
out.push(...item.files());
|
|
492
|
+
} else {
|
|
493
|
+
out.push(...item.files);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return out;
|
|
497
|
+
}
|
|
482
498
|
function createOutput(options) {
|
|
483
499
|
if (!options.url && !options.baseUrl) {
|
|
484
500
|
console.warn("`loader()` now requires a `baseUrl` option to be defined.");
|
|
@@ -492,14 +508,15 @@ function createOutput(options) {
|
|
|
492
508
|
transformers = []
|
|
493
509
|
} = options;
|
|
494
510
|
const defaultLanguage = i18n?.defaultLanguage ?? "";
|
|
495
|
-
const files =
|
|
511
|
+
const files = loadSource(source);
|
|
496
512
|
const transformerSlugs = ({ storage }) => {
|
|
497
513
|
const indexFiles = /* @__PURE__ */ new Set();
|
|
498
514
|
const taken = /* @__PURE__ */ new Set();
|
|
515
|
+
const autoIndex = slugsFn === void 0;
|
|
499
516
|
for (const path of storage.getFiles()) {
|
|
500
517
|
const file = storage.read(path);
|
|
501
518
|
if (!file || file.format !== "page" || file.slugs) continue;
|
|
502
|
-
if (isIndex(path) &&
|
|
519
|
+
if (isIndex(path) && autoIndex) {
|
|
503
520
|
indexFiles.add(path);
|
|
504
521
|
continue;
|
|
505
522
|
}
|
|
@@ -537,10 +554,7 @@ function createOutput(options) {
|
|
|
537
554
|
},
|
|
538
555
|
transformers: [transformerSlugs, ...transformers]
|
|
539
556
|
},
|
|
540
|
-
i18n
|
|
541
|
-
...i18n,
|
|
542
|
-
parser: i18n.parser ?? "dot"
|
|
543
|
-
} : {
|
|
557
|
+
i18n ?? {
|
|
544
558
|
defaultLanguage,
|
|
545
559
|
parser: "none",
|
|
546
560
|
languages: [defaultLanguage]
|
|
@@ -564,7 +578,7 @@ function createOutput(options) {
|
|
|
564
578
|
pageTree = v;
|
|
565
579
|
} else {
|
|
566
580
|
pageTree = {
|
|
567
|
-
defaultLanguage: v
|
|
581
|
+
[defaultLanguage]: v
|
|
568
582
|
};
|
|
569
583
|
}
|
|
570
584
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumadocs-core",
|
|
3
|
-
"version": "15.7.
|
|
3
|
+
"version": "15.7.2",
|
|
4
4
|
"description": "The library for building a documentation website in Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NextJs",
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
},
|
|
111
111
|
"devDependencies": {
|
|
112
112
|
"@mdx-js/mdx": "^3.1.0",
|
|
113
|
-
"@mixedbread/sdk": "^0.
|
|
113
|
+
"@mixedbread/sdk": "^0.26.0",
|
|
114
114
|
"@oramacloud/client": "^2.1.4",
|
|
115
115
|
"@tanstack/react-router": "^1.131.27",
|
|
116
116
|
"@types/estree-jsx": "^1.0.5",
|
|
@@ -118,21 +118,21 @@
|
|
|
118
118
|
"@types/mdast": "^4.0.3",
|
|
119
119
|
"@types/negotiator": "^0.6.4",
|
|
120
120
|
"@types/node": "24.3.0",
|
|
121
|
-
"@types/react": "^19.1.
|
|
121
|
+
"@types/react": "^19.1.11",
|
|
122
122
|
"@types/react-dom": "^19.1.7",
|
|
123
123
|
"algoliasearch": "5.35.0",
|
|
124
124
|
"mdast-util-mdx-jsx": "^3.2.0",
|
|
125
125
|
"mdast-util-mdxjs-esm": "^2.0.1",
|
|
126
126
|
"next": "^15.5.0",
|
|
127
|
-
"react-router": "^7.8.
|
|
127
|
+
"react-router": "^7.8.2",
|
|
128
128
|
"remark-mdx": "^3.1.0",
|
|
129
129
|
"remove-markdown": "^0.6.2",
|
|
130
130
|
"typescript": "^5.9.2",
|
|
131
131
|
"unified": "^11.0.5",
|
|
132
132
|
"vfile": "^6.0.3",
|
|
133
133
|
"waku": "^0.25.0",
|
|
134
|
-
"
|
|
135
|
-
"
|
|
134
|
+
"tsconfig": "0.0.0",
|
|
135
|
+
"eslint-config-custom": "0.0.0"
|
|
136
136
|
},
|
|
137
137
|
"peerDependencies": {
|
|
138
138
|
"@mixedbread/sdk": "^0.19.0",
|