fumadocs-core 16.15.17 → 16.16.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.
- package/dist/mdx-plugins/index.js +1 -1
- package/dist/mdx-plugins/rehype-code.core.js +1 -1
- package/dist/mdx-plugins/rehype-code.js +1 -1
- package/dist/{rehype-code.core-BwKlAUQz.js → rehype-code.core-BFENmmvo.js} +8 -4
- package/dist/search/client/meilisearch.d.ts +20 -0
- package/dist/search/client/meilisearch.js +50 -0
- package/dist/search/meilisearch.d.ts +50 -0
- package/dist/search/meilisearch.js +55 -0
- package/package.json +19 -12
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { remarkHeading } from "./remark-heading.js";
|
|
2
2
|
import { generateCodeBlockTabs, parseCodeBlockAttributes } from "./codeblock-utils.js";
|
|
3
3
|
import { remarkGfm } from "./remark-gfm.js";
|
|
4
|
-
import { r as transformerTab } from "../rehype-code.core-
|
|
4
|
+
import { r as transformerTab } from "../rehype-code.core-BFENmmvo.js";
|
|
5
5
|
import { transformerIcon } from "./transformer-icon.js";
|
|
6
6
|
import { rehypeCode, rehypeCodeDefaultOptions } from "./rehype-code.js";
|
|
7
7
|
import { remarkImage } from "./remark-image.js";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as rehypeCodeDefaultOptions, r as transformerTab, t as createRehypeCode } from "../rehype-code.core-
|
|
1
|
+
import { n as rehypeCodeDefaultOptions, r as transformerTab, t as createRehypeCode } from "../rehype-code.core-BFENmmvo.js";
|
|
2
2
|
import { transformerIcon } from "./transformer-icon.js";
|
|
3
3
|
export { createRehypeCode, rehypeCodeDefaultOptions, transformerIcon, transformerTab };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defaultShikiFactory, wasmShikiFactory } from "../highlight/shiki/full.js";
|
|
2
|
-
import { n as rehypeCodeDefaultOptions$1, r as transformerTab, t as createRehypeCode } from "../rehype-code.core-
|
|
2
|
+
import { n as rehypeCodeDefaultOptions$1, r as transformerTab, t as createRehypeCode } from "../rehype-code.core-BFENmmvo.js";
|
|
3
3
|
import { transformerIcon } from "./transformer-icon.js";
|
|
4
4
|
//#region src/mdx-plugins/rehype-code.ts
|
|
5
5
|
const rehypeCodeDefaultOptions = {
|
|
@@ -121,10 +121,11 @@ function transformerAddLanguage(lang) {
|
|
|
121
121
|
};
|
|
122
122
|
}
|
|
123
123
|
//#endregion
|
|
124
|
-
//#region ../../node_modules/.pnpm/@shikijs+transformers@4.
|
|
124
|
+
//#region ../../node_modules/.pnpm/@shikijs+transformers@4.5.0/node_modules/@shikijs/transformers/dist/index.mjs
|
|
125
125
|
const RE_SPLIT_COMMENT = /(\s+\/\/)/;
|
|
126
126
|
const RE_V1_END_COMMENT_PREFIX = /(?:\/\/|["'#]|;{1,2}|%{1,2}|--)(\s*)$/;
|
|
127
127
|
const RE_V3_END_COMMENT_PREFIX = /(?:\/\/|#|;{1,2}|%{1,2}|--)(\s*)$/;
|
|
128
|
+
const RE_LINE_COMMENT_PREFIX = /^(?:\/\/|["'#]|;{1,2}|%{1,2}|--)$/;
|
|
128
129
|
/**
|
|
129
130
|
* some comment formats have to be located at the end of line
|
|
130
131
|
* hence we can skip matching them for other tokens
|
|
@@ -184,7 +185,7 @@ function parseComments(lines, jsx, matchAlgorithm) {
|
|
|
184
185
|
const prevToken = elements[i - 1];
|
|
185
186
|
if (prevToken?.type === "element") {
|
|
186
187
|
const prevHead = prevToken.children.at(0);
|
|
187
|
-
if (prevHead?.type === "text" && prevHead.value.includes("//")) {
|
|
188
|
+
if (prevHead?.type === "text" && (prevHead.value.includes("//") || RE_LINE_COMMENT_PREFIX.test(prevHead.value.trim()))) {
|
|
188
189
|
const combinedMatch = matchToken(prevHead.value + head.value, isLast);
|
|
189
190
|
if (combinedMatch) {
|
|
190
191
|
match = combinedMatch;
|
|
@@ -270,6 +271,7 @@ function v3ClearEndCommentPrefix(text) {
|
|
|
270
271
|
if (match && match[1].trim().length === 0) return text.slice(0, match.index).trimEnd();
|
|
271
272
|
return text;
|
|
272
273
|
}
|
|
274
|
+
const RE_NOTATION = /#?\s*\[!code\b(?:\\.|[^\]])*\]/gi;
|
|
273
275
|
function createCommentNotationTransformer(name, regex, onMatch, matchAlgorithm) {
|
|
274
276
|
matchAlgorithm ??= "v3";
|
|
275
277
|
return {
|
|
@@ -284,7 +286,8 @@ function createCommentNotationTransformer(name, regex, onMatch, matchAlgorithm)
|
|
|
284
286
|
for (const comment of parsed) {
|
|
285
287
|
if (comment.info[1].length === 0) continue;
|
|
286
288
|
let lineIdx = lines.indexOf(comment.line);
|
|
287
|
-
|
|
289
|
+
const isStandaloneNotation = comment.info[1].replace(RE_NOTATION, "").replace(regex, "").trim().length === 0;
|
|
290
|
+
if (comment.isLineCommentOnly && isStandaloneNotation && matchAlgorithm !== "v1") lineIdx++;
|
|
288
291
|
let replaced = false;
|
|
289
292
|
comment.info[1] = comment.info[1].replace(regex, (...match) => {
|
|
290
293
|
if (onMatch.call(this, match, comment.line, comment.token, lines, lineIdx)) {
|
|
@@ -449,12 +452,13 @@ function inheritElement(original, overrides) {
|
|
|
449
452
|
const RE_CODE_WORD = /\s*\[!code word:((?:\\.|[^:\]])+)(:\d+)?\]/;
|
|
450
453
|
const RE_UNESCAPE = /\\(.)/g;
|
|
451
454
|
function transformerNotationWordHighlight(options = {}) {
|
|
452
|
-
const { classActiveWord = "highlighted-word", classActivePre = void 0 } = options;
|
|
455
|
+
const { classActiveWord = "highlighted-word", classActivePre = void 0, classActiveCode = void 0 } = options;
|
|
453
456
|
return createCommentNotationTransformer("@shikijs/transformers:notation-highlight-word", RE_CODE_WORD, function([_, word, range], _line, comment, lines, index) {
|
|
454
457
|
const lineNum = range ? Number.parseInt(range.slice(1), 10) : lines.length;
|
|
455
458
|
word = word.replace(RE_UNESCAPE, "$1");
|
|
456
459
|
for (let i = index; i < Math.min(index + lineNum, lines.length); i++) highlightWordInLine.call(this, lines[i], comment, word, classActiveWord);
|
|
457
460
|
if (classActivePre) this.addClassToHast(this.pre, classActivePre);
|
|
461
|
+
if (classActiveCode) this.addClassToHast(this.code, classActiveCode);
|
|
458
462
|
return true;
|
|
459
463
|
}, options.matchAlgorithm);
|
|
460
464
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { n as SearchClient } from "../../client-BcR4jyFl.js";
|
|
2
|
+
import { Meilisearch } from "meilisearch";
|
|
3
|
+
//#region src/search/client/meilisearch.d.ts
|
|
4
|
+
export interface MeilisearchOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Meilisearch client with a search API key
|
|
7
|
+
*/
|
|
8
|
+
client: Meilisearch;
|
|
9
|
+
indexName: string;
|
|
10
|
+
/**
|
|
11
|
+
* Filter results with specific tag(s).
|
|
12
|
+
*/
|
|
13
|
+
tag?: string | string[];
|
|
14
|
+
/**
|
|
15
|
+
* Filter results by locale.
|
|
16
|
+
*/
|
|
17
|
+
locale?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function meilisearchClient(options: MeilisearchOptions): SearchClient;
|
|
20
|
+
//#endregion
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createContentHighlighter } from "../index.js";
|
|
2
|
+
//#region src/search/client/meilisearch.ts
|
|
3
|
+
function meilisearchClient(options) {
|
|
4
|
+
const { client, indexName, tag, locale } = options;
|
|
5
|
+
return {
|
|
6
|
+
deps: [
|
|
7
|
+
client,
|
|
8
|
+
indexName,
|
|
9
|
+
tag,
|
|
10
|
+
locale
|
|
11
|
+
],
|
|
12
|
+
async search(query) {
|
|
13
|
+
if (query.trim().length === 0) return [];
|
|
14
|
+
const filter = [];
|
|
15
|
+
if (locale) filter.push(`locale = ${JSON.stringify(locale)}`);
|
|
16
|
+
for (const item of typeof tag === "string" ? [tag] : tag ?? []) filter.push(`tag = ${JSON.stringify(item)}`);
|
|
17
|
+
const { hits } = await client.index(indexName).search(query, {
|
|
18
|
+
filter,
|
|
19
|
+
limit: 20
|
|
20
|
+
});
|
|
21
|
+
const highlighter = createContentHighlighter(query);
|
|
22
|
+
const groups = /* @__PURE__ */ new Map();
|
|
23
|
+
for (const hit of hits) {
|
|
24
|
+
let group = groups.get(hit.url);
|
|
25
|
+
if (!group) {
|
|
26
|
+
group = [{
|
|
27
|
+
id: hit.url,
|
|
28
|
+
type: "page",
|
|
29
|
+
content: highlighter.highlightMarkdown(hit.title),
|
|
30
|
+
breadcrumbs: hit.breadcrumbs,
|
|
31
|
+
url: hit.url
|
|
32
|
+
}];
|
|
33
|
+
groups.set(hit.url, group);
|
|
34
|
+
}
|
|
35
|
+
if (hit.type === "page") continue;
|
|
36
|
+
group.push({
|
|
37
|
+
id: hit.id.toString(),
|
|
38
|
+
type: hit.type,
|
|
39
|
+
content: highlighter.highlightMarkdown(hit.content),
|
|
40
|
+
url: hit.heading ? `${hit.url}#${hit.heading}` : hit.url
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const results = [];
|
|
44
|
+
for (const group of groups.values()) results.push(...group);
|
|
45
|
+
return results;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { meilisearchClient };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { t as Awaitable } from "../types-D89QoQR-.js";
|
|
2
|
+
import { i as StructuredData } from "../remark-structure-CnHwvNZr.js";
|
|
3
|
+
import { S as LoaderOutput, b as LoaderConfig } from "../index-CBtz3H2e.js";
|
|
4
|
+
import { Meilisearch } from "meilisearch";
|
|
5
|
+
//#region src/search/meilisearch.d.ts
|
|
6
|
+
export interface DocumentRecord {
|
|
7
|
+
title: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
breadcrumbs?: string[];
|
|
10
|
+
/**
|
|
11
|
+
* URL to the page
|
|
12
|
+
*/
|
|
13
|
+
url: string;
|
|
14
|
+
structured: StructuredData;
|
|
15
|
+
/**
|
|
16
|
+
* Tag(s) to filter results
|
|
17
|
+
*/
|
|
18
|
+
tag?: string | string[];
|
|
19
|
+
locale?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Document in Meilisearch, for the title, headings and paragraphs of a page
|
|
23
|
+
*/
|
|
24
|
+
export interface MeilisearchDocument extends Omit<DocumentRecord, 'description' | 'structured'> {
|
|
25
|
+
id: number;
|
|
26
|
+
type: 'page' | 'heading' | 'text';
|
|
27
|
+
/**
|
|
28
|
+
* ID of the heading it belongs to
|
|
29
|
+
*/
|
|
30
|
+
heading?: string;
|
|
31
|
+
content: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build the search documents of every page in a source.
|
|
35
|
+
*/
|
|
36
|
+
export declare function toDocuments<C extends LoaderConfig>(source: LoaderOutput<C> | (() => Awaitable<LoaderOutput<C>>), options?: {
|
|
37
|
+
/** Tag to filter results by. */
|
|
38
|
+
tag?: (page: C['page']) => string | string[];
|
|
39
|
+
}): Promise<DocumentRecord[]>;
|
|
40
|
+
export interface SyncOptions {
|
|
41
|
+
indexName: string;
|
|
42
|
+
documents: DocumentRecord[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Configure the index and replace its documents, existing documents stay searchable until the new ones are indexed.
|
|
46
|
+
*
|
|
47
|
+
* @param client - Meilisearch client with an admin API key
|
|
48
|
+
*/
|
|
49
|
+
export declare function sync(client: Meilisearch, options: SyncOptions): Promise<void>;
|
|
50
|
+
//#endregion
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { n as buildDocuments, t as buildBreadcrumbs } from "../build-index-BD-VRKOW.js";
|
|
2
|
+
//#region src/search/meilisearch.ts
|
|
3
|
+
/**
|
|
4
|
+
* Build the search documents of every page in a source.
|
|
5
|
+
*/
|
|
6
|
+
async function toDocuments(source, options = {}) {
|
|
7
|
+
const loader = typeof source === "function" ? await source() : source;
|
|
8
|
+
return buildDocuments(loader, (index, page) => ({
|
|
9
|
+
title: index.title,
|
|
10
|
+
description: index.description,
|
|
11
|
+
breadcrumbs: buildBreadcrumbs(loader, page),
|
|
12
|
+
url: index.url,
|
|
13
|
+
structured: index.structuredData,
|
|
14
|
+
tag: options.tag?.(page),
|
|
15
|
+
locale: page.locale
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Configure the index and replace its documents, existing documents stay searchable until the new ones are indexed.
|
|
20
|
+
*
|
|
21
|
+
* @param client - Meilisearch client with an admin API key
|
|
22
|
+
*/
|
|
23
|
+
async function sync(client, options) {
|
|
24
|
+
const index = client.index(options.indexName);
|
|
25
|
+
const documents = [];
|
|
26
|
+
for (const { description, structured, ...page } of options.documents) {
|
|
27
|
+
const add = (type, content, heading) => documents.push({
|
|
28
|
+
...page,
|
|
29
|
+
id: documents.length,
|
|
30
|
+
type,
|
|
31
|
+
content,
|
|
32
|
+
heading
|
|
33
|
+
});
|
|
34
|
+
add("page", page.title);
|
|
35
|
+
if (description && !structured.contents.some((item) => item.content === description)) add("text", description);
|
|
36
|
+
for (const heading of structured.headings) add("heading", heading.content, heading.id);
|
|
37
|
+
for (const item of structured.contents) add("text", item.content, item.heading);
|
|
38
|
+
}
|
|
39
|
+
await run(index.updateSettings({
|
|
40
|
+
searchableAttributes: ["content"],
|
|
41
|
+
filterableAttributes: [
|
|
42
|
+
"id",
|
|
43
|
+
"tag",
|
|
44
|
+
"locale"
|
|
45
|
+
]
|
|
46
|
+
}));
|
|
47
|
+
await run(index.addDocuments(documents, { primaryKey: "id" }));
|
|
48
|
+
await run(index.deleteDocuments({ filter: `id >= ${documents.length}` }));
|
|
49
|
+
}
|
|
50
|
+
async function run(task) {
|
|
51
|
+
const { status, error } = await task.waitTask({ timeout: 0 });
|
|
52
|
+
if (status !== "succeeded") throw new Error(error ? error.message : `Meilisearch task ${status}`, { cause: error });
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { sync, toDocuments };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumadocs-core",
|
|
3
|
-
"version": "16.
|
|
3
|
+
"version": "16.16.0",
|
|
4
4
|
"description": "The React.js library for building a documentation website",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Docs",
|
|
@@ -75,11 +75,13 @@
|
|
|
75
75
|
"./search/client/algolia": "./dist/search/client/algolia.js",
|
|
76
76
|
"./search/client/fetch": "./dist/search/client/fetch.js",
|
|
77
77
|
"./search/client/flexsearch-static": "./dist/search/client/flexsearch-static.js",
|
|
78
|
+
"./search/client/meilisearch": "./dist/search/client/meilisearch.js",
|
|
78
79
|
"./search/client/mixedbread": "./dist/search/client/mixedbread.js",
|
|
79
80
|
"./search/client/orama-cloud": "./dist/search/client/orama-cloud.js",
|
|
80
81
|
"./search/client/orama-cloud-legacy": "./dist/search/client/orama-cloud-legacy.js",
|
|
81
82
|
"./search/client/orama-static": "./dist/search/client/orama-static.js",
|
|
82
83
|
"./search/flexsearch": "./dist/search/flexsearch.js",
|
|
84
|
+
"./search/meilisearch": "./dist/search/meilisearch.js",
|
|
83
85
|
"./search/mixedbread": "./dist/search/mixedbread.js",
|
|
84
86
|
"./search/orama-cloud": "./dist/search/orama-cloud.js",
|
|
85
87
|
"./search/orama-cloud-legacy": "./dist/search/orama-cloud-legacy.js",
|
|
@@ -116,39 +118,40 @@
|
|
|
116
118
|
"hast-util-to-estree": "^3.1.3",
|
|
117
119
|
"hast-util-to-jsx-runtime": "^2.3.6",
|
|
118
120
|
"mdast-util-mdx": "^3.0.0",
|
|
119
|
-
"mdast-util-to-markdown": "^2.1.
|
|
121
|
+
"mdast-util-to-markdown": "^2.1.3",
|
|
120
122
|
"npm-to-yarn": "3.2.0",
|
|
121
123
|
"remark": "^15.0.1",
|
|
122
124
|
"remark-gfm": "^4.0.1",
|
|
123
125
|
"remark-rehype": "^11.1.2",
|
|
124
126
|
"scroll-into-view-if-needed": "^3.1.0",
|
|
125
|
-
"shiki": "^4.
|
|
127
|
+
"shiki": "^4.5.0",
|
|
126
128
|
"tinyglobby": "^0.2.17",
|
|
127
129
|
"unified": "^11.0.5",
|
|
128
130
|
"unist-util-visit": "^5.1.0",
|
|
129
131
|
"vfile": "^6.0.3",
|
|
130
132
|
"yaml": "^2.9.1",
|
|
131
|
-
"zbsearch": "^4.0.
|
|
133
|
+
"zbsearch": "^4.0.1"
|
|
132
134
|
},
|
|
133
135
|
"devDependencies": {
|
|
134
136
|
"@formatjs/intl-localematcher": "^0.9.0",
|
|
135
137
|
"@mdx-js/mdx": "^3.1.1",
|
|
136
138
|
"@mixedbread/sdk": "0.78.0",
|
|
137
|
-
"@modelcontextprotocol/server": "2.
|
|
139
|
+
"@modelcontextprotocol/server": "2.2.0",
|
|
138
140
|
"@orama/core": "^1.2.19",
|
|
139
141
|
"@oramacloud/client": "^2.1.4",
|
|
140
|
-
"@shikijs/transformers": "^4.
|
|
141
|
-
"@tanstack/react-router": "1.170.
|
|
142
|
+
"@shikijs/transformers": "^4.5.0",
|
|
143
|
+
"@tanstack/react-router": "1.170.41",
|
|
142
144
|
"@types/estree-jsx": "^1.0.5",
|
|
143
145
|
"@types/hast": "^3.0.5",
|
|
144
146
|
"@types/mdast": "^4.0.4",
|
|
145
|
-
"@types/node": "26.6.
|
|
147
|
+
"@types/node": "26.6.4",
|
|
146
148
|
"@types/react": "^19.3.0",
|
|
147
149
|
"@types/react-dom": "^19.3.0",
|
|
148
150
|
"algoliasearch": "5.59.0",
|
|
149
151
|
"flexsearch": "^0.8.212",
|
|
150
|
-
"lucide-react": "^1.
|
|
151
|
-
"
|
|
152
|
+
"lucide-react": "^1.50.0",
|
|
153
|
+
"meilisearch": "0.62.0",
|
|
154
|
+
"next": "16.3.8",
|
|
152
155
|
"path-to-regexp": "^8.4.2",
|
|
153
156
|
"react-router": "^8.4.0",
|
|
154
157
|
"rehype-raw": "^7.0.0",
|
|
@@ -157,7 +160,7 @@
|
|
|
157
160
|
"tsconfig": "0.0.0",
|
|
158
161
|
"tsdown": "0.23.0",
|
|
159
162
|
"typescript": "^7.0.2",
|
|
160
|
-
"waku": "1.0.0-rc.
|
|
163
|
+
"waku": "1.0.0-rc.2",
|
|
161
164
|
"zod": "4.6.5"
|
|
162
165
|
},
|
|
163
166
|
"peerDependencies": {
|
|
@@ -174,6 +177,7 @@
|
|
|
174
177
|
"algoliasearch": "5.x.x",
|
|
175
178
|
"flexsearch": "*",
|
|
176
179
|
"lucide-react": "*",
|
|
180
|
+
"meilisearch": ">=0.50.0 <1.0.0",
|
|
177
181
|
"next": "16.x.x",
|
|
178
182
|
"react": "^19.2.0",
|
|
179
183
|
"react-dom": "^19.2.0",
|
|
@@ -215,6 +219,9 @@
|
|
|
215
219
|
"algoliasearch": {
|
|
216
220
|
"optional": true
|
|
217
221
|
},
|
|
222
|
+
"meilisearch": {
|
|
223
|
+
"optional": true
|
|
224
|
+
},
|
|
218
225
|
"next": {
|
|
219
226
|
"optional": true
|
|
220
227
|
},
|
|
@@ -243,7 +250,7 @@
|
|
|
243
250
|
"inlinedDependencies": {
|
|
244
251
|
"@formatjs/fast-memoize": "3.1.7",
|
|
245
252
|
"@formatjs/intl-localematcher": "0.9.0",
|
|
246
|
-
"@shikijs/transformers": "4.
|
|
253
|
+
"@shikijs/transformers": "4.5.0",
|
|
247
254
|
"path-to-regexp": "8.4.2"
|
|
248
255
|
},
|
|
249
256
|
"scripts": {
|