fumadocs-core 11.1.2 → 11.1.3

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.
@@ -5,6 +5,11 @@ interface MiddlewareOptions {
5
5
  defaultLanguage: string;
6
6
  format?: (locale: string, path: string) => string;
7
7
  }
8
+ /**
9
+ * @param languages - Supported locale codes
10
+ * @param defaultLanguage - Default local if not specified
11
+ * @param format - A function that returns the redirected url with locale code
12
+ */
8
13
  declare function createI18nMiddleware({ languages, defaultLanguage, format, }: MiddlewareOptions): NextMiddleware;
9
14
 
10
15
  export { createI18nMiddleware };
@@ -3,7 +3,7 @@ import "./chunk-WEAGW6MQ.js";
3
3
  // src/middleware.ts
4
4
  import { match as matchLocale } from "@formatjs/intl-localematcher";
5
5
  import Negotiator from "negotiator";
6
- import nextLib from "next/server";
6
+ import { NextResponse } from "next/server";
7
7
  function getLocale(request, locales, defaultLanguage) {
8
8
  const negotiatorHeaders = {};
9
9
  request.headers.forEach((value, key) => negotiatorHeaders[key] = value);
@@ -31,11 +31,9 @@ function createI18nMiddleware({
31
31
  while (path.startsWith("/")) {
32
32
  path = path.slice(1);
33
33
  }
34
- return nextLib.NextResponse.redirect(
35
- new URL(format(locale, path), request.url)
36
- );
34
+ return NextResponse.redirect(new URL(format(locale, path), request.url));
37
35
  }
38
- return nextLib.NextResponse.next();
36
+ return NextResponse.next();
39
37
  };
40
38
  }
41
39
  export {
@@ -26,10 +26,13 @@ interface AdvancedOptions {
26
26
  type ToI18n<T extends {
27
27
  indexes: unknown;
28
28
  }> = Omit<T, 'indexes' | 'language'> & {
29
- indexes: [language: string, indexes: T['indexes']][];
29
+ indexes: ([language: string, indexes: T['indexes']] | {
30
+ language: string;
31
+ indexes: T['indexes'];
32
+ })[];
30
33
  };
31
34
  declare function createSearchAPI<T extends 'simple' | 'advanced'>(type: T, options: T extends 'simple' ? SimpleOptions : AdvancedOptions): SearchAPI;
32
- declare function createI18nSearchAPI<T extends 'simple' | 'advanced'>(type: T, options: ToI18n<T extends 'simple' ? SimpleOptions : AdvancedOptions>): SearchAPI;
35
+ declare function createI18nSearchAPI<T extends 'simple' | 'advanced'>(type: T, options: T extends 'simple' ? ToI18n<SimpleOptions> : ToI18n<AdvancedOptions>): SearchAPI;
33
36
  interface Index {
34
37
  title: string;
35
38
  content: string;
@@ -52,4 +55,4 @@ interface AdvancedIndex {
52
55
  }
53
56
  declare function initSearchAPIAdvanced({ indexes, language, tag, }: AdvancedOptions): SearchAPI;
54
57
 
55
- export { createI18nSearchAPI, createSearchAPI, initSearchAPI, initSearchAPIAdvanced };
58
+ export { type AdvancedIndex, type Index, createI18nSearchAPI, createSearchAPI, initSearchAPI, initSearchAPIAdvanced };
@@ -31,13 +31,14 @@ function createSearchAPI(type, options) {
31
31
  }
32
32
  function createI18nSearchAPI(type, options) {
33
33
  const map = /* @__PURE__ */ new Map();
34
- for (const [k, v] of options.indexes) {
34
+ for (const entry of options.indexes) {
35
+ const v = Array.isArray(entry) ? { language: entry[0], indexes: entry[1] } : entry;
35
36
  map.set(
36
- k,
37
+ v.language,
37
38
  createSearchAPI(type, __spreadProps(__spreadValues({}, options), {
38
- language: k,
39
+ language: v.language,
39
40
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment -- Avoid complicated types
40
- indexes: v
41
+ indexes: v.indexes
41
42
  }))
42
43
  );
43
44
  }
@@ -41,6 +41,7 @@ declare class Storage {
41
41
  constructor();
42
42
  /**
43
43
  * @param path - flattened path
44
+ * @param format - file format
44
45
  */
45
46
  read(path: string, format: string): File | undefined;
46
47
  readDir(path: string): Folder | undefined;
@@ -58,27 +59,10 @@ declare namespace fileSystem {
58
59
  export { type fileSystem_File as File, type fileSystem_Folder as Folder, fileSystem_Storage as Storage };
59
60
  }
60
61
 
61
- interface BuildPageTreeOptionsWithI18n {
62
- languages: string[];
63
- }
64
- interface PageTreeBuilder {
65
- build: () => Root;
66
- /**
67
- * Build page tree and fallback to the default language if the localized page doesn't exist
68
- */
69
- buildI18n: (options?: Partial<BuildPageTreeOptionsWithI18n>) => Record<string, Root>;
70
- }
71
- interface CreatePageTreeBuilderOptions {
72
- storage: Storage;
73
- resolveIcon?: (icon: string) => ReactElement | undefined;
74
- }
75
- declare function createPageTreeBuilder({ storage, resolveIcon, }: CreatePageTreeBuilderOptions): PageTreeBuilder;
76
-
77
62
  interface LoadOptions {
78
63
  transformers?: Transformer[];
79
64
  rootDir?: string;
80
65
  getSlugs: (info: FileInfo) => string[];
81
- getUrl: (slugs: string[], locale?: string) => string;
82
66
  }
83
67
  interface VirtualFile {
84
68
  /**
@@ -95,33 +79,6 @@ type Transformer = (context: {
95
79
  options: LoadOptions;
96
80
  }) => void;
97
81
 
98
- interface MetaData {
99
- icon?: string;
100
- title?: string;
101
- root?: boolean;
102
- pages?: string[];
103
- defaultOpen?: boolean;
104
- }
105
- interface PageData {
106
- icon?: string;
107
- title: string;
108
- }
109
- type InferPageType<Utils extends LoaderOutput<any>> = Utils extends LoaderOutput<infer Config> ? Page<Config['source']['pageData']> : never;
110
- type InferMetaType<Utils extends LoaderOutput<any>> = Utils extends LoaderOutput<infer Config> ? Meta<Config['source']['metaData']> : never;
111
- /**
112
- * @internal
113
- */
114
- interface FileData {
115
- meta: {
116
- data: MetaData;
117
- };
118
- file: {
119
- url: string;
120
- slugs: string[];
121
- data: PageData;
122
- };
123
- }
124
-
125
82
  interface LoaderConfig {
126
83
  source: SourceConfig;
127
84
  i18n: boolean;
@@ -142,7 +99,7 @@ interface LoaderOptions {
142
99
  languages?: string[];
143
100
  icon?: NonNullable<CreatePageTreeBuilderOptions['resolveIcon']>;
144
101
  slugs?: LoadOptions['getSlugs'];
145
- url?: LoadOptions['getUrl'];
102
+ url?: UrlFn;
146
103
  source: Source<any>;
147
104
  transformers?: Transformer[];
148
105
  }
@@ -163,6 +120,10 @@ interface Meta<Data = MetaData> {
163
120
  file: FileInfo;
164
121
  data: Data;
165
122
  }
123
+ interface LanguageEntry<Data = PageData> {
124
+ language: string;
125
+ pages: Page<Data>[];
126
+ }
166
127
  interface LoaderOutput<Config extends LoaderConfig> {
167
128
  pageTree: Config['i18n'] extends true ? Record<string, Root> : Root;
168
129
  files: File[];
@@ -172,12 +133,13 @@ interface LoaderOutput<Config extends LoaderConfig> {
172
133
  * @param language - If empty, the default language will be used
173
134
  */
174
135
  getPages: (language?: string) => Page<Config['source']['pageData']>[];
136
+ getLanguages: () => LanguageEntry<Config['source']['pageData']>[];
175
137
  /**
176
138
  * @param language - If empty, the default language will be used
177
139
  */
178
140
  getPage: (slugs: string[] | undefined, language?: string) => Page<Config['source']['pageData']> | undefined;
179
141
  }
180
- declare function createGetUrl(baseUrl: string): (slugs: string[], locale?: string) => string;
142
+ declare function createGetUrl(baseUrl: string): UrlFn;
181
143
  declare function getSlugs(info: FileInfo): string[];
182
144
  type InferSourceConfig<T> = T extends Source<infer Config> ? Config : never;
183
145
  declare function loader<Options extends LoaderOptions>(options: Options): LoaderOutput<{
@@ -185,4 +147,51 @@ declare function loader<Options extends LoaderOptions>(options: Options): Loader
185
147
  i18n: Options['languages'] extends string[] ? true : false;
186
148
  }>;
187
149
 
188
- export { type BuildPageTreeOptionsWithI18n, type CreatePageTreeBuilderOptions, type FileData, type FileInfo, fileSystem as FileSystem, type InferMetaType, type InferPageType, 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 VirtualFile, createGetUrl, createPageTreeBuilder, getSlugs, loader, parseFilePath, parseFolderPath };
150
+ interface MetaData {
151
+ icon?: string;
152
+ title?: string;
153
+ root?: boolean;
154
+ pages?: string[];
155
+ defaultOpen?: boolean;
156
+ }
157
+ interface PageData {
158
+ icon?: string;
159
+ title: string;
160
+ }
161
+ type InferPageType<Utils extends LoaderOutput<any>> = Utils extends LoaderOutput<infer Config> ? Page<Config['source']['pageData']> : never;
162
+ type InferMetaType<Utils extends LoaderOutput<any>> = Utils extends LoaderOutput<infer Config> ? Meta<Config['source']['metaData']> : never;
163
+ /**
164
+ * @internal
165
+ */
166
+ type UrlFn = (slugs: string[], locale?: string) => string;
167
+ /**
168
+ * @internal
169
+ */
170
+ interface FileData {
171
+ meta: {
172
+ data: MetaData;
173
+ };
174
+ file: {
175
+ slugs: string[];
176
+ data: PageData;
177
+ };
178
+ }
179
+
180
+ interface BuildPageTreeOptionsWithI18n {
181
+ languages: string[];
182
+ }
183
+ interface PageTreeBuilder {
184
+ build: () => Root;
185
+ /**
186
+ * Build page tree and fallback to the default language if the localized page doesn't exist
187
+ */
188
+ buildI18n: (options?: Partial<BuildPageTreeOptionsWithI18n>) => Record<string, Root>;
189
+ }
190
+ interface CreatePageTreeBuilderOptions {
191
+ storage: Storage;
192
+ getUrl: UrlFn;
193
+ resolveIcon?: (icon: string | undefined) => ReactElement | undefined;
194
+ }
195
+ declare function createPageTreeBuilder(options: CreatePageTreeBuilderOptions): PageTreeBuilder;
196
+
197
+ export { type BuildPageTreeOptionsWithI18n, type CreatePageTreeBuilderOptions, type FileData, 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, loader, parseFilePath, parseFolderPath };
@@ -2,7 +2,9 @@ import {
2
2
  slash
3
3
  } from "../chunk-UWEEHUJV.js";
4
4
  import {
5
- __export
5
+ __export,
6
+ __spreadProps,
7
+ __spreadValues
6
8
  } from "../chunk-WEAGW6MQ.js";
7
9
 
8
10
  // src/source/path.ts
@@ -41,7 +43,7 @@ function normalizePath(path) {
41
43
  function splitPath(path) {
42
44
  return path.split("/").filter((p) => p.length > 0);
43
45
  }
44
- function resolvePath(from, join, slashMode = "none") {
46
+ function resolvePath(from, join) {
45
47
  const v1 = splitPath(from), v2 = splitPath(join);
46
48
  while (v2.length > 0) {
47
49
  switch (v2[0]) {
@@ -55,15 +57,7 @@ function resolvePath(from, join, slashMode = "none") {
55
57
  }
56
58
  v2.shift();
57
59
  }
58
- const joined = v1.join("/");
59
- switch (slashMode) {
60
- case "leading":
61
- return `/${joined}`;
62
- case "trailing":
63
- return `${joined}/`;
64
- default:
65
- return joined;
66
- }
60
+ return v1.join("/");
67
61
  }
68
62
 
69
63
  // src/source/page-tree-builder.ts
@@ -133,7 +127,7 @@ function resolveFolderItem(folder, item, ctx, addedNodePaths) {
133
127
  return [buildFileNode(itemNode, ctx)];
134
128
  }
135
129
  function buildFolderNode(folder, defaultIsRoot, ctx) {
136
- var _a, _b, _c, _d, _e;
130
+ var _a, _b, _c, _d, _e, _f;
137
131
  const metaPath = resolvePath(folder.file.path, "meta");
138
132
  let meta = ctx.storage.read(metaPath, "meta");
139
133
  meta = (_a = findLocalizedFile(metaPath, "meta", ctx)) != null ? _a : meta;
@@ -168,7 +162,7 @@ function buildFolderNode(folder, defaultIsRoot, ctx) {
168
162
  return removeUndefined({
169
163
  type: "folder",
170
164
  name: (_e = (_d = metadata == null ? void 0 : metadata.title) != null ? _d : index == null ? void 0 : index.name) != null ? _e : pathToName(folder.file.name),
171
- icon: ctx.resolveIcon(metadata == null ? void 0 : metadata.icon),
165
+ icon: (_f = ctx.resolveIcon) == null ? void 0 : _f.call(ctx, metadata == null ? void 0 : metadata.icon),
172
166
  root: metadata == null ? void 0 : metadata.root,
173
167
  defaultOpen: metadata == null ? void 0 : metadata.defaultOpen,
174
168
  index,
@@ -176,14 +170,14 @@ function buildFolderNode(folder, defaultIsRoot, ctx) {
176
170
  });
177
171
  }
178
172
  function buildFileNode(file, ctx) {
179
- var _a;
173
+ var _a, _b;
180
174
  const localized = (_a = findLocalizedFile(file.file.flattenedPath, "page", ctx)) != null ? _a : file;
181
175
  const data = localized.data;
182
176
  return removeUndefined({
183
177
  type: "page",
184
178
  name: data.data.title,
185
- icon: ctx.resolveIcon(data.data.icon),
186
- url: data.url
179
+ icon: (_b = ctx.resolveIcon) == null ? void 0 : _b.call(ctx, data.data.icon),
180
+ url: ctx.getUrl(data.slugs, ctx.lang)
187
181
  });
188
182
  }
189
183
  function build(ctx) {
@@ -194,21 +188,12 @@ function build(ctx) {
194
188
  children: folder.children
195
189
  };
196
190
  }
197
- function createPageTreeBuilder({
198
- storage,
199
- resolveIcon = () => void 0
200
- }) {
191
+ function createPageTreeBuilder(options) {
201
192
  function getContext(builder, locale) {
202
- return {
203
- storage,
193
+ return __spreadProps(__spreadValues({}, options), {
204
194
  lang: locale,
205
- resolveIcon(icon) {
206
- if (!icon)
207
- return;
208
- return resolveIcon(icon);
209
- },
210
195
  builder
211
- };
196
+ });
212
197
  }
213
198
  return {
214
199
  build() {
@@ -257,6 +242,7 @@ var Storage = class {
257
242
  }
258
243
  /**
259
244
  * @param path - flattened path
245
+ * @param format - file format
260
246
  */
261
247
  read(path, format) {
262
248
  return this.files.get(`${path}.${format}`);
@@ -314,7 +300,6 @@ function loadFiles(files, options) {
314
300
  const slugs = options.getSlugs(parsedPath);
315
301
  storage.write(relativePath, file.type, {
316
302
  slugs,
317
- url: options.getUrl(slugs, parsedPath.locale),
318
303
  data: file.data
319
304
  });
320
305
  }
@@ -334,7 +319,7 @@ function loadFiles(files, options) {
334
319
  }
335
320
 
336
321
  // src/source/loader.ts
337
- function buildPageMap(storage, languages) {
322
+ function buildPageMap(storage, languages, getUrl) {
338
323
  var _a;
339
324
  const map = /* @__PURE__ */ new Map();
340
325
  const defaultMap = /* @__PURE__ */ new Map();
@@ -342,7 +327,7 @@ function buildPageMap(storage, languages) {
342
327
  for (const file of storage.list()) {
343
328
  if (file.format !== "page" || file.file.locale)
344
329
  continue;
345
- const page = fileToPage(file);
330
+ const page = fileToPage(file, getUrl);
346
331
  defaultMap.set(page.slugs.join("/"), page);
347
332
  for (const lang of languages) {
348
333
  const langMap = (_a = map.get(lang)) != null ? _a : /* @__PURE__ */ new Map();
@@ -350,7 +335,7 @@ function buildPageMap(storage, languages) {
350
335
  `${file.file.flattenedPath}.${lang}`,
351
336
  "page"
352
337
  );
353
- const localizedPage = localized ? fileToPage(localized) : page;
338
+ const localizedPage = fileToPage(localized != null ? localized : file, getUrl, lang);
354
339
  langMap.set(localizedPage.slugs.join("/"), localizedPage);
355
340
  map.set(lang, langMap);
356
341
  }
@@ -378,21 +363,21 @@ function createOutput({
378
363
  transformers,
379
364
  baseUrl = "/",
380
365
  slugs: slugsFn = getSlugs,
381
- url: urlFn = createGetUrl(baseUrl)
366
+ url: getUrl = createGetUrl(baseUrl)
382
367
  }) {
383
368
  const storage = loadFiles(
384
369
  typeof source.files === "function" ? source.files(rootDir) : source.files,
385
370
  {
386
371
  transformers,
387
372
  rootDir,
388
- getSlugs: slugsFn,
389
- getUrl: urlFn
373
+ getSlugs: slugsFn
390
374
  }
391
375
  );
392
- const i18nMap = buildPageMap(storage, languages != null ? languages : []);
376
+ const i18nMap = buildPageMap(storage, languages != null ? languages : [], getUrl);
393
377
  const builder = createPageTreeBuilder({
394
378
  storage,
395
- resolveIcon: icon
379
+ resolveIcon: icon,
380
+ getUrl
396
381
  });
397
382
  const pageTree = languages === void 0 ? builder.build() : builder.buildI18n({ languages });
398
383
  return {
@@ -402,17 +387,27 @@ function createOutput({
402
387
  var _a, _b;
403
388
  return Array.from((_b = (_a = i18nMap.get(language)) == null ? void 0 : _a.values()) != null ? _b : []);
404
389
  },
390
+ getLanguages() {
391
+ const list = [];
392
+ for (const [language, pages] of i18nMap) {
393
+ list.push({
394
+ language,
395
+ pages: Array.from(pages.values())
396
+ });
397
+ }
398
+ return list;
399
+ },
405
400
  getPage(slugs = [], language = "") {
406
401
  var _a;
407
402
  return (_a = i18nMap.get(language)) == null ? void 0 : _a.get(slugs.join("/"));
408
403
  }
409
404
  };
410
405
  }
411
- function fileToPage(file) {
406
+ function fileToPage(file, getUrl, locale) {
412
407
  const data = file.data;
413
408
  return {
414
409
  file: file.file,
415
- url: data.url,
410
+ url: getUrl(data.slugs, locale),
416
411
  slugs: data.slugs,
417
412
  data: data.data
418
413
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-core",
3
- "version": "11.1.2",
3
+ "version": "11.1.3",
4
4
  "description": "The library for building a documentation website in Next.js",
5
5
  "keywords": [
6
6
  "NextJs",