fumadocs-core 8.0.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.
@@ -0,0 +1,353 @@
1
+ import {
2
+ flattenNode,
3
+ remarkHeading,
4
+ visit
5
+ } from "../chunk-GT3Y35O6.js";
6
+ import {
7
+ slash
8
+ } from "../chunk-2ZGUSAWB.js";
9
+ import {
10
+ __async,
11
+ __spreadValues
12
+ } from "../chunk-WEAGW6MQ.js";
13
+
14
+ // src/mdx-plugins/index.ts
15
+ import {
16
+ default as default2
17
+ } from "remark-gfm";
18
+
19
+ // src/mdx-plugins/rehype-code.ts
20
+ import rehypeShikiji from "rehype-shikiji";
21
+ import {
22
+ transformerNotationHighlight,
23
+ transformerNotationWordHighlight
24
+ } from "shikiji-transformers";
25
+
26
+ // src/mdx-plugins/hast-utils.ts
27
+ function visit2(node, tagNames, handler) {
28
+ if (node.type === "element") {
29
+ if (tagNames.includes(node.tagName)) {
30
+ handler(node);
31
+ return;
32
+ }
33
+ }
34
+ if ("children" in node)
35
+ node.children.forEach((n) => {
36
+ visit2(n, tagNames, handler);
37
+ });
38
+ }
39
+
40
+ // src/mdx-plugins/rehype-code.ts
41
+ var metaValues = [
42
+ {
43
+ name: "title",
44
+ regex: new RegExp('title="(?<value>[^"]*)"')
45
+ },
46
+ {
47
+ name: "custom",
48
+ regex: new RegExp('custom="(?<value>[^"]+)"')
49
+ }
50
+ ];
51
+ var rehypeCodeDefaultOptions = {
52
+ themes: {
53
+ light: "github-light",
54
+ dark: "github-dark"
55
+ },
56
+ defaultLang: "plaintext",
57
+ defaultColor: false,
58
+ transformers: [
59
+ transformerNotationHighlight(),
60
+ transformerNotationWordHighlight()
61
+ ],
62
+ parseMetaString(meta) {
63
+ const map = {};
64
+ for (const value of metaValues) {
65
+ const result = value.regex.exec(meta);
66
+ if (result == null ? void 0 : result.groups) {
67
+ map[value.name] = result.groups.value;
68
+ }
69
+ }
70
+ return map;
71
+ },
72
+ filterMetaString(meta) {
73
+ let replaced = meta;
74
+ for (const value of metaValues) {
75
+ replaced = replaced.replace(value.regex, "");
76
+ }
77
+ return replaced;
78
+ }
79
+ };
80
+ function rehypeCode(options = {}) {
81
+ const codeOptions = __spreadValues(__spreadValues({}, rehypeCodeDefaultOptions), options);
82
+ codeOptions.transformers || (codeOptions.transformers = []);
83
+ codeOptions.transformers = [
84
+ {
85
+ name: "rehype-code:filter-meta",
86
+ preprocess(code, { meta }) {
87
+ var _a;
88
+ if (meta && codeOptions.filterMetaString) {
89
+ meta.__raw = codeOptions.filterMetaString((_a = meta.__raw) != null ? _a : "");
90
+ }
91
+ return code.replace(/\n$/, "");
92
+ }
93
+ },
94
+ ...codeOptions.transformers
95
+ ];
96
+ const prefix = "language-";
97
+ const transformer = rehypeShikiji.call(this, codeOptions);
98
+ return (root, vfile) => __async(this, null, function* () {
99
+ visit2(root, ["pre"], (element) => {
100
+ var _a;
101
+ const head = element.children[0];
102
+ if (element.children.length === 0 || head.type !== "element" || head.tagName !== "code")
103
+ return;
104
+ (_a = head.properties).className || (_a.className = []);
105
+ const classes = head.properties.className;
106
+ if (!Array.isArray(classes))
107
+ return;
108
+ const hasLanguage = classes.some(
109
+ (d) => typeof d === "string" && d.startsWith(prefix)
110
+ );
111
+ if (!hasLanguage && codeOptions.defaultLang)
112
+ classes.push(`${prefix}${codeOptions.defaultLang}`);
113
+ });
114
+ if (transformer)
115
+ yield transformer.call(this, root, vfile, () => {
116
+ });
117
+ });
118
+ }
119
+
120
+ // src/mdx-plugins/remark-image.ts
121
+ import { existsSync } from "fs";
122
+ import path from "path";
123
+ var VALID_BLUR_EXT = [".jpeg", ".png", ".webp", ".avif", ".jpg"];
124
+ var EXTERNAL_URL_REGEX = /^https?:\/\//;
125
+ var PUBLIC_DIR = path.join(process.cwd(), "public");
126
+ function remarkImage({
127
+ placeholder = "blur"
128
+ } = {}) {
129
+ return (tree, _file, done) => {
130
+ const importsToInject = [];
131
+ visit(tree, ["image"], (node) => {
132
+ var _a;
133
+ let url = decodeURI(node.url);
134
+ if (!url || EXTERNAL_URL_REGEX.test(url)) {
135
+ return;
136
+ }
137
+ if (url.startsWith("/")) {
138
+ const urlPath = path.join(PUBLIC_DIR, url);
139
+ if (!existsSync(urlPath)) {
140
+ return;
141
+ }
142
+ url = slash(urlPath);
143
+ }
144
+ const variableName = `__img${importsToInject.length}`;
145
+ const hasBlur = placeholder === "blur" && VALID_BLUR_EXT.some((ext) => url.endsWith(ext));
146
+ importsToInject.push({ variableName, importPath: url });
147
+ Object.assign(node, {
148
+ type: "mdxJsxFlowElement",
149
+ name: "img",
150
+ attributes: [
151
+ {
152
+ type: "mdxJsxAttribute",
153
+ name: "alt",
154
+ value: (_a = node.alt) != null ? _a : "image"
155
+ },
156
+ hasBlur && {
157
+ type: "mdxJsxAttribute",
158
+ name: "placeholder",
159
+ value: "blur"
160
+ },
161
+ {
162
+ type: "mdxJsxAttribute",
163
+ name: "src",
164
+ value: {
165
+ type: "mdxJsxAttributeValueExpression",
166
+ value: variableName,
167
+ data: {
168
+ estree: {
169
+ body: [
170
+ {
171
+ type: "ExpressionStatement",
172
+ expression: { type: "Identifier", name: variableName }
173
+ }
174
+ ]
175
+ }
176
+ }
177
+ }
178
+ }
179
+ ].filter(Boolean)
180
+ });
181
+ });
182
+ if (importsToInject.length) {
183
+ const imports = importsToInject.map(
184
+ ({ variableName, importPath }) => ({
185
+ type: "mdxjsEsm",
186
+ data: {
187
+ estree: {
188
+ body: [
189
+ {
190
+ type: "ImportDeclaration",
191
+ source: { type: "Literal", value: importPath },
192
+ specifiers: [
193
+ {
194
+ type: "ImportDefaultSpecifier",
195
+ local: { type: "Identifier", name: variableName }
196
+ }
197
+ ]
198
+ }
199
+ ]
200
+ }
201
+ }
202
+ })
203
+ );
204
+ tree.children.unshift(...imports);
205
+ }
206
+ done();
207
+ };
208
+ }
209
+
210
+ // src/mdx-plugins/remark-dynamic-content.ts
211
+ import fs from "fs";
212
+ import path2 from "path";
213
+ var regex = new RegExp("^\\|reference:(?<path>.+)\\|");
214
+ function remarkDynamicContent(options = {}) {
215
+ const {
216
+ cwd = process.cwd(),
217
+ trim = true,
218
+ visit: filter = ["text", "code"]
219
+ } = options;
220
+ return (tree) => {
221
+ visit(tree, filter, (node) => {
222
+ var _a;
223
+ if (!("value" in node) || typeof node.value !== "string")
224
+ return;
225
+ const result = regex.exec(node.value);
226
+ if ((_a = result == null ? void 0 : result.groups) == null ? void 0 : _a.path) {
227
+ const dest = path2.resolve(cwd, result[1]);
228
+ let value = fs.readFileSync(dest).toString();
229
+ if (trim)
230
+ value = value.trim();
231
+ node.value = value;
232
+ }
233
+ });
234
+ };
235
+ }
236
+
237
+ // src/mdx-plugins/remark-structure.ts
238
+ import Slugger from "github-slugger";
239
+ import { remark } from "remark";
240
+ import remarkGfm from "remark-gfm";
241
+ import remarkMdx from "remark-mdx";
242
+ var slugger = new Slugger();
243
+ function remarkStructure({
244
+ types = ["paragraph", "blockquote", "heading"]
245
+ } = {}) {
246
+ return (node, file) => {
247
+ slugger.reset();
248
+ const data = { contents: [], headings: [] };
249
+ let lastHeading = "";
250
+ visit(node, types, (element) => {
251
+ var _a, _b;
252
+ const content = flattenNode(element).trim();
253
+ if (element.type === "heading") {
254
+ element.data || (element.data = {});
255
+ (_a = element.data).hProperties || (_a.hProperties = {});
256
+ const properties = element.data.hProperties;
257
+ const id = (_b = properties.id) != null ? _b : slugger.slug(content);
258
+ data.headings.push({
259
+ id,
260
+ content
261
+ });
262
+ lastHeading = id;
263
+ return "skip";
264
+ }
265
+ if (content.length > 0) {
266
+ data.contents.push({
267
+ heading: lastHeading,
268
+ content
269
+ });
270
+ }
271
+ return "skip";
272
+ });
273
+ file.data.structuredData = data;
274
+ };
275
+ }
276
+ function structure(content, remarkPlugins = [], options = {}) {
277
+ const result = remark().use(remarkGfm).use(remarkMdx).use(remarkPlugins).use(remarkStructure, options).processSync(content);
278
+ return result.data.structuredData;
279
+ }
280
+
281
+ // src/mdx-plugins/remark-install.ts
282
+ function remarkInstall({
283
+ Tab = "Tab",
284
+ Tabs = "Tabs",
285
+ packageManagers = [
286
+ (name) => ({ command: `npm install ${name}`, packageManager: "npm" }),
287
+ (name) => ({ command: `pnpm add ${name}`, packageManager: "pnpm" }),
288
+ (name) => ({ command: `yarn add ${name}`, packageManager: "yarn" })
289
+ ]
290
+ } = {}) {
291
+ return (tree) => {
292
+ visit(tree, ["code"], (node) => {
293
+ if (node.lang !== "package-install")
294
+ return "skip";
295
+ const managers = packageManagers.map((manager) => manager(node.value));
296
+ const insert = {
297
+ type: "mdxJsxFlowElement",
298
+ name: Tabs,
299
+ attributes: [
300
+ {
301
+ type: "mdxJsxAttribute",
302
+ name: "items",
303
+ value: {
304
+ type: "mdxJsxAttributeValueExpression",
305
+ data: {
306
+ estree: {
307
+ body: [
308
+ {
309
+ type: "ExpressionStatement",
310
+ expression: {
311
+ type: "ArrayExpression",
312
+ elements: managers.map(({ packageManager }) => ({
313
+ type: "Literal",
314
+ value: packageManager
315
+ }))
316
+ }
317
+ }
318
+ ]
319
+ }
320
+ }
321
+ }
322
+ }
323
+ ],
324
+ children: managers.map(({ command, packageManager }) => ({
325
+ type: "mdxJsxFlowElement",
326
+ name: Tab,
327
+ attributes: [
328
+ { type: "mdxJsxAttribute", name: "value", value: packageManager }
329
+ ],
330
+ children: [
331
+ {
332
+ type: "code",
333
+ lang: "bash",
334
+ value: command
335
+ }
336
+ ]
337
+ }))
338
+ };
339
+ Object.assign(node, insert);
340
+ });
341
+ };
342
+ }
343
+ export {
344
+ rehypeCode,
345
+ rehypeCodeDefaultOptions,
346
+ remarkDynamicContent,
347
+ default2 as remarkGfm,
348
+ remarkHeading,
349
+ remarkImage,
350
+ remarkInstall,
351
+ remarkStructure,
352
+ structure
353
+ };
@@ -0,0 +1,10 @@
1
+ import { NextMiddleware } from 'next/dist/server/web/types';
2
+
3
+ interface MiddlewareOptions {
4
+ languages: string[];
5
+ defaultLanguage: string;
6
+ format?: (locale: string, path: string) => string;
7
+ }
8
+ declare function createI18nMiddleware({ languages, defaultLanguage, format, }: MiddlewareOptions): NextMiddleware;
9
+
10
+ export { createI18nMiddleware };
@@ -0,0 +1,43 @@
1
+ import "./chunk-WEAGW6MQ.js";
2
+
3
+ // src/middleware.ts
4
+ import { match as matchLocale } from "@formatjs/intl-localematcher";
5
+ import Negotiator from "negotiator";
6
+ import nextLib from "next/server";
7
+ function getLocale(request, locales, defaultLanguage) {
8
+ const negotiatorHeaders = {};
9
+ request.headers.forEach((value, key) => negotiatorHeaders[key] = value);
10
+ const languages = new Negotiator({ headers: negotiatorHeaders }).languages(
11
+ locales
12
+ );
13
+ return matchLocale(languages, locales, defaultLanguage);
14
+ }
15
+ var defaultFormat = (locale, path) => {
16
+ return `/${locale}/${path}`;
17
+ };
18
+ function createI18nMiddleware({
19
+ languages,
20
+ defaultLanguage,
21
+ format = defaultFormat
22
+ }) {
23
+ return (request) => {
24
+ const { pathname } = request.nextUrl;
25
+ const pathnameIsMissingLocale = languages.every(
26
+ (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
27
+ );
28
+ if (pathnameIsMissingLocale) {
29
+ const locale = getLocale(request, languages, defaultLanguage);
30
+ let path = pathname;
31
+ while (path.startsWith("/")) {
32
+ path = path.slice(1);
33
+ }
34
+ return nextLib.NextResponse.redirect(
35
+ new URL(format(locale, path), request.url)
36
+ );
37
+ }
38
+ return nextLib.NextResponse.next();
39
+ };
40
+ }
41
+ export {
42
+ createI18nMiddleware
43
+ };
@@ -0,0 +1,37 @@
1
+ import { ReactElement } from 'react';
2
+
3
+ interface Root {
4
+ name: string;
5
+ children: Node[];
6
+ }
7
+ type Node = Item | Separator | Folder;
8
+ interface Item {
9
+ type: 'page';
10
+ name: string;
11
+ url: string;
12
+ external?: boolean;
13
+ icon?: ReactElement;
14
+ }
15
+ interface Separator {
16
+ type: 'separator';
17
+ name: string;
18
+ }
19
+ interface Folder {
20
+ type: 'folder';
21
+ name: string;
22
+ root?: boolean;
23
+ index?: Item;
24
+ icon?: ReactElement;
25
+ children: Node[];
26
+ }
27
+
28
+ type pageTree_Folder = Folder;
29
+ type pageTree_Item = Item;
30
+ type pageTree_Node = Node;
31
+ type pageTree_Root = Root;
32
+ type pageTree_Separator = Separator;
33
+ declare namespace pageTree {
34
+ export type { pageTree_Folder as Folder, pageTree_Item as Item, pageTree_Node as Node, pageTree_Root as Root, pageTree_Separator as Separator };
35
+ }
36
+
37
+ export { type Item as I, type Node as N, type Root as R, pageTree as p };
@@ -0,0 +1,34 @@
1
+ import { Root } from 'mdast';
2
+ import { Transformer, PluggableList } from 'unified';
3
+
4
+ interface Heading {
5
+ id: string;
6
+ content: string;
7
+ }
8
+ interface Content {
9
+ heading: string | undefined;
10
+ content: string;
11
+ }
12
+ interface StructuredData {
13
+ headings: Heading[];
14
+ /**
15
+ * Refer to paragraphs, a heading may contains multiple contents as well
16
+ */
17
+ contents: Content[];
18
+ }
19
+ interface Options {
20
+ /**
21
+ * Types to be scanned, default: `["heading", "blockquote", "paragraph"]`
22
+ */
23
+ types?: string[];
24
+ }
25
+ /**
26
+ * Attach structured data to VFile, you can access via `vfile.data.structuredData`.
27
+ */
28
+ declare function remarkStructure({ types, }?: Options): Transformer<Root, Root>;
29
+ /**
30
+ * Extract data from markdown/mdx content
31
+ */
32
+ declare function structure(content: string, remarkPlugins?: PluggableList, options?: Options): StructuredData;
33
+
34
+ export { type StructuredData as S, remarkStructure as r, structure as s };
@@ -0,0 +1,13 @@
1
+ import { SWRResponse } from 'swr';
2
+ import { SortedResult } from './shared.js';
3
+
4
+ interface UseDocsSearch {
5
+ search: string;
6
+ setSearch: (v: string) => void;
7
+ query: SWRResponse<SortedResult[] | 'empty', Error, {
8
+ keepPreviousData: true;
9
+ }>;
10
+ }
11
+ declare function useDocsSearch(locale?: string, tag?: string): UseDocsSearch;
12
+
13
+ export { useDocsSearch };
@@ -0,0 +1,52 @@
1
+ import {
2
+ __async
3
+ } from "../chunk-WEAGW6MQ.js";
4
+
5
+ // src/search/client.ts
6
+ import { useEffect, useState } from "react";
7
+ import useSWR from "swr";
8
+ function fetchDocs(api, query, locale, tag) {
9
+ return __async(this, null, function* () {
10
+ if (query.length === 0)
11
+ return "empty";
12
+ const params = new URLSearchParams();
13
+ params.set("query", query);
14
+ if (locale)
15
+ params.set("locale", locale);
16
+ if (tag)
17
+ params.set("tag", tag);
18
+ const res = yield fetch(`${api}?${params.toString()}`);
19
+ if (!res.ok)
20
+ throw new Error(yield res.text());
21
+ return yield res.json();
22
+ });
23
+ }
24
+ function useDocsSearch(locale, tag) {
25
+ const [search, setSearch] = useState("");
26
+ const debouncedValue = useDebounce(search, 100);
27
+ const query = useSWR(
28
+ ["/api/search", debouncedValue, locale, tag],
29
+ (_0) => __async(this, [_0], function* ([api, value]) {
30
+ return fetchDocs(api, value, locale, tag);
31
+ }),
32
+ {
33
+ keepPreviousData: true
34
+ }
35
+ );
36
+ return { search, setSearch, query };
37
+ }
38
+ function useDebounce(value, delayMs = 1e3) {
39
+ const [debouncedValue, setDebouncedValue] = useState(value);
40
+ useEffect(() => {
41
+ const handler = setTimeout(() => {
42
+ setDebouncedValue(value);
43
+ }, delayMs);
44
+ return () => {
45
+ clearTimeout(handler);
46
+ };
47
+ }, [value, delayMs]);
48
+ return debouncedValue;
49
+ }
50
+ export {
51
+ useDocsSearch
52
+ };
@@ -0,0 +1,51 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { S as StructuredData } from '../remark-structure-RwYPDA6M.js';
3
+ import { SortedResult } from './shared.js';
4
+ import 'mdast';
5
+ import 'unified';
6
+
7
+ interface SearchAPI {
8
+ GET: (request: NextRequest) => NextResponse<SortedResult[]> | Promise<NextResponse<SortedResult[]>>;
9
+ }
10
+ interface SimpleOptions {
11
+ indexes: Index[];
12
+ language?: string;
13
+ }
14
+ interface AdvancedOptions {
15
+ indexes: AdvancedIndex[];
16
+ /**
17
+ * Enabled custom tags
18
+ */
19
+ tag?: boolean;
20
+ language?: string;
21
+ }
22
+ type ToI18n<T extends {
23
+ indexes: unknown;
24
+ }> = Omit<T, 'indexes' | 'language'> & {
25
+ indexes: [language: string, indexes: T['indexes']][];
26
+ };
27
+ declare function createSearchAPI<T extends 'simple' | 'advanced'>(type: T, options: T extends 'simple' ? SimpleOptions : AdvancedOptions): SearchAPI;
28
+ declare function createI18nSearchAPI<T extends 'simple' | 'advanced'>(type: T, options: ToI18n<T extends 'simple' ? SimpleOptions : AdvancedOptions>): SearchAPI;
29
+ interface Index {
30
+ title: string;
31
+ content: string;
32
+ url: string;
33
+ keywords?: string;
34
+ }
35
+ declare function initSearchAPI({ indexes, language }: SimpleOptions): SearchAPI;
36
+ interface AdvancedIndex {
37
+ id: string;
38
+ title: string;
39
+ /**
40
+ * Required if `tag` is enabled
41
+ */
42
+ tag?: string;
43
+ /**
44
+ * preprocess mdx content with `structure`
45
+ */
46
+ structuredData: StructuredData;
47
+ url: string;
48
+ }
49
+ declare function initSearchAPIAdvanced({ indexes, language, tag, }: AdvancedOptions): SearchAPI;
50
+
51
+ export { createI18nSearchAPI, createSearchAPI, initSearchAPI, initSearchAPIAdvanced };