@rspress/plugin-llms 2.0.0-beta.8 → 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/README.md CHANGED
@@ -1,3 +1,3 @@
1
1
  # @rspress/plugin-llms
2
2
 
3
- [Documentation](https://rspress.dev/plugin/official-plugins/llms)
3
+ [Documentation](https://rspress.rs/plugin/official-plugins/llms)
package/dist/index.d.ts CHANGED
@@ -1,7 +1,19 @@
1
- import type { PageIndexInfo } from '@rspress/shared';
2
- import type { RspressPlugin } from '@rspress/shared';
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?: boolean | 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?: boolean;
46
+ mdFiles?: false | MdFiles;
24
47
  /**
25
48
  * Whether to generate llms-full.txt.
26
- * @default true
27
49
  */
28
- llmsFullTxt?: boolean;
50
+ llmsFullTxt?: false | LlmsFullTxt;
29
51
  /**
30
52
  * Whether to include some routes from llms.txt.
31
- * @param context
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?: Options): RspressPlugin;
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
- /*! For license information please see index.js.LICENSE.txt */
2
- import * as __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__ from "node:path";
3
- import * as __WEBPACK_EXTERNAL_MODULE__rspress_shared_baa012d0__ from "@rspress/shared";
4
- import * as __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__ from "@rspress/shared/logger";
5
- import * as __WEBPACK_EXTERNAL_MODULE__rspress_core_1b2e46ce__ from "@rspress/core";
6
- import * as __WEBPACK_EXTERNAL_MODULE_remark_mdx_177f7527__ from "remark-mdx";
7
- import * as __WEBPACK_EXTERNAL_MODULE_remark_parse_85cfcb3b__ from "remark-parse";
8
- import * as __WEBPACK_EXTERNAL_MODULE_remark_stringify_a75cbb8b__ from "remark-stringify";
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 = (0, __WEBPACK_EXTERNAL_MODULE__rspress_shared_baa012d0__.normalizeHref)(url, false);
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 } = 'boolean' == typeof llmsTxtOptions ? {} : llmsTxtOptions;
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
- (0, __WEBPACK_EXTERNAL_MODULE_unist_util_visit_555e002a__.visit)(tree, 'mdxjsEsm', (node)=>{
73
+ visit(tree, 'mdxjsEsm', (node)=>{
185
74
  if (node.data?.estree?.body[0].type === 'ImportDeclaration') {
186
75
  node.value = '';
187
- return __WEBPACK_EXTERNAL_MODULE_unist_util_visit_555e002a__.SKIP;
76
+ return SKIP;
188
77
  }
189
78
  });
190
- (0, __WEBPACK_EXTERNAL_MODULE_unist_util_visit_555e002a__.visit)(tree, 'mdxJsxFlowElement', (node, index, parent)=>{
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
- (0, __WEBPACK_EXTERNAL_MODULE_unist_util_visit_555e002a__.visit)(tree, 'mdxJsxTextElement', (node, index, parent)=>{
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 mdxToMd(content, filepath, docDirectory, routeService) {
204
- return (0, __WEBPACK_EXTERNAL_MODULE_unified__.unified)().use(__WEBPACK_EXTERNAL_MODULE_remark_parse_85cfcb3b__["default"]).use(__WEBPACK_EXTERNAL_MODULE_remark_mdx_177f7527__["default"]).use(mdxToMdPlugin).use(__WEBPACK_EXTERNAL_MODULE__rspress_core_1b2e46ce__.remarkPluginNormalizeLink, {
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
- root: docDirectory,
207
- routeService
208
- }).use(__WEBPACK_EXTERNAL_MODULE_remark_stringify_a75cbb8b__["default"]).process({
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, baseRef, docDirectoryRef, routeServiceRef, nav, rspressPluginOptions })=>({
214
- name: 'rsbuild-plugin-llms',
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 = true, mdFiles = true, llmsFullTxt = true, include, exclude } = rspressPluginOptions;
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((0, __WEBPACK_EXTERNAL_MODULE__rspress_shared_baa012d0__.removeBase)(routePath, base))) return void pageArrayItem.push(pageData);
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, base);
146
+ for (const array of pageArray)organizeBySidebar(sidebar, array);
242
147
  if (llmsTxt) {
243
- const llmsTxtContent = generateLlmsTxt(pageArray, navList, others, rspressPluginOptions.llmsTxt ?? {}, titleRef.current, descriptionRef.current);
148
+ const { name } = llmsTxt;
149
+ const llmsTxtContent = generateLlmsTxt(pageArray, navList, others, llmsTxt, titleRef.current, descriptionRef.current, baseRef.current);
244
150
  api.processAssets({
245
- targets: disableSSG ? [
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('llms.txt', source);
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' !== __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].extname(filepath).slice(1);
168
+ const isMD = 'mdx' !== node_path.extname(filepath).slice(1);
263
169
  let mdContent;
264
- if (isMD) mdContent = content;
265
- else try {
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
- __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.debug(e);
173
+ logger.debug('normalizeMdFile failed', pageData.routePath, e);
269
174
  mdContent = content;
270
- return;
271
175
  }
272
- pageData.mdContent = mdContent;
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
- targets: disableSSG ? [
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 llmsFullTxtContent = generateLlmsFullTxt(pageArray, navList, others);
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('llms-full.txt', source);
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, base) {
244
+ function organizeBySidebar(sidebar, pages) {
341
245
  if (0 === pages.length) return;
342
246
  const pageItem = pages[0];
343
- const currSidebar = (0, __WEBPACK_EXTERNAL_MODULE__rspress_shared_baa012d0__.getSidebarDataGroup)(sidebar, pageItem.routePath, base);
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
- const aIndex = orderList.findIndex((order)=>matchPath(order, a.routePath));
348
- const bIndex = orderList.findIndex((order)=>matchPath(order, b.routePath));
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 pluginLlms(options = {}) {
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 };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Inspired from fumadocs docsite
3
+ * @from https://github.com/fuma-nama/fumadocs/blob/5723bbe58ef805a5421a780abf235a10b251be2f/apps/docs/app/docs/%5B...slug%5D/page.client.tsx#L11
4
+ * @license MIT
5
+ */
package/package.json CHANGED
@@ -1,15 +1,25 @@
1
1
  {
2
2
  "name": "@rspress/plugin-llms",
3
- "version": "2.0.0-beta.8",
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.0",
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.8"
35
+ "unist-util-visit": "^5.0.0"
28
36
  },
29
37
  "devDependencies": {
30
- "@microsoft/api-extractor": "^7.52.8",
31
- "@rsbuild/core": "~1.3.21",
32
- "@rslib/core": "0.8.0",
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/runtime": "2.0.0-beta.8",
38
50
  "@rspress/config": "1.0.0"
39
51
  },
40
52
  "peerDependencies": {
41
- "@rspress/core": "^2.0.0-beta.8"
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": {
@@ -1,10 +0,0 @@
1
- /**
2
- * @remix-run/router v1.22.0
3
- *
4
- * Copyright (c) Remix Software Inc.
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE.md file in the root directory of this source tree.
8
- *
9
- * @license MIT
10
- */