fumadocs-core 15.0.17 → 15.1.0

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.
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { R as Root, N as Node } from './page-tree-CfT5zlWh.js';
2
+ import { R as Root, N as Node } from './page-tree-9q98UqWL.js';
3
3
 
4
4
  interface BreadcrumbItem {
5
5
  name: ReactNode;
@@ -15,6 +15,7 @@ interface Item {
15
15
  name: ReactNode;
16
16
  url: string;
17
17
  external?: boolean;
18
+ description?: ReactNode;
18
19
  icon?: ReactElement;
19
20
  }
20
21
  interface Separator {
@@ -7,7 +7,7 @@ import { LoaderOutput, LoaderConfig, InferPageType } from '../source/index.js';
7
7
  import 'mdast';
8
8
  import 'unified';
9
9
  import 'react';
10
- import '../page-tree-CfT5zlWh.js';
10
+ import '../page-tree-9q98UqWL.js';
11
11
 
12
12
  type AdvancedDocument = TypedDocument<Orama<typeof advancedSchema>>;
13
13
  declare const advancedSchema: {
@@ -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-CfT5zlWh.js';
3
- export { p as PageTree } from '../page-tree-CfT5zlWh.js';
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 };
@@ -1,7 +1,7 @@
1
- import "../chunk-WQMD6AUR.js";
2
1
  import {
3
2
  remarkHeading
4
3
  } from "../chunk-IYQ35KI2.js";
4
+ import "../chunk-WQMD6AUR.js";
5
5
  import {
6
6
  createStyleTransformer,
7
7
  highlight
@@ -34,18 +34,34 @@ function flattenTree(tree) {
34
34
  return [node];
35
35
  });
36
36
  }
37
- function findNeighbour(tree, url) {
38
- const list = flattenTree(tree.children);
39
- for (let i = 0; i < list.length; i++) {
40
- if (list[i].url === url) {
41
- return {
42
- next: list[i + 1],
43
- previous: list[i - 1]
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
@@ -1,6 +1,6 @@
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-CfT5zlWh.js';
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
  /**
@@ -102,7 +102,16 @@ interface LanguageEntry<Data = PageData> {
102
102
  }
103
103
  interface LoaderOutput<Config extends LoaderConfig> {
104
104
  pageTree: Config['i18n'] extends true ? Record<string, Root> : Root;
105
- getPageTree(locale?: string): Root;
105
+ getPageTree: (locale?: string) => Root;
106
+ getPageByHref: (href: string, options?: {
107
+ /**
108
+ * resolve relative file paths in `href` from specified directory
109
+ */
110
+ dir?: string;
111
+ }) => {
112
+ page: Page<Config['source']['pageData']>;
113
+ hash?: string;
114
+ } | undefined;
106
115
  _i18n?: I18nConfig;
107
116
  /**
108
117
  * Get list of pages from language, empty if language hasn't specified
@@ -141,6 +150,7 @@ interface MetaData {
141
150
  interface PageData {
142
151
  icon?: string | undefined;
143
152
  title?: string;
153
+ description?: string | undefined;
144
154
  }
145
155
  type InferPageType<Utils extends LoaderOutput<any>> = Utils extends LoaderOutput<infer Config> ? Page<Config['source']['pageData']> : never;
146
156
  type InferMetaType<Utils extends LoaderOutput<any>> = Utils extends LoaderOutput<infer Config> ? Meta<Config['source']['metaData']> : never;
@@ -75,8 +75,8 @@ function resolveFolderItem(folder, item, ctx, idx, addedNodePaths) {
75
75
  } else if (isExtract) {
76
76
  filename = item.slice(extractPrefix.length);
77
77
  }
78
- const path = resolvePath(folder.file.path, filename);
79
- const itemNode = ctx.storage.readDir(path) ?? ctx.storage.read(path, "page");
78
+ const path2 = resolvePath(folder.file.path, filename);
79
+ const itemNode = ctx.storage.readDir(path2) ?? ctx.storage.read(path2, "page");
80
80
  if (!itemNode) return [];
81
81
  addedNodePaths.add(itemNode.file.path);
82
82
  if (isExcept) return [];
@@ -142,6 +142,7 @@ function buildFileNode(file, ctx) {
142
142
  $id: localized.file.path,
143
143
  type: "page",
144
144
  name: localized.data.data.title ?? pathToName(localized.file.name),
145
+ description: localized.data.data.description,
145
146
  icon: ctx.options.resolveIcon?.(localized.data.data.icon),
146
147
  url: ctx.options.getUrl(localized.data.slugs, ctx.lang),
147
148
  $ref: !ctx.options.noRef ? {
@@ -182,9 +183,9 @@ function createPageTreeBuilder() {
182
183
  }
183
184
  };
184
185
  }
185
- function findLocalizedFile(path, format, ctx) {
186
+ function findLocalizedFile(path2, format, ctx) {
186
187
  if (!ctx.lang) return;
187
- return ctx.storage.read(`${path}.${ctx.lang}`, format);
188
+ return ctx.storage.read(`${path2}.${ctx.lang}`, format);
188
189
  }
189
190
  function pathToName(name) {
190
191
  const result = [];
@@ -197,8 +198,8 @@ function pathToName(name) {
197
198
  }
198
199
 
199
200
  // src/source/path.ts
200
- function parseFilePath(path) {
201
- const segments = splitPath(slash(path));
201
+ function parseFilePath(path2) {
202
+ const segments = splitPath(slash(path2));
202
203
  const dirname = segments.slice(0, -1).join("/");
203
204
  const base = segments.at(-1) ?? "";
204
205
  const dotIdx = base.lastIndexOf(".");
@@ -213,8 +214,8 @@ function parseFilePath(path) {
213
214
  path: segments.join("/")
214
215
  };
215
216
  }
216
- function parseFolderPath(path) {
217
- const segments = splitPath(slash(path));
217
+ function parseFolderPath(path2) {
218
+ const segments = splitPath(slash(path2));
218
219
  const base = segments.at(-1) ?? "";
219
220
  const [name, locale] = getLocale(base);
220
221
  const flattenedPath = segments.join("/");
@@ -233,8 +234,8 @@ function getLocale(name) {
233
234
  if (/\d+/.exec(locale)) return [name];
234
235
  return [name.slice(0, sep), locale];
235
236
  }
236
- function normalizePath(path) {
237
- const segments = splitPath(slash(path));
237
+ function normalizePath(path2) {
238
+ const segments = splitPath(slash(path2));
238
239
  if (segments[0] === "." || segments[0] === "..")
239
240
  throw new Error("It must not start with './' or '../'");
240
241
  return segments.join("/");
@@ -259,19 +260,19 @@ var Storage = class {
259
260
  * @param path - flattened path
260
261
  * @param format - file format
261
262
  */
262
- read(path, format) {
263
- return this.files.get(`${path}.${format}`);
263
+ read(path2, format) {
264
+ return this.files.get(`${path2}.${format}`);
264
265
  }
265
- readDir(path) {
266
- return this.folders.get(path);
266
+ readDir(path2) {
267
+ return this.folders.get(path2);
267
268
  }
268
269
  root() {
269
270
  return this.rootFolder;
270
271
  }
271
- write(path, format, data) {
272
+ write(path2, format, data) {
272
273
  const node = {
273
274
  format,
274
- file: parseFilePath(path),
275
+ file: parseFilePath(path2),
275
276
  data
276
277
  };
277
278
  this.makeDir(node.file.dirname);
@@ -281,8 +282,8 @@ var Storage = class {
281
282
  list() {
282
283
  return [...this.files.values()];
283
284
  }
284
- makeDir(path) {
285
- const segments = splitPath(path);
285
+ makeDir(path2) {
286
+ const segments = splitPath(path2);
286
287
  for (let i = 0; i < segments.length; i++) {
287
288
  const segment = segments.slice(0, i + 1).join("/");
288
289
  if (this.folders.has(segment)) continue;
@@ -326,6 +327,7 @@ function loadFiles(files, options) {
326
327
  }
327
328
 
328
329
  // src/source/loader.ts
330
+ import * as path from "node:path";
329
331
  function indexPages(storage, getUrl, i18n) {
330
332
  const defaultLanguage = i18n?.defaultLanguage ?? "";
331
333
  const map = /* @__PURE__ */ new Map();
@@ -355,6 +357,7 @@ function indexPages(storage, getUrl, i18n) {
355
357
  };
356
358
  }
357
359
  function createGetUrl(baseUrl, i18n) {
360
+ const baseSlugs = baseUrl.split("/");
358
361
  return (slugs, locale) => {
359
362
  const hideLocale = i18n?.hideLocale ?? "never";
360
363
  let urlLocale;
@@ -363,7 +366,8 @@ function createGetUrl(baseUrl, i18n) {
363
366
  } else if (hideLocale === "default-locale" && locale !== i18n?.defaultLanguage) {
364
367
  urlLocale = locale;
365
368
  }
366
- const paths = urlLocale ? [urlLocale, ...baseUrl.split("/"), ...slugs] : [...baseUrl.split("/"), ...slugs];
369
+ const paths = [...baseSlugs, ...slugs];
370
+ if (urlLocale) paths.unshift(urlLocale);
367
371
  return `/${paths.filter((v) => v.length > 0).join("/")}`;
368
372
  };
369
373
  }
@@ -395,21 +399,50 @@ function createOutput(options) {
395
399
  );
396
400
  const walker = indexPages(storage, getUrl, options.i18n);
397
401
  const builder = createPageTreeBuilder();
398
- const pageTree = options.i18n === void 0 ? builder.build({
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
- });
402
+ let pageTree;
410
403
  return {
411
404
  _i18n: options.i18n,
412
- pageTree,
405
+ get pageTree() {
406
+ if (options.i18n) {
407
+ pageTree ??= builder.buildI18n({
408
+ storage,
409
+ resolveIcon: options.icon,
410
+ getUrl,
411
+ i18n: options.i18n,
412
+ ...options.pageTree
413
+ });
414
+ } else {
415
+ pageTree ??= builder.build({
416
+ storage,
417
+ resolveIcon: options.icon,
418
+ getUrl,
419
+ ...options.pageTree
420
+ });
421
+ }
422
+ return pageTree;
423
+ },
424
+ set pageTree(v) {
425
+ pageTree = v;
426
+ },
427
+ getPageByHref(href, { dir = "" } = {}) {
428
+ const pages = Array.from(walker.pages.values());
429
+ const [value, hash] = href.split("#", 2);
430
+ if (value.startsWith(".") && (value.endsWith(".md") || value.endsWith(".mdx"))) {
431
+ const hrefPath = path.join(dir, value);
432
+ const target2 = pages.find((item) => item.file.path === hrefPath);
433
+ if (target2)
434
+ return {
435
+ page: target2,
436
+ hash
437
+ };
438
+ }
439
+ const target = pages.find((item) => item.url === value);
440
+ if (target)
441
+ return {
442
+ page: target,
443
+ hash
444
+ };
445
+ },
413
446
  getPages(language = options.i18n?.defaultLanguage ?? "") {
414
447
  const pages = [];
415
448
  for (const key of walker.pages.keys()) {
@@ -437,9 +470,9 @@ function createOutput(options) {
437
470
  },
438
471
  getPageTree(locale) {
439
472
  if (options.i18n) {
440
- return pageTree[locale ?? options.i18n.defaultLanguage];
473
+ return this.pageTree[locale ?? options.i18n.defaultLanguage];
441
474
  }
442
- return pageTree;
475
+ return this.pageTree;
443
476
  },
444
477
  getNodePage(node) {
445
478
  const ref = node.$ref?.file ?? node.$id;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-core",
3
- "version": "15.0.17",
3
+ "version": "15.1.0",
4
4
  "description": "The library for building a documentation website in Next.js",
5
5
  "keywords": [
6
6
  "NextJs",