@rspress/plugin-llms 2.0.0-beta.9 → 2.0.0-rc.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/index.d.ts +34 -11
- package/dist/index.js +132 -183
- package/dist/runtime/index.css +168 -0
- package/dist/runtime/index.d.ts +66 -0
- package/dist/runtime/index.js +359 -0
- package/dist/runtime/index.js.LICENSE.txt +5 -0
- package/package.json +24 -13
- package/dist/index.js.LICENSE.txt +0 -10
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import type { PageIndexInfo } from '@rspress/
|
|
2
|
-
import type {
|
|
1
|
+
import type { PageIndexInfo } from '@rspress/core';
|
|
2
|
+
import type { PluggableList } from 'unified';
|
|
3
|
+
import type { RspressPlugin } from '@rspress/core';
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @default { name: 'llms-full.txt' }
|
|
7
|
+
*/
|
|
8
|
+
declare interface LlmsFullTxt {
|
|
9
|
+
name: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @default { name: "llms.txt" }
|
|
14
|
+
*/
|
|
4
15
|
export declare interface LlmsTxt {
|
|
16
|
+
name: string;
|
|
5
17
|
onTitleGenerate?: (context: {
|
|
6
18
|
title: string | undefined;
|
|
7
19
|
description: string | undefined;
|
|
@@ -10,26 +22,35 @@ export declare interface LlmsTxt {
|
|
|
10
22
|
onAfterLlmsTxtGenerate?: (llmsTxtContent: string) => string;
|
|
11
23
|
}
|
|
12
24
|
|
|
25
|
+
declare interface MdFiles {
|
|
26
|
+
/**
|
|
27
|
+
* Whether to convert mdx to md.
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
mdxToMd?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Allow users to customize remarkPlugins and edit the content of generated md files.
|
|
33
|
+
* @default []
|
|
34
|
+
*/
|
|
35
|
+
remarkPlugins?: PluggableList;
|
|
36
|
+
}
|
|
37
|
+
|
|
13
38
|
export declare interface Options {
|
|
14
39
|
/**
|
|
15
40
|
* Whether to generate llms.txt.
|
|
16
|
-
* @default true
|
|
17
41
|
*/
|
|
18
|
-
llmsTxt?:
|
|
42
|
+
llmsTxt?: false | LlmsTxt;
|
|
19
43
|
/**
|
|
20
44
|
* Whether to generate llms.txt related md files for each route.
|
|
21
|
-
* @default true
|
|
22
45
|
*/
|
|
23
|
-
mdFiles?:
|
|
46
|
+
mdFiles?: false | MdFiles;
|
|
24
47
|
/**
|
|
25
48
|
* Whether to generate llms-full.txt.
|
|
26
|
-
* @default true
|
|
27
49
|
*/
|
|
28
|
-
llmsFullTxt?:
|
|
50
|
+
llmsFullTxt?: false | LlmsFullTxt;
|
|
29
51
|
/**
|
|
30
52
|
* Whether to include some routes from llms.txt.
|
|
31
|
-
* @
|
|
32
|
-
* @default (context) => context.page.lang === config.lang
|
|
53
|
+
* @default undefined
|
|
33
54
|
*/
|
|
34
55
|
include?: (context: {
|
|
35
56
|
page: PageIndexInfo;
|
|
@@ -47,6 +68,8 @@ export declare interface Options {
|
|
|
47
68
|
/**
|
|
48
69
|
* A plugin for rspress to generate llms.txt, llms-full.txt, md files to let llm understand your website.
|
|
49
70
|
*/
|
|
50
|
-
export declare function pluginLlms(options?:
|
|
71
|
+
export declare function pluginLlms(options?: RspressPluginLlmsOptions): RspressPlugin;
|
|
72
|
+
|
|
73
|
+
declare type RspressPluginLlmsOptions = Options | Options[];
|
|
51
74
|
|
|
52
75
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,130 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
import * as __WEBPACK_EXTERNAL_MODULE_unified__ from "unified";
|
|
10
|
-
import * as __WEBPACK_EXTERNAL_MODULE_unist_util_visit_555e002a__ from "unist-util-visit";
|
|
11
|
-
var router_Action;
|
|
12
|
-
(function(Action) {
|
|
13
|
-
Action["Pop"] = "POP";
|
|
14
|
-
Action["Push"] = "PUSH";
|
|
15
|
-
Action["Replace"] = "REPLACE";
|
|
16
|
-
})(router_Action || (router_Action = {}));
|
|
17
|
-
function warning(cond, message) {
|
|
18
|
-
if (!cond) {
|
|
19
|
-
if ("undefined" != typeof console) console.warn(message);
|
|
20
|
-
try {
|
|
21
|
-
throw new Error(message);
|
|
22
|
-
} catch (e) {}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
var router_ResultType;
|
|
26
|
-
(function(ResultType) {
|
|
27
|
-
ResultType["data"] = "data";
|
|
28
|
-
ResultType["deferred"] = "deferred";
|
|
29
|
-
ResultType["redirect"] = "redirect";
|
|
30
|
-
ResultType["error"] = "error";
|
|
31
|
-
})(router_ResultType || (router_ResultType = {}));
|
|
32
|
-
new Set([
|
|
33
|
-
"lazy",
|
|
34
|
-
"caseSensitive",
|
|
35
|
-
"path",
|
|
36
|
-
"id",
|
|
37
|
-
"index",
|
|
38
|
-
"children"
|
|
39
|
-
]);
|
|
40
|
-
function matchPath(pattern, pathname) {
|
|
41
|
-
if ("string" == typeof pattern) pattern = {
|
|
42
|
-
path: pattern,
|
|
43
|
-
caseSensitive: false,
|
|
44
|
-
end: true
|
|
45
|
-
};
|
|
46
|
-
let [matcher, compiledParams] = compilePath(pattern.path, pattern.caseSensitive, pattern.end);
|
|
47
|
-
let match = pathname.match(matcher);
|
|
48
|
-
if (!match) return null;
|
|
49
|
-
let matchedPathname = match[0];
|
|
50
|
-
let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
|
|
51
|
-
let captureGroups = match.slice(1);
|
|
52
|
-
let params = compiledParams.reduce((memo, _ref, index)=>{
|
|
53
|
-
let { paramName, isOptional } = _ref;
|
|
54
|
-
if ("*" === paramName) {
|
|
55
|
-
let splatValue = captureGroups[index] || "";
|
|
56
|
-
pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
|
|
57
|
-
}
|
|
58
|
-
const value = captureGroups[index];
|
|
59
|
-
if (isOptional && !value) memo[paramName] = void 0;
|
|
60
|
-
else memo[paramName] = (value || "").replace(/%2F/g, "/");
|
|
61
|
-
return memo;
|
|
62
|
-
}, {});
|
|
63
|
-
return {
|
|
64
|
-
params,
|
|
65
|
-
pathname: matchedPathname,
|
|
66
|
-
pathnameBase,
|
|
67
|
-
pattern
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
function compilePath(path, caseSensitive, end) {
|
|
71
|
-
if (void 0 === caseSensitive) caseSensitive = false;
|
|
72
|
-
if (void 0 === end) end = true;
|
|
73
|
-
warning("*" === path || !path.endsWith("*") || path.endsWith("/*"), "Route path \"" + path + '" will be treated as if it were "' + path.replace(/\*$/, "/*") + '" because the `*` character must always follow a `/` in the pattern. To get rid of this warning, please change the route path to "' + path.replace(/\*$/, "/*") + "\".");
|
|
74
|
-
let params = [];
|
|
75
|
-
let regexpSource = "^" + path.replace(/\/*\*?$/, "").replace(/^\/*/, "/").replace(/[\\.*+^${}|()[\]]/g, "\\$&").replace(/\/:([\w-]+)(\?)?/g, (_, paramName, isOptional)=>{
|
|
76
|
-
params.push({
|
|
77
|
-
paramName,
|
|
78
|
-
isOptional: null != isOptional
|
|
79
|
-
});
|
|
80
|
-
return isOptional ? "/?([^\\/]+)?" : "/([^\\/]+)";
|
|
81
|
-
});
|
|
82
|
-
if (path.endsWith("*")) {
|
|
83
|
-
params.push({
|
|
84
|
-
paramName: "*"
|
|
85
|
-
});
|
|
86
|
-
regexpSource += "*" === path || "/*" === path ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
|
|
87
|
-
} else if (end) regexpSource += "\\/*$";
|
|
88
|
-
else if ("" !== path && "/" !== path) regexpSource += "(?:(?=\\/|$))";
|
|
89
|
-
let matcher = new RegExp(regexpSource, caseSensitive ? void 0 : "i");
|
|
90
|
-
return [
|
|
91
|
-
matcher,
|
|
92
|
-
params
|
|
93
|
-
];
|
|
94
|
-
}
|
|
95
|
-
const validMutationMethodsArr = [
|
|
96
|
-
"post",
|
|
97
|
-
"put",
|
|
98
|
-
"patch",
|
|
99
|
-
"delete"
|
|
100
|
-
];
|
|
101
|
-
new Set(validMutationMethodsArr);
|
|
102
|
-
const validRequestMethodsArr = [
|
|
103
|
-
"get",
|
|
104
|
-
...validMutationMethodsArr
|
|
105
|
-
];
|
|
106
|
-
new Set(validRequestMethodsArr);
|
|
107
|
-
new Set([
|
|
108
|
-
301,
|
|
109
|
-
302,
|
|
110
|
-
303,
|
|
111
|
-
307,
|
|
112
|
-
308
|
|
113
|
-
]);
|
|
114
|
-
new Set([
|
|
115
|
-
307,
|
|
116
|
-
308
|
|
117
|
-
]);
|
|
118
|
-
Symbol("deferred");
|
|
119
|
-
function routePathToMdPath(routePath) {
|
|
1
|
+
import node_path from "node:path";
|
|
2
|
+
import { getSidebarDataGroup, logger, matchPath, normalizeHref, remarkFileCodeBlock, remarkLink, withBase } from "@rspress/core";
|
|
3
|
+
import remark_mdx from "remark-mdx";
|
|
4
|
+
import remark_parse from "remark-parse";
|
|
5
|
+
import remark_stringify from "remark-stringify";
|
|
6
|
+
import { unified } from "unified";
|
|
7
|
+
import { SKIP, visit } from "unist-util-visit";
|
|
8
|
+
function routePathToMdPath(routePath, base) {
|
|
120
9
|
let url = routePath;
|
|
121
|
-
url =
|
|
10
|
+
url = normalizeHref(url, false);
|
|
122
11
|
url = url.replace(/\.html$/, '.md');
|
|
123
|
-
return url;
|
|
12
|
+
return withBase(url, base);
|
|
124
13
|
}
|
|
125
|
-
function generateLlmsTxt(pageDataArray, navList, others, llmsTxtOptions, title, description) {
|
|
14
|
+
function generateLlmsTxt(pageDataArray, navList, others, llmsTxtOptions, title, description, base) {
|
|
126
15
|
const lines = [];
|
|
127
|
-
const { onAfterLlmsTxtGenerate, onLineGenerate, onTitleGenerate } =
|
|
16
|
+
const { onAfterLlmsTxtGenerate, onLineGenerate, onTitleGenerate } = llmsTxtOptions;
|
|
128
17
|
const summary = onTitleGenerate ? onTitleGenerate({
|
|
129
18
|
title,
|
|
130
19
|
description
|
|
@@ -139,7 +28,7 @@ function generateLlmsTxt(pageDataArray, navList, others, llmsTxtOptions, title,
|
|
|
139
28
|
for (const page of pages){
|
|
140
29
|
const { routePath, lang, title, frontmatter } = page;
|
|
141
30
|
if ('/' === routePath || routePath === `/${lang}/`) continue;
|
|
142
|
-
const line = onLineGenerate ? onLineGenerate(page) : `- [${title}](${routePathToMdPath(routePath)})${frontmatter.description ? `: ${frontmatter.description}` : ''}`;
|
|
31
|
+
const line = onLineGenerate ? onLineGenerate(page) : `- [${title}](${routePathToMdPath(routePath, base)})${frontmatter.description ? `: ${frontmatter.description}` : ''}`;
|
|
143
32
|
lines.push(line);
|
|
144
33
|
}
|
|
145
34
|
}
|
|
@@ -149,7 +38,7 @@ function generateLlmsTxt(pageDataArray, navList, others, llmsTxtOptions, title,
|
|
|
149
38
|
for (const page of others){
|
|
150
39
|
const { routePath, lang, title, frontmatter } = page;
|
|
151
40
|
if ('/' === routePath || routePath === `/${lang}/`) continue;
|
|
152
|
-
const line = onLineGenerate ? onLineGenerate(page) : `- [${title}](${routePathToMdPath(routePath)})${frontmatter.description ? `: ${frontmatter.description}` : ''}`;
|
|
41
|
+
const line = onLineGenerate ? onLineGenerate(page) : `- [${title}](${routePathToMdPath(routePath, base)})${frontmatter.description ? `: ${frontmatter.description}` : ''}`;
|
|
153
42
|
otherLines.push(line);
|
|
154
43
|
hasOthers = true;
|
|
155
44
|
}
|
|
@@ -157,13 +46,13 @@ function generateLlmsTxt(pageDataArray, navList, others, llmsTxtOptions, title,
|
|
|
157
46
|
const llmsTxt = `${summary}\n${lines.join('\n')}`;
|
|
158
47
|
return onAfterLlmsTxtGenerate ? onAfterLlmsTxtGenerate(llmsTxt) : llmsTxt;
|
|
159
48
|
}
|
|
160
|
-
function generateLlmsFullTxt(pageDataArray, navList, others) {
|
|
49
|
+
function generateLlmsFullTxt(pageDataArray, navList, others, base) {
|
|
161
50
|
const lines = [];
|
|
162
51
|
for(let i = 0; i < navList.length; i++){
|
|
163
52
|
const pages = pageDataArray[i];
|
|
164
53
|
if (0 !== pages.length) for (const page of pages){
|
|
165
54
|
lines.push(`---
|
|
166
|
-
url: ${routePathToMdPath(page.routePath)}
|
|
55
|
+
url: ${routePathToMdPath(page.routePath, base)}
|
|
167
56
|
---
|
|
168
57
|
`);
|
|
169
58
|
lines.push(page.mdContent ?? page._flattenContent ?? page.content);
|
|
@@ -172,7 +61,7 @@ url: ${routePathToMdPath(page.routePath)}
|
|
|
172
61
|
}
|
|
173
62
|
for (const page of others){
|
|
174
63
|
lines.push(`---
|
|
175
|
-
url: ${routePathToMdPath(page.routePath)}
|
|
64
|
+
url: ${routePathToMdPath(page.routePath, base)}
|
|
176
65
|
---
|
|
177
66
|
`);
|
|
178
67
|
lines.push(page.mdContent ?? page._flattenContent ?? page.content);
|
|
@@ -181,46 +70,62 @@ url: ${routePathToMdPath(page.routePath)}
|
|
|
181
70
|
return lines.join('\n');
|
|
182
71
|
}
|
|
183
72
|
const mdxToMdPlugin = ()=>(tree)=>{
|
|
184
|
-
|
|
73
|
+
visit(tree, 'mdxjsEsm', (node)=>{
|
|
185
74
|
if (node.data?.estree?.body[0].type === 'ImportDeclaration') {
|
|
186
75
|
node.value = '';
|
|
187
|
-
return
|
|
76
|
+
return SKIP;
|
|
188
77
|
}
|
|
189
78
|
});
|
|
190
|
-
|
|
79
|
+
visit(tree, 'mdxJsxFlowElement', (node, index, parent)=>{
|
|
191
80
|
if (parent && void 0 !== index && Array.isArray(parent.children)) {
|
|
192
81
|
parent.children.splice(index, 1, ...node.children);
|
|
193
82
|
return index - 1;
|
|
194
83
|
}
|
|
195
84
|
});
|
|
196
|
-
|
|
85
|
+
visit(tree, 'mdxJsxTextElement', (node, index, parent)=>{
|
|
197
86
|
if (parent && void 0 !== index && Array.isArray(parent.children)) {
|
|
198
87
|
parent.children.splice(index, 1, ...node.children);
|
|
199
88
|
return index - 1;
|
|
200
89
|
}
|
|
201
90
|
});
|
|
202
91
|
};
|
|
203
|
-
function
|
|
204
|
-
|
|
92
|
+
function noopPlugin() {}
|
|
93
|
+
async function normalizeMdFile(content, filepath, routeService, base, mdxToMd, isMd, remarkPlugins) {
|
|
94
|
+
const compiler = unified().use(remark_parse).use(isMd ? noopPlugin : remark_mdx).use(remarkFileCodeBlock, {
|
|
95
|
+
filepath
|
|
96
|
+
}).use(!isMd && mdxToMd ? mdxToMdPlugin : noopPlugin).use(remarkLink, {
|
|
205
97
|
cleanUrls: '.md',
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
98
|
+
routeService,
|
|
99
|
+
remarkLinkOptions: {
|
|
100
|
+
checkDeadLinks: false,
|
|
101
|
+
autoPrefix: true
|
|
102
|
+
},
|
|
103
|
+
__base: base
|
|
104
|
+
}).use(remarkPlugins).use(remark_stringify);
|
|
105
|
+
const vfile = await compiler.process({
|
|
209
106
|
value: content,
|
|
210
107
|
path: filepath
|
|
211
108
|
});
|
|
109
|
+
const result = vfile.toString();
|
|
110
|
+
if ('' === result.trim()) return '\n';
|
|
111
|
+
return result;
|
|
212
112
|
}
|
|
213
|
-
const rsbuildPluginLlms = ({ disableSSGRef, pageDataList, routes, titleRef, descriptionRef, langRef, sidebar,
|
|
214
|
-
name:
|
|
113
|
+
const rsbuildPluginLlms = ({ disableSSGRef, baseRef, pageDataList, routes, titleRef, descriptionRef, langRef, sidebar, routeServiceRef, nav, rspressPluginOptions, index = 0 })=>({
|
|
114
|
+
name: `rsbuild-plugin-llms-${index}`,
|
|
215
115
|
async setup (api) {
|
|
216
|
-
const { llmsTxt =
|
|
116
|
+
const { llmsTxt = {
|
|
117
|
+
name: 'llms.txt'
|
|
118
|
+
}, mdFiles = {
|
|
119
|
+
mdxToMd: false,
|
|
120
|
+
remarkPlugins: []
|
|
121
|
+
}, llmsFullTxt = {
|
|
122
|
+
name: 'llms-full.txt'
|
|
123
|
+
}, include, exclude } = rspressPluginOptions;
|
|
217
124
|
api.onBeforeBuild(async ()=>{
|
|
218
|
-
const base = baseRef.current;
|
|
219
|
-
const docDirectory = docDirectoryRef.current;
|
|
220
125
|
const disableSSG = disableSSGRef.current;
|
|
221
126
|
const newPageDataList = mergeRouteMetaWithPageData(routes, pageDataList, langRef.current, include, exclude);
|
|
222
127
|
const navList = Array.isArray(nav) ? nav.map((i)=>{
|
|
223
|
-
const nav = i.nav.default;
|
|
128
|
+
const nav = i.nav.default || i.nav;
|
|
224
129
|
const lang = i.lang;
|
|
225
130
|
return nav.map((i)=>({
|
|
226
131
|
...i,
|
|
@@ -234,15 +139,16 @@ const rsbuildPluginLlms = ({ disableSSGRef, pageDataList, routes, titleRef, desc
|
|
|
234
139
|
for(let i = 0; i < pageArray.length; i++){
|
|
235
140
|
const pageArrayItem = pageArray[i];
|
|
236
141
|
const navItem = navList[i];
|
|
237
|
-
if (lang === navItem.lang && new RegExp(navItem.activeMatch ?? navItem.link).test(
|
|
142
|
+
if (lang === navItem.lang && new RegExp(navItem.activeMatch ?? navItem.link).test(routePath)) return void pageArrayItem.push(pageData);
|
|
238
143
|
}
|
|
239
144
|
others.push(pageData);
|
|
240
145
|
});
|
|
241
|
-
for (const array of pageArray)organizeBySidebar(sidebar, array
|
|
146
|
+
for (const array of pageArray)organizeBySidebar(sidebar, array);
|
|
242
147
|
if (llmsTxt) {
|
|
243
|
-
const
|
|
148
|
+
const { name } = llmsTxt;
|
|
149
|
+
const llmsTxtContent = generateLlmsTxt(pageArray, navList, others, llmsTxt, titleRef.current, descriptionRef.current, baseRef.current);
|
|
244
150
|
api.processAssets({
|
|
245
|
-
|
|
151
|
+
environments: disableSSG ? [
|
|
246
152
|
'web'
|
|
247
153
|
] : [
|
|
248
154
|
'node'
|
|
@@ -250,7 +156,7 @@ const rsbuildPluginLlms = ({ disableSSGRef, pageDataList, routes, titleRef, desc
|
|
|
250
156
|
stage: 'additional'
|
|
251
157
|
}, async ({ compilation, sources })=>{
|
|
252
158
|
const source = new sources.RawSource(llmsTxtContent);
|
|
253
|
-
compilation.emitAsset(
|
|
159
|
+
compilation.emitAsset(name, source);
|
|
254
160
|
});
|
|
255
161
|
}
|
|
256
162
|
const mdContents = {};
|
|
@@ -259,22 +165,19 @@ const rsbuildPluginLlms = ({ disableSSGRef, pageDataList, routes, titleRef, desc
|
|
|
259
165
|
].map(async (pageData)=>{
|
|
260
166
|
const content = pageData._flattenContent ?? pageData.content;
|
|
261
167
|
const filepath = pageData._filepath;
|
|
262
|
-
const isMD = 'mdx' !==
|
|
168
|
+
const isMD = 'mdx' !== node_path.extname(filepath).slice(1);
|
|
263
169
|
let mdContent;
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
mdContent = (await mdxToMd(content, filepath, docDirectory, routeServiceRef.current)).toString();
|
|
170
|
+
try {
|
|
171
|
+
mdContent = await normalizeMdFile(content, filepath, routeServiceRef.current, baseRef.current, 'boolean' != typeof mdFiles ? mdFiles?.mdxToMd ?? false : false, isMD, 'boolean' != typeof mdFiles ? mdFiles?.remarkPlugins ?? [] : []);
|
|
267
172
|
} catch (e) {
|
|
268
|
-
|
|
173
|
+
logger.debug('normalizeMdFile failed', pageData.routePath, e);
|
|
269
174
|
mdContent = content;
|
|
270
|
-
return;
|
|
271
175
|
}
|
|
272
|
-
pageData.
|
|
273
|
-
const outFilePath = `${pageData.routePath.endsWith('/') ? `${pageData.routePath}index` : pageData.routePath}.md`;
|
|
176
|
+
const outFilePath = routePathToMdPath(pageData.routePath, '');
|
|
274
177
|
mdContents[outFilePath] = mdContent.toString();
|
|
275
178
|
}) ?? []);
|
|
276
179
|
if (mdFiles) api.processAssets({
|
|
277
|
-
|
|
180
|
+
environments: disableSSG ? [
|
|
278
181
|
'web'
|
|
279
182
|
] : [
|
|
280
183
|
'node'
|
|
@@ -287,7 +190,8 @@ const rsbuildPluginLlms = ({ disableSSGRef, pageDataList, routes, titleRef, desc
|
|
|
287
190
|
});
|
|
288
191
|
});
|
|
289
192
|
if (llmsFullTxt) {
|
|
290
|
-
const
|
|
193
|
+
const { name } = llmsFullTxt;
|
|
194
|
+
const llmsFullTxtContent = generateLlmsFullTxt(pageArray, navList, others, baseRef.current);
|
|
291
195
|
api.processAssets({
|
|
292
196
|
targets: disableSSG ? [
|
|
293
197
|
'web'
|
|
@@ -297,7 +201,7 @@ const rsbuildPluginLlms = ({ disableSSGRef, pageDataList, routes, titleRef, desc
|
|
|
297
201
|
stage: 'additional'
|
|
298
202
|
}, async ({ compilation, sources })=>{
|
|
299
203
|
const source = new sources.RawSource(llmsFullTxtContent);
|
|
300
|
-
compilation.emitAsset(
|
|
204
|
+
compilation.emitAsset(name, source);
|
|
301
205
|
});
|
|
302
206
|
}
|
|
303
207
|
});
|
|
@@ -337,19 +241,45 @@ function flatSidebar(sidebar) {
|
|
|
337
241
|
if ('items' in i && Array.isArray(i.items)) return flatSidebar(i.items);
|
|
338
242
|
}).filter(Boolean);
|
|
339
243
|
}
|
|
340
|
-
function organizeBySidebar(sidebar, pages
|
|
244
|
+
function organizeBySidebar(sidebar, pages) {
|
|
341
245
|
if (0 === pages.length) return;
|
|
342
246
|
const pageItem = pages[0];
|
|
343
|
-
const currSidebar =
|
|
247
|
+
const currSidebar = getSidebarDataGroup(sidebar, pageItem.routePath);
|
|
344
248
|
if (0 === currSidebar.length) return;
|
|
345
249
|
const orderList = flatSidebar(currSidebar);
|
|
346
250
|
pages.sort((a, b)=>{
|
|
347
|
-
|
|
348
|
-
|
|
251
|
+
let aIndex = orderList.findIndex((order)=>matchPath(order, a.routePath));
|
|
252
|
+
if (-1 === aIndex) aIndex = Number.MAX_SAFE_INTEGER;
|
|
253
|
+
let bIndex = orderList.findIndex((order)=>matchPath(order, b.routePath));
|
|
254
|
+
if (-1 === bIndex) bIndex = Number.MAX_SAFE_INTEGER;
|
|
349
255
|
return aIndex - bIndex;
|
|
350
256
|
});
|
|
351
257
|
}
|
|
352
|
-
function
|
|
258
|
+
function getDefaultOptions(lang, langs) {
|
|
259
|
+
if (!lang || 0 === langs.length) return {};
|
|
260
|
+
return langs.map((l)=>{
|
|
261
|
+
if (l === lang) return {
|
|
262
|
+
llmsTxt: {
|
|
263
|
+
name: 'llms.txt'
|
|
264
|
+
},
|
|
265
|
+
llmsFullTxt: {
|
|
266
|
+
name: 'llms-full.txt'
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
return {
|
|
270
|
+
llmsTxt: {
|
|
271
|
+
name: `${l}/llms.txt`
|
|
272
|
+
},
|
|
273
|
+
llmsFullTxt: {
|
|
274
|
+
name: `${l}/llms-full.txt`
|
|
275
|
+
},
|
|
276
|
+
include ({ page }) {
|
|
277
|
+
return page.lang === l;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
function pluginLlms(options) {
|
|
353
283
|
const baseRef = {
|
|
354
284
|
current: ''
|
|
355
285
|
};
|
|
@@ -386,6 +316,44 @@ function pluginLlms(options = {}) {
|
|
|
386
316
|
routeGenerated (_routes, isProd) {
|
|
387
317
|
if (isProd) routes.push(..._routes);
|
|
388
318
|
},
|
|
319
|
+
config (config) {
|
|
320
|
+
config.themeConfig = config.themeConfig || {};
|
|
321
|
+
config.themeConfig.locales = config.themeConfig.locales || config.locales || [];
|
|
322
|
+
const langs = config.themeConfig.locales.map((locale)=>locale.lang);
|
|
323
|
+
let mergedOptions;
|
|
324
|
+
mergedOptions = void 0 === options ? getDefaultOptions(config.lang, langs) : options;
|
|
325
|
+
if (!config.builderConfig) config.builderConfig = {};
|
|
326
|
+
if (!config.builderConfig.plugins) config.builderConfig.plugins = [];
|
|
327
|
+
config.builderConfig.plugins.push(...Array.isArray(mergedOptions) ? mergedOptions.map((item, index)=>rsbuildPluginLlms({
|
|
328
|
+
pageDataList,
|
|
329
|
+
routes,
|
|
330
|
+
titleRef,
|
|
331
|
+
descriptionRef,
|
|
332
|
+
langRef,
|
|
333
|
+
sidebar,
|
|
334
|
+
routeServiceRef,
|
|
335
|
+
nav,
|
|
336
|
+
baseRef,
|
|
337
|
+
disableSSGRef,
|
|
338
|
+
rspressPluginOptions: item,
|
|
339
|
+
index
|
|
340
|
+
})) : [
|
|
341
|
+
rsbuildPluginLlms({
|
|
342
|
+
pageDataList,
|
|
343
|
+
routes,
|
|
344
|
+
titleRef,
|
|
345
|
+
descriptionRef,
|
|
346
|
+
langRef,
|
|
347
|
+
sidebar,
|
|
348
|
+
routeServiceRef,
|
|
349
|
+
nav,
|
|
350
|
+
baseRef,
|
|
351
|
+
disableSSGRef,
|
|
352
|
+
rspressPluginOptions: mergedOptions
|
|
353
|
+
})
|
|
354
|
+
]);
|
|
355
|
+
return config;
|
|
356
|
+
},
|
|
389
357
|
beforeBuild (config) {
|
|
390
358
|
disableSSGRef.current = false === config.ssg;
|
|
391
359
|
const locales = config.themeConfig?.locales;
|
|
@@ -413,25 +381,6 @@ function pluginLlms(options = {}) {
|
|
|
413
381
|
langRef.current = config.lang ?? '';
|
|
414
382
|
baseRef.current = config.base ?? '/';
|
|
415
383
|
docDirectoryRef.current = config.root ?? 'docs';
|
|
416
|
-
},
|
|
417
|
-
builderConfig: {
|
|
418
|
-
plugins: [
|
|
419
|
-
rsbuildPluginLlms({
|
|
420
|
-
...options,
|
|
421
|
-
pageDataList,
|
|
422
|
-
routes,
|
|
423
|
-
titleRef,
|
|
424
|
-
descriptionRef,
|
|
425
|
-
langRef,
|
|
426
|
-
sidebar,
|
|
427
|
-
docDirectoryRef,
|
|
428
|
-
routeServiceRef,
|
|
429
|
-
nav,
|
|
430
|
-
baseRef,
|
|
431
|
-
disableSSGRef,
|
|
432
|
-
rspressPluginOptions: options
|
|
433
|
-
})
|
|
434
|
-
]
|
|
435
384
|
}
|
|
436
385
|
};
|
|
437
386
|
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
.llmsContainer-glE3L4 {
|
|
2
|
+
align-items: center;
|
|
3
|
+
gap: 8px;
|
|
4
|
+
margin-bottom: 20px;
|
|
5
|
+
display: flex;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.llmsCopyButtonContainer-osHvFn {
|
|
9
|
+
border: 1px solid var(--rp-c-divider-light);
|
|
10
|
+
background: var(--rp-c-bg);
|
|
11
|
+
height: 40px;
|
|
12
|
+
color: var(--rp-c-text-1);
|
|
13
|
+
cursor: pointer;
|
|
14
|
+
border-radius: 8px;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
align-items: center;
|
|
17
|
+
gap: 8px;
|
|
18
|
+
padding: 8px 12px;
|
|
19
|
+
font-size: 14px;
|
|
20
|
+
font-style: normal;
|
|
21
|
+
font-weight: 400;
|
|
22
|
+
transition: background .3s, border .3s, opacity .3s;
|
|
23
|
+
display: inline-flex;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.llmsCopyButtonContainer-osHvFn:hover {
|
|
27
|
+
background: var(--rp-c-bg-mute);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.llmsCopyButtonContainer-osHvFn.loading-p5nEhg {
|
|
31
|
+
background: var(--rp-c-bg-mute);
|
|
32
|
+
opacity: .5;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.llmsCopyButtonContainer-osHvFn.success-F4Qj8u .iconCopy-g1n4MZ {
|
|
36
|
+
display: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.llmsCopyButtonContainer-osHvFn.success-F4Qj8u .iconSuccess-PId4Mj {
|
|
40
|
+
opacity: 1;
|
|
41
|
+
visibility: inherit;
|
|
42
|
+
transition-delay: 75ms;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.iconContainer-G_2NC6 {
|
|
46
|
+
width: 16px;
|
|
47
|
+
height: 16px;
|
|
48
|
+
position: relative;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.iconCopy-g1n4MZ {
|
|
52
|
+
width: 16px;
|
|
53
|
+
height: 16px;
|
|
54
|
+
position: absolute;
|
|
55
|
+
top: 50%;
|
|
56
|
+
left: 50%;
|
|
57
|
+
transform: translate(-50%, -50%);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.iconSuccess-PId4Mj {
|
|
61
|
+
visibility: hidden;
|
|
62
|
+
opacity: 0;
|
|
63
|
+
width: 16px;
|
|
64
|
+
height: 16px;
|
|
65
|
+
transition: opacity .2s, transform .2s;
|
|
66
|
+
position: absolute;
|
|
67
|
+
top: 50%;
|
|
68
|
+
left: 50%;
|
|
69
|
+
transform: translate(-50%, -50%);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.dropdownButton-Mj4g7p {
|
|
73
|
+
border: 1px solid var(--rp-c-divider-light);
|
|
74
|
+
background: var(--rp-c-bg);
|
|
75
|
+
height: 40px;
|
|
76
|
+
color: var(--rp-c-text-1);
|
|
77
|
+
cursor: pointer;
|
|
78
|
+
border-radius: 8px;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
align-items: center;
|
|
81
|
+
gap: 8px;
|
|
82
|
+
padding: 8px 12px;
|
|
83
|
+
font-size: 14px;
|
|
84
|
+
font-style: normal;
|
|
85
|
+
font-weight: 400;
|
|
86
|
+
line-height: 22px;
|
|
87
|
+
transition: background .3s, border .3s;
|
|
88
|
+
display: inline-flex;
|
|
89
|
+
position: relative;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.dropdownButton-Mj4g7p:hover, .dropdownButton-Mj4g7p.active-SacMuO {
|
|
93
|
+
background: var(--rp-c-bg-mute);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.dropdownArrow-UjqrjW {
|
|
97
|
+
transition: transform .2s;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.dropdownArrow-UjqrjW.rotated-YGs7Vp {
|
|
101
|
+
transform: rotate(180deg);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.dropdownMenu-_ggfjT {
|
|
105
|
+
z-index: 2;
|
|
106
|
+
border: 1px solid var(--rp-c-divider-light);
|
|
107
|
+
background: var(--rp-c-bg);
|
|
108
|
+
width: 250px;
|
|
109
|
+
color: var(--rp-c-text-1);
|
|
110
|
+
border-radius: 8px;
|
|
111
|
+
flex-direction: column;
|
|
112
|
+
align-items: flex-start;
|
|
113
|
+
margin-top: 4px;
|
|
114
|
+
padding: 8px;
|
|
115
|
+
animation: .15s ease-in-out fadeIn-_SWLWZ;
|
|
116
|
+
display: inline-flex;
|
|
117
|
+
position: absolute;
|
|
118
|
+
top: 100%;
|
|
119
|
+
left: -10%;
|
|
120
|
+
box-shadow: 0 4px 16px #0000000a;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@keyframes fadeIn-_SWLWZ {
|
|
124
|
+
0% {
|
|
125
|
+
opacity: 0;
|
|
126
|
+
transform: translateY(-4px);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
100% {
|
|
130
|
+
opacity: 1;
|
|
131
|
+
transform: translateY(0);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.dropdownItem-taWikf {
|
|
136
|
+
text-align: left;
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
background: none;
|
|
139
|
+
border: none;
|
|
140
|
+
border-radius: 8px;
|
|
141
|
+
align-items: center;
|
|
142
|
+
gap: 8px;
|
|
143
|
+
width: 100%;
|
|
144
|
+
padding: 8px 12px;
|
|
145
|
+
font-size: 14px;
|
|
146
|
+
display: flex;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.dropdownItem-taWikf:hover {
|
|
150
|
+
background: var(--rp-c-bg-mute);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.leftIcon-JI6iFK {
|
|
154
|
+
justify-content: center;
|
|
155
|
+
align-items: center;
|
|
156
|
+
width: 16px;
|
|
157
|
+
height: 16px;
|
|
158
|
+
font-size: 16px;
|
|
159
|
+
display: inline-flex;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.externalIcon-r8tMpa {
|
|
163
|
+
width: 16px;
|
|
164
|
+
height: 16px;
|
|
165
|
+
margin-left: auto;
|
|
166
|
+
font-size: 16px;
|
|
167
|
+
}
|
|
168
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { JSX } from 'react/jsx-runtime';
|
|
2
|
+
import type { default as React_2 } from 'react';
|
|
3
|
+
|
|
4
|
+
export declare function LlmsContainer(props: LlmsContainerProps): JSX.Element;
|
|
5
|
+
|
|
6
|
+
export declare interface LlmsContainerProps extends React_2.HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export declare function LlmsCopyButton(props: LlmsCopyButtonProps): JSX.Element;
|
|
10
|
+
|
|
11
|
+
export declare interface LlmsCopyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
12
|
+
/**
|
|
13
|
+
* Text by language, used with `useLang`.
|
|
14
|
+
* @default en: 'Copy Markdown', zh: '复制 Markdown'
|
|
15
|
+
*/
|
|
16
|
+
textByLang?: Record<string, string>;
|
|
17
|
+
/**
|
|
18
|
+
* Priority is higher than textByLang
|
|
19
|
+
* @default ''
|
|
20
|
+
*/
|
|
21
|
+
text?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Overrides the default click handler.
|
|
24
|
+
* If provided, the default copy to clipboard functionality will not be executed.
|
|
25
|
+
*/
|
|
26
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export declare const LlmsViewOptions: ({ options, text, textByLang, }: LlmsViewOptionsProps) => JSX.Element;
|
|
30
|
+
|
|
31
|
+
export declare interface LlmsViewOptionsProps extends React_2.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
32
|
+
/**
|
|
33
|
+
* Default options for the dropdown.
|
|
34
|
+
* @default ['markdownLink', 'chatgpt', 'claude']
|
|
35
|
+
* - 'chatgpt': Open in ChatGPT
|
|
36
|
+
* - 'claude': Open in Claude
|
|
37
|
+
*/
|
|
38
|
+
options?: Option_2[];
|
|
39
|
+
/**
|
|
40
|
+
* Button text by language, used with `useLang`.
|
|
41
|
+
* @default en: 'Open', zh: '打开'
|
|
42
|
+
*/
|
|
43
|
+
textByLang?: Record<string, string>;
|
|
44
|
+
/**
|
|
45
|
+
* Button text.
|
|
46
|
+
* Priority is higher than textByLang
|
|
47
|
+
* @default ''
|
|
48
|
+
*/
|
|
49
|
+
text?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
declare type Option_2 = {
|
|
53
|
+
title: string;
|
|
54
|
+
icon?: React_2.ReactNode;
|
|
55
|
+
onClick?: () => void;
|
|
56
|
+
} | {
|
|
57
|
+
title: string;
|
|
58
|
+
href: string;
|
|
59
|
+
icon?: React_2.ReactNode;
|
|
60
|
+
} | 'markdownLink' | 'chatgpt' | 'claude';
|
|
61
|
+
|
|
62
|
+
export declare function useMdUrl(): {
|
|
63
|
+
pathname: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export { }
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import "./index.css"
|
|
2
|
+
/*! For license information please see index.js.LICENSE.txt */
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { normalizeHref, useLang, usePageData, withBase } from "@rspress/core/runtime";
|
|
5
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
var _1 = "llmsContainer-glE3L4";
|
|
7
|
+
function LlmsContainer(props) {
|
|
8
|
+
return /*#__PURE__*/ jsx("div", {
|
|
9
|
+
...props,
|
|
10
|
+
className: `rp-not-doc ${_1}`
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function IconCopy({ className }) {
|
|
14
|
+
return /*#__PURE__*/ jsxs("svg", {
|
|
15
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
16
|
+
width: "16",
|
|
17
|
+
height: "16",
|
|
18
|
+
viewBox: "0 0 16 16",
|
|
19
|
+
className: className,
|
|
20
|
+
fill: "none",
|
|
21
|
+
children: [
|
|
22
|
+
/*#__PURE__*/ jsx("path", {
|
|
23
|
+
d: "M4.33301 4.14386V2.60416C4.33301 2.08639 4.75274 1.66666 5.27051 1.66666H13.3955C13.9133 1.66666 14.333 2.08639 14.333 2.60416V10.7292C14.333 11.2469 13.9133 11.6667 13.3955 11.6667H11.8384",
|
|
24
|
+
stroke: "#808080",
|
|
25
|
+
strokeWidth: "1.33333",
|
|
26
|
+
strokeLinecap: "round",
|
|
27
|
+
strokeLinejoin: "round"
|
|
28
|
+
}),
|
|
29
|
+
/*#__PURE__*/ jsx("path", {
|
|
30
|
+
d: "M10.7295 4.33334H2.60449C2.08673 4.33334 1.66699 4.75308 1.66699 5.27084V13.3958C1.66699 13.9136 2.08673 14.3333 2.60449 14.3333H10.7295C11.2473 14.3333 11.667 13.9136 11.667 13.3958V5.27084C11.667 4.75308 11.2473 4.33334 10.7295 4.33334Z",
|
|
31
|
+
stroke: "#808080",
|
|
32
|
+
strokeWidth: "1.33333",
|
|
33
|
+
strokeLinejoin: "round"
|
|
34
|
+
})
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
var LlmsCopyButton_module_1 = "iconContainer-G_2NC6";
|
|
39
|
+
var _2 = "iconCopy-g1n4MZ";
|
|
40
|
+
var _3 = "iconSuccess-PId4Mj";
|
|
41
|
+
var _4 = "llmsCopyButtonContainer-osHvFn";
|
|
42
|
+
var _5 = "loading-p5nEhg";
|
|
43
|
+
var _6 = "success-F4Qj8u";
|
|
44
|
+
function routePathToMdPath(routePath) {
|
|
45
|
+
let url = routePath;
|
|
46
|
+
url = normalizeHref(url, false);
|
|
47
|
+
url = url.replace(/\.html$/, '.md');
|
|
48
|
+
return withBase(url);
|
|
49
|
+
}
|
|
50
|
+
function useMdUrl() {
|
|
51
|
+
const { page } = usePageData();
|
|
52
|
+
const mdPath = useMemo(()=>{
|
|
53
|
+
const pathname = routePathToMdPath(page.routePath);
|
|
54
|
+
return {
|
|
55
|
+
pathname
|
|
56
|
+
};
|
|
57
|
+
}, [
|
|
58
|
+
page.routePath
|
|
59
|
+
]);
|
|
60
|
+
return mdPath;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Inspired from fumadocs docsite
|
|
64
|
+
* @from https://github.com/fuma-nama/fumadocs/blob/5723bbe58ef805a5421a780abf235a10b251be2f/apps/docs/app/docs/%5B...slug%5D/page.client.tsx#L11
|
|
65
|
+
* @license MIT
|
|
66
|
+
*/ function IconSuccess({ className }) {
|
|
67
|
+
return /*#__PURE__*/ jsx("svg", {
|
|
68
|
+
width: "32",
|
|
69
|
+
height: "32",
|
|
70
|
+
viewBox: "0 0 30 30",
|
|
71
|
+
className: className,
|
|
72
|
+
children: /*#__PURE__*/ jsx("path", {
|
|
73
|
+
fill: "#49cd37",
|
|
74
|
+
d: "m13 24l-9-9l1.414-1.414L13 21.171L26.586 7.586L28 9L13 24z"
|
|
75
|
+
})
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const cache = new Map();
|
|
79
|
+
function LlmsCopyButton(props) {
|
|
80
|
+
const { onClick, text, textByLang = {
|
|
81
|
+
zh: '复制 Markdown',
|
|
82
|
+
en: 'Copy Markdown'
|
|
83
|
+
}, ...otherProps } = props;
|
|
84
|
+
const lang = useLang();
|
|
85
|
+
const { pathname } = useMdUrl();
|
|
86
|
+
const [isLoading, setLoading] = useState(false);
|
|
87
|
+
const [isFinished, setFinished] = useState(false);
|
|
88
|
+
const timer = useRef(null);
|
|
89
|
+
const handleClick = useCallback(async ()=>{
|
|
90
|
+
setLoading(true);
|
|
91
|
+
const url = pathname;
|
|
92
|
+
try {
|
|
93
|
+
const content = cache.get(url) ?? await fetch(url).then((res)=>res.text());
|
|
94
|
+
cache.set(url, content);
|
|
95
|
+
await navigator.clipboard.writeText(content);
|
|
96
|
+
} finally{
|
|
97
|
+
setLoading(false);
|
|
98
|
+
setFinished(true);
|
|
99
|
+
if (timer.current) {
|
|
100
|
+
clearTimeout(timer.current);
|
|
101
|
+
timer.current = null;
|
|
102
|
+
}
|
|
103
|
+
timer.current = window.setTimeout(()=>{
|
|
104
|
+
setFinished(false);
|
|
105
|
+
timer.current = null;
|
|
106
|
+
}, 500);
|
|
107
|
+
}
|
|
108
|
+
}, [
|
|
109
|
+
pathname
|
|
110
|
+
]);
|
|
111
|
+
if (!pathname) return /*#__PURE__*/ jsx(Fragment, {});
|
|
112
|
+
return /*#__PURE__*/ jsxs("button", {
|
|
113
|
+
...otherProps,
|
|
114
|
+
disabled: isLoading,
|
|
115
|
+
className: [
|
|
116
|
+
'rp-not-doc',
|
|
117
|
+
_4,
|
|
118
|
+
isLoading ? _5 : '',
|
|
119
|
+
isFinished ? _6 : ''
|
|
120
|
+
].filter(Boolean).join(' '),
|
|
121
|
+
onClick: onClick ?? handleClick,
|
|
122
|
+
children: [
|
|
123
|
+
/*#__PURE__*/ jsxs("div", {
|
|
124
|
+
className: LlmsCopyButton_module_1,
|
|
125
|
+
children: [
|
|
126
|
+
/*#__PURE__*/ jsx(IconSuccess, {
|
|
127
|
+
className: _3
|
|
128
|
+
}),
|
|
129
|
+
/*#__PURE__*/ jsx(IconCopy, {
|
|
130
|
+
className: _2
|
|
131
|
+
})
|
|
132
|
+
]
|
|
133
|
+
}),
|
|
134
|
+
/*#__PURE__*/ jsx("span", {
|
|
135
|
+
children: text ?? textByLang?.[lang] ?? 'Copy Markdown'
|
|
136
|
+
})
|
|
137
|
+
]
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
var LlmsViewOptions_module_1 = "active-SacMuO";
|
|
141
|
+
var LlmsViewOptions_module_2 = "dropdownArrow-UjqrjW";
|
|
142
|
+
var LlmsViewOptions_module_3 = "dropdownButton-Mj4g7p";
|
|
143
|
+
var LlmsViewOptions_module_4 = "dropdownItem-taWikf";
|
|
144
|
+
var LlmsViewOptions_module_5 = "dropdownMenu-_ggfjT";
|
|
145
|
+
var LlmsViewOptions_module_6 = "externalIcon-r8tMpa";
|
|
146
|
+
var _8 = "leftIcon-JI6iFK";
|
|
147
|
+
var _9 = "rotated-YGs7Vp";
|
|
148
|
+
/**
|
|
149
|
+
* Inspired from fumadocs docsite
|
|
150
|
+
* @from https://github.com/fuma-nama/fumadocs/blob/5723bbe58ef805a5421a780abf235a10b251be2f/apps/docs/app/docs/%5B...slug%5D/page.client.tsx#L11
|
|
151
|
+
* @license MIT
|
|
152
|
+
*/ const IconArrow = ({ className })=>/*#__PURE__*/ jsx("svg", {
|
|
153
|
+
className: className,
|
|
154
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
155
|
+
width: "16",
|
|
156
|
+
height: "16",
|
|
157
|
+
viewBox: "0 0 15 16",
|
|
158
|
+
fill: "none",
|
|
159
|
+
children: /*#__PURE__*/ jsx("path", {
|
|
160
|
+
d: "M11.125 5.27885L7 9.72115L2.875 5.27885",
|
|
161
|
+
stroke: "#4E5969",
|
|
162
|
+
strokeWidth: "1.125",
|
|
163
|
+
strokeLinecap: "round",
|
|
164
|
+
strokeLinejoin: "round"
|
|
165
|
+
})
|
|
166
|
+
});
|
|
167
|
+
const IconExternalLink = ()=>/*#__PURE__*/ jsxs("svg", {
|
|
168
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
169
|
+
width: "16",
|
|
170
|
+
height: "16",
|
|
171
|
+
viewBox: "0 0 16 16",
|
|
172
|
+
fill: "none",
|
|
173
|
+
children: [
|
|
174
|
+
/*#__PURE__*/ jsx("path", {
|
|
175
|
+
d: "M9.33301 2H13.9997V6.66667",
|
|
176
|
+
stroke: "#808080",
|
|
177
|
+
strokeWidth: "1.33333",
|
|
178
|
+
strokeLinecap: "round",
|
|
179
|
+
strokeLinejoin: "round"
|
|
180
|
+
}),
|
|
181
|
+
/*#__PURE__*/ jsx("path", {
|
|
182
|
+
d: "M14 9.82457V13C14 13.5523 13.5523 14 13 14H3C2.44772 14 2 13.5523 2 13V3C2 2.44772 2.44772 2 3 2H6",
|
|
183
|
+
stroke: "#808080",
|
|
184
|
+
strokeWidth: "1.33333",
|
|
185
|
+
strokeLinecap: "round",
|
|
186
|
+
strokeLinejoin: "round"
|
|
187
|
+
}),
|
|
188
|
+
/*#__PURE__*/ jsx("path", {
|
|
189
|
+
d: "M8.59961 7.39996L13.6996 2.29996",
|
|
190
|
+
stroke: "#808080",
|
|
191
|
+
strokeWidth: "1.33333",
|
|
192
|
+
strokeLinecap: "round",
|
|
193
|
+
strokeLinejoin: "round"
|
|
194
|
+
})
|
|
195
|
+
]
|
|
196
|
+
});
|
|
197
|
+
const LlmsViewOptions = ({ options = [
|
|
198
|
+
'markdownLink',
|
|
199
|
+
'chatgpt',
|
|
200
|
+
'claude'
|
|
201
|
+
], text, textByLang = {
|
|
202
|
+
en: 'Open',
|
|
203
|
+
zh: '打开'
|
|
204
|
+
} })=>{
|
|
205
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
206
|
+
const dropdownRef = useRef(null);
|
|
207
|
+
useEffect(()=>{
|
|
208
|
+
const handleClickOutside = (event)=>{
|
|
209
|
+
if (dropdownRef.current && event.target && !dropdownRef.current.contains(event.target)) setIsOpen(false);
|
|
210
|
+
};
|
|
211
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
212
|
+
return ()=>{
|
|
213
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
214
|
+
};
|
|
215
|
+
}, []);
|
|
216
|
+
const toggleDropdown = ()=>{
|
|
217
|
+
setIsOpen(!isOpen);
|
|
218
|
+
};
|
|
219
|
+
const { pathname } = useMdUrl();
|
|
220
|
+
const lang = useLang();
|
|
221
|
+
const isEn = !lang || 'en' === lang;
|
|
222
|
+
const items = useMemo(()=>{
|
|
223
|
+
const fullMarkdownUrl = 'undefined' != typeof window ? new URL(pathname, window.location.origin).toString() : 'loading';
|
|
224
|
+
const q = `Read ${fullMarkdownUrl}, I want to ask questions about it.`;
|
|
225
|
+
return {
|
|
226
|
+
markdownLink: {
|
|
227
|
+
title: isEn ? 'Copy Markdown link' : '复制 Markdown 链接',
|
|
228
|
+
icon: /*#__PURE__*/ jsx("svg", {
|
|
229
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
230
|
+
viewBox: "0 0 24 24",
|
|
231
|
+
width: "24",
|
|
232
|
+
height: "24",
|
|
233
|
+
children: /*#__PURE__*/ jsxs("g", {
|
|
234
|
+
fill: "none",
|
|
235
|
+
stroke: "currentColor",
|
|
236
|
+
strokeLinecap: "round",
|
|
237
|
+
strokeLinejoin: "round",
|
|
238
|
+
strokeWidth: "2",
|
|
239
|
+
children: [
|
|
240
|
+
/*#__PURE__*/ jsx("path", {
|
|
241
|
+
d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"
|
|
242
|
+
}),
|
|
243
|
+
/*#__PURE__*/ jsx("path", {
|
|
244
|
+
d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
|
|
245
|
+
})
|
|
246
|
+
]
|
|
247
|
+
})
|
|
248
|
+
}),
|
|
249
|
+
onClick: ()=>{
|
|
250
|
+
navigator.clipboard.writeText(fullMarkdownUrl);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
chatgpt: {
|
|
254
|
+
title: isEn ? 'Open in ChatGPT' : '在 ChatGPT 中打开',
|
|
255
|
+
href: `https://chatgpt.com/?${new URLSearchParams({
|
|
256
|
+
hints: 'search',
|
|
257
|
+
q
|
|
258
|
+
})}`,
|
|
259
|
+
icon: /*#__PURE__*/ jsxs("svg", {
|
|
260
|
+
role: "img",
|
|
261
|
+
viewBox: "0 0 24 24",
|
|
262
|
+
fill: "currentColor",
|
|
263
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
264
|
+
children: [
|
|
265
|
+
/*#__PURE__*/ jsx("title", {
|
|
266
|
+
children: "OpenAI"
|
|
267
|
+
}),
|
|
268
|
+
/*#__PURE__*/ jsx("path", {
|
|
269
|
+
d: "M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"
|
|
270
|
+
})
|
|
271
|
+
]
|
|
272
|
+
})
|
|
273
|
+
},
|
|
274
|
+
claude: {
|
|
275
|
+
title: isEn ? 'Open in Claude' : '在 Claude 中打开',
|
|
276
|
+
href: `https://claude.ai/new?${new URLSearchParams({
|
|
277
|
+
q
|
|
278
|
+
})}`,
|
|
279
|
+
icon: /*#__PURE__*/ jsxs("svg", {
|
|
280
|
+
fill: "currentColor",
|
|
281
|
+
role: "img",
|
|
282
|
+
viewBox: "0 0 24 24",
|
|
283
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
284
|
+
children: [
|
|
285
|
+
/*#__PURE__*/ jsx("title", {
|
|
286
|
+
children: "Anthropic"
|
|
287
|
+
}),
|
|
288
|
+
/*#__PURE__*/ jsx("path", {
|
|
289
|
+
d: "M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z"
|
|
290
|
+
})
|
|
291
|
+
]
|
|
292
|
+
})
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}, [
|
|
296
|
+
pathname,
|
|
297
|
+
isEn
|
|
298
|
+
]);
|
|
299
|
+
return /*#__PURE__*/ jsx(Fragment, {
|
|
300
|
+
children: /*#__PURE__*/ jsxs("button", {
|
|
301
|
+
ref: dropdownRef,
|
|
302
|
+
className: [
|
|
303
|
+
'rp-not-doc',
|
|
304
|
+
LlmsViewOptions_module_3,
|
|
305
|
+
isOpen ? LlmsViewOptions_module_1 : ''
|
|
306
|
+
].filter(Boolean).join(' '),
|
|
307
|
+
type: "button",
|
|
308
|
+
onClick: toggleDropdown,
|
|
309
|
+
children: [
|
|
310
|
+
text ?? textByLang[lang] ?? 'Open',
|
|
311
|
+
/*#__PURE__*/ jsx(IconArrow, {
|
|
312
|
+
className: `${LlmsViewOptions_module_2} ${isOpen ? _9 : ''}`
|
|
313
|
+
}),
|
|
314
|
+
isOpen && /*#__PURE__*/ jsx("div", {
|
|
315
|
+
className: LlmsViewOptions_module_5,
|
|
316
|
+
children: options.map((item)=>{
|
|
317
|
+
let displayItem = item;
|
|
318
|
+
if ('markdownLink' === item) displayItem = items.markdownLink;
|
|
319
|
+
else if ('chatgpt' === item) displayItem = items.chatgpt;
|
|
320
|
+
else if ('claude' === item) displayItem = items.claude;
|
|
321
|
+
if (displayItem.href) return /*#__PURE__*/ jsxs("a", {
|
|
322
|
+
className: LlmsViewOptions_module_4,
|
|
323
|
+
href: displayItem.href,
|
|
324
|
+
target: "_blank",
|
|
325
|
+
rel: "noopener noreferrer",
|
|
326
|
+
children: [
|
|
327
|
+
/*#__PURE__*/ jsx("span", {
|
|
328
|
+
className: _8,
|
|
329
|
+
children: displayItem.icon
|
|
330
|
+
}),
|
|
331
|
+
/*#__PURE__*/ jsx("span", {
|
|
332
|
+
children: displayItem.title
|
|
333
|
+
}),
|
|
334
|
+
/*#__PURE__*/ jsx("span", {
|
|
335
|
+
className: LlmsViewOptions_module_6,
|
|
336
|
+
children: /*#__PURE__*/ jsx(IconExternalLink, {})
|
|
337
|
+
})
|
|
338
|
+
]
|
|
339
|
+
}, displayItem.title);
|
|
340
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
341
|
+
className: LlmsViewOptions_module_4,
|
|
342
|
+
onClick: displayItem.onClick,
|
|
343
|
+
children: [
|
|
344
|
+
/*#__PURE__*/ jsx("span", {
|
|
345
|
+
className: _8,
|
|
346
|
+
children: displayItem.icon
|
|
347
|
+
}),
|
|
348
|
+
/*#__PURE__*/ jsx("span", {
|
|
349
|
+
children: displayItem.title
|
|
350
|
+
})
|
|
351
|
+
]
|
|
352
|
+
}, displayItem.title);
|
|
353
|
+
})
|
|
354
|
+
})
|
|
355
|
+
]
|
|
356
|
+
})
|
|
357
|
+
});
|
|
358
|
+
};
|
|
359
|
+
export { LlmsContainer, LlmsCopyButton, LlmsViewOptions, useMdUrl };
|
package/package.json
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rspress/plugin-llms",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-rc.0",
|
|
4
4
|
"description": "A plugin for rspress to generate llms.txt, llms-full.txt, md files to let llm understand your website.",
|
|
5
5
|
"bugs": "https://github.com/web-infra-dev/rspress/issues",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/web-infra-dev/rspress",
|
|
8
|
+
"url": "git+https://github.com/web-infra-dev/rspress.git",
|
|
9
9
|
"directory": "packages/plugin-llm"
|
|
10
10
|
},
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"type": "module",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./runtime": {
|
|
19
|
+
"types": "./dist/runtime/index.d.ts",
|
|
20
|
+
"default": "./dist/runtime/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
13
23
|
"main": "./dist/index.js",
|
|
14
24
|
"module": "./dist/index.js",
|
|
15
25
|
"types": "./dist/index.d.ts",
|
|
@@ -18,34 +28,35 @@
|
|
|
18
28
|
"static"
|
|
19
29
|
],
|
|
20
30
|
"dependencies": {
|
|
21
|
-
"remark-mdx": "^3.1.
|
|
31
|
+
"remark-mdx": "^3.1.1",
|
|
22
32
|
"remark-parse": "^11.0.0",
|
|
23
33
|
"remark-stringify": "^11.0.0",
|
|
24
34
|
"unified": "^11.0.5",
|
|
25
|
-
"unist-util-visit": "^5.0.0"
|
|
26
|
-
"unist-util-visit-children": "^3.0.0",
|
|
27
|
-
"@rspress/shared": "2.0.0-beta.9"
|
|
35
|
+
"unist-util-visit": "^5.0.0"
|
|
28
36
|
},
|
|
29
37
|
"devDependencies": {
|
|
30
|
-
"@microsoft/api-extractor": "^7.
|
|
31
|
-
"@rsbuild/core": "~1.3
|
|
32
|
-
"@
|
|
38
|
+
"@microsoft/api-extractor": "^7.54.0",
|
|
39
|
+
"@rsbuild/core": "~1.6.3",
|
|
40
|
+
"@rsbuild/plugin-react": "~1.4.2",
|
|
41
|
+
"@rsbuild/plugin-sass": "~1.4.0",
|
|
42
|
+
"@rslib/core": "0.16.1",
|
|
33
43
|
"@types/hast": "^3.0.4",
|
|
34
44
|
"@types/node": "^22.8.1",
|
|
45
|
+
"@types/react": "^19.2.2",
|
|
46
|
+
"react": "^19.2.0",
|
|
47
|
+
"rsbuild-plugin-publint": "^0.3.3",
|
|
35
48
|
"typescript": "^5.8.2",
|
|
36
49
|
"vfile": "^6.0.3",
|
|
37
|
-
"@rspress/config": "1.0.0"
|
|
38
|
-
"@rspress/runtime": "2.0.0-beta.9"
|
|
50
|
+
"@rspress/config": "1.0.0"
|
|
39
51
|
},
|
|
40
52
|
"peerDependencies": {
|
|
41
|
-
"@rspress/core": "^2.0.0-
|
|
53
|
+
"@rspress/core": "^2.0.0-rc.0"
|
|
42
54
|
},
|
|
43
55
|
"engines": {
|
|
44
56
|
"node": ">=18.0.0"
|
|
45
57
|
},
|
|
46
58
|
"publishConfig": {
|
|
47
59
|
"access": "public",
|
|
48
|
-
"provenance": true,
|
|
49
60
|
"registry": "https://registry.npmjs.org/"
|
|
50
61
|
},
|
|
51
62
|
"scripts": {
|